2024-04-20 16:23:08 +00:00
/*
* Descent 3
* Copyright ( C ) 2024 Parallax Software
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2024-05-06 15:12:44 +00:00
- - - HISTORICAL COMMENTS FOLLOW - - -
2024-04-19 20:58:24 +00:00
* $ Logfile : / DescentIII / Main / editor / editor_lighting . cpp $
* $ Revision : 1.1 .1 .1 $
* $ Date : 2003 - 08 - 26 03 : 57 : 38 $
* $ Author : kevinb $
* $ NoKeywords : $
*/
# include <windows.h>
# include "3d.h"
# include "texture.h"
# include "gametexture.h"
# include "erooms.h"
# include "editor_lighting.h"
# include "descent.h"
# include "room.h"
# include "lightmap.h"
# include "polymodel.h"
# include <string.h>
# include <stdlib.h>
# include "terrain.h"
# include "radiosity.h"
# include "lighting.h"
# include "findintersection.h"
# include "lightmap_info.h"
# include "object_lighting.h"
# include "d3edit.h"
# include "ddio.h"
# include "bsp.h"
# include "Application.h"
# include "AppDatabase.h"
# include "program.h"
# include "loadlevel.h"
# include "special_face.h"
# include "boa.h"
# include "mem.h"
typedef struct
{
float x , y ;
} spec_vertex ;
int AllowCombining = 1 ;
float GlobalMultiplier = 1.0 ;
rad_surface * Light_surfaces = NULL ;
vector ScratchCenters [ MAX_LIGHTMAP_INFOS ] ;
vector ScratchRVecs [ MAX_LIGHTMAP_INFOS ] ;
vector ScratchUVecs [ MAX_LIGHTMAP_INFOS ] ;
float Room_multiplier [ MAX_ROOMS + MAX_PALETTE_ROOMS ] ;
float Room_ambience_r [ MAX_ROOMS + MAX_PALETTE_ROOMS ] , Room_ambience_g [ MAX_ROOMS + MAX_PALETTE_ROOMS ] , Room_ambience_b [ MAX_ROOMS + MAX_PALETTE_ROOMS ] ;
2024-05-24 03:07:26 +00:00
uint8_t * TerrainLightSpeedup [ MAX_SATELLITES ] ;
2024-04-19 20:58:24 +00:00
int LightSpacing = LIGHTMAP_SPACING ;
int BestFit = 0 ;
int Square_surfaces = 0 ;
int Lightmaps_for_rad = 0 ;
// Ambient values for terrain
float Ambient_red = 0.0f , Ambient_green = 0.0f , Ambient_blue = 0.0f ;
void DoTerrainDynamicTable ( ) ;
2024-05-24 03:07:26 +00:00
uint8_t * Lightmap_mask = NULL ;
static uint8_t * Lmi_spoken_for ;
2024-04-19 20:58:24 +00:00
int Squeeze_lightmap_handle = - 1 ;
int FindEmptyMaskSpot ( int w , int h , int * dest_x , int * dest_y )
{
int cur_x = 0 , cur_y = 0 ;
int i , t ;
for ( cur_y = 0 ; cur_y < 128 ; cur_y + + )
{
if ( cur_y + h > 128 )
return 0 ;
for ( cur_x = 0 ; cur_x < 128 ; cur_x + + )
{
if ( cur_x + w > 128 )
continue ;
int hit_mask = 0 ;
for ( i = 0 ; i < h & & ! hit_mask ; i + + )
{
for ( t = 0 ; t < w & & ! hit_mask ; t + + )
{
if ( Lightmap_mask [ ( ( cur_y + i ) * 128 ) + cur_x + t ] )
hit_mask = 1 ;
}
}
if ( hit_mask = = 0 )
{
// Hurray! We found an empty spot
* dest_x = cur_x ;
* dest_y = cur_y ;
return 1 ;
}
}
}
return 0 ;
}
2024-05-24 03:16:40 +00:00
void CopySqueezeBodyAndEdges ( uint16_t * dest_data , uint16_t * src_data , int w , int h , int dest_x , int dest_y )
2024-04-19 20:58:24 +00:00
{
int i , t ;
ASSERT ( w + dest_x < = 126 ) ;
ASSERT ( h + dest_y < = 126 ) ;
ASSERT ( dest_x > = 0 & & dest_y > = 0 ) ;
// First copy the main body
for ( i = 0 ; i < h ; i + + )
{
for ( t = 0 ; t < w ; t + + )
{
dest_data [ ( ( dest_y + 1 + i ) * 128 ) + ( dest_x + 1 + t ) ] = src_data [ ( w * i ) + t ] ;
Lightmap_mask [ ( ( dest_y + i + 1 ) * 128 ) + dest_x + 1 + t ] = 1 ;
}
}
// Now copy the edges
// Left edge
for ( i = 0 ; i < h ; i + + )
{
dest_data [ ( ( dest_y + 1 + i ) * 128 ) + ( dest_x + 0 ) ] = src_data [ ( w * i ) + 0 ] ;
Lightmap_mask [ ( ( dest_y + i + 1 ) * 128 ) + dest_x + 0 ] = 1 ;
}
// Right edge
for ( i = 0 ; i < h ; i + + )
{
dest_data [ ( ( dest_y + 1 + i ) * 128 ) + ( dest_x + w + 1 ) ] = src_data [ ( w * i ) + ( w - 1 ) ] ;
Lightmap_mask [ ( ( dest_y + i + 1 ) * 128 ) + dest_x + w + 1 ] = 1 ;
}
// Top edge
for ( i = 0 ; i < w ; i + + )
{
dest_data [ ( dest_y * 128 ) + ( dest_x + i + 1 ) ] = src_data [ i ] ;
Lightmap_mask [ ( dest_y * 128 ) + ( dest_x + i + 1 ) ] = 1 ;
}
// Bottom edge
for ( i = 0 ; i < w ; i + + )
{
dest_data [ ( ( dest_y + 1 + h ) * 128 ) + ( dest_x + i + 1 ) ] = src_data [ ( w * ( h - 1 ) ) + i ] ;
Lightmap_mask [ ( ( dest_y + 1 + h ) * 128 ) + ( dest_x + i + 1 ) ] = 1 ;
}
// Now copy the corners
// Upper left
dest_data [ ( dest_y * 128 ) + ( dest_x ) ] = src_data [ 0 ] ;
Lightmap_mask [ ( dest_y * 128 ) + ( dest_x ) ] = 1 ;
// Upper right
dest_data [ ( dest_y * 128 ) + ( dest_x + w + 1 ) ] = src_data [ w - 1 ] ;
Lightmap_mask [ ( dest_y * 128 ) + ( dest_x + w + 1 ) ] = 1 ;
// Lower left
dest_data [ ( ( dest_y + h + 1 ) * 128 ) + ( dest_x ) ] = src_data [ w * ( h - 1 ) ] ;
Lightmap_mask [ ( ( dest_y + h + 1 ) * 128 ) + ( dest_x ) ] = 1 ;
// Lower right
dest_data [ ( ( dest_y + h + 1 ) * 128 ) + ( dest_x + w + 1 ) ] = src_data [ ( w * ( h - 1 ) ) + ( w - 1 ) ] ;
Lightmap_mask [ ( ( dest_y + h + 1 ) * 128 ) + ( dest_x + w + 1 ) ] = 1 ;
}
2024-05-24 03:16:40 +00:00
void CopySqueezeDataForRooms ( int roomnum , int facenum , uint16_t * dest_data , int dest_x , int dest_y )
2024-04-19 20:58:24 +00:00
{
room * rp = & Rooms [ roomnum ] ;
lightmap_info * lmi_ptr = & LightmapInfo [ rp - > faces [ facenum ] . lmi_handle ] ;
2024-05-24 03:16:40 +00:00
uint16_t * src_data = ( uint16_t * ) lm_data ( lmi_ptr - > lm_handle ) ;
2024-04-19 20:58:24 +00:00
int w = lmi_ptr - > width ;
int h = lmi_ptr - > height ;
// Copy over the actual lightmap data
CopySqueezeBodyAndEdges ( dest_data , src_data , w , h , dest_x , dest_y ) ;
// Now alter all face uvs that have this lightmap info
float dest_u = ( float ) ( dest_x + 1 ) / 128.0 ;
float dest_v = ( float ) ( dest_y + 1 ) / 128.0 ;
float u_scalar = ( float ) w / 128.0 ;
float v_scalar = ( float ) h / 128.0 ;
for ( int t = roomnum ; t < = Highest_room_index ; t + + )
{
room * this_rp = & Rooms [ t ] ;
if ( ! this_rp - > used )
continue ;
for ( int j = 0 ; j < this_rp - > num_faces ; j + + )
{
if ( ! ( this_rp - > faces [ j ] . flags & FF_LIGHTMAP ) )
continue ;
if ( this_rp - > faces [ j ] . lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ this_rp - > faces [ j ] . lmi_handle ] )
continue ;
if ( this_rp - > faces [ j ] . lmi_handle = = rp - > faces [ facenum ] . lmi_handle )
{
lmi_ptr - > x1 = dest_x + 1 ;
lmi_ptr - > y1 = dest_y + 1 ;
// We have to alter our uvs for this face to reflect our change
face * fp = & this_rp - > faces [ j ] ;
for ( int k = 0 ; k < fp - > num_verts ; k + + )
{
fp - > face_uvls [ k ] . u2 * = u_scalar ;
fp - > face_uvls [ k ] . u2 + = dest_u ;
fp - > face_uvls [ k ] . v2 * = v_scalar ;
fp - > face_uvls [ k ] . v2 + = dest_v ;
}
}
}
}
ASSERT ( rp - > faces [ facenum ] . lmi_handle ! = BAD_LMI_INDEX ) ;
Lmi_spoken_for [ rp - > faces [ facenum ] . lmi_handle ] = 1 ;
// Free our old lightmap
GameLightmaps [ lmi_ptr - > lm_handle ] . used = 1 ;
lm_FreeLightmap ( lmi_ptr - > lm_handle ) ;
lmi_ptr - > lm_handle = Squeeze_lightmap_handle ;
GameLightmaps [ Squeeze_lightmap_handle ] . used + + ;
}
2024-05-24 03:16:40 +00:00
void CopySqueezeDataForObject ( object * obj , int subnum , int facenum , uint16_t * dest_data , int dest_x , int dest_y )
2024-04-19 20:58:24 +00:00
{
lightmap_object_face * fp = & obj - > lm_object . lightmap_faces [ subnum ] [ facenum ] ;
lightmap_info * lmi_ptr = & LightmapInfo [ fp - > lmi_handle ] ;
2024-05-24 03:16:40 +00:00
uint16_t * src_data = ( uint16_t * ) lm_data ( lmi_ptr - > lm_handle ) ;
2024-04-19 20:58:24 +00:00
int t , k ;
int w = lmi_ptr - > width ;
int h = lmi_ptr - > height ;
// Copy over the actual lightmap data
CopySqueezeBodyAndEdges ( dest_data , src_data , w , h , dest_x , dest_y ) ;
// Now alter all face uvs that have this lightmap info
float dest_u = ( float ) ( dest_x + 1 ) / 128.0 ;
float dest_v = ( float ) ( dest_y + 1 ) / 128.0 ;
float u_scalar = ( float ) w / 128.0 ;
float v_scalar = ( float ) h / 128.0 ;
for ( int objnum = obj - Objects ; objnum ! = - 1 ; objnum = Objects [ objnum ] . next )
{
object * this_obj = & Objects [ objnum ] ;
if ( this_obj - > lighting_render_type ! = LRT_LIGHTMAPS )
continue ;
if ( ! this_obj - > lm_object . used )
continue ;
for ( t = 0 ; t < this_obj - > lm_object . num_models ; t + + )
{
if ( IsNonRenderableSubmodel ( & Poly_models [ this_obj - > rtype . pobj_info . model_num ] , t ) )
continue ;
for ( k = 0 ; k < this_obj - > lm_object . num_faces [ t ] ; k + + )
{
lightmap_object_face * this_fp = & this_obj - > lm_object . lightmap_faces [ t ] [ k ] ;
int lmi_handle = this_fp - > lmi_handle ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
if ( lmi_handle = = fp - > lmi_handle )
{
lmi_ptr - > x1 = dest_x + 1 ;
lmi_ptr - > y1 = dest_y + 1 ;
// We have to alter our uvs for this face to reflect our change
for ( int j = 0 ; j < this_fp - > num_verts ; j + + )
{
this_fp - > u2 [ j ] * = u_scalar ;
this_fp - > u2 [ j ] + = dest_u ;
this_fp - > v2 [ j ] * = v_scalar ;
this_fp - > v2 [ j ] + = dest_v ;
}
}
}
}
}
ASSERT ( fp - > lmi_handle ! = BAD_LMI_INDEX ) ;
Lmi_spoken_for [ fp - > lmi_handle ] = 1 ;
// Free our old lightmap
GameLightmaps [ lmi_ptr - > lm_handle ] . used = 1 ;
lm_FreeLightmap ( lmi_ptr - > lm_handle ) ;
lmi_ptr - > lm_handle = Squeeze_lightmap_handle ;
GameLightmaps [ Squeeze_lightmap_handle ] . used + + ;
}
// Simply clears flags for combine portals
void ClearCombinePortals ( int terrain )
{
for ( int i = 0 ; i < = Highest_room_index ; i + + )
{
room * rp = & Rooms [ i ] ;
if ( ! rp - > used )
continue ;
if ( terrain & & ! ( rp - > flags & RF_EXTERNAL ) )
continue ;
if ( ! terrain & & ( rp - > flags & RF_EXTERNAL ) )
continue ;
for ( int t = 0 ; t < rp - > num_portals ; t + + )
{
portal * portal_a = & rp - > portals [ t ] ;
portal_a - > flags & = ~ PF_COMBINED ;
}
}
}
// For rendering...combines all portals if they are on the same plane
void CheckCombinePortals ( int terrain )
{
ClearCombinePortals ( terrain ) ;
int combine_count = 0 ;
mprintf ( ( 0 , " Combining portals... " ) ) ;
for ( int i = 0 ; i < = Highest_room_index ; i + + )
{
room * rp = & Rooms [ i ] ;
if ( ! rp - > used )
continue ;
if ( terrain & & ! ( rp - > flags & RF_EXTERNAL ) )
continue ;
if ( ! terrain & & ( rp - > flags & RF_EXTERNAL ) )
continue ;
for ( int t = 0 ; t < rp - > num_portals ; t + + )
{
portal * portal_a = & rp - > portals [ t ] ;
face * face_a = & rp - > faces [ portal_a - > portal_face ] ;
if ( portal_a - > flags & PF_COMBINED )
continue ;
//Don't combine if face is breakable
if ( GameTextures [ face_a - > tmap ] . flags & TF_BREAKABLE )
continue ;
float dist_a = vm_DotProduct ( & rp - > verts [ face_a - > face_verts [ 0 ] ] , & face_a - > normal ) ;
for ( int k = 0 ; k < rp - > num_portals ; k + + )
{
portal * portal_b = & rp - > portals [ k ] ;
face * face_b = & rp - > faces [ portal_b - > portal_face ] ;
if ( portal_b - > flags & PF_COMBINED )
continue ;
//Don't combine if one portal is render-faces and the other is not
if ( ( portal_a - > flags & PF_RENDER_FACES ) ! = ( portal_b - > flags & PF_RENDER_FACES ) )
continue ;
//Don't combine if face is breakable
if ( GameTextures [ face_b - > tmap ] . flags & TF_BREAKABLE )
continue ;
if ( t = = k )
continue ;
//Check to see if the portals connect to the same room
if ( portal_a - > croom ! = portal_b - > croom )
continue ;
/*// Check to see if they share a normal
float dp = vm_DotProduct ( & face_a - > normal , & face_b - > normal ) ;
if ( dp < .95f )
continue ;
// Check to see if the distances are same
float dist_b = vm_DotProduct ( & rp - > verts [ face_b - > face_verts [ 0 ] ] , & face_b - > normal ) ;
if ( fabs ( dist_b - dist_a ) > .5 )
continue ;
int match = 0 ;
// Test to see if any points at all can touch
for ( int x = 0 ; x < face_a - > num_verts & & ! match ; x + + )
{
for ( int y = 0 ; y < face_b - > num_verts & & ! match ; y + + )
{
if ( PointsAreSame ( & rp - > verts [ face_a - > face_verts [ x ] ] , & rp - > verts [ face_b - > face_verts [ y ] ] ) )
match = 1 ;
}
}
if ( match = = 0 )
continue ;
//Check to see if the portals connect to the same room
if ( portal_a - > croom ! = portal_b - > croom )
continue ;
// Hurray! These portals can be combined*/
portal_a - > flags | = PF_COMBINED ;
portal_b - > flags | = PF_COMBINED ;
portal_a - > combine_master = t ;
portal_b - > combine_master = t ;
combine_count + + ;
}
}
}
mprintf ( ( 0 , " %d portals combined. \n " , combine_count ) ) ;
}
// Squeezes all the lightmaps down into as few 128x128s as possible
void SqueezeLightmaps ( int external , int target_roomnum )
{
int i , t , k ;
mprintf ( ( 0 , " Squeezing %s lightmaps, please wait... \n " , external ? " external " : " internal " ) ) ;
2024-05-24 03:07:26 +00:00
Lmi_spoken_for = ( uint8_t * ) mem_malloc ( MAX_LIGHTMAP_INFOS ) ;
Lightmap_mask = ( uint8_t * ) mem_malloc ( 128 * 128 ) ;
2024-04-19 20:58:24 +00:00
Squeeze_lightmap_handle = - 1 ;
ASSERT ( Lightmap_mask ) ;
ASSERT ( Lmi_spoken_for ) ;
memset ( Lmi_spoken_for , 0 , MAX_LIGHTMAP_INFOS ) ;
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
// Go through all the rooms and sqeeze them one by one
for ( i = 0 ; i < = Highest_room_index ; i + + )
{
room * rp = & Rooms [ i ] ;
if ( ! rp - > used )
continue ;
if ( rp - > flags & RF_NO_LIGHT )
continue ;
if ( external )
{
if ( ! ( rp - > flags & RF_EXTERNAL ) )
continue ;
}
else
{
if ( ( rp - > flags & RF_EXTERNAL ) )
continue ;
if ( target_roomnum ! = - 1 & & target_roomnum ! = i )
continue ;
}
// Go through each face
for ( t = 0 ; t < rp - > num_faces ; t + + )
{
face * fp = & rp - > faces [ t ] ;
int lmi_handle = fp - > lmi_handle ;
if ( ! ( fp - > flags & FF_LIGHTMAP ) )
continue ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
lightmap_info * lmi = & LightmapInfo [ lmi_handle ] ;
int dest_x , dest_y ;
int src_w = lmi - > width ;
int src_h = lmi - > height ;
if ( Squeeze_lightmap_handle = = - 1 )
{
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
Squeeze_lightmap_handle = lm_AllocLightmap ( 128 , 128 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * fill_data = ( uint16_t * ) lm_data ( Squeeze_lightmap_handle ) ;
2024-04-19 20:58:24 +00:00
memset ( fill_data , 0 , 128 * 128 * 2 ) ;
}
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
// Cool, found a spot
CopySqueezeDataForRooms ( i , t , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
else
{
// Can't find an empty slot, so search through all the other remaining faces
for ( k = t ; k < rp - > num_faces ; k + + )
{
face * fp = & rp - > faces [ k ] ;
int lmi_handle = fp - > lmi_handle ;
if ( ! ( fp - > flags & FF_LIGHTMAP ) )
continue ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
lightmap_info * lmi = & LightmapInfo [ lmi_handle ] ;
int src_w = lmi - > width ;
int src_h = lmi - > height ;
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
CopySqueezeDataForRooms ( i , k , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
}
// Now, allocate a new lightmap and start over
ASSERT ( Squeeze_lightmap_handle ! = - 1 ) ;
ASSERT ( GameLightmaps [ Squeeze_lightmap_handle ] . used ! = 1 ) ;
GameLightmaps [ Squeeze_lightmap_handle ] . used - - ;
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
Squeeze_lightmap_handle = lm_AllocLightmap ( 128 , 128 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * fill_data = ( uint16_t * ) lm_data ( Squeeze_lightmap_handle ) ;
2024-04-19 20:58:24 +00:00
memset ( fill_data , 0 , 128 * 128 * 2 ) ;
ASSERT ( Lmi_spoken_for [ lmi_handle ] = = 0 ) ;
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
CopySqueezeDataForRooms ( i , t , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
else
{
Int3 ( ) ; // Get Jason, how did this happen????
}
}
}
// Now search through all the objects in this room
for ( k = rp - > objects ; k ! = - 1 ; k = Objects [ k ] . next )
{
object * obj = & Objects [ k ] ;
if ( obj - > lighting_render_type ! = LRT_LIGHTMAPS )
continue ;
if ( ! obj - > lm_object . used )
continue ;
for ( t = 0 ; t < obj - > lm_object . num_models ; t + + )
{
if ( IsNonRenderableSubmodel ( & Poly_models [ obj - > rtype . pobj_info . model_num ] , t ) )
continue ;
for ( int j = 0 ; j < obj - > lm_object . num_faces [ t ] ; j + + )
{
lightmap_object_face * fp = & obj - > lm_object . lightmap_faces [ t ] [ j ] ;
int lmi_handle = fp - > lmi_handle ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
lightmap_info * lmi = & LightmapInfo [ lmi_handle ] ;
int dest_x , dest_y ;
int src_w = lmi - > width ;
int src_h = lmi - > height ;
if ( Squeeze_lightmap_handle = = - 1 )
{
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
Squeeze_lightmap_handle = lm_AllocLightmap ( 128 , 128 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * fill_data = ( uint16_t * ) lm_data ( Squeeze_lightmap_handle ) ;
2024-04-19 20:58:24 +00:00
memset ( fill_data , 0 , 128 * 128 * 2 ) ;
}
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
// Cool, found a spot
CopySqueezeDataForObject ( obj , t , j , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
else
{
// Can't find an empty slot, so search through all the other remaining faces
for ( int a = rp - > objects ; a ! = - 1 ; a = Objects [ a ] . next )
{
object * obj = & Objects [ a ] ;
if ( obj - > lighting_render_type ! = LRT_LIGHTMAPS )
continue ;
if ( ! obj - > lm_object . used )
continue ;
for ( int b = 0 ; b < obj - > lm_object . num_models ; b + + )
{
if ( IsNonRenderableSubmodel ( & Poly_models [ obj - > rtype . pobj_info . model_num ] , b ) )
continue ;
for ( int c = 0 ; c < obj - > lm_object . num_faces [ b ] ; c + + )
{
lightmap_object_face * fp = & obj - > lm_object . lightmap_faces [ b ] [ c ] ;
int lmi_handle = fp - > lmi_handle ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
lightmap_info * lmi = & LightmapInfo [ lmi_handle ] ;
int src_w = lmi - > width ;
int src_h = lmi - > height ;
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
CopySqueezeDataForObject ( obj , b , c , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
}
}
}
// Now, allocate a new lightmap and start over
ASSERT ( Squeeze_lightmap_handle ! = - 1 ) ;
ASSERT ( GameLightmaps [ Squeeze_lightmap_handle ] . used ! = 1 ) ;
GameLightmaps [ Squeeze_lightmap_handle ] . used - - ;
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
Squeeze_lightmap_handle = lm_AllocLightmap ( 128 , 128 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * fill_data = ( uint16_t * ) lm_data ( Squeeze_lightmap_handle ) ;
2024-04-19 20:58:24 +00:00
memset ( fill_data , 0 , 128 * 128 * 2 ) ;
ASSERT ( Lmi_spoken_for [ lmi_handle ] = = 0 ) ;
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
CopySqueezeDataForObject ( obj , t , j , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
else
{
Int3 ( ) ; // Get Jason, how did this happen????
}
}
}
}
}
}
if ( Squeeze_lightmap_handle ! = - 1 )
{
ASSERT ( GameLightmaps [ Squeeze_lightmap_handle ] . used ! = 1 ) ;
GameLightmaps [ Squeeze_lightmap_handle ] . used - - ;
}
// Squeeze all terrain object lightmaps now
if ( external )
{
Squeeze_lightmap_handle = - 1 ;
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
object * obj = & Objects [ i ] ;
if ( obj - > type = = OBJ_ROOM )
continue ;
if ( obj - > lighting_render_type ! = LRT_LIGHTMAPS )
continue ;
if ( ! obj - > lm_object . used )
continue ;
if ( ! OBJECT_OUTSIDE ( obj ) )
continue ;
for ( t = 0 ; t < obj - > lm_object . num_models ; t + + )
{
if ( IsNonRenderableSubmodel ( & Poly_models [ obj - > rtype . pobj_info . model_num ] , t ) )
continue ;
for ( k = 0 ; k < obj - > lm_object . num_faces [ t ] ; k + + )
{
lightmap_object_face * fp = & obj - > lm_object . lightmap_faces [ t ] [ k ] ;
int lmi_handle = fp - > lmi_handle ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
lightmap_info * lmi = & LightmapInfo [ lmi_handle ] ;
int dest_x , dest_y ;
int src_w = lmi - > width ;
int src_h = lmi - > height ;
if ( Squeeze_lightmap_handle = = - 1 )
{
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
Squeeze_lightmap_handle = lm_AllocLightmap ( 128 , 128 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * fill_data = ( uint16_t * ) lm_data ( Squeeze_lightmap_handle ) ;
2024-04-19 20:58:24 +00:00
memset ( fill_data , 0 , 128 * 128 * 2 ) ;
}
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
// Cool, found a spot
CopySqueezeDataForObject ( obj , t , k , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
else
{
// Search through the remaining objects on the terrain
for ( int a = i ; a < = Highest_object_index ; a + + )
{
object * obj = & Objects [ a ] ;
if ( ! obj - > lm_object . used )
continue ;
if ( ! OBJECT_OUTSIDE ( obj ) )
continue ;
for ( int b = 0 ; b < obj - > lm_object . num_models ; b + + )
{
if ( IsNonRenderableSubmodel ( & Poly_models [ obj - > rtype . pobj_info . model_num ] , b ) )
continue ;
for ( int c = 0 ; c < obj - > lm_object . num_faces [ b ] ; c + + )
{
lightmap_object_face * fp = & obj - > lm_object . lightmap_faces [ b ] [ c ] ;
int lmi_handle = fp - > lmi_handle ;
if ( lmi_handle = = BAD_LMI_INDEX )
continue ;
if ( Lmi_spoken_for [ lmi_handle ] )
continue ;
lightmap_info * lmi = & LightmapInfo [ lmi_handle ] ;
int src_w = lmi - > width ;
int src_h = lmi - > height ;
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
CopySqueezeDataForObject ( obj , b , c , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
}
}
}
// Now, allocate a new lightmap and start over
ASSERT ( Squeeze_lightmap_handle ! = - 1 ) ;
ASSERT ( GameLightmaps [ Squeeze_lightmap_handle ] . used ! = 1 ) ;
GameLightmaps [ Squeeze_lightmap_handle ] . used - - ;
memset ( Lightmap_mask , 0 , 128 * 128 ) ;
Squeeze_lightmap_handle = lm_AllocLightmap ( 128 , 128 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * fill_data = ( uint16_t * ) lm_data ( Squeeze_lightmap_handle ) ;
2024-04-19 20:58:24 +00:00
memset ( fill_data , 0 , 128 * 128 * 2 ) ;
ASSERT ( Lmi_spoken_for [ lmi_handle ] = = 0 ) ;
if ( FindEmptyMaskSpot ( src_w + 2 , src_h + 2 , & dest_x , & dest_y ) )
{
CopySqueezeDataForObject ( obj , t , k , lm_data ( Squeeze_lightmap_handle ) , dest_x , dest_y ) ;
}
else
{
Int3 ( ) ; // Get Jason, how did this happen????
}
}
}
}
}
if ( Squeeze_lightmap_handle ! = - 1 )
{
ASSERT ( GameLightmaps [ Squeeze_lightmap_handle ] . used ! = 1 ) ;
GameLightmaps [ Squeeze_lightmap_handle ] . used - - ;
}
}
mem_free ( Lightmap_mask ) ;
mem_free ( Lmi_spoken_for ) ;
mprintf ( ( 0 , " Done squeezing lightmaps. \n " ) ) ;
}
void ComputeSurfaceRes ( rad_surface * surf , room * rp , int facenum )
{
int i ;
float left = 1.1f , right = - 1 , top = 1.1f , bottom = - 1 ;
face * fp = & rp - > faces [ facenum ] ;
int lw = lmi_w ( fp - > lmi_handle ) ;
int lh = lmi_h ( fp - > lmi_handle ) ;
for ( i = 0 ; i < fp - > num_verts ; i + + )
{
if ( fp - > face_uvls [ i ] . u2 < left )
left = fp - > face_uvls [ i ] . u2 ;
if ( fp - > face_uvls [ i ] . u2 > right )
right = fp - > face_uvls [ i ] . u2 ;
if ( fp - > face_uvls [ i ] . v2 < top )
top = fp - > face_uvls [ i ] . v2 ;
if ( fp - > face_uvls [ i ] . v2 > bottom )
bottom = fp - > face_uvls [ i ] . v2 ;
}
float left_result = ( left * lw ) + .0001 ;
float right_result = ( right * lw ) + .0001 ;
float top_result = ( top * lh ) + .0001 ;
float bottom_result = ( bottom * lh ) + .0001 ;
surf - > x1 = floor ( left_result ) ;
surf - > x2 = floor ( right_result ) ;
surf - > y1 = floor ( top_result ) ;
surf - > y2 = floor ( bottom_result ) ;
surf - > xresolution = ( surf - > x2 - surf - > x1 ) ;
surf - > yresolution = ( surf - > y2 - surf - > y1 ) ;
// Adjust for a accuracy errors
if ( ( ( right_result ) - ( float ) surf - > x2 ) > .005 )
surf - > xresolution + + ;
if ( ( ( bottom_result ) - ( float ) surf - > y2 ) > .005 )
surf - > yresolution + + ;
if ( ( ( top_result ) - ( float ) surf - > y1 ) > .99 )
surf - > y1 + + ;
if ( ( ( left_result ) - ( float ) surf - > x1 ) > .99 )
surf - > x1 + + ;
ASSERT ( ( surf - > x1 + surf - > xresolution ) < = lw ) ;
ASSERT ( ( surf - > y1 + surf - > yresolution ) < = lh ) ;
}
// Take the computed volume spectra of a room and save it in the room struct
void AssignVolumeSpectraToRoom ( int roomnum )
{
ASSERT ( Rooms [ roomnum ] . used ) ;
ASSERT ( ! ( Rooms [ roomnum ] . flags & RF_EXTERNAL ) ) ;
ASSERT ( ! ( Rooms [ roomnum ] . flags & RF_NO_LIGHT ) ) ;
room * rp = & Rooms [ roomnum ] ;
int i , t , j ;
int w = rp - > volume_width ;
int h = rp - > volume_height ;
int d = rp - > volume_depth ;
for ( i = 0 ; i < d ; i + + )
{
for ( t = 0 ; t < h ; t + + )
{
for ( j = 0 ; j < w ; j + + )
{
spectra * this_spectra = & Volume_elements [ roomnum ] [ ( i * w * h ) + ( t * w ) + j ] . color ;
if ( this_spectra - > r < 0 )
{
Int3 ( ) ; // Shouldn't hit this
rp - > volume_lights [ ( i * w * h ) + ( t * w ) + j ] = INVISIBLE_VOLUME_ELEMENT ;
}
else
{
float rmax = GetMaxColor ( this_spectra ) ;
if ( rmax > 1.0 & & rmax > 0.0 )
{
this_spectra - > r / = rmax ;
this_spectra - > g / = rmax ;
this_spectra - > b / = rmax ;
}
int r = ( this_spectra - > r * 7 ) ;
r < < = 5 ;
int g = ( this_spectra - > g * 7 ) ;
g < < = 2 ;
int b = ( this_spectra - > b * 3 ) ;
2024-05-24 03:07:26 +00:00
uint8_t volume_color = r | g | b ;
2024-04-19 20:58:24 +00:00
if ( ! UseVolumeLights )
rp - > volume_lights [ ( i * w * h ) + ( t * w ) + j ] = 255 ;
else
rp - > volume_lights [ ( i * w * h ) + ( t * w ) + j ] = volume_color ;
}
}
}
}
}
// Returns 0 if there are bad faces in this level
int CheckForBadFaces ( int roomnum )
{
int i , t ;
for ( i = 0 ; i < = Highest_room_index ; i + + )
{
if ( roomnum ! = - 1 & & i ! = roomnum )
continue ;
room * rp = & Rooms [ i ] ;
if ( ! rp - > used )
continue ;
for ( t = 0 ; t < rp - > num_faces ; t + + )
{
if ( rp - > faces [ t ] . num_verts < 3 )
return 0 ; // Bad face detected!
}
}
return 1 ;
}
// Calculates radiosity and sets lightmaps for indoor faces only
void DoRadiosityForRooms ( )
{
int i , t , j ;
int facecount = 0 ;
int surface_index = 0 ;
int max_index ;
int save_after_bsp = 0 ;
if ( ! CheckForBadFaces ( - 1 ) )
{
OutrageMessageBox ( " You have bad faces in your level. Please do a Verify Level. " ) ;
return ;
}
MakeBOAVisTable ( 1 ) ;
if ( UseBSP )
{
//if ((MessageBox(NULL,"Do you wish to save the level after BSP construction?","Question",MB_YESNO))==IDYES)
//save_after_bsp=1;
}
BuildBSPTree ( ) ;
if ( save_after_bsp )
{
char filename [ PSPATHNAME_LEN ] ;
ddio_MakePath ( filename , Base_directory , " BSPSave.D3L " , NULL ) ;
//Save the level to
SaveLevel ( filename ) ;
}
mprintf ( ( 0 , " Setting up... \n " ) ) ;
Lightmaps_for_rad = 0 ;
if ( UseVolumeLights )
Do_volume_lighting = 1 ;
ClearAllVolumeLights ( ) ;
ClearAllRoomLightmaps ( 0 ) ;
ClearAllObjectLightmaps ( 0 ) ;
ComputeAllRoomLightmapUVs ( 0 ) ;
// Figure out memory for volume lights
int vw , vh , vd ;
for ( int roomnum = 0 ; roomnum < MAX_ROOMS ; roomnum + + )
{
Volume_elements [ roomnum ] = NULL ;
if ( Rooms [ roomnum ] . used & & ! ( Rooms [ roomnum ] . flags & RF_EXTERNAL ) & & ! ( Rooms [ roomnum ] . flags & RF_NO_LIGHT ) )
{
int num_bytes = GetVolumeSizeOfRoom ( & Rooms [ roomnum ] , & vw , & vh , & vd ) ;
Rooms [ roomnum ] . volume_width = vw ;
Rooms [ roomnum ] . volume_height = vh ;
Rooms [ roomnum ] . volume_depth = vd ;
2024-05-24 03:07:26 +00:00
Rooms [ roomnum ] . volume_lights = ( uint8_t * ) mem_malloc ( vw * vh * vd ) ;
2024-04-19 20:58:24 +00:00
ASSERT ( Rooms [ roomnum ] . volume_lights ) ;
Volume_elements [ roomnum ] = ( volume_element * ) mem_malloc ( ( vw * vh * vd ) * sizeof ( volume_element ) ) ;
ASSERT ( Volume_elements [ roomnum ] ) ;
// Now go through and find all the valid spectra points
float cur_z = Rooms [ roomnum ] . min_xyz . z + .1 ;
for ( i = 0 ; i < vd ; i + + , cur_z + = VOLUME_SPACING )
{
float cur_y = Rooms [ roomnum ] . min_xyz . y + .1 ;
for ( t = 0 ; t < vh ; t + + , cur_y + = VOLUME_SPACING )
{
float cur_x = Rooms [ roomnum ] . min_xyz . x + .1 ;
for ( j = 0 ; j < vw ; j + + , cur_x + = VOLUME_SPACING )
{
vector dest_vec ;
dest_vec . x = cur_x ;
dest_vec . y = cur_y ;
dest_vec . z = cur_z ;
Volume_elements [ roomnum ] [ ( i * vw * vh ) + ( t * vw ) + j ] . pos = dest_vec ;
if ( FindPointRoom ( & dest_vec ) ! = roomnum )
{
Volume_elements [ roomnum ] [ ( i * vw * vh ) + ( t * vw ) + j ] . color . r = 0 ;
Volume_elements [ roomnum ] [ ( i * vw * vh ) + ( t * vw ) + j ] . flags = VEF_REVERSE_SHOOT ;
}
else
{
Volume_elements [ roomnum ] [ ( i * vw * vh ) + ( t * vw ) + j ] . color . r = 0 ;
Volume_elements [ roomnum ] [ ( i * vw * vh ) + ( t * vw ) + j ] . flags = 0 ;
}
}
}
}
}
}
// First count how many faces we'll need
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used & & ! ( Rooms [ i ] . flags & RF_EXTERNAL ) & & ! ( Rooms [ i ] . flags & RF_NO_LIGHT ) )
{
facecount + = Rooms [ i ] . num_faces ;
}
}
// Setup specular lighting
Calculate_specular_lighting = 1 ;
SetupSpecularLighting ( 0 ) ;
// Do objects
facecount + = GetTotalObjectFaces ( 0 ) ;
// Do satellites
facecount + = Terrain_sky . num_satellites ;
// Allocate enough memory to hold all surfaces
Light_surfaces = ( rad_surface * ) mem_malloc ( facecount * sizeof ( rad_surface ) ) ;
ASSERT ( Light_surfaces ! = NULL ) ;
// Set initial surface properties
max_index = surface_index = 0 ;
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( ( Rooms [ i ] . flags & RF_EXTERNAL ) | | ( Rooms [ i ] . flags & RF_NO_LIGHT ) )
continue ;
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + , surface_index + + , max_index + + )
{
ComputeSurfaceRes ( & Light_surfaces [ surface_index ] , & Rooms [ i ] , t ) ;
if ( Rooms [ i ] . faces [ t ] . num_verts )
{
Light_surfaces [ surface_index ] . verts = ( vector * ) mem_malloc ( Rooms [ i ] . faces [ t ] . num_verts * sizeof ( vector ) ) ;
ASSERT ( Light_surfaces [ surface_index ] . verts ! = NULL ) ;
}
else
{
Light_surfaces [ surface_index ] . verts = NULL ;
mprintf ( ( 0 , " Room=%d Face %d has no verts! \n " , i , t ) ) ;
}
if ( Light_surfaces [ surface_index ] . xresolution * Light_surfaces [ surface_index ] . yresolution )
{
Light_surfaces [ surface_index ] . elements = ( rad_element * ) mem_malloc ( Light_surfaces [ surface_index ] . xresolution * Light_surfaces [ surface_index ] . yresolution * sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ surface_index ] . elements ! = NULL ) ;
}
else
{
Light_surfaces [ surface_index ] . elements = NULL ;
mprintf ( ( 0 , " Room=%d Face %d is slivered! \n " , i , t ) ) ;
}
Light_surfaces [ surface_index ] . flags = 0 ;
if ( Rooms [ i ] . faces [ t ] . portal_num ! = - 1 & &
( ( ( Rooms [ i ] . portals [ Rooms [ i ] . faces [ t ] . portal_num ] . flags & PF_RENDER_FACES ) = = 0 )
| | ( ( Rooms [ i ] . portals [ Rooms [ i ] . faces [ t ] . portal_num ] . flags & PF_RENDER_FACES )
& & ( GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . flags & TF_TMAP2 ) ) ) )
{
Light_surfaces [ surface_index ] . surface_type = ST_PORTAL ;
Light_surfaces [ surface_index ] . emittance . r = 0 ;
Light_surfaces [ surface_index ] . emittance . g = 0 ;
Light_surfaces [ surface_index ] . emittance . b = 0 ;
}
else
{
if ( Rooms [ i ] . faces [ t ] . light_multiple > 200 )
Rooms [ i ] . faces [ t ] . light_multiple = 4 ;
float mul = ( ( float ) Rooms [ i ] . faces [ t ] . light_multiple ) / 4.0 ;
mul * = GlobalMultiplier * Room_multiplier [ i ] ;
Light_surfaces [ surface_index ] . emittance . r = ( float ) GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . r * mul ;
Light_surfaces [ surface_index ] . emittance . g = ( float ) GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . g * mul ;
Light_surfaces [ surface_index ] . emittance . b = ( float ) GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . b * mul ;
Light_surfaces [ surface_index ] . surface_type = ST_ROOM ;
if ( ( GetMaxColor ( & Light_surfaces [ surface_index ] . emittance ) ) > .005 )
Light_surfaces [ surface_index ] . flags | = SF_LIGHTSOURCE ;
}
Light_surfaces [ surface_index ] . normal = LightmapInfo [ Rooms [ i ] . faces [ t ] . lmi_handle ] . normal ;
Light_surfaces [ surface_index ] . roomnum = i ;
Light_surfaces [ surface_index ] . facenum = t ;
if ( Rooms [ i ] . flags & RF_TOUCHES_TERRAIN )
Light_surfaces [ surface_index ] . flags | = SF_TOUCHES_TERRAIN ;
for ( int k = 0 ; k < Rooms [ i ] . num_portals ; k + + )
{
if ( Rooms [ i ] . portals [ k ] . croom = = - 1 | | ( Rooms [ Rooms [ i ] . portals [ k ] . croom ] . flags & RF_EXTERNAL ) )
Light_surfaces [ surface_index ] . flags | = SF_TOUCHES_TERRAIN ;
}
Light_surfaces [ surface_index ] . reflectivity = GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . reflectivity ;
// Set the vertices for each element
BuildElementListForRoomFace ( i , t , & Light_surfaces [ surface_index ] ) ;
int xres = Light_surfaces [ surface_index ] . xresolution ;
int yres = Light_surfaces [ surface_index ] . yresolution ;
}
}
}
// Setup satellites
for ( i = 0 ; i < Terrain_sky . num_satellites ; i + + , surface_index + + )
{
Light_surfaces [ surface_index ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ surface_index ] . verts ! = NULL ) ;
Light_surfaces [ surface_index ] . elements = ( rad_element * ) mem_malloc ( sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ surface_index ] . elements ! = NULL ) ;
Light_surfaces [ surface_index ] . elements [ 0 ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ surface_index ] . elements [ 0 ] . verts ) ;
Light_surfaces [ surface_index ] . surface_type = ST_SATELLITE ;
Light_surfaces [ surface_index ] . emittance . r = Terrain_sky . satellite_r [ i ] ;
Light_surfaces [ surface_index ] . emittance . g = Terrain_sky . satellite_g [ i ] ;
Light_surfaces [ surface_index ] . emittance . b = Terrain_sky . satellite_b [ i ] ;
Light_surfaces [ surface_index ] . roomnum = i ;
Light_surfaces [ surface_index ] . facenum = 0 ;
Light_surfaces [ surface_index ] . reflectivity = 0 ;
Light_surfaces [ surface_index ] . xresolution = 1 ;
Light_surfaces [ surface_index ] . yresolution = 1 ;
vm_MakeZero ( & Light_surfaces [ surface_index ] . normal ) ;
Light_surfaces [ surface_index ] . verts [ 0 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surface_index ] . verts [ 1 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surface_index ] . verts [ 2 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surface_index ] . num_verts = 3 ;
Light_surfaces [ surface_index ] . elements [ 0 ] . verts [ 0 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surface_index ] . elements [ 0 ] . verts [ 1 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surface_index ] . elements [ 0 ] . verts [ 2 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surface_index ] . elements [ 0 ] . num_verts = 3 ;
Light_surfaces [ surface_index ] . elements [ 0 ] . flags = 0 ;
}
// Setup Objects
ComputeSurfacesForObjects ( surface_index , 0 ) ;
mprintf ( ( 0 , " This radiosity run is using %d lightmaps. \n " , Lightmaps_for_rad ) ) ;
mprintf ( ( 0 , " Solving radiosity equation (press tilde key to stop)... \n " ) ) ;
if ( D3EditState . hemicube_radiosity )
DoRadiosityRun ( SM_HEMICUBE , Light_surfaces , facecount ) ;
else
DoRadiosityRun ( SM_RAYCAST , Light_surfaces , facecount ) ;
mprintf ( ( 0 , " Done solving radiosity - cleaning up... \n " ) ) ;
surface_index = 0 ;
// Assign lightap properties
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( ( Rooms [ i ] . flags & RF_EXTERNAL ) | | ( Rooms [ i ] . flags & RF_NO_LIGHT ) )
continue ;
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + , surface_index + + )
{
AssignRoomSurfaceToLightmap ( i , t , & Light_surfaces [ surface_index ] ) ;
}
AssignVolumeSpectraToRoom ( i ) ;
mem_free ( Volume_elements [ i ] ) ;
}
}
surface_index + = Terrain_sky . num_satellites ;
AssignLightmapsToObjectSurfaces ( surface_index , 0 ) ;
BlurLightmapInfos ( LMI_ROOM ) ;
BlurLightmapInfos ( LMI_ROOM_OBJECT ) ;
ShadeLightmapInfoEdges ( LMI_ROOM ) ;
ShadeLightmapInfoEdges ( LMI_ROOM_OBJECT ) ;
// Free our memory
for ( i = 0 ; i < facecount ; i + + )
{
if ( Light_surfaces [ i ] . verts )
mem_free ( Light_surfaces [ i ] . verts ) ;
for ( t = 0 ; t < Light_surfaces [ i ] . xresolution * Light_surfaces [ i ] . yresolution ; t + + )
if ( Light_surfaces [ i ] . elements [ t ] . num_verts > 0 )
mem_free ( Light_surfaces [ i ] . elements [ t ] . verts ) ;
if ( Light_surfaces [ i ] . elements )
mem_free ( Light_surfaces [ i ] . elements ) ;
Light_surfaces [ i ] . elements = NULL ;
}
mem_free ( Light_surfaces ) ;
Light_surfaces = NULL ;
Do_volume_lighting = 0 ;
// Free specular lighting stuff
CleanupSpecularLighting ( 0 ) ;
Calculate_specular_lighting = 0 ;
// Figure out combined portals
CheckCombinePortals ( 0 ) ;
// Finally, squeeze the lightmaps
SqueezeLightmaps ( 0 , - 1 ) ;
char filename [ PSPATHNAME_LEN + 1 ] ;
ddio_MakePath ( filename , Base_directory , " LightSave.D3L " , NULL ) ;
//Save the level to disk
SaveLevel ( filename ) ;
OutrageMessageBox ( " Mine radiosity complete! " ) ;
}
// Calculates radiosity and sets lightmaps for indoor faces only
void DoRadiosityForCurrentRoom ( room * rp )
{
int t ;
int facecount = 0 ;
int surface_index = 0 ;
int max_index ;
if ( ! CheckForBadFaces ( rp - Rooms ) )
{
OutrageMessageBox ( " You have bad faces in your level. Please do a Verify Level. " ) ;
return ;
}
mprintf ( ( 0 , " Setting up... \n " ) ) ;
ASSERT ( rp ! = NULL ) ;
ASSERT ( rp - > used ) ;
if ( rp - > flags & RF_EXTERNAL )
{
OutrageMessageBox ( " You cannot run single room radiosity on external rooms! " ) ;
return ;
}
if ( rp - > flags & RF_NO_LIGHT )
{
OutrageMessageBox ( " You cannot run single room radiosity on a room marked not to light! " ) ;
return ;
}
// Build bsp tree
BuildSingleBSPTree ( rp - Rooms ) ;
ClearRoomLightmaps ( rp - Rooms ) ;
for ( t = 0 ; t < = Highest_object_index ; t + + )
{
if ( Objects [ t ] . type ! = OBJ_NONE & & ( Objects [ t ] . roomnum = = rp - Rooms ) )
ClearObjectLightmaps ( & Objects [ t ] ) ;
}
// Build lightmap uvs
for ( t = 0 ; t < rp - > num_faces ; t + + )
{
vector verts [ MAX_VERTS_PER_FACE * 5 ] ;
int room_list [ 2 ] , face_list [ 2 ] ;
for ( int k = 0 ; k < rp - > faces [ t ] . num_verts ; k + + )
verts [ k ] = rp - > verts [ rp - > faces [ t ] . face_verts [ k ] ] ;
room_list [ 0 ] = rp - Rooms ;
face_list [ 0 ] = t ;
BuildLightmapUVs ( room_list , face_list , 1 , verts , rp - > faces [ t ] . num_verts , 0 ) ;
}
// First count how many faces we'll need
facecount + = rp - > num_faces ;
// Do objects
facecount + = GetTotalObjectFacesForSingleRoom ( rp - Rooms ) ;
// Allocate enough memory to hold all surfaces
Light_surfaces = ( rad_surface * ) mem_malloc ( facecount * sizeof ( rad_surface ) ) ;
ASSERT ( Light_surfaces ! = NULL ) ;
// Set initial surface properties
max_index = surface_index = 0 ;
for ( t = 0 ; t < rp - > num_faces ; t + + , surface_index + + , max_index + + )
{
ComputeSurfaceRes ( & Light_surfaces [ surface_index ] , rp , t ) ;
if ( rp - > faces [ t ] . num_verts )
{
Light_surfaces [ surface_index ] . verts = ( vector * ) mem_malloc ( rp - > faces [ t ] . num_verts * sizeof ( vector ) ) ;
ASSERT ( Light_surfaces [ surface_index ] . verts ! = NULL ) ;
}
else
{
Light_surfaces [ surface_index ] . verts = NULL ;
mprintf ( ( 0 , " Room=%d Face %d has no verts! \n " , rp - Rooms , t ) ) ;
}
if ( Light_surfaces [ surface_index ] . xresolution * Light_surfaces [ surface_index ] . yresolution )
{
Light_surfaces [ surface_index ] . elements = ( rad_element * ) mem_malloc ( Light_surfaces [ surface_index ] . xresolution * Light_surfaces [ surface_index ] . yresolution * sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ surface_index ] . elements ! = NULL ) ;
}
else
{
Light_surfaces [ surface_index ] . elements = NULL ;
mprintf ( ( 0 , " Room=%d Face %d is slivered! \n " , rp - Rooms , t ) ) ;
}
if ( rp - > faces [ t ] . portal_num ! = - 1 & &
( ( ( rp - > portals [ rp - > faces [ t ] . portal_num ] . flags & PF_RENDER_FACES ) = = 0 )
| | ( ( rp - > portals [ rp - > faces [ t ] . portal_num ] . flags & PF_RENDER_FACES )
& & ( GameTextures [ rp - > faces [ t ] . tmap ] . flags & TF_TMAP2 ) ) ) )
{
Light_surfaces [ surface_index ] . surface_type = ST_PORTAL ;
Light_surfaces [ surface_index ] . emittance . r = 0 ;
Light_surfaces [ surface_index ] . emittance . g = 0 ;
Light_surfaces [ surface_index ] . emittance . b = 0 ;
}
else
{
float mul = ( ( float ) rp - > faces [ t ] . light_multiple ) / 4.0 ;
mul * = GlobalMultiplier * Room_multiplier [ rp - Rooms ] ;
Light_surfaces [ surface_index ] . emittance . r = ( float ) GameTextures [ rp - > faces [ t ] . tmap ] . r * mul ;
Light_surfaces [ surface_index ] . emittance . g = ( float ) GameTextures [ rp - > faces [ t ] . tmap ] . g * mul ;
Light_surfaces [ surface_index ] . emittance . b = ( float ) GameTextures [ rp - > faces [ t ] . tmap ] . b * mul ;
Light_surfaces [ surface_index ] . surface_type = ST_ROOM ;
}
Light_surfaces [ surface_index ] . normal = rp - > faces [ t ] . normal ;
Light_surfaces [ surface_index ] . roomnum = ROOMNUM ( rp ) ;
Light_surfaces [ surface_index ] . facenum = t ;
Light_surfaces [ surface_index ] . reflectivity = GameTextures [ rp - > faces [ t ] . tmap ] . reflectivity ;
// Set the vertices for each element
BuildElementListForRoomFace ( rp - Rooms , t , & Light_surfaces [ surface_index ] ) ;
int xres = Light_surfaces [ surface_index ] . xresolution ;
int yres = Light_surfaces [ surface_index ] . yresolution ;
}
// Setup Objects
ComputeSurfacesForObjectsForSingleRoom ( surface_index , rp - Rooms ) ;
mprintf ( ( 0 , " Solving radiosity equation (press tilde key to stop)... \n " ) ) ;
if ( D3EditState . hemicube_radiosity )
DoRadiosityRun ( SM_HEMICUBE , Light_surfaces , facecount ) ;
else
DoRadiosityRun ( SM_RAYCAST , Light_surfaces , facecount ) ;
mprintf ( ( 0 , " Done solving radiosity - cleaning up... \n " ) ) ;
surface_index = 0 ;
// Assign lightap properties
for ( t = 0 ; t < rp - > num_faces ; t + + , surface_index + + )
{
AssignRoomSurfaceToLightmap ( rp - Rooms , t , & Light_surfaces [ surface_index ] ) ;
}
AssignLightmapsToObjectSurfacesForSingleRoom ( surface_index , rp - Rooms ) ;
//BlurLightmapInfos (LMI_ROOM);
//BlurLightmapInfos (LMI_ROOM_OBJECT);
//ShadeLightmapInfoEdges (LMI_ROOM);
//ShadeLightmapInfoEdges (LMI_ROOM_OBJECT);
// Free our memory
for ( int i = 0 ; i < facecount ; i + + )
{
mem_free ( Light_surfaces [ i ] . verts ) ;
for ( t = 0 ; t < Light_surfaces [ i ] . xresolution * Light_surfaces [ i ] . yresolution ; t + + )
if ( Light_surfaces [ i ] . elements [ t ] . num_verts > 0 )
mem_free ( Light_surfaces [ i ] . elements [ t ] . verts ) ;
mem_free ( Light_surfaces [ i ] . elements ) ;
Light_surfaces [ i ] . elements = NULL ;
}
mem_free ( Light_surfaces ) ;
Light_surfaces = NULL ;
// Finally, squeeze the lightmaps
SqueezeLightmaps ( 0 , rp - Rooms ) ;
OutrageMessageBox ( " Room radiosity complete! " ) ;
}
// Allocates and sets a lightmap based on the surface elements given
void AssignRoomSurfaceToLightmap ( int roomnum , int facenum , rad_surface * sp )
{
face * fp = & Rooms [ roomnum ] . faces [ facenum ] ;
room * rp = & Rooms [ roomnum ] ;
int i , t , lmi_handle ;
int xres , yres ;
int lw , lh ;
int x1 = sp - > x1 ;
int y1 = sp - > y1 ;
int use_lightmap = 1 ;
xres = sp - > xresolution ;
yres = sp - > yresolution ;
ASSERT ( fp - > lmi_handle ! = BAD_LMI_INDEX ) ;
lmi_handle = fp - > lmi_handle ;
lw = lmi_w ( lmi_handle ) ;
lh = lmi_h ( lmi_handle ) ;
ASSERT ( ( xres + x1 ) < = lw ) ;
ASSERT ( ( yres + y1 ) < = lh ) ;
ASSERT ( lw > = 2 ) ;
ASSERT ( lh > = 2 ) ;
2024-05-24 03:16:40 +00:00
uint16_t * dest_data = lm_data ( LightmapInfo [ lmi_handle ] . lm_handle ) ;
2024-04-19 20:58:24 +00:00
// Set face pointer
if ( GameTextures [ fp - > tmap ] . flags & TF_ALPHA )
use_lightmap = 0 ;
if ( GameTextures [ fp - > tmap ] . flags & ( TF_FORCE_LIGHTMAP | TF_SATURATE_LIGHTMAP ) )
use_lightmap = 1 ;
if ( use_lightmap )
fp - > flags | = FF_LIGHTMAP ;
for ( i = 0 ; i < yres ; i + + )
{
for ( t = 0 ; t < xres ; t + + )
{
if ( ! ( sp - > elements [ i * xres + t ] . flags & EF_IGNORE ) )
{
ddgr_color color = GR_16_TO_COLOR ( dest_data [ ( i + y1 ) * lw + ( t + x1 ) ] ) ;
int red = GR_COLOR_RED ( color ) ;
int green = GR_COLOR_GREEN ( color ) ;
int blue = GR_COLOR_BLUE ( color ) ;
float fr , fg , fb ;
if ( ! ( dest_data [ ( i + y1 ) * lw + ( t + x1 ) ] & OPAQUE_FLAG ) )
{
red = green = blue = 0 ;
}
fr = min ( 1.0 , sp - > elements [ i * xres + t ] . exitance . r + Ambient_red + Room_ambience_r [ roomnum ] ) ;
fg = min ( 1.0 , sp - > elements [ i * xres + t ] . exitance . g + Ambient_green + Room_ambience_g [ roomnum ] ) ;
fb = min ( 1.0 , sp - > elements [ i * xres + t ] . exitance . b + Ambient_blue + Room_ambience_b [ roomnum ] ) ;
fr = ( fr * 255 ) + .5 ;
fg = ( fg * 255 ) + .5 ;
fb = ( fb * 255 ) + .5 ;
red + = ( int ) fr ;
green + = ( int ) fg ;
blue + = ( int ) fb ;
if ( dest_data [ ( i + y1 ) * lw + ( t + x1 ) ] & OPAQUE_FLAG )
{
red / = 2 ;
green / = 2 ;
blue / = 2 ;
}
red = min ( red , 255 ) ;
green = min ( green , 255 ) ;
blue = min ( blue , 255 ) ;
2024-05-24 03:16:40 +00:00
uint16_t texel = OPAQUE_FLAG | GR_RGB16 ( red , green , blue ) ;
2024-04-19 20:58:24 +00:00
dest_data [ ( i + y1 ) * lw + ( t + x1 ) ] = texel ;
}
}
}
}
// Important - vertnum is the index into the face_verts[] array in the face structure,
// not an index into the verts[] array of the room structure
void BuildElementListForRoomFace ( int roomnum , int facenum , rad_surface * surf )
{
matrix face_matrix , trans_matrix ;
vector fvec ;
vector avg_vert ;
vector verts [ MAX_VERTS_PER_FACE * 5 ] ;
vector rot_vert ;
vector vert ;
int i , t ;
int xres , yres ;
int lmi_handle ;
int x1 = surf - > x1 ;
int y1 = surf - > y1 ;
xres = surf - > xresolution ;
yres = surf - > yresolution ;
ASSERT ( Rooms [ roomnum ] . used ) ;
ASSERT ( Rooms [ roomnum ] . faces [ facenum ] . num_verts > = 3 ) ;
ASSERT ( Rooms [ roomnum ] . faces [ facenum ] . lmi_handle ! = BAD_LMI_INDEX ) ;
lmi_handle = Rooms [ roomnum ] . faces [ facenum ] . lmi_handle ;
avg_vert = ScratchCenters [ lmi_handle ] ;
// Make the orientation matrix
// Reverse the normal because we're looking "at" the face, not from it
fvec = - LightmapInfo [ lmi_handle ] . normal ;
vm_VectorToMatrix ( & face_matrix , & fvec , NULL , NULL ) ;
// Make the transformation matrix
angvec avec ;
vm_ExtractAnglesFromMatrix ( & avec , & face_matrix ) ;
vm_AnglesToMatrix ( & trans_matrix , avec . p , avec . h , avec . b ) ;
// Rotate all the points
for ( i = 0 ; i < Rooms [ roomnum ] . faces [ facenum ] . num_verts ; i + + )
{
vert = Rooms [ roomnum ] . verts [ Rooms [ roomnum ] . faces [ facenum ] . face_verts [ i ] ] ;
vert - = avg_vert ;
vm_MatrixMulVector ( & rot_vert , & vert , & trans_matrix ) ;
verts [ i ] = rot_vert ;
}
// Find a base vector
vector base_vector ;
vector xdiff , ydiff ;
vm_MakeZero ( & xdiff ) ;
vm_MakeZero ( & ydiff ) ;
// Rotate our upper left point into our 2d space
vert = LightmapInfo [ lmi_handle ] . upper_left - avg_vert ;
vm_MatrixMulVector ( & base_vector , & vert , & trans_matrix ) ;
xdiff . x = LightmapInfo [ lmi_handle ] . xspacing ;
ydiff . y = LightmapInfo [ lmi_handle ] . yspacing ;
vm_TransposeMatrix ( & trans_matrix ) ;
for ( i = 0 ; i < yres ; i + + )
{
for ( t = 0 ; t < xres ; t + + )
{
int element_index = i * xres + t ;
vector clip_verts [ 4 ] ;
rad_element * ep = & surf - > elements [ element_index ] ;
// Allocate some free space
clip_verts [ 0 ] = base_vector + ( xdiff * ( t + x1 ) ) - ( ydiff * ( i + y1 ) ) ;
clip_verts [ 1 ] = base_vector + ( xdiff * ( t + x1 + 1 ) ) - ( ydiff * ( i + y1 ) ) ;
clip_verts [ 2 ] = base_vector + ( xdiff * ( t + x1 + 1 ) ) - ( ydiff * ( i + y1 + 1 ) ) ;
clip_verts [ 3 ] = base_vector + ( xdiff * ( t + x1 ) ) - ( ydiff * ( i + y1 + 1 ) ) ;
ClipSurfaceElement ( verts , ep , clip_verts , Rooms [ roomnum ] . faces [ facenum ] . num_verts ) ;
for ( int k = 0 ; k < ep - > num_verts ; k + + )
{
vm_MatrixMulVector ( & rot_vert , & ep - > verts [ k ] , & trans_matrix ) ;
ep - > verts [ k ] = rot_vert + avg_vert ;
}
}
}
if ( Square_surfaces )
{
surf - > verts [ 0 ] = base_vector ;
surf - > verts [ 1 ] = base_vector + ( xdiff * xres ) ;
surf - > verts [ 2 ] = base_vector + ( xdiff * xres ) - ( ydiff * yres ) ;
surf - > verts [ 3 ] = base_vector - ( ydiff * yres ) ;
for ( int k = 0 ; k < 4 ; k + + )
{
vm_MatrixMulVector ( & rot_vert , & surf - > verts [ k ] , & trans_matrix ) ;
surf - > verts [ k ] = rot_vert + avg_vert ;
}
surf - > num_verts = 4 ;
}
else
{
surf - > num_verts = Rooms [ roomnum ] . faces [ facenum ] . num_verts ;
for ( int k = 0 ; k < surf - > num_verts ; k + + )
{
surf - > verts [ k ] = Rooms [ roomnum ] . verts [ Rooms [ roomnum ] . faces [ facenum ] . face_verts [ k ] ] ;
}
}
}
vector * rad_ClipTop , * rad_ClipBottom , * rad_ClipLeft , * rad_ClipRight ;
rad_point GlobalTempRadPoint ;
void SetRadClipLines ( vector * tp , vector * rp , vector * bp , vector * lp )
{
rad_ClipTop = tp ;
rad_ClipRight = rp ;
rad_ClipBottom = bp ;
rad_ClipLeft = lp ;
}
2024-05-24 03:07:26 +00:00
uint8_t CodeRadPoint ( rad_point * rp )
2024-04-19 20:58:24 +00:00
{
2024-05-24 03:07:26 +00:00
uint8_t code = 0 ;
2024-04-19 20:58:24 +00:00
if ( rp - > pos . x < rad_ClipLeft - > x )
code | = CC_OFF_LEFT ;
if ( rp - > pos . x > rad_ClipRight - > x )
code | = CC_OFF_RIGHT ;
if ( rp - > pos . y < rad_ClipBottom - > y )
code | = CC_OFF_BOT ;
if ( rp - > pos . y > rad_ClipTop - > y )
code | = CC_OFF_TOP ;
rp - > code = code ;
return code ;
}
void ClipSurfaceElement ( vector * surf_verts , rad_element * ep , vector * clip_verts , int nv )
{
rad_point src_verts [ 50 ] ;
rad_point dest_verts [ 50 ] ;
rad_point * slist , * dlist ;
2024-05-24 03:07:26 +00:00
uint8_t and = 0xff ;
uint8_t or = 0 ;
2024-04-19 20:58:24 +00:00
int i ;
ASSERT ( nv < 50 ) ;
ep - > flags = 0 ;
SetRadClipLines ( & clip_verts [ 0 ] , & clip_verts [ 1 ] , & clip_verts [ 2 ] , & clip_verts [ 3 ] ) ;
for ( i = 0 ; i < nv ; i + + )
{
src_verts [ i ] . pos = surf_verts [ i ] ;
src_verts [ i ] . code = CodeRadPoint ( & src_verts [ i ] ) ;
}
for ( i = 0 ; i < nv ; i + + )
{
and & = src_verts [ i ] . code ;
or | = src_verts [ i ] . code ;
}
if ( and )
{
// This element is not even in the face, ignore it
ep - > flags | = EF_IGNORE ;
ep - > num_verts = 0 ;
return ;
}
int pnv = nv , nnv ;
slist = src_verts ; dlist = dest_verts ;
nnv = ClipRadPointList ( & slist , & dlist , & pnv , or ) ;
ep - > num_verts = nnv ;
if ( ep - > num_verts = = 0 )
ep - > flags | = EF_IGNORE ;
else
{
ep - > verts = ( vector * ) mem_malloc ( sizeof ( vector ) * nnv ) ;
ASSERT ( ep - > verts ) ;
for ( i = 0 ; i < nnv ; i + + )
{
ep - > verts [ i ] = dlist [ i ] . pos ;
}
}
}
// Takes a points and clips all its viewpoints so they fit into the view frustum
// Puts the new clipped list in dest
// Returns number of points in clipped polygon
int ClipRadPointList ( rad_point * * src , rad_point * * dest , int * nv , int code )
{
int plane , num = 0 ;
rad_point * * save_src = src , * t ;
rad_point * * save_dest = dest ;
for ( plane = 1 ; plane < 16 ; plane < < = 1 )
{
if ( plane & code ) // Is this point off this plane?
{
* nv = ClipRadToPlane ( plane , * src , * dest , * nv ) ;
if ( * nv = = 0 )
return 0 ;
ASSERT ( * nv > = 3 ) ;
t = * dest ; * dest = * src ; * src = t ;
num + + ;
}
}
t = * dest ; * dest = * src ; * src = t ;
return ( * nv ) ;
}
// Clips to a specific plane, putting resulting points in dest and returning number of points in dest
int ClipRadToPlane ( int plane , rad_point * src , rad_point * dest , int nv )
{
int i , num = 0 , limit = nv - 1 , ppoint , npoint ;
ASSERT ( nv > = 3 ) ;
for ( i = 0 ; i < nv ; i + + )
{
if ( i = = limit )
npoint = 0 ;
else npoint = i + 1 ;
if ( i = = 0 )
ppoint = limit ;
else
ppoint = i - 1 ;
//mprintf ((0,"checking point %d ",i));
if ( src [ i ] . code & plane ) // off this plane?
{
if ( ! ( src [ ppoint ] . code & plane ) ) // prev point on?
{
//mprintf ((0,"pVertex %d off %d plane.\n",i,plane));
ClipRadEdge ( plane , & src [ ppoint ] , & src [ i ] ) ;
memcpy ( & dest [ num ] , & GlobalTempRadPoint , sizeof ( rad_point ) ) ;
num + + ;
}
if ( ! ( src [ npoint ] . code & plane ) ) // next point on?
{
//mprintf ((0,"nVertex %d off %d plane.\n",i,plane));
ClipRadEdge ( plane , & src [ npoint ] , & src [ i ] ) ;
memcpy ( & dest [ num ] , & GlobalTempRadPoint , sizeof ( rad_point ) ) ;
num + + ;
}
}
else // This point is on
{
//mprintf ((0,"is on\n"));
memcpy ( & dest [ num ] , & src [ i ] , sizeof ( rad_point ) ) ;
num + + ;
}
}
return ( num ) ;
}
// Takes two points and a plane, and clips.
void ClipRadEdge ( int plane_flag , rad_point * on_pnt , rad_point * off_pnt )
{
if ( plane_flag & CC_OFF_TOP )
{
float percent_on = 1.0 - ( ( off_pnt - > pos . y - rad_ClipTop - > y ) / ( off_pnt - > pos . y - on_pnt - > pos . y ) ) ;
GlobalTempRadPoint . pos = on_pnt - > pos + ( ( off_pnt - > pos - on_pnt - > pos ) * percent_on ) ;
}
if ( plane_flag & CC_OFF_RIGHT )
{
float percent_on = 1.0 - ( ( off_pnt - > pos . x - rad_ClipRight - > x ) / ( off_pnt - > pos . x - on_pnt - > pos . x ) ) ;
GlobalTempRadPoint . pos = on_pnt - > pos + ( ( off_pnt - > pos - on_pnt - > pos ) * percent_on ) ;
}
if ( plane_flag & CC_OFF_LEFT )
{
float percent_on = 1.0 - ( ( off_pnt - > pos . x - rad_ClipLeft - > x ) / ( off_pnt - > pos . x - on_pnt - > pos . x ) ) ;
GlobalTempRadPoint . pos = on_pnt - > pos + ( ( off_pnt - > pos - on_pnt - > pos ) * percent_on ) ;
}
if ( plane_flag & CC_OFF_BOT )
{
float percent_on = 1.0 - ( ( off_pnt - > pos . y - rad_ClipBottom - > y ) / ( off_pnt - > pos . y - on_pnt - > pos . y ) ) ;
GlobalTempRadPoint . pos = on_pnt - > pos + ( ( off_pnt - > pos - on_pnt - > pos ) * percent_on ) ;
}
CodeRadPoint ( & GlobalTempRadPoint ) ;
}
// Adds color spectrums together
void AddSpectra ( spectra * dest , spectra * a , spectra * b )
{
dest - > r = a - > r + b - > r ;
dest - > g = a - > g + b - > g ;
dest - > b = a - > b + b - > b ;
}
// Returns 1 if a src vector can hit dest vector unobstructed, else 0
int ShootRayForTerrainLight ( vector * src , vector * dest , int cellnum )
{
fvi_info hit_info ;
fvi_query fq ;
vector temp_dest = * dest ;
if ( temp_dest . y > = MAX_TERRAIN_HEIGHT * 3 )
{
float mag ;
float ydiff ;
vector ray = temp_dest - * src ;
mag = vm_GetMagnitude ( & ray ) ;
ray / = mag ;
ydiff = ( ( MAX_TERRAIN_HEIGHT * 3 ) - src - > y ) / ray . y ;
temp_dest = * src + ( ray * ydiff ) ;
}
// shoot a ray from the light position to the current vertex
fq . p0 = src ;
fq . p1 = & temp_dest ;
fq . startroom = MAKE_ROOMNUM ( cellnum ) ;
fq . rad = 0.0f ;
fq . flags = FQ_CHECK_OBJS | FQ_IGNORE_NON_LIGHTMAP_OBJECTS | FQ_OBJ_BACKFACE | FQ_NO_RELINK | FQ_IGNORE_RENDER_THROUGH_PORTALS ;
fq . thisobjnum = - 1 ;
fq . ignore_obj_list = NULL ;
int fate = fvi_FindIntersection ( & fq , & hit_info ) ;
if ( fate = = HIT_OUT_OF_TERRAIN_BOUNDS | | fate = = HIT_NONE )
return 1 ;
return 0 ;
}
# define AREA_X (TERRAIN_WIDTH-1)
# define AREA_Z (TERRAIN_DEPTH-1)
//#define AREA_X 128
//#define AREA_Z 128
// Puts a 3d grid of points on the terrain and sets a bit indicating if a light source
// can reach that point. This is used for the dynamic lighting of objects on the terrain
void DoTerrainDynamicTable ( )
{
int i , t , k , j , maxrays ;
int raynum = 0 ;
int key ;
maxrays = AREA_X * AREA_Z * 8 * Terrain_sky . num_satellites ;
mprintf ( ( 0 , " Calculating dynamic light table for %d points... \n " , maxrays ) ) ;
mprintf ( ( 0 , " Press tilde key to abort! \n " ) ) ;
memset ( Terrain_dynamic_table , 0 , ( TERRAIN_DEPTH * TERRAIN_WIDTH ) ) ;
for ( i = 0 ; i < AREA_Z ; i + + )
{
// ddio_KeyFrame();
while ( ( key = ddio_KeyInKey ( ) ) ! = 0 )
{
if ( key = = KEY_LAPOSTRO )
{
for ( ; i < AREA_Z ; i + + )
{
for ( t = 0 ; t < AREA_X ; t + + )
{
int tseg = i * TERRAIN_WIDTH + t ;
Terrain_dynamic_table [ tseg ] = 255 ;
}
}
return ;
}
}
for ( t = 0 ; t < AREA_X ; t + + )
{
int tseg = i * TERRAIN_WIDTH + t ;
vector gp ;
gp . x = ( t * TERRAIN_SIZE ) ;
gp . z = ( i * TERRAIN_SIZE ) ;
gp . y = Terrain_seg [ tseg ] . y ;
for ( k = 0 ; k < 8 ; k + + )
{
vector pos ;
pos . x = gp . x ;
pos . z = gp . z ;
pos . y = k * ( MAX_TERRAIN_HEIGHT / 8 ) ;
for ( j = 0 ; j < Terrain_sky . num_satellites ; j + + )
{
raynum + + ;
mprintf_at ( ( 2 , 4 , 0 , " Ray=%d " , raynum ) ) ;
if ( gp . y > pos . y )
continue ;
int answer ;
answer = ShootRayForTerrainLight ( & pos , & Terrain_sky . satellite_vectors [ j ] , tseg ) ;
if ( ! answer )
continue ;
Terrain_dynamic_table [ tseg ] | = ( 1 < < k ) ;
j = Terrain_sky . num_satellites ;
}
}
}
}
}
void ComputeTerrainSpeedTable ( )
{
int i , t , j , raynum = 0 ;
mprintf ( ( 0 , " Precomputing terrain speed table...(%d rays) \n " , AREA_X * AREA_Z ) ) ;
for ( i = 0 ; i < AREA_Z ; i + + )
{
for ( t = 0 ; t < AREA_X ; t + + )
{
int tseg = i * TERRAIN_WIDTH + t ;
vector pos ;
pos . x = ( t * TERRAIN_SIZE ) ;
pos . z = ( i * TERRAIN_SIZE ) ;
pos . y = ( Terrain_seg [ tseg ] . y ) + .001 ;
raynum + + ;
if ( ( raynum % 1000 ) = = 0 )
mprintf_at ( ( 2 , 4 , 0 , " Ray=%d " , raynum ) ) ;
for ( j = 0 ; j < Terrain_sky . num_satellites ; j + + )
TerrainLightSpeedup [ j ] [ tseg ] = ShootRayForTerrainLight ( & pos , & Terrain_sky . satellite_vectors [ j ] , tseg ) ;
}
}
}
float GetMaxColor ( spectra * sp ) ;
// Calculates radiosity for the outdoor surfaces
void DoRadiosityForTerrain ( )
{
int i , t , raynum = 0 ;
int extra_surfaces = 0 , total_surfaces = 0 ;
int surf_index = 0 ;
spectra * terrain_sums [ 2 ] ;
int room_surf_start , obj_surf_start ;
int do_dynamic = 0 ;
int lit = 0 ;
// First make sure there is even a light source
for ( i = 0 ; i < Terrain_sky . num_satellites ; i + + )
{
int tmap = Terrain_sky . satellite_texture [ i ] ;
if ( Terrain_sky . satellite_r [ i ] > 0 | | Terrain_sky . satellite_g [ i ] > 0 | | Terrain_sky . satellite_b [ i ] > 0 )
lit = 1 ;
}
if ( ! lit )
{
OutrageMessageBox ( " No moons/suns cast light so there is no point in running terrain radiosity! " ) ;
return ;
}
for ( i = 0 ; i < Terrain_sky . num_satellites ; i + + )
{
2024-05-24 03:07:26 +00:00
TerrainLightSpeedup [ i ] = ( uint8_t * ) mem_malloc ( TERRAIN_WIDTH * TERRAIN_DEPTH ) ;
2024-04-19 20:58:24 +00:00
ASSERT ( TerrainLightSpeedup [ i ] ) ;
}
if ( ( MessageBox ( NULL , " Do you wish to calculate dynamic terrain lighting when radiosity is completed? (Note: Dynamic lighting takes a long time) " , " Question " , MB_YESNO ) ) = = IDYES )
do_dynamic = 1 ;
if ( ! Ignore_terrain )
ComputeTerrainSpeedTable ( ) ;
extra_surfaces + = Terrain_sky . num_satellites ;
extra_surfaces + = GetTotalObjectFaces ( 1 ) ;
// Get our external rooms ready
ClearAllRoomLightmaps ( 1 ) ;
ComputeAllRoomLightmapUVs ( 1 ) ;
// count how many faces we'll need
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used & & ( Rooms [ i ] . flags & RF_EXTERNAL ) )
extra_surfaces + = Rooms [ i ] . num_faces ;
}
if ( ! Ignore_terrain )
total_surfaces = ( ( AREA_X ) * ( AREA_Z ) * 2 ) ;
total_surfaces + = extra_surfaces ;
// Get our object lightmaps ready
ClearAllObjectLightmaps ( 1 ) ;
// Allocate memory
terrain_sums [ 0 ] = ( spectra * ) mem_malloc ( TERRAIN_WIDTH * TERRAIN_DEPTH * sizeof ( spectra ) ) ;
terrain_sums [ 1 ] = ( spectra * ) mem_malloc ( TERRAIN_WIDTH * TERRAIN_DEPTH * sizeof ( spectra ) ) ;
ASSERT ( terrain_sums [ 0 ] & & terrain_sums [ 1 ] ) ;
Light_surfaces = ( rad_surface * ) mem_malloc ( total_surfaces * sizeof ( rad_surface ) ) ;
ASSERT ( Light_surfaces ! = NULL ) ;
// Setup radiosity surfaces
if ( ! Ignore_terrain )
{
for ( i = 0 ; i < ( AREA_X ) * ( AREA_Z ) ; i + + , surf_index + = 2 )
{
vector a , b , c ;
int x , z ;
x = i % AREA_X ;
z = i / AREA_Z ;
int seg = z * TERRAIN_WIDTH + x ;
// Do common stuff (for both triangles)
for ( x = 0 ; x < 2 ; x + + )
{
Light_surfaces [ i * 2 + x ] . surface_type = ST_TERRAIN ;
Light_surfaces [ i * 2 + x ] . emittance . r = ( float ) GameTextures [ Terrain_tex_seg [ Terrain_seg [ seg ] . texseg_index ] . tex_index ] . r ;
Light_surfaces [ i * 2 + x ] . emittance . g = ( float ) GameTextures [ Terrain_tex_seg [ Terrain_seg [ seg ] . texseg_index ] . tex_index ] . g ;
Light_surfaces [ i * 2 + x ] . emittance . b = ( float ) GameTextures [ Terrain_tex_seg [ Terrain_seg [ seg ] . texseg_index ] . tex_index ] . b ;
Light_surfaces [ i * 2 + x ] . roomnum = MAKE_ROOMNUM ( seg ) ;
Light_surfaces [ i * 2 + x ] . facenum = x ;
Light_surfaces [ i * 2 + x ] . reflectivity = GameTextures [ Terrain_tex_seg [ Terrain_seg [ seg ] . texseg_index ] . tex_index ] . reflectivity ;
Light_surfaces [ i * 2 + x ] . xresolution = 1 ;
Light_surfaces [ i * 2 + x ] . yresolution = 1 ;
}
// Do upper left triangle
Light_surfaces [ i * 2 ] . elements = ( rad_element * ) mem_malloc ( sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ i * 2 ] . elements ! = NULL ) ;
Light_surfaces [ i * 2 ] . elements [ 0 ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ i * 2 ] . elements [ 0 ] . verts ) ;
Light_surfaces [ i * 2 ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ i * 2 ] . verts ! = NULL ) ;
Light_surfaces [ i * 2 ] . normal = TerrainNormals [ MAX_TERRAIN_LOD - 1 ] [ seg ] . normal1 ;
z = i / ( AREA_X ) ;
x = i % ( AREA_X ) ;
a . x = x * TERRAIN_SIZE ;
a . y = Terrain_seg [ ( z * TERRAIN_WIDTH ) + ( x ) ] . y ;
a . z = z * TERRAIN_SIZE ;
b . x = x * TERRAIN_SIZE ;
b . y = Terrain_seg [ ( ( z + 1 ) * TERRAIN_WIDTH ) + ( x ) ] . y ;
b . z = ( z + 1 ) * TERRAIN_SIZE ;
c . x = ( x + 1 ) * TERRAIN_SIZE ;
c . y = Terrain_seg [ ( ( z + 1 ) * TERRAIN_WIDTH ) + ( x + 1 ) ] . y ;
c . z = ( z + 1 ) * TERRAIN_SIZE ;
Light_surfaces [ i * 2 ] . verts [ 0 ] = a ;
Light_surfaces [ i * 2 ] . verts [ 1 ] = b ;
Light_surfaces [ i * 2 ] . verts [ 2 ] = c ;
Light_surfaces [ i * 2 ] . num_verts = 3 ;
Light_surfaces [ i * 2 ] . elements [ 0 ] . verts [ 0 ] = a ;
Light_surfaces [ i * 2 ] . elements [ 0 ] . verts [ 1 ] = b ;
Light_surfaces [ i * 2 ] . elements [ 0 ] . verts [ 2 ] = c ;
Light_surfaces [ i * 2 ] . elements [ 0 ] . num_verts = 3 ;
Light_surfaces [ i * 2 ] . elements [ 0 ] . flags = 0 ;
// Now do lower right
Light_surfaces [ i * 2 + 1 ] . elements = ( rad_element * ) mem_malloc ( sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ i * 2 + 1 ] . elements ! = NULL ) ;
Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . verts ) ;
Light_surfaces [ i * 2 + 1 ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ i * 2 + 1 ] . verts ! = NULL ) ;
Light_surfaces [ i * 2 + 1 ] . normal = TerrainNormals [ MAX_TERRAIN_LOD - 1 ] [ seg ] . normal2 ;
z = i / ( AREA_X ) ;
x = i % ( AREA_X ) ;
a . x = x * TERRAIN_SIZE ;
a . y = Terrain_seg [ ( z * TERRAIN_WIDTH ) + ( x ) ] . y ;
a . z = z * TERRAIN_SIZE ;
b . x = ( x + 1 ) * TERRAIN_SIZE ;
b . y = Terrain_seg [ ( ( z + 1 ) * TERRAIN_WIDTH ) + ( x + 1 ) ] . y ;
b . z = ( z + 1 ) * TERRAIN_SIZE ;
c . x = ( x + 1 ) * TERRAIN_SIZE ;
c . y = Terrain_seg [ ( z * TERRAIN_WIDTH ) + ( x + 1 ) ] . y ;
c . z = z * TERRAIN_SIZE ;
Light_surfaces [ i * 2 + 1 ] . verts [ 0 ] = a ;
Light_surfaces [ i * 2 + 1 ] . verts [ 1 ] = b ;
Light_surfaces [ i * 2 + 1 ] . verts [ 2 ] = c ;
Light_surfaces [ i * 2 + 1 ] . num_verts = 3 ;
Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . verts [ 0 ] = a ;
Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . verts [ 1 ] = b ;
Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . verts [ 2 ] = c ;
Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . num_verts = 3 ;
Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . flags = 0 ;
}
}
// Setup satellites
for ( i = 0 ; i < Terrain_sky . num_satellites ; i + + , surf_index + + )
{
Light_surfaces [ surf_index ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ surf_index ] . verts ! = NULL ) ;
Light_surfaces [ surf_index ] . elements = ( rad_element * ) mem_malloc ( sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ surf_index ] . elements ! = NULL ) ;
Light_surfaces [ surf_index ] . elements [ 0 ] . verts = ( vector * ) mem_malloc ( sizeof ( vector ) * 3 ) ;
ASSERT ( Light_surfaces [ surf_index ] . elements [ 0 ] . verts ) ;
Light_surfaces [ surf_index ] . surface_type = ST_SATELLITE ;
Light_surfaces [ surf_index ] . emittance . r = Terrain_sky . satellite_r [ i ] ;
Light_surfaces [ surf_index ] . emittance . g = Terrain_sky . satellite_g [ i ] ;
Light_surfaces [ surf_index ] . emittance . b = Terrain_sky . satellite_b [ i ] ;
Light_surfaces [ surf_index ] . roomnum = i ;
Light_surfaces [ surf_index ] . facenum = 0 ;
Light_surfaces [ surf_index ] . reflectivity = 0 ;
Light_surfaces [ surf_index ] . xresolution = 1 ;
Light_surfaces [ surf_index ] . yresolution = 1 ;
vm_MakeZero ( & Light_surfaces [ surf_index ] . normal ) ;
Light_surfaces [ surf_index ] . verts [ 0 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surf_index ] . verts [ 1 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surf_index ] . verts [ 2 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surf_index ] . num_verts = 3 ;
Light_surfaces [ surf_index ] . elements [ 0 ] . verts [ 0 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surf_index ] . elements [ 0 ] . verts [ 1 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surf_index ] . elements [ 0 ] . verts [ 2 ] = Terrain_sky . satellite_vectors [ i ] ;
Light_surfaces [ surf_index ] . elements [ 0 ] . num_verts = 3 ;
Light_surfaces [ surf_index ] . elements [ 0 ] . flags = 0 ;
}
// Setup external rooms
room_surf_start = surf_index ;
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + , surf_index + + )
{
ComputeSurfaceRes ( & Light_surfaces [ surf_index ] , & Rooms [ i ] , t ) ;
Light_surfaces [ surf_index ] . verts = ( vector * ) mem_malloc ( Rooms [ i ] . faces [ t ] . num_verts * sizeof ( vector ) ) ;
ASSERT ( Light_surfaces [ surf_index ] . verts ! = NULL ) ;
Light_surfaces [ surf_index ] . elements = ( rad_element * ) mem_malloc ( Light_surfaces [ surf_index ] . xresolution * Light_surfaces [ surf_index ] . yresolution * sizeof ( rad_element ) ) ;
ASSERT ( Light_surfaces [ surf_index ] . elements ! = NULL ) ;
if ( Rooms [ i ] . faces [ t ] . portal_num ! = - 1 & & ! ( Rooms [ i ] . portals [ Rooms [ i ] . faces [ t ] . portal_num ] . flags & PF_RENDER_FACES ) )
{
Light_surfaces [ surf_index ] . surface_type = ST_PORTAL ;
Light_surfaces [ surf_index ] . emittance . r = 0 ;
Light_surfaces [ surf_index ] . emittance . g = 0 ;
Light_surfaces [ surf_index ] . emittance . b = 0 ;
}
else
{
float mul = ( ( float ) Rooms [ i ] . faces [ t ] . light_multiple ) / 4.0 ;
mul * = GlobalMultiplier * Room_multiplier [ i ] ;
Light_surfaces [ surf_index ] . emittance . r = ( float ) GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . r * mul ;
Light_surfaces [ surf_index ] . emittance . g = ( float ) GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . g * mul ;
Light_surfaces [ surf_index ] . emittance . b = ( float ) GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . b * mul ;
Light_surfaces [ surf_index ] . surface_type = ST_EXTERNAL_ROOM ;
//if ((GetMaxColor (&Light_surfaces[surf_index].emittance))>.005)
// Light_surfaces[surf_index].flags|=SF_LIGHTSOURCE;
}
Light_surfaces [ surf_index ] . normal = LightmapInfo [ Rooms [ i ] . faces [ t ] . lmi_handle ] . normal ;
Light_surfaces [ surf_index ] . roomnum = i ;
Light_surfaces [ surf_index ] . facenum = t ;
Light_surfaces [ surf_index ] . reflectivity = GameTextures [ Rooms [ i ] . faces [ t ] . tmap ] . reflectivity ;
// Set the vertices for each element
BuildElementListForRoomFace ( i , t , & Light_surfaces [ surf_index ] ) ;
int xres = Light_surfaces [ surf_index ] . xresolution ;
int yres = Light_surfaces [ surf_index ] . yresolution ;
}
}
}
// Setup objects
obj_surf_start = surf_index ;
ComputeSurfacesForObjects ( surf_index , 1 ) ;
mprintf ( ( 0 , " Solving radiosity equation (press tilde key to stop)... \n " ) ) ;
if ( D3EditState . hemicube_radiosity )
DoRadiosityRun ( SM_SWITCH_AFTER_SATELLITES , Light_surfaces , total_surfaces ) ;
else
DoRadiosityRun ( SM_RAYCAST , Light_surfaces , total_surfaces ) ;
// Figure out lighting by averaging the two triangles per terrain cell
if ( ! Ignore_terrain )
{
for ( i = 0 ; i < AREA_X * AREA_Z ; i + + )
{
// Add in ambient terrain light
terrain_sums [ 0 ] [ i ] . r = min ( 1.0 , Light_surfaces [ i * 2 ] . elements [ 0 ] . exitance . r + Ambient_red ) ;
terrain_sums [ 0 ] [ i ] . g = min ( 1.0 , Light_surfaces [ i * 2 ] . elements [ 0 ] . exitance . g + Ambient_green ) ;
terrain_sums [ 0 ] [ i ] . b = min ( 1.0 , Light_surfaces [ i * 2 ] . elements [ 0 ] . exitance . b + Ambient_blue ) ;
terrain_sums [ 1 ] [ i ] . r = min ( 1.0 , Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . exitance . r + Ambient_red ) ;
terrain_sums [ 1 ] [ i ] . g = min ( 1.0 , Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . exitance . g + Ambient_green ) ;
terrain_sums [ 1 ] [ i ] . b = min ( 1.0 , Light_surfaces [ i * 2 + 1 ] . elements [ 0 ] . exitance . b + Ambient_blue ) ;
}
for ( i = 0 ; i < ( AREA_X ) * ( AREA_Z ) ; i + + )
{
int x , z ;
spectra total ;
int num_items = 0 ;
int seg ;
memset ( & total , 0 , sizeof ( spectra ) ) ;
x = i % ( AREA_X ) ;
z = i / ( AREA_Z ) ;
seg = z * TERRAIN_WIDTH + x ;
if ( x ! = 0 )
{
AddSpectra ( & total , & total , & terrain_sums [ 1 ] [ z * ( AREA_X ) + ( x - 1 ) ] ) ;
num_items + + ;
}
AddSpectra ( & total , & total , & terrain_sums [ 0 ] [ z * ( AREA_X ) + x ] ) ;
AddSpectra ( & total , & total , & terrain_sums [ 1 ] [ z * ( AREA_X ) + x ] ) ;
num_items + = 2 ;
if ( x ! = 0 )
{
if ( z ! = 0 )
{
AddSpectra ( & total , & total , & terrain_sums [ 0 ] [ ( z - 1 ) * ( AREA_X ) + ( x - 1 ) ] ) ;
AddSpectra ( & total , & total , & terrain_sums [ 1 ] [ ( z - 1 ) * ( AREA_X ) + ( x - 1 ) ] ) ;
num_items + = 2 ;
}
}
if ( z ! = 0 )
{
AddSpectra ( & total , & total , & terrain_sums [ 0 ] [ ( z - 1 ) * ( AREA_X ) + x ] ) ;
num_items + + ;
}
total . r / = num_items ;
total . g / = num_items ;
total . b / = num_items ;
if ( total . r > 1.0 )
total . r = 1.0 ;
if ( total . g > 1.0 )
total . g = 1.0 ;
if ( total . b > 1.0 )
total . b = 1.0 ;
Terrain_seg [ seg ] . l = Float_to_ubyte ( GetMaxColor ( & total ) ) ;
Terrain_seg [ seg ] . r = Float_to_ubyte ( total . r ) ;
Terrain_seg [ seg ] . g = Float_to_ubyte ( total . g ) ;
Terrain_seg [ seg ] . b = Float_to_ubyte ( total . b ) ;
}
}
// Assign lightmaps to external rooms
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + , room_surf_start + + )
{
AssignRoomSurfaceToLightmap ( i , t , & Light_surfaces [ room_surf_start ] ) ;
}
}
}
// Now assign lightmaps to objects
AssignLightmapsToObjectSurfaces ( obj_surf_start , 1 ) ;
// Shade room/object lightmaps
BlurLightmapInfos ( LMI_EXTERNAL_ROOM ) ;
BlurLightmapInfos ( LMI_TERRAIN_OBJECT ) ;
ShadeLightmapInfoEdges ( LMI_EXTERNAL_ROOM ) ;
ShadeLightmapInfoEdges ( LMI_TERRAIN_OBJECT ) ;
// Free memory
for ( i = 0 ; i < total_surfaces ; i + + )
{
mem_free ( Light_surfaces [ i ] . verts ) ;
for ( int t = 0 ; t < Light_surfaces [ i ] . xresolution * Light_surfaces [ i ] . yresolution ; t + + )
if ( Light_surfaces [ i ] . elements [ t ] . num_verts > 0 )
mem_free ( Light_surfaces [ i ] . elements [ t ] . verts ) ;
mem_free ( Light_surfaces [ i ] . elements ) ;
}
mem_free ( Light_surfaces ) ;
mem_free ( terrain_sums [ 0 ] ) ;
mem_free ( terrain_sums [ 1 ] ) ;
for ( i = 0 ; i < Terrain_sky . num_satellites ; i + + )
mem_free ( TerrainLightSpeedup [ i ] ) ;
UpdateTerrainLightmaps ( ) ;
SqueezeLightmaps ( 1 , - 1 ) ;
// Figure out combined portals
CheckCombinePortals ( 1 ) ;
if ( do_dynamic )
DoTerrainDynamicTable ( ) ;
OutrageMessageBox ( " Terrain radiosity complete! \n It is recommended you save the level so you won't have to rerun this operation. " ) ;
}
/*
void DoRadiosityForTerrain ( )
{
int i , t , j , maxrays ;
int raynum = 0 ;
spectra * exitance ;
int lit = 0 ;
int do_dynamic = 0 ;
if ( ( MessageBox ( NULL , " Do you wish to calculate dynamic terrain lighting when radiosity is completed? (Note: Dynamic lighting takes a long time) " , " Question " , MB_YESNO ) ) = = IDYES )
do_dynamic = 1 ;
// First make sure there is even a light source
for ( i = 0 ; i < Terrain_sky . num_satellites ; i + + )
{
int tmap = Terrain_sky . satellite_texture [ i ] ;
if ( GameTextures [ tmap ] . r > 0 | | GameTextures [ tmap ] . g | | GameTextures [ tmap ] . b )
lit = 1 ;
}
if ( ! lit )
{
OutrageMessageBox ( " No moons/suns cast light so there is no point in running terrain radiosity! " ) ;
return ;
}
maxrays = ( TERRAIN_DEPTH - 1 ) * ( TERRAIN_WIDTH - 1 ) * Terrain_sky . num_satellites ;
mprintf ( ( 0 , " Calculating terrain radiosity for %d points! (be patient!) \n " , maxrays ) ) ;
// Malloc some memory
exitance = ( spectra * ) mem_malloc ( TERRAIN_DEPTH * TERRAIN_WIDTH * sizeof ( spectra ) ) ;
ASSERT ( exitance ! = NULL ) ;
for ( i = 0 ; i < TERRAIN_DEPTH * TERRAIN_WIDTH ; i + + )
{
exitance [ i ] . r = 0 ;
exitance [ i ] . g = 0 ;
exitance [ i ] . b = 0 ;
}
// Now shoot a ray from every triangle on the terrain to every moon/sun in the
// sky, tallying the results
for ( i = 0 ; i < TERRAIN_DEPTH - 1 ; i + + )
{
for ( t = 0 ; t < TERRAIN_WIDTH - 1 ; t + + )
{
int tseg = i * TERRAIN_WIDTH + t ;
vector pos1 , pos2 ;
pos1 . x = ( t * TERRAIN_SIZE ) + ( TERRAIN_SIZE / 3 ) ;
pos1 . z = ( i * TERRAIN_SIZE ) + ( TERRAIN_SIZE * .66 ) ;
pos1 . y = GetTerrainGroundPoint ( & pos1 ) ;
pos1 + = ( ( TerrainNormals [ MAX_TERRAIN_LOD - 1 ] [ tseg ] . normal1 ) / 16 ) ;
pos2 . x = ( t * TERRAIN_SIZE ) + ( TERRAIN_SIZE * .66 ) ;
pos2 . z = ( i * TERRAIN_SIZE ) + ( TERRAIN_SIZE / 3 ) ;
pos2 . y = GetTerrainGroundPoint ( & pos2 ) ;
pos2 + = ( ( TerrainNormals [ MAX_TERRAIN_LOD - 1 ] [ tseg ] . normal2 ) / 16 ) ;
for ( j = 0 ; j < Terrain_sky . num_satellites ; j + + )
{
raynum + + ;
mprintf_at ( ( 2 , 4 , 0 , " Ray=%d " , raynum ) ) ;
int answer1 , answer2 ;
answer1 = ShootRayForTerrainLight ( & pos1 , & Terrain_sky . satellite_vectors [ j ] , tseg ) ;
answer2 = ShootRayForTerrainLight ( & pos2 , & Terrain_sky . satellite_vectors [ j ] , tseg ) ;
if ( answer1 = = 0 & & answer2 = = 0 )
continue ;
float r = exitance [ tseg ] . r ;
float g = exitance [ tseg ] . g ;
float b = exitance [ tseg ] . b ;
int tmap = Terrain_sky . satellite_texture [ j ] ;
float light1 , light2 , light_avg ;
vector tnorm1 = TerrainNormals [ MAX_TERRAIN_LOD - 1 ] [ tseg ] . normal1 ;
vector tnorm2 = TerrainNormals [ MAX_TERRAIN_LOD - 1 ] [ tseg ] . normal2 ;
vector normal ;
vm_GetNormalizedDir ( & normal , & Terrain_sky . satellite_vectors [ j ] , & pos1 ) ;
light1 = answer1 * ( vm_DotProduct ( & normal , & tnorm1 ) ) ;
if ( light1 < 0 )
light1 = 0 ;
vm_GetNormalizedDir ( & normal , & Terrain_sky . satellite_vectors [ j ] , & pos2 ) ;
light2 = answer2 * ( vm_DotProduct ( & normal , & tnorm2 ) ) ;
if ( light2 < 0 )
light2 = 0 ;
light_avg = ( light1 + light2 ) / 2 ;
r + = ( light_avg * GameTextures [ tmap ] . r ) ;
g + = ( light_avg * GameTextures [ tmap ] . g ) ;
b + = ( light_avg * GameTextures [ tmap ] . b ) ;
exitance [ tseg ] . r = r ;
exitance [ tseg ] . g = g ;
exitance [ tseg ] . b = b ;
}
}
}
// Clip to 1.0
for ( i = 0 ; i < TERRAIN_DEPTH * TERRAIN_WIDTH ; i + + )
{
exitance [ i ] . r = min ( exitance [ i ] . r , 1.0 ) ;
exitance [ i ] . g = min ( exitance [ i ] . g , 1.0 ) ;
exitance [ i ] . b = min ( exitance [ i ] . b , 1.0 ) ;
}
// Now average the surrounding cells to get a 'smooth' shadow effect
for ( i = 0 ; i < TERRAIN_DEPTH ; i + + )
{
for ( t = 0 ; t < TERRAIN_WIDTH ; t + + )
{
int tseg = i * TERRAIN_WIDTH + t ;
spectra total = { 0 , 0 , 0 } ;
int num = 0 ;
AddSpectra ( & total , & total , & exitance [ tseg ] ) ;
num + + ;
if ( i ! = 0 )
{
AddSpectra ( & total , & total , & exitance [ ( i - 1 ) * TERRAIN_WIDTH + t ] ) ;
num + + ;
if ( t ! = 0 )
{
AddSpectra ( & total , & total , & exitance [ ( i - 1 ) * TERRAIN_WIDTH + ( t - 1 ) ] ) ;
num + + ;
}
}
if ( t ! = 0 )
{
AddSpectra ( & total , & total , & exitance [ i * TERRAIN_WIDTH + ( t - 1 ) ] ) ;
num + + ;
}
total . r / = num ;
total . g / = num ;
total . b / = num ;
Terrain_seg [ tseg ] . r = total . r * 255 ;
Terrain_seg [ tseg ] . g = total . g * 255 ;
Terrain_seg [ tseg ] . b = total . b * 255 ;
Terrain_seg [ tseg ] . l = ( ( total . r + total . g + total . b ) * 255 ) / 3 ;
}
}
free ( exitance ) ;
if ( do_dynamic )
DoTerrainDynamicTable ( ) ;
UpdateTerrainLightmaps ( ) ;
OutrageMessageBox ( " Terrain radiosity complete! \n It is recommended you save the level so you won't have to rerun this operation. " ) ;
} */
void BuildLightmapUVs ( int * room_list , int * face_list , int count , vector * lightmap_poly , int nv , int external )
{
matrix face_matrix , trans_matrix ;
vector fvec ;
vector avg_vert ;
vector verts [ MAX_VERTS_PER_FACE * 5 ] ;
vector facevert ;
vector rot_vert ;
int i , t ;
int lmi_handle ;
// find the center point of this face
vm_MakeZero ( & avg_vert ) ;
for ( i = 0 ; i < nv ; i + + )
avg_vert + = lightmap_poly [ i ] ;
avg_vert / = nv ;
// Make the orientation matrix
// Reverse the normal because we're looking "at" the face, not from it
fvec = - Rooms [ room_list [ 0 ] ] . faces [ face_list [ 0 ] ] . normal ;
vm_VectorToMatrix ( & face_matrix , & fvec , NULL , NULL ) ;
// Make the transformation matrix
angvec avec ;
vm_ExtractAnglesFromMatrix ( & avec , & face_matrix ) ;
vm_AnglesToMatrix ( & trans_matrix , avec . p , avec . h , avec . b ) ;
// Rotate all the points
for ( i = 0 ; i < nv ; i + + )
{
vector vert = lightmap_poly [ i ] ;
vert - = avg_vert ;
vm_MatrixMulVector ( & rot_vert , & vert , & trans_matrix ) ;
verts [ i ] = rot_vert ;
}
// Find left most point
int leftmost_point = - 1 ;
float leftmost_x = 900000.00f ; // a big number
for ( i = 0 ; i < nv ; i + + )
{
if ( verts [ i ] . x < leftmost_x )
{
leftmost_point = i ;
leftmost_x = verts [ i ] . x ;
}
}
ASSERT ( leftmost_point ! = - 1 ) ;
// Find top most point
int topmost_point = - 1 ;
float topmost_y = - 900000.0f ; // a big number
for ( i = 0 ; i < nv ; i + + )
{
if ( verts [ i ] . y > topmost_y )
{
topmost_point = i ;
topmost_y = verts [ i ] . y ;
}
}
ASSERT ( topmost_point ! = - 1 ) ;
// Find right most point
int rightmost_point = - 1 ;
float rightmost_x = - 900000.00f ; // a big number
for ( i = 0 ; i < nv ; i + + )
{
if ( verts [ i ] . x > rightmost_x )
{
rightmost_point = i ;
rightmost_x = verts [ i ] . x ;
}
}
ASSERT ( rightmost_point ! = - 1 ) ;
// Find bottom most point
int bottommost_point = - 1 ;
float bottommost_y = 900000.0f ; // a big number
for ( i = 0 ; i < nv ; i + + )
{
if ( verts [ i ] . y < bottommost_y )
{
bottommost_point = i ;
bottommost_y = verts [ i ] . y ;
}
}
ASSERT ( bottommost_point ! = - 1 ) ;
// now set the base vertex, which is where we base uv 0,0 on
vector base_vector ;
base_vector . x = verts [ leftmost_point ] . x ;
base_vector . y = verts [ topmost_point ] . y ;
base_vector . z = 0 ;
// Figure out lightmap resolution
float xdiff = verts [ rightmost_point ] . x - verts [ leftmost_point ] . x ;
float ydiff = verts [ topmost_point ] . y - verts [ bottommost_point ] . y ;
float max_diff = ( float ) max ( xdiff , ydiff ) ;
int lightmap_x_res = - 1 , lightmap_y_res = - 1 ;
float xspacing = LightSpacing ;
float yspacing = LightSpacing ;
float spacing = LightSpacing ;
int res , done_spacing = 0 ;
int xspace_int , yspace_int ;
// If the default spacing would make us go over our lightmap resolution
// limit, then increase the spacing and try again
while ( ! done_spacing )
{
res = ( xdiff / xspacing ) ;
if ( ( ( xdiff / xspacing ) - res ) > 0 )
res + + ;
res + + ;
if ( res > 126 )
xspacing + = 1 ;
else
done_spacing = 1 ;
}
// Set a mininum, at least
if ( res < 2 )
res = 2 ;
lightmap_x_res = res ;
done_spacing = 0 ;
while ( ! done_spacing )
{
res = ( ydiff / yspacing ) ;
if ( ( ( ydiff / yspacing ) - res ) > 0 )
res + + ;
res + + ;
if ( res > 126 )
yspacing + = 1 ;
else
done_spacing = 1 ;
}
// Set a mininum, at least
if ( res < 2 )
res = 2 ;
lightmap_y_res = res ;
/*// Find power of 2 number
for ( i = 0 ; i < = 7 ; i + + )
{
int low_num = 1 < i ;
int hi_num = 2 < < i ;
if ( res < = hi_num & & res > low_num )
{
lightmap_res = hi_num ;
break ;
}
} */
if ( external )
lmi_handle = AllocLightmapInfo ( lightmap_x_res , lightmap_y_res , LMI_EXTERNAL_ROOM ) ;
else
lmi_handle = AllocLightmapInfo ( lightmap_x_res , lightmap_y_res , LMI_ROOM ) ;
ASSERT ( lmi_handle ! = BAD_LMI_INDEX ) ;
ASSERT ( lmi_handle > = 0 & & lmi_handle < = MAX_LIGHTMAP_INFOS ) ;
Lightmaps_for_rad + + ;
// Now do best fit spacing
if ( BestFit )
{
xspace_int = ( xdiff / lightmap_x_res ) ;
if ( ( xdiff - ( lightmap_x_res * xspace_int ) ) > 0 )
xspace_int + + ;
yspace_int = ( ydiff / lightmap_y_res ) ;
if ( ( ydiff - ( lightmap_y_res * yspace_int ) ) > 0 )
yspace_int + + ;
}
else
{
xspace_int = xspacing ;
yspace_int = yspacing ;
}
// Figure out lightmap uvs
// Rotate all the face points
for ( i = 0 ; i < count ; i + + )
{
Rooms [ room_list [ i ] ] . faces [ face_list [ i ] ] . lmi_handle = lmi_handle ;
for ( t = 0 ; t < Rooms [ room_list [ i ] ] . faces [ face_list [ i ] ] . num_verts ; t + + )
{
room * rp = & Rooms [ room_list [ i ] ] ;
face * fp = & rp - > faces [ face_list [ i ] ] ;
vector vert = rp - > verts [ fp - > face_verts [ t ] ] ;
vert - = avg_vert ;
vm_MatrixMulVector ( & rot_vert , & vert , & trans_matrix ) ;
facevert = rot_vert ;
// Find uv2s for this vertex
fp - > face_uvls [ t ] . u2 = ( facevert . x - verts [ leftmost_point ] . x ) / ( float ) ( lightmap_x_res * xspace_int ) ;
fp - > face_uvls [ t ] . v2 = fabs ( ( verts [ topmost_point ] . y - facevert . y ) ) / ( float ) ( lightmap_y_res * yspace_int ) ;
if ( fp - > face_uvls [ t ] . u2 < 0 )
fp - > face_uvls [ t ] . u2 = 0 ;
if ( fp - > face_uvls [ t ] . v2 < 0 )
fp - > face_uvls [ t ] . v2 = 0 ;
ASSERT ( fp - > face_uvls [ t ] . u2 > = 0 & & fp - > face_uvls [ t ] . u2 < = 1.0 ) ;
ASSERT ( fp - > face_uvls [ t ] . v2 > = 0 & & fp - > face_uvls [ t ] . v2 < = 1.0 ) ;
}
}
// Find upper left corner
vm_TransposeMatrix ( & trans_matrix ) ;
vm_MatrixMulVector ( & rot_vert , & base_vector , & trans_matrix ) ;
LightmapInfo [ lmi_handle ] . upper_left = rot_vert + avg_vert ;
LightmapInfo [ lmi_handle ] . xspacing = xspace_int ;
LightmapInfo [ lmi_handle ] . yspacing = yspace_int ;
LightmapInfo [ lmi_handle ] . normal = Rooms [ room_list [ 0 ] ] . faces [ face_list [ 0 ] ] . normal ;
ScratchCenters [ lmi_handle ] = avg_vert ;
}
# define MAX_COMBINES 50
# define LM_ADJACENT_FACE_THRESHOLD .999
2024-05-24 03:07:26 +00:00
uint8_t * RoomsAlreadyCombined [ MAX_ROOMS ] ;
2024-04-19 20:58:24 +00:00
/*
// Returns number of verts in dest if face a can be safely combined with face b
// Returns 0 if not
int CombineLightFaces ( vector * dest_verts , vector * averts , int nva , vector * norma , vector * bverts , int nvb , vector * normb , int aroom , int broom )
{
int starta , startb , i ;
vector va ;
float dp ;
dp = vm_DotProduct ( normb , norma ) ;
if ( dp < LM_ADJACENT_FACE_THRESHOLD )
return 0 ;
ASSERT ( nva > 2 ) ;
ASSERT ( nvb > 2 ) ;
// Go through each vertex and get a match
for ( starta = 0 ; starta < nva ; starta + + )
{
int nexta = ( starta + 1 ) % nva ;
for ( startb = 0 ; startb < nvb ; startb + + )
{
int nextb = ( startb + 1 ) % nvb ;
if ( ( PointsAreSame ( & averts [ starta ] , & bverts [ nextb ] ) ) & &
( PointsAreSame ( & averts [ nexta ] , & bverts [ startb ] ) ) )
{
//MATCH!!!!!!!!
int dnv = 0 ;
for ( i = 1 ; i < nva ; i + + )
{
ASSERT ( dnv < MAX_VERTS_PER_FACE * 5 ) ;
dest_verts [ dnv ] = averts [ ( starta + i ) % nva ] ;
va = dest_verts [ dnv ] ;
dnv + + ;
}
if ( ( PointsAreSame ( & va , & bverts [ ( startb + 2 ) % nvb ] ) ) )
mprintf ( ( 0 , " WARNING!!! Faces were combined that caused the loss of a vertex! \n " ) ) ;
for ( i = 1 ; i < nvb ; i + + )
{
ASSERT ( dnv < MAX_VERTS_PER_FACE * 5 ) ;
if ( ( i = = 1 ) & & ( PointsAreSame ( & va , & bverts [ ( startb + i + 1 ) % nvb ] ) ) )
continue ;
else if ( ( i = = 2 ) & & ( PointsAreSame ( & va , & bverts [ ( startb + i ) % nvb ] ) ) )
continue ;
else
{
dest_verts [ dnv ] = bverts [ ( startb + i ) % nvb ] ;
dnv + + ;
}
}
ASSERT ( dnv > 2 ) ;
return dnv ;
}
}
}
Now check for tjoint faces
for ( starta = 0 ; starta < nva ; starta + + )
{
int nexta = ( starta + 1 ) % nva ;
for ( startb = 0 ; startb < nvb ; startb + + )
{
vector line_a = averts [ nexta ] - averts [ starta ] ;
}
}
// If these two faces are in the same room and are on the same plane
// then we should combine them by default
if ( aroom ! = - 1 & & aroom = = broom )
{
int dnv = 0 ;
int match = 0 ;
// Test to see if any points at all can touch
for ( i = 0 ; i < nva & & ! match ; i + + )
{
for ( int t = 0 ; t < nvb & & ! match ; t + + )
{
if ( PointsAreSame ( & averts [ i ] , & bverts [ t ] ) )
match = 1 ;
}
}
if ( ! match )
return 0 ;
// At least one point is the same, so combine them!
for ( i = 0 ; i < nva ; i + + )
{
dest_verts [ dnv ] = averts [ i ] ;
dnv + + ;
ASSERT ( dnv < MAX_VERTS_PER_FACE * 5 ) ;
}
for ( i = 0 ; i < nvb ; i + + )
{
dest_verts [ dnv ] = bverts [ i ] ;
dnv + + ;
ASSERT ( dnv < MAX_VERTS_PER_FACE * 5 ) ;
}
return dnv ;
}
return 0 ;
} */
// Returns number of verts in dest if face a can be safely combined with face b
// Returns 0 if not
int CombineLightFaces ( vector * dest_verts , vector * averts , int nva , vector * norma , vector * bverts , int nvb , vector * normb , int aroom , int broom )
{
int i ;
float dp ;
dp = vm_DotProduct ( normb , norma ) ;
if ( dp < LM_ADJACENT_FACE_THRESHOLD )
return 0 ;
ASSERT ( nva > 2 ) ;
ASSERT ( nvb > 2 ) ;
// Go through each vertex and get a match
// If these two faces are in the same room and are on the same plane
// then we should combine them by default
if ( 1 | | ( aroom ! = - 1 & & aroom = = broom ) )
{
int dnv = 0 ;
int match = 0 ;
// Don't go over our point limit
if ( ( nva + nvb ) > = ( MAX_VERTS_PER_FACE * 5 ) )
return 0 ;
// Test to see if any points at all can touch
for ( i = 0 ; i < nva & & ! match ; i + + )
{
for ( int t = 0 ; t < nvb & & ! match ; t + + )
{
if ( PointsAreSame ( & averts [ i ] , & bverts [ t ] ) )
match = 1 ;
}
}
if ( ! match )
return 0 ;
// At least one point is the same, so combine them!
for ( i = 0 ; i < nva ; i + + )
{
dest_verts [ dnv ] = averts [ i ] ;
dnv + + ;
ASSERT ( dnv < MAX_VERTS_PER_FACE * 5 ) ;
}
for ( i = 0 ; i < nvb ; i + + )
{
dest_verts [ dnv ] = bverts [ i ] ;
dnv + + ;
ASSERT ( dnv < MAX_VERTS_PER_FACE * 5 ) ;
}
return dnv ;
}
return 0 ;
}
// Given a roomnumber and a face, goes through the entire mine and checks to see
// if this face can share a lightmap with any other face
int TestLightAdjacency ( int roomnum , int facenum , int external )
{
int i , t , k ;
room * arp = & Rooms [ roomnum ] ;
face * afp = & arp - > faces [ facenum ] ;
vector averts [ MAX_VERTS_PER_FACE * 5 ] ;
vector bverts [ MAX_VERTS_PER_FACE * 5 ] ;
vector dest_verts [ MAX_VERTS_PER_FACE * 5 ] ;
int face_combine_list [ MAX_COMBINES ] ;
int room_combine_list [ MAX_COMBINES ] ;
ASSERT ( roomnum > = 0 & & roomnum < MAX_ROOMS ) ;
if ( ! AllowCombining )
return 0 ;
//if (GameTextures[afp->tmap].r>0 || GameTextures[afp->tmap].g>0 || GameTextures[afp->tmap].b>0)
// return 0;
// Don't combine portals!
if ( afp - > portal_num ! = - 1 )
return 0 ;
// Setup our 'base' face
int anv = afp - > num_verts ;
int total_faces = 1 ;
room_combine_list [ 0 ] = roomnum ;
face_combine_list [ 0 ] = facenum ;
for ( i = 0 ; i < afp - > num_verts ; i + + )
averts [ i ] = arp - > verts [ afp - > face_verts [ i ] ] ;
StartOver :
// Go through each room and find an adjacent face
for ( i = roomnum ; i < MAX_ROOMS ; i + + )
{
if ( ! Rooms [ i ] . used )
continue ;
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( external & & ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
if ( ! external & & ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
/*if (i!=roomnum) // Only combine faces in the same room
continue ; */
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + )
{
if ( total_faces > = MAX_COMBINES - 1 )
continue ;
if ( & Rooms [ i ] = = arp & & t = = facenum )
continue ; // don't do self
// Don't do if already spoken fore
if ( RoomsAlreadyCombined [ i ] [ t ] )
continue ;
room * brp = & Rooms [ i ] ;
face * bfp = & brp - > faces [ t ] ;
// Don't do combine light sources
//if (GameTextures[bfp->tmap].r>0 || GameTextures[bfp->tmap].g>0 || GameTextures[bfp->tmap].b>0)
// continue;
// Don't combine portals!
if ( bfp - > portal_num ! = - 1 )
continue ;
for ( k = 0 ; k < bfp - > num_verts ; k + + )
bverts [ k ] = brp - > verts [ bfp - > face_verts [ k ] ] ;
int nv = CombineLightFaces ( dest_verts , averts , anv , & afp - > normal , bverts , bfp - > num_verts , & bfp - > normal , roomnum , i ) ;
// We have a combine! Mark this face in the appropriate list
// And update our new polygon
if ( nv > 0 )
{
room_combine_list [ total_faces ] = i ;
face_combine_list [ total_faces ] = t ;
total_faces + + ;
RoomsAlreadyCombined [ roomnum ] [ facenum ] = 1 ;
RoomsAlreadyCombined [ i ] [ t ] = 1 ;
for ( k = 0 ; k < nv ; k + + )
averts [ k ] = dest_verts [ k ] ;
anv = nv ;
goto StartOver ;
}
}
}
// Now build 1 lightmap to be shared across all the faces that were combined
if ( total_faces > 1 )
{
BuildLightmapUVs ( room_combine_list , face_combine_list , total_faces , averts , anv , external ) ;
}
return 1 ;
}
// Computes the the mines UVs
// Faces can now share one lightmap, so this routine goes through and tries to
// combine as many faces as it can into one lightmap
void ComputeAllRoomLightmapUVs ( int external )
{
int i , t , k ;
int not_combined = 0 ;
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( external & & ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
if ( ! external & & ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
2024-05-24 03:07:26 +00:00
RoomsAlreadyCombined [ i ] = ( uint8_t * ) mem_malloc ( Rooms [ i ] . num_faces ) ;
2024-04-19 20:58:24 +00:00
ASSERT ( RoomsAlreadyCombined [ i ] ) ;
for ( k = 0 ; k < Rooms [ i ] . num_faces ; k + + )
RoomsAlreadyCombined [ i ] [ k ] = 0 ;
}
}
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( external & & ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
if ( ! external & & ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + )
{
if ( * ( RoomsAlreadyCombined [ i ] + t ) = = 0 )
TestLightAdjacency ( i , t , external ) ;
}
}
}
// Now build lightmaps for any faces that couldn't be combined
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( external & & ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
if ( ! external & & ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
for ( t = 0 ; t < Rooms [ i ] . num_faces ; t + + )
{
if ( ! RoomsAlreadyCombined [ i ] [ t ] )
{
vector verts [ MAX_VERTS_PER_FACE * 5 ] ;
int room_list [ 2 ] , face_list [ 2 ] ;
for ( k = 0 ; k < Rooms [ i ] . faces [ t ] . num_verts ; k + + )
verts [ k ] = Rooms [ i ] . verts [ Rooms [ i ] . faces [ t ] . face_verts [ k ] ] ;
room_list [ 0 ] = i ;
face_list [ 0 ] = t ;
BuildLightmapUVs ( room_list , face_list , 1 , verts , Rooms [ i ] . faces [ t ] . num_verts , external ) ;
not_combined + + ;
}
}
}
}
mprintf ( ( 0 , " %d faces couldn't be combined! \n " , not_combined ) ) ;
// Free memory
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( external & & ! ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
if ( ! external & & ( Rooms [ i ] . flags & RF_EXTERNAL ) )
continue ;
mem_free ( RoomsAlreadyCombined [ i ] ) ;
}
}
}
// Returns number preceding val modulo modulus.
// prevmod(3,4) = 2
// prevmod(0,4) = 3
int SpecularPrevIndex ( int val , int modulus )
{
if ( val > 0 )
return val - 1 ;
else
return modulus - 1 ;
}
// Returns number succeeding val modulo modulus.
// succmod(3,4) = 0
// succmod(0,4) = 1
int SpecularNextIndex ( int val , int modulus )
{
if ( val < modulus - 1 )
return val + 1 ;
else
return 0 ;
}
// Gets the left top, left bottom, right top, and right bottom indices. Also finds
// lowest y index.
void GetSpecularVertexOrdering ( spec_vertex * verts , int nv , int * vlt , int * vlb , int * vrt , int * vrb , int * bottom_y_ind )
{
int i ;
float min_y , max_y ;
int min_y_ind ;
int original_vrt ;
float min_x ;
// Scan all vertices, set min_y_ind to vertex with smallest y coordinate.
min_y = verts [ 0 ] . y ;
max_y = min_y ;
min_y_ind = 0 ;
min_x = verts [ 0 ] . x ;
* bottom_y_ind = 0 ;
for ( i = 1 ; i < nv ; i + + )
{
if ( verts [ i ] . y < min_y )
{
min_y = verts [ i ] . y ;
min_y_ind = i ;
min_x = verts [ i ] . x ;
}
else if ( verts [ i ] . y = = min_y )
{
if ( verts [ i ] . x < min_x )
{
min_y_ind = i ;
min_x = verts [ i ] . x ;
}
}
if ( verts [ i ] . y > max_y )
{
max_y = verts [ i ] . y ;
* bottom_y_ind = i ;
}
}
// Set "vertex left top", etc. based on vertex with topmost y coordinate
* vlt = min_y_ind ;
* vrt = * vlt ;
* vlb = SpecularPrevIndex ( * vlt , nv ) ;
* vrb = SpecularNextIndex ( * vrt , nv ) ;
// If right edge is horizontal, then advance along polygon bound until it no longer is or until all
// vertices have been examined.
// (Left edge cannot be horizontal, because *vlt is set to leftmost point with highest y coordinate.)
original_vrt = * vrt ;
while ( verts [ * vrt ] . y = = verts [ * vrb ] . y )
{
if ( SpecularNextIndex ( * vrt , nv ) = = original_vrt )
break ;
* vrt = SpecularNextIndex ( * vrt , nv ) ;
* vrb = SpecularNextIndex ( * vrt , nv ) ;
}
}
/*
// Creates a map that contains all the interpolated normals for a particular face
// Used in specular mapping
void CreateNormalMapForFace ( room * rp , face * fp )
{
int w = lmi_w ( fp - > lmi_handle ) ;
int h = lmi_h ( fp - > lmi_handle ) ;
special_face * sfp = & SpecialFaces [ fp - > special_handle ] ;
spec_vertex spec_verts [ MAX_VERTS_PER_FACE ] ;
vector vertnorms [ MAX_VERTS_PER_FACE ] ;
int vlt , vlb , vrt , vrb , max_y_vertex , top_y , bottom_y , height ;
int no_height = 0 , no_width = 0 , no_right = 0 , no_left = 0 ;
lightmap_info * lmi_ptr = & LightmapInfo [ fp - > lmi_handle ] ;
2024-05-24 03:16:40 +00:00
uint16_t * src_data = lm_data ( lmi_ptr - > lm_handle ) ;
2024-04-19 20:58:24 +00:00
matrix facematrix ;
vector fvec = - lmi_ptr - > normal ;
vm_VectorToMatrix ( & facematrix , & fvec , NULL , NULL ) ;
2024-05-24 03:07:26 +00:00
sfp - > normal_map = ( uint8_t * ) mem_malloc ( w * h * 3 ) ;
2024-04-19 20:58:24 +00:00
ASSERT ( sfp - > normal_map ) ;
for ( int i = 0 ; i < ( w * h ) ; i + + )
{
sfp - > normal_map [ i * 3 + 0 ] = 0 ;
sfp - > normal_map [ i * 3 + 1 ] = 0 ;
sfp - > normal_map [ i * 3 + 2 ] = 128 ;
}
for ( i = 0 ; i < fp - > num_verts ; i + + )
{
vm_MatrixMulVector ( & vertnorms [ i ] , & sfp - > vertnorms [ i ] , & facematrix ) ;
spec_verts [ i ] . x = fp - > face_uvls [ i ] . u2 ;
spec_verts [ i ] . y = fp - > face_uvls [ i ] . v2 ;
}
GetSpecularVertexOrdering ( spec_verts , fp - > num_verts , & vlt , & vlb , & vrt , & vrb , & max_y_vertex ) ;
top_y = spec_verts [ vlt ] . y * h ;
bottom_y = spec_verts [ max_y_vertex ] . y * h ;
height = bottom_y - top_y ;
if ( height = = 0 )
no_height = 1 ;
// Setup left interpolant
int left_height = ( ( spec_verts [ vlb ] . y - spec_verts [ vlt ] . y ) * ( float ) h ) ;
float left_x = spec_verts [ vlt ] . x * w ;
float delta_left_x = ( ( spec_verts [ vlb ] . x - spec_verts [ vlt ] . x ) * w ) / left_height ;
vector left_vnorm = vertnorms [ vlt ] ;
vector delta_left_vnorm = ( vertnorms [ vlb ] - vertnorms [ vlt ] ) / left_height ;
int next_break_left = spec_verts [ vlb ] . y * h ;
// Setup right interpolant
int right_height = ( ( spec_verts [ vrb ] . y - spec_verts [ vrt ] . y ) * ( float ) h ) ;
float right_x = spec_verts [ vrt ] . x * w ;
float delta_right_x = ( ( spec_verts [ vrb ] . x - spec_verts [ vrt ] . x ) * w ) / right_height ;
vector right_vnorm = vertnorms [ vrt ] ;
vector delta_right_vnorm = ( vertnorms [ vrb ] - vertnorms [ vrt ] ) / right_height ;
int next_break_right = spec_verts [ vrb ] . y * h ;
// Do the loop
for ( int y = top_y ; y < = bottom_y ; y + + )
{
if ( y = = next_break_left & & ! no_height )
{
while ( y = = ( int ) ( spec_verts [ vlb ] . y * h ) )
{
vlt = vlb ;
vlb = SpecularPrevIndex ( vlb , fp - > num_verts ) ;
}
// Setup left interpolant
left_height = ( ( spec_verts [ vlb ] . y - spec_verts [ vlt ] . y ) * ( float ) h ) ;
left_x = spec_verts [ vlt ] . x * w ;
delta_left_x = ( ( spec_verts [ vlb ] . x - spec_verts [ vlt ] . x ) * w ) / left_height ;
left_vnorm = vertnorms [ vlt ] ;
delta_left_vnorm = ( vertnorms [ vlb ] - vertnorms [ vlt ] ) / left_height ;
next_break_left = spec_verts [ vlb ] . y * h ;
}
if ( y = = next_break_right & & ! no_height )
{
while ( y = = ( int ) ( spec_verts [ vrb ] . y * h ) )
{
vrt = vrb ;
vrb = SpecularNextIndex ( vrb , fp - > num_verts ) ;
}
right_height = ( ( spec_verts [ vrb ] . y - spec_verts [ vrt ] . y ) * ( float ) h ) ;
right_x = spec_verts [ vrt ] . x * w ;
delta_right_x = ( ( spec_verts [ vrb ] . x - spec_verts [ vrt ] . x ) * w ) / right_height ;
right_vnorm = vertnorms [ vrt ] ;
delta_right_vnorm = ( vertnorms [ vrb ] - vertnorms [ vrt ] ) / right_height ;
next_break_right = spec_verts [ vrb ] . y * h ;
}
int width = ( right_x - left_x ) + 1 ;
vector delta_vnorm = ( right_vnorm - left_vnorm ) / width ;
vector vnorm = left_vnorm ;
for ( i = left_x ; i < ( left_x + width ) ; i + + )
{
int offset = y * w + i ;
if ( ! ( src_data [ offset ] & OPAQUE_FLAG ) )
continue ;
sfp - > normal_map [ ( offset * 3 ) + 0 ] = ( ( vnorm . x + 1.0 ) / 2.0 ) * 255.0 ;
sfp - > normal_map [ ( offset * 3 ) + 1 ] = ( ( vnorm . y + 1.0 ) / 2.0 ) * 255.0 ;
sfp - > normal_map [ ( offset * 3 ) + 2 ] = ( ( vnorm . z + 1.0 ) / 2.0 ) * 255.0 ;
vnorm + = delta_vnorm ;
}
// Update our interpolants
left_x + = delta_left_x ;
right_x + = delta_right_x ;
right_vnorm + = delta_right_vnorm ;
left_vnorm + = delta_left_vnorm ;
}
} */
// Frees memory for specular lighting
void CleanupSpecularLighting ( int external )
{
int i , t ;
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( ( Rooms [ i ] . flags & RF_EXTERNAL ) & & ! external )
continue ;
if ( ! ( Rooms [ i ] . flags & RF_EXTERNAL ) & & external )
continue ;
room * rp = & Rooms [ i ] ;
for ( t = 0 ; t < 4 ; t + + )
{
mem_free ( Room_strongest_value [ i ] [ t ] ) ;
}
for ( t = 0 ; t < rp - > num_faces ; t + + )
{
face * fp = & rp - > faces [ t ] ;
if ( GameTextures [ fp - > tmap ] . flags & TF_SPECULAR )
{
ASSERT ( fp - > special_handle ! = BAD_SPECIAL_FACE_INDEX ) ;
int j , k , l ;
if ( SpecialFaces [ fp - > special_handle ] . spec_instance [ 0 ] . bright_color = = 0 )
{
// This face didn't get enough light, either free it up or
// find another face that shares a lightmap and just use that
// faces values
int found = 0 ;
float strongest_light = 0 ;
face * best_face ;
for ( l = 0 ; l < fp - > num_verts ; l + + )
{
int vert_to_check = fp - > face_verts [ l ] ;
for ( j = 0 ; j < rp - > num_faces ; j + + )
{
face * this_fp = & rp - > faces [ j ] ;
if ( this_fp = = fp )
continue ; // don't do self
if ( this_fp - > lmi_handle ! = fp - > lmi_handle )
continue ; // only do faces that have same lightmaps
if ( this_fp - > special_handle = = BAD_SPECIAL_FACE_INDEX )
continue ; // Only do specmaps
if ( SpecialFaces [ this_fp - > special_handle ] . spec_instance [ 0 ] . bright_color = = 0 )
continue ; // Don't do dark ones
if ( GameTextures [ fp - > tmap ] . flags & TF_SMOOTH_SPECULAR )
continue ; // Don't do smooth shades
for ( k = 0 ; k < this_fp - > num_verts ; k + + )
{
if ( vert_to_check = = this_fp - > face_verts [ k ] )
{
// We have a match, so see if this face is brighter
// than all the others
int color = SpecialFaces [ this_fp - > special_handle ] . spec_instance [ 0 ] . bright_color ;
int r = ( color > > 10 ) & 0x1f ;
int g = ( color > > 5 ) & 0x1f ;
int b = ( color & 0x1f ) ;
float sr = ( float ) r / 31.0 ;
float sg = ( float ) g / 31.0 ;
float sb = ( float ) b / 31.0 ;
float mono_color = ( sr * .3 ) + ( sg * .59 ) + ( sb * .11 ) ;
if ( mono_color > strongest_light )
{
strongest_light = mono_color ;
found = 1 ;
best_face = this_fp ;
}
}
}
}
}
// If after all that searching we couldn't find a good light, free it!
if ( ! found )
{
FreeSpecialFace ( fp - > special_handle ) ;
fp - > special_handle = BAD_SPECIAL_FACE_INDEX ;
}
else
{
for ( int z = 0 ; z < 4 ; z + + )
SpecialFaces [ fp - > special_handle ] . spec_instance [ z ] = SpecialFaces [ best_face - > special_handle ] . spec_instance [ z ] ;
}
}
}
}
}
}
}
// Sets up memory usage for specular lighting
void SetupSpecularLighting ( int external )
{
int i , t ;
ClearAllRoomSpecmaps ( external ) ;
for ( i = 0 ; i < MAX_ROOMS ; i + + )
{
if ( Rooms [ i ] . used )
{
if ( Rooms [ i ] . flags & RF_NO_LIGHT )
continue ;
if ( ( Rooms [ i ] . flags & RF_EXTERNAL ) & & ! external )
continue ;
if ( ! ( Rooms [ i ] . flags & RF_EXTERNAL ) & & external )
continue ;
room * rp = & Rooms [ i ] ;
// Calculate vertex normals for this room
vector * vertnorms = ( vector * ) mem_malloc ( sizeof ( vector ) * rp - > num_verts ) ;
ASSERT ( vertnorms ) ;
for ( t = 0 ; t < rp - > num_verts ; t + + )
{
int total = 0 ;
vector normal ;
vm_MakeZero ( & normal ) ;
for ( int k = 0 ; k < rp - > num_faces ; k + + )
{
face * fp = & rp - > faces [ k ] ;
for ( int j = 0 ; j < fp - > num_verts ; j + + )
{
if ( fp - > face_verts [ j ] = = t )
{
total + + ;
normal + = fp - > normal ;
}
}
}
if ( total ! = 0 )
normal / = total ;
vertnorms [ t ] = normal ;
}
for ( t = 0 ; t < 4 ; t + + )
{
Room_strongest_value [ i ] [ t ] = ( float * ) mem_malloc ( sizeof ( float ) * rp - > num_faces ) ;
ASSERT ( Room_strongest_value [ i ] [ t ] ) ;
memset ( Room_strongest_value [ i ] [ t ] , 0 , sizeof ( float ) * rp - > num_faces ) ;
}
for ( t = 0 ; t < rp - > num_faces ; t + + )
{
face * fp = & rp - > faces [ t ] ;
if ( GameTextures [ fp - > tmap ] . flags & TF_SPECULAR )
{
ASSERT ( fp - > special_handle = = BAD_SPECIAL_FACE_INDEX ) ;
int n ;
if ( GameTextures [ fp - > tmap ] . flags & TF_SMOOTH_SPECULAR )
n = AllocSpecialFace ( SFT_SPECULAR , 4 , true , fp - > num_verts ) ;
else
n = AllocSpecialFace ( SFT_SPECULAR , 4 ) ;
fp - > special_handle = n ;
for ( int k = 0 ; k < 4 ; k + + )
{
SpecialFaces [ n ] . spec_instance [ k ] . bright_color = 0 ;
vm_MakeZero ( & SpecialFaces [ n ] . spec_instance [ k ] . bright_center ) ;
}
// Get vertex normals for this punk
if ( GameTextures [ fp - > tmap ] . flags & TF_SMOOTH_SPECULAR )
{
for ( k = 0 ; k < fp - > num_verts ; k + + )
{
SpecialFaces [ n ] . vertnorms [ k ] = vertnorms [ fp - > face_verts [ k ] ] ;
}
}
}
}
mem_free ( vertnorms ) ;
}
}
}
// Computes the the mines UVs
// Faces can now share one lightmap, so this routine goes through and tries to
// combine as many faces as it can into one lightmap
// Only works on one room
/*void ComputeSingleRoomLightmapUVs (int roomnum)
{
int t , k ;
int not_combined = 0 ;
2024-05-24 03:07:26 +00:00
RoomsAlreadyCombined [ roomnum ] = ( uint8_t * ) mem_malloc ( Rooms [ roomnum ] . num_faces ) ;
2024-04-19 20:58:24 +00:00
ASSERT ( RoomsAlreadyCombined [ roomnum ] ) ;
for ( k = 0 ; k < Rooms [ roomnum ] . num_faces ; k + + )
RoomsAlreadyCombined [ roomnum ] [ k ] = 0 ;
for ( t = 0 ; t < Rooms [ roomnum ] . num_faces ; t + + )
{
if ( * ( RoomsAlreadyCombined [ roomnum ] + t ) = = 0 )
TestLightAdjacency ( roomnum , t , 0 ) ;
}
for ( t = 0 ; t < Rooms [ roomnum ] . num_faces ; t + + )
{
if ( ! RoomsAlreadyCombined [ roomnum ] [ t ] )
{
vector verts [ MAX_VERTS_PER_FACE ] ;
int room_list [ 2 ] , face_list [ 2 ] ;
for ( k = 0 ; k < Rooms [ roomnum ] . faces [ t ] . num_verts ; k + + )
verts [ k ] = Rooms [ roomnum ] . verts [ Rooms [ roomnum ] . faces [ t ] . face_verts [ k ] ] ;
room_list [ 0 ] = i ;
face_list [ 0 ] = t ;
BuildLightmapUVs ( room_list , face_list , 1 , verts , Rooms [ roomnum ] . faces [ t ] . num_verts , external ) ;
not_combined + + ;
}
}
mprintf ( ( 0 , " %d faces couldn't be combined! \n " , not_combined ) ) ;
// Free memory
free ( RoomsAlreadyCombined [ roomnum ] ) ;
} */