2016-09-20 21:07:53 +00:00
# include "cmdlib.h"
# include "filelib.h"
# include "messages.h"
# include "hlassert.h"
# include "log.h"
# include "mathlib.h"
# include "bspfile.h"
# include "scriplib.h"
# include "blockmem.h"
//=============================================================================
int g_max_map_miptex = DEFAULT_MAX_MAP_MIPTEX ;
int g_max_map_lightdata = DEFAULT_MAX_MAP_LIGHTDATA ;
int g_nummodels ;
dmodel_t g_dmodels [ MAX_MAP_MODELS ] ;
int g_dmodels_checksum ;
int g_visdatasize ;
byte g_dvisdata [ MAX_MAP_VISIBILITY ] ;
int g_dvisdata_checksum ;
int g_lightdatasize ;
byte * g_dlightdata ;
int g_dlightdata_checksum ;
int g_texdatasize ;
byte * g_dtexdata ; // (dmiptexlump_t)
int g_dtexdata_checksum ;
int g_entdatasize ;
char g_dentdata [ MAX_MAP_ENTSTRING ] ;
int g_dentdata_checksum ;
int g_numleafs ;
dleaf_t g_dleafs [ MAX_MAP_LEAFS ] ;
int g_dleafs_checksum ;
int g_numplanes ;
dplane_t g_dplanes [ MAX_INTERNAL_MAP_PLANES ] ;
int g_dplanes_checksum ;
int g_numvertexes ;
dvertex_t g_dvertexes [ MAX_MAP_VERTS ] ;
int g_dvertexes_checksum ;
int g_numnodes ;
dnode_t g_dnodes [ MAX_MAP_NODES ] ;
int g_dnodes_checksum ;
int g_numtexinfo ;
# ifdef HLCSG_HLBSP_REDUCETEXTURE
texinfo_t g_texinfo [ MAX_INTERNAL_MAP_TEXINFO ] ;
# else
texinfo_t g_texinfo [ MAX_MAP_TEXINFO ] ;
# endif
int g_texinfo_checksum ;
int g_numfaces ;
dface_t g_dfaces [ MAX_MAP_FACES ] ;
int g_dfaces_checksum ;
# ifdef ZHLT_XASH2
int g_numclipnodes [ MAX_MAP_HULLS - 1 ] ;
dclipnode_t g_dclipnodes [ MAX_MAP_HULLS - 1 ] [ MAX_MAP_CLIPNODES ] ;
int g_dclipnodes_checksum [ MAX_MAP_HULLS - 1 ] ;
# else
int g_numclipnodes ;
dclipnode_t g_dclipnodes [ MAX_MAP_CLIPNODES ] ;
int g_dclipnodes_checksum ;
# endif
int g_numedges ;
dedge_t g_dedges [ MAX_MAP_EDGES ] ;
int g_dedges_checksum ;
int g_nummarksurfaces ;
unsigned short g_dmarksurfaces [ MAX_MAP_MARKSURFACES ] ;
int g_dmarksurfaces_checksum ;
int g_numsurfedges ;
int g_dsurfedges [ MAX_MAP_SURFEDGES ] ;
int g_dsurfedges_checksum ;
int g_numentities ;
entity_t g_entities [ MAX_MAP_ENTITIES ] ;
/*
* = = = = = = = = = = = = = = =
* FastChecksum
* = = = = = = = = = = = = = = =
*/
static int FastChecksum ( const void * const buffer , int bytes )
{
int checksum = 0 ;
char * buf = ( char * ) buffer ;
while ( bytes - - )
{
checksum = rotl ( checksum , 4 ) ^ ( * buf ) ;
buf + + ;
}
return checksum ;
}
/*
* = = = = = = = = = = = = = = =
* CompressVis
* = = = = = = = = = = = = = = =
*/
int CompressVis ( const byte * const src , const unsigned int src_length , byte * dest , unsigned int dest_length )
{
unsigned int j ;
byte * dest_p = dest ;
unsigned int current_length = 0 ;
for ( j = 0 ; j < src_length ; j + + )
{
current_length + + ;
hlassume ( current_length < = dest_length , assume_COMPRESSVIS_OVERFLOW ) ;
* dest_p = src [ j ] ;
dest_p + + ;
if ( src [ j ] )
{
continue ;
}
unsigned char rep = 1 ;
for ( j + + ; j < src_length ; j + + )
{
if ( src [ j ] | | rep = = 255 )
{
break ;
}
else
{
rep + + ;
}
}
current_length + + ;
hlassume ( current_length < = dest_length , assume_COMPRESSVIS_OVERFLOW ) ;
* dest_p = rep ;
dest_p + + ;
j - - ;
}
return dest_p - dest ;
}
// =====================================================================================
// DecompressVis
//
// =====================================================================================
void DecompressVis ( const byte * src , byte * const dest , const unsigned int dest_length )
{
unsigned int current_length = 0 ;
int c ;
byte * out ;
int row ;
# ifdef ZHLT_DecompressVis_FIX
row = ( g_dmodels [ 0 ] . visleafs + 7 ) > > 3 ; // same as the length used by VIS program in CompressVis
// The wrong size will cause DecompressVis to spend extremely long time once the source pointer runs into the invalid area in g_dvisdata (for example, in BuildFaceLights, some faces could hang for a few seconds), and sometimes to crash.
# else
row = ( g_numleafs + 7 ) > > 3 ;
# endif
out = dest ;
do
{
# ifdef ZHLT_DecompressVis_FIX
hlassume ( src - g_dvisdata < g_visdatasize , assume_DECOMPRESSVIS_OVERFLOW ) ;
# endif
if ( * src )
{
current_length + + ;
hlassume ( current_length < = dest_length , assume_DECOMPRESSVIS_OVERFLOW ) ;
* out = * src ;
out + + ;
src + + ;
continue ;
}
# ifdef ZHLT_DecompressVis_FIX
hlassume ( & src [ 1 ] - g_dvisdata < g_visdatasize , assume_DECOMPRESSVIS_OVERFLOW ) ;
# endif
c = src [ 1 ] ;
src + = 2 ;
while ( c )
{
current_length + + ;
hlassume ( current_length < = dest_length , assume_DECOMPRESSVIS_OVERFLOW ) ;
* out = 0 ;
out + + ;
c - - ;
if ( out - dest > = row )
{
return ;
}
}
}
while ( out - dest < row ) ;
}
//
// =====================================================================================
//
// =====================================================================================
// SwapBSPFile
// byte swaps all data in a bsp file
// =====================================================================================
static void SwapBSPFile ( const bool todisk )
{
int i , j , c ;
dmodel_t * d ;
dmiptexlump_t * mtl ;
// models
for ( i = 0 ; i < g_nummodels ; i + + )
{
d = & g_dmodels [ i ] ;
for ( j = 0 ; j < MAX_MAP_HULLS ; j + + )
{
d - > headnode [ j ] = LittleLong ( d - > headnode [ j ] ) ;
}
d - > visleafs = LittleLong ( d - > visleafs ) ;
d - > firstface = LittleLong ( d - > firstface ) ;
d - > numfaces = LittleLong ( d - > numfaces ) ;
for ( j = 0 ; j < 3 ; j + + )
{
d - > mins [ j ] = LittleFloat ( d - > mins [ j ] ) ;
d - > maxs [ j ] = LittleFloat ( d - > maxs [ j ] ) ;
d - > origin [ j ] = LittleFloat ( d - > origin [ j ] ) ;
}
}
//
// vertexes
//
for ( i = 0 ; i < g_numvertexes ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
{
g_dvertexes [ i ] . point [ j ] = LittleFloat ( g_dvertexes [ i ] . point [ j ] ) ;
}
}
//
// planes
//
for ( i = 0 ; i < g_numplanes ; i + + )
{
for ( j = 0 ; j < 3 ; j + + )
{
g_dplanes [ i ] . normal [ j ] = LittleFloat ( g_dplanes [ i ] . normal [ j ] ) ;
}
g_dplanes [ i ] . dist = LittleFloat ( g_dplanes [ i ] . dist ) ;
g_dplanes [ i ] . type = ( planetypes ) LittleLong ( g_dplanes [ i ] . type ) ;
}
//
// texinfos
//
for ( i = 0 ; i < g_numtexinfo ; i + + )
{
for ( j = 0 ; j < 8 ; j + + )
{
g_texinfo [ i ] . vecs [ 0 ] [ j ] = LittleFloat ( g_texinfo [ i ] . vecs [ 0 ] [ j ] ) ;
}
g_texinfo [ i ] . miptex = LittleLong ( g_texinfo [ i ] . miptex ) ;
g_texinfo [ i ] . flags = LittleLong ( g_texinfo [ i ] . flags ) ;
}
//
// faces
//
for ( i = 0 ; i < g_numfaces ; i + + )
{
g_dfaces [ i ] . texinfo = LittleShort ( g_dfaces [ i ] . texinfo ) ;
g_dfaces [ i ] . planenum = LittleShort ( g_dfaces [ i ] . planenum ) ;
g_dfaces [ i ] . side = LittleShort ( g_dfaces [ i ] . side ) ;
g_dfaces [ i ] . lightofs = LittleLong ( g_dfaces [ i ] . lightofs ) ;
g_dfaces [ i ] . firstedge = LittleLong ( g_dfaces [ i ] . firstedge ) ;
g_dfaces [ i ] . numedges = LittleShort ( g_dfaces [ i ] . numedges ) ;
}
//
// nodes
//
for ( i = 0 ; i < g_numnodes ; i + + )
{
g_dnodes [ i ] . planenum = LittleLong ( g_dnodes [ i ] . planenum ) ;
for ( j = 0 ; j < 3 ; j + + )
{
g_dnodes [ i ] . mins [ j ] = LittleShort ( g_dnodes [ i ] . mins [ j ] ) ;
g_dnodes [ i ] . maxs [ j ] = LittleShort ( g_dnodes [ i ] . maxs [ j ] ) ;
}
g_dnodes [ i ] . children [ 0 ] = LittleShort ( g_dnodes [ i ] . children [ 0 ] ) ;
g_dnodes [ i ] . children [ 1 ] = LittleShort ( g_dnodes [ i ] . children [ 1 ] ) ;
g_dnodes [ i ] . firstface = LittleShort ( g_dnodes [ i ] . firstface ) ;
g_dnodes [ i ] . numfaces = LittleShort ( g_dnodes [ i ] . numfaces ) ;
}
//
// leafs
//
for ( i = 0 ; i < g_numleafs ; i + + )
{
g_dleafs [ i ] . contents = LittleLong ( g_dleafs [ i ] . contents ) ;
for ( j = 0 ; j < 3 ; j + + )
{
g_dleafs [ i ] . mins [ j ] = LittleShort ( g_dleafs [ i ] . mins [ j ] ) ;
g_dleafs [ i ] . maxs [ j ] = LittleShort ( g_dleafs [ i ] . maxs [ j ] ) ;
}
g_dleafs [ i ] . firstmarksurface = LittleShort ( g_dleafs [ i ] . firstmarksurface ) ;
g_dleafs [ i ] . nummarksurfaces = LittleShort ( g_dleafs [ i ] . nummarksurfaces ) ;
g_dleafs [ i ] . visofs = LittleLong ( g_dleafs [ i ] . visofs ) ;
}
//
// clipnodes
//
# ifdef ZHLT_XASH2
for ( int hull = 1 ; hull < MAX_MAP_HULLS ; hull + + )
{
for ( i = 0 ; i < g_numclipnodes [ hull - 1 ] ; i + + )
{
g_dclipnodes [ hull - 1 ] [ i ] . planenum = LittleLong ( g_dclipnodes [ hull - 1 ] [ i ] . planenum ) ;
g_dclipnodes [ hull - 1 ] [ i ] . children [ 0 ] = LittleShort ( g_dclipnodes [ hull - 1 ] [ i ] . children [ 0 ] ) ;
g_dclipnodes [ hull - 1 ] [ i ] . children [ 1 ] = LittleShort ( g_dclipnodes [ hull - 1 ] [ i ] . children [ 1 ] ) ;
}
}
# else
for ( i = 0 ; i < g_numclipnodes ; i + + )
{
g_dclipnodes [ i ] . planenum = LittleLong ( g_dclipnodes [ i ] . planenum ) ;
g_dclipnodes [ i ] . children [ 0 ] = LittleShort ( g_dclipnodes [ i ] . children [ 0 ] ) ;
g_dclipnodes [ i ] . children [ 1 ] = LittleShort ( g_dclipnodes [ i ] . children [ 1 ] ) ;
}
# endif
//
// miptex
//
if ( g_texdatasize )
{
mtl = ( dmiptexlump_t * ) g_dtexdata ;
if ( todisk )
{
c = mtl - > nummiptex ;
}
else
{
c = LittleLong ( mtl - > nummiptex ) ;
}
mtl - > nummiptex = LittleLong ( mtl - > nummiptex ) ;
for ( i = 0 ; i < c ; i + + )
{
mtl - > dataofs [ i ] = LittleLong ( mtl - > dataofs [ i ] ) ;
}
}
//
// marksurfaces
//
for ( i = 0 ; i < g_nummarksurfaces ; i + + )
{
g_dmarksurfaces [ i ] = LittleShort ( g_dmarksurfaces [ i ] ) ;
}
//
// surfedges
//
for ( i = 0 ; i < g_numsurfedges ; i + + )
{
g_dsurfedges [ i ] = LittleLong ( g_dsurfedges [ i ] ) ;
}
//
// edges
//
for ( i = 0 ; i < g_numedges ; i + + )
{
g_dedges [ i ] . v [ 0 ] = LittleShort ( g_dedges [ i ] . v [ 0 ] ) ;
g_dedges [ i ] . v [ 1 ] = LittleShort ( g_dedges [ i ] . v [ 1 ] ) ;
}
}
// =====================================================================================
// CopyLump
// balh
// =====================================================================================
static int CopyLump ( int lump , void * dest , int size , const dheader_t * const header )
{
int length , ofs ;
length = header - > lumps [ lump ] . filelen ;
ofs = header - > lumps [ lump ] . fileofs ;
if ( length % size )
{
Error ( " LoadBSPFile: odd lump size " ) ;
}
//special handling for tex and lightdata to keep things from exploding - KGP
if ( lump = = LUMP_TEXTURES & & dest = = ( void * ) g_dtexdata )
{ hlassume ( g_max_map_miptex > length , assume_MAX_MAP_MIPTEX ) ; }
else if ( lump = = LUMP_LIGHTING & & dest = = ( void * ) g_dlightdata )
{ hlassume ( g_max_map_lightdata > length , assume_MAX_MAP_LIGHTING ) ; }
memcpy ( dest , ( byte * ) header + ofs , length ) ;
return length / size ;
}
// =====================================================================================
// LoadBSPFile
// balh
// =====================================================================================
void LoadBSPFile ( const char * const filename )
{
dheader_t * header ;
LoadFile ( filename , ( char * * ) & header ) ;
LoadBSPImage ( header ) ;
}
// =====================================================================================
// LoadBSPImage
// balh
// =====================================================================================
void LoadBSPImage ( dheader_t * const header )
{
unsigned int i ;
// swap the header
for ( i = 0 ; i < sizeof ( dheader_t ) / 4 ; i + + )
{
( ( int * ) header ) [ i ] = LittleLong ( ( ( int * ) header ) [ i ] ) ;
}
if ( header - > version ! = BSPVERSION )
{
Error ( " BSP is version %i, not %i " , header - > version , BSPVERSION ) ;
}
g_nummodels = CopyLump ( LUMP_MODELS , g_dmodels , sizeof ( dmodel_t ) , header ) ;
g_numvertexes = CopyLump ( LUMP_VERTEXES , g_dvertexes , sizeof ( dvertex_t ) , header ) ;
g_numplanes = CopyLump ( LUMP_PLANES , g_dplanes , sizeof ( dplane_t ) , header ) ;
g_numleafs = CopyLump ( LUMP_LEAFS , g_dleafs , sizeof ( dleaf_t ) , header ) ;
g_numnodes = CopyLump ( LUMP_NODES , g_dnodes , sizeof ( dnode_t ) , header ) ;
g_numtexinfo = CopyLump ( LUMP_TEXINFO , g_texinfo , sizeof ( texinfo_t ) , header ) ;
# ifdef ZHLT_XASH2
for ( int hull = 1 ; hull < MAX_MAP_HULLS ; hull + + )
{
int lump ;
switch ( hull )
{
case 1 : lump = LUMP_CLIPNODES ; break ;
case 2 : lump = LUMP_CLIPNODES2 ; break ;
case 3 : lump = LUMP_CLIPNODES3 ; break ;
default :
Error ( " bad hull number %d " , hull ) ;
break ;
}
g_numclipnodes [ hull - 1 ] = CopyLump ( lump , g_dclipnodes [ hull - 1 ] , sizeof ( dclipnode_t ) , header ) ;
}
# else
g_numclipnodes = CopyLump ( LUMP_CLIPNODES , g_dclipnodes , sizeof ( dclipnode_t ) , header ) ;
# endif
g_numfaces = CopyLump ( LUMP_FACES , g_dfaces , sizeof ( dface_t ) , header ) ;
g_nummarksurfaces = CopyLump ( LUMP_MARKSURFACES , g_dmarksurfaces , sizeof ( g_dmarksurfaces [ 0 ] ) , header ) ;
g_numsurfedges = CopyLump ( LUMP_SURFEDGES , g_dsurfedges , sizeof ( g_dsurfedges [ 0 ] ) , header ) ;
g_numedges = CopyLump ( LUMP_EDGES , g_dedges , sizeof ( dedge_t ) , header ) ;
g_texdatasize = CopyLump ( LUMP_TEXTURES , g_dtexdata , 1 , header ) ;
g_visdatasize = CopyLump ( LUMP_VISIBILITY , g_dvisdata , 1 , header ) ;
g_lightdatasize = CopyLump ( LUMP_LIGHTING , g_dlightdata , 1 , header ) ;
g_entdatasize = CopyLump ( LUMP_ENTITIES , g_dentdata , 1 , header ) ;
Free ( header ) ; // everything has been copied out
//
// swap everything
//
SwapBSPFile ( false ) ;
g_dmodels_checksum = FastChecksum ( g_dmodels , g_nummodels * sizeof ( g_dmodels [ 0 ] ) ) ;
g_dvertexes_checksum = FastChecksum ( g_dvertexes , g_numvertexes * sizeof ( g_dvertexes [ 0 ] ) ) ;
g_dplanes_checksum = FastChecksum ( g_dplanes , g_numplanes * sizeof ( g_dplanes [ 0 ] ) ) ;
g_dleafs_checksum = FastChecksum ( g_dleafs , g_numleafs * sizeof ( g_dleafs [ 0 ] ) ) ;
g_dnodes_checksum = FastChecksum ( g_dnodes , g_numnodes * sizeof ( g_dnodes [ 0 ] ) ) ;
g_texinfo_checksum = FastChecksum ( g_texinfo , g_numtexinfo * sizeof ( g_texinfo [ 0 ] ) ) ;
# ifdef ZHLT_XASH2
for ( int hull = 1 ; hull < MAX_MAP_HULLS ; hull + + )
{
g_dclipnodes_checksum [ hull - 1 ] = FastChecksum ( g_dclipnodes [ hull - 1 ] , g_numclipnodes [ hull - 1 ] * sizeof ( g_dclipnodes [ hull - 1 ] [ 0 ] ) ) ;
}
# else
g_dclipnodes_checksum = FastChecksum ( g_dclipnodes , g_numclipnodes * sizeof ( g_dclipnodes [ 0 ] ) ) ;
# endif
g_dfaces_checksum = FastChecksum ( g_dfaces , g_numfaces * sizeof ( g_dfaces [ 0 ] ) ) ;
g_dmarksurfaces_checksum = FastChecksum ( g_dmarksurfaces , g_nummarksurfaces * sizeof ( g_dmarksurfaces [ 0 ] ) ) ;
g_dsurfedges_checksum = FastChecksum ( g_dsurfedges , g_numsurfedges * sizeof ( g_dsurfedges [ 0 ] ) ) ;
g_dedges_checksum = FastChecksum ( g_dedges , g_numedges * sizeof ( g_dedges [ 0 ] ) ) ;
g_dtexdata_checksum = FastChecksum ( g_dtexdata , g_numedges * sizeof ( g_dtexdata [ 0 ] ) ) ;
g_dvisdata_checksum = FastChecksum ( g_dvisdata , g_visdatasize * sizeof ( g_dvisdata [ 0 ] ) ) ;
g_dlightdata_checksum = FastChecksum ( g_dlightdata , g_lightdatasize * sizeof ( g_dlightdata [ 0 ] ) ) ;
g_dentdata_checksum = FastChecksum ( g_dentdata , g_entdatasize * sizeof ( g_dentdata [ 0 ] ) ) ;
}
//
// =====================================================================================
//
// =====================================================================================
// AddLump
// balh
// =====================================================================================
static void AddLump ( int lumpnum , void * data , int len , dheader_t * header , FILE * bspfile )
{
lump_t * lump = & header - > lumps [ lumpnum ] ;
lump - > fileofs = LittleLong ( ftell ( bspfile ) ) ;
lump - > filelen = LittleLong ( len ) ;
SafeWrite ( bspfile , data , ( len + 3 ) & ~ 3 ) ;
}
// =====================================================================================
// WriteBSPFile
// Swaps the bsp file in place, so it should not be referenced again
// =====================================================================================
void WriteBSPFile ( const char * const filename )
{
dheader_t outheader ;
dheader_t * header ;
FILE * bspfile ;
header = & outheader ;
memset ( header , 0 , sizeof ( dheader_t ) ) ;
SwapBSPFile ( true ) ;
header - > version = LittleLong ( BSPVERSION ) ;
bspfile = SafeOpenWrite ( filename ) ;
SafeWrite ( bspfile , header , sizeof ( dheader_t ) ) ; // overwritten later
// LUMP TYPE DATA LENGTH HEADER BSPFILE
AddLump ( LUMP_PLANES , g_dplanes , g_numplanes * sizeof ( dplane_t ) , header , bspfile ) ;
AddLump ( LUMP_LEAFS , g_dleafs , g_numleafs * sizeof ( dleaf_t ) , header , bspfile ) ;
AddLump ( LUMP_VERTEXES , g_dvertexes , g_numvertexes * sizeof ( dvertex_t ) , header , bspfile ) ;
AddLump ( LUMP_NODES , g_dnodes , g_numnodes * sizeof ( dnode_t ) , header , bspfile ) ;
AddLump ( LUMP_TEXINFO , g_texinfo , g_numtexinfo * sizeof ( texinfo_t ) , header , bspfile ) ;
AddLump ( LUMP_FACES , g_dfaces , g_numfaces * sizeof ( dface_t ) , header , bspfile ) ;
# ifdef ZHLT_XASH2
for ( int hull = 1 ; hull < MAX_MAP_HULLS ; hull + + )
{
int lump ;
switch ( hull )
{
case 1 : lump = LUMP_CLIPNODES ; break ;
case 2 : lump = LUMP_CLIPNODES2 ; break ;
case 3 : lump = LUMP_CLIPNODES3 ; break ;
default :
Error ( " bad hull number %d " , hull ) ;
break ;
}
AddLump ( lump , g_dclipnodes [ hull - 1 ] , g_numclipnodes [ hull - 1 ] * sizeof ( dclipnode_t ) , header , bspfile ) ;
}
# else
AddLump ( LUMP_CLIPNODES , g_dclipnodes , g_numclipnodes * sizeof ( dclipnode_t ) , header , bspfile ) ;
# endif
AddLump ( LUMP_MARKSURFACES , g_dmarksurfaces , g_nummarksurfaces * sizeof ( g_dmarksurfaces [ 0 ] ) , header , bspfile ) ;
AddLump ( LUMP_SURFEDGES , g_dsurfedges , g_numsurfedges * sizeof ( g_dsurfedges [ 0 ] ) , header , bspfile ) ;
AddLump ( LUMP_EDGES , g_dedges , g_numedges * sizeof ( dedge_t ) , header , bspfile ) ;
AddLump ( LUMP_MODELS , g_dmodels , g_nummodels * sizeof ( dmodel_t ) , header , bspfile ) ;
AddLump ( LUMP_LIGHTING , g_dlightdata , g_lightdatasize , header , bspfile ) ;
AddLump ( LUMP_VISIBILITY , g_dvisdata , g_visdatasize , header , bspfile ) ;
AddLump ( LUMP_ENTITIES , g_dentdata , g_entdatasize , header , bspfile ) ;
AddLump ( LUMP_TEXTURES , g_dtexdata , g_texdatasize , header , bspfile ) ;
fseek ( bspfile , 0 , SEEK_SET ) ;
SafeWrite ( bspfile , header , sizeof ( dheader_t ) ) ;
fclose ( bspfile ) ;
}
# ifdef ZHLT_64BIT_FIX
# ifdef PLATFORM_CAN_CALC_EXTENT
// =====================================================================================
// GetFaceExtents (with PLATFORM_CAN_CALC_EXTENT on)
// =====================================================================================
# ifdef SYSTEM_WIN32
# ifdef VERSION_32BIT
static void CorrectFPUPrecision ( )
{
unsigned int currentcontrol ;
if ( _controlfp_s ( & currentcontrol , 0 , 0 ) )
{
Warning ( " Couldn't get FPU precision " ) ;
}
else
{
unsigned int val = ( currentcontrol & _MCW_PC ) ;
if ( val ! = _PC_53 )
{
Warning ( " FPU precision is %s. Setting to %s. " , ( val = = _PC_24 ? " 24 " : val = = _PC_64 ? " 64 " : " invalid " ) , " 53 " ) ;
if ( _controlfp_s ( & currentcontrol , _PC_53 , _MCW_PC )
| | ( currentcontrol & _MCW_PC ) ! = _PC_53 )
{
Warning ( " Couldn't set FPU precision " ) ;
}
}
}
}
# endif
# ifdef VERSION_64BIT
static void CorrectFPUPrecision ( )
{
// do nothing, because we use SSE registers
}
# endif
# endif
# ifdef SYSTEM_POSIX
static void CorrectFPUPrecision ( )
{
// just leave it to default and see if CalcFaceExtents_test gives us any error
}
# endif
float CalculatePointVecsProduct ( const volatile float * point , const volatile float * vecs )
{
volatile double val ;
volatile double tmp ;
val = ( double ) point [ 0 ] * ( double ) vecs [ 0 ] ; // always do one operation at a time and save to memory
tmp = ( double ) point [ 1 ] * ( double ) vecs [ 1 ] ;
val = val + tmp ;
tmp = ( double ) point [ 2 ] * ( double ) vecs [ 2 ] ;
val = val + tmp ;
val = val + ( double ) vecs [ 3 ] ;
return ( float ) val ;
}
bool CalcFaceExtents_test ( )
{
const int numtestcases = 6 ;
volatile float testcases [ numtestcases ] [ 8 ] = {
{ 1 , 1 , 1 , 1 , 0.375 * DBL_EPSILON , 0.375 * DBL_EPSILON , - 1 , 0 } ,
{ 1 , 1 , 1 , 0.375 * DBL_EPSILON , 0.375 * DBL_EPSILON , 1 , - 1 , DBL_EPSILON } ,
{ DBL_EPSILON , DBL_EPSILON , 1 , 0.375 , 0.375 , 1 , - 1 , DBL_EPSILON } ,
{ 1 , 1 , 1 , 1 , 1 , 0.375 * FLT_EPSILON , - 2 , 0.375 * FLT_EPSILON } ,
{ 1 , 1 , 1 , 1 , 0.375 * FLT_EPSILON , 1 , - 2 , 0.375 * FLT_EPSILON } ,
{ 1 , 1 , 1 , 0.375 * FLT_EPSILON , 1 , 1 , - 2 , 0.375 * FLT_EPSILON } } ;
bool ok ;
// If the test failed, please check:
// 1. whether the calculation is performed on FPU
// 2. whether the register precision is too low
CorrectFPUPrecision ( ) ;
ok = true ;
for ( int i = 0 ; i < 6 ; i + + )
{
float val = CalculatePointVecsProduct ( & testcases [ i ] [ 0 ] , & testcases [ i ] [ 3 ] ) ;
if ( val ! = testcases [ i ] [ 7 ] )
{
Warning ( " internal error: CalcFaceExtents_test failed on case %d (%.20f != %.20f). " , i , val , testcases [ i ] [ 7 ] ) ;
ok = false ;
}
}
return ok ;
}
void GetFaceExtents ( int facenum , int mins_out [ 2 ] , int maxs_out [ 2 ] )
{
CorrectFPUPrecision ( ) ;
dface_t * f ;
float mins [ 2 ] , maxs [ 2 ] , val ;
int i , j , e ;
dvertex_t * v ;
texinfo_t * tex ;
int bmins [ 2 ] , bmaxs [ 2 ] ;
f = & g_dfaces [ facenum ] ;
mins [ 0 ] = mins [ 1 ] = 999999 ;
maxs [ 0 ] = maxs [ 1 ] = - 99999 ;
# ifdef ZHLT_EMBEDLIGHTMAP
tex = & g_texinfo [ ParseTexinfoForFace ( f ) ] ;
# else
tex = & g_texinfo [ f - > texinfo ] ;
# endif
for ( i = 0 ; i < f - > numedges ; i + + )
{
e = g_dsurfedges [ f - > firstedge + i ] ;
if ( e > = 0 )
{
v = & g_dvertexes [ g_dedges [ e ] . v [ 0 ] ] ;
}
else
{
v = & g_dvertexes [ g_dedges [ - e ] . v [ 1 ] ] ;
}
for ( j = 0 ; j < 2 ; j + + )
{
// The old code: val = v->point[0] * tex->vecs[j][0] + v->point[1] * tex->vecs[j][1] + v->point[2] * tex->vecs[j][2] + tex->vecs[j][3];
// was meant to be compiled for x86 under MSVC (prior to VS 11), so the intermediate values were stored as 64-bit double by default.
// The new code will produce the same result as the old code, but it's portable for different platforms.
// See this article for details: Intermediate Floating-Point Precision by Bruce-Dawson http://www.altdevblogaday.com/2012/03/22/intermediate-floating-point-precision/
// The essential reason for having this ugly code is to get exactly the same value as the counterpart of game engine.
// The counterpart of game engine is the function CalcFaceExtents in HLSDK.
// So we must also know how Valve compiles HLSDK. I think Valve compiles HLSDK with VC6.0 in the past.
val = CalculatePointVecsProduct ( v - > point , tex - > vecs [ j ] ) ;
if ( val < mins [ j ] )
{
mins [ j ] = val ;
}
if ( val > maxs [ j ] )
{
maxs [ j ] = val ;
}
}
}
for ( i = 0 ; i < 2 ; i + + )
{
bmins [ i ] = ( int ) floor ( mins [ i ] / TEXTURE_STEP ) ;
bmaxs [ i ] = ( int ) ceil ( maxs [ i ] / TEXTURE_STEP ) ;
}
for ( i = 0 ; i < 2 ; i + + )
{
mins_out [ i ] = bmins [ i ] ;
maxs_out [ i ] = bmaxs [ i ] ;
}
}
// =====================================================================================
// WriteExtentFile
// =====================================================================================
void WriteExtentFile ( const char * const filename )
{
FILE * f ;
f = fopen ( filename , " w " ) ;
if ( ! f )
{
Error ( " Error opening %s: %s " , filename , strerror ( errno ) ) ;
}
fprintf ( f , " %i \n " , g_numfaces ) ;
for ( int i = 0 ; i < g_numfaces ; i + + )
{
int mins [ 2 ] ;
int maxs [ 2 ] ;
GetFaceExtents ( i , mins , maxs ) ;
fprintf ( f , " %i %i %i %i \n " , mins [ 0 ] , mins [ 1 ] , maxs [ 0 ] , maxs [ 1 ] ) ;
}
fclose ( f ) ;
}
# else
typedef struct
{
int mins [ 2 ] ;
int maxs [ 2 ] ;
}
faceextent_t ;
bool g_faceextents_loaded = false ;
faceextent_t g_faceextents [ MAX_MAP_FACES ] ; //[g_numfaces]
// =====================================================================================
// LoadExtentFile
// =====================================================================================
void LoadExtentFile ( const char * const filename )
{
FILE * f ;
f = fopen ( filename , " r " ) ;
if ( ! f )
{
Error ( " Error opening %s: %s " , filename , strerror ( errno ) ) ;
}
int count ;
int numfaces ;
count = fscanf ( f , " %i \n " , ( int * ) & numfaces ) ;
if ( count ! = 1 )
{
Error ( " LoadExtentFile (line %i): scanf failure " , 1 ) ;
}
if ( numfaces ! = g_numfaces )
{
Error ( " LoadExtentFile: numfaces(%i) doesn't match g_numfaces(%i) " , numfaces , g_numfaces ) ;
}
for ( int i = 0 ; i < g_numfaces ; i + + )
{
faceextent_t * e = & g_faceextents [ i ] ;
count = fscanf ( f , " %i %i %i %i \n " , ( int * ) & e - > mins [ 0 ] , ( int * ) & e - > mins [ 1 ] , ( int * ) & e - > maxs [ 0 ] , ( int * ) & e - > maxs [ 1 ] ) ;
if ( count ! = 4 )
{
Error ( " LoadExtentFile (line %i): scanf failure " , i + 2 ) ;
}
}
fclose ( f ) ;
g_faceextents_loaded = true ;
}
// =====================================================================================
// GetFaceExtents (with PLATFORM_CAN_CALC_EXTENT off)
// =====================================================================================
// ZHLT_EMBEDLIGHTMAP: the result of "GetFaceExtents" and the values stored in ".ext" file should always be the original extents;
// the new extents of the "?_rad" textures should never appear ("?_rad" textures should be transparent to the tools).
// As a consequance, the reported AllocBlock might be inaccurate (usually falsely larger), but it accurately predicts the amount of AllocBlock after the embedded lightmaps are deleted.
void GetFaceExtents ( int facenum , int mins_out [ 2 ] , int maxs_out [ 2 ] )
{
if ( ! g_faceextents_loaded )
{
Error ( " GetFaceExtents: internal error: extent file has not been loaded. " ) ;
}
faceextent_t * e = & g_faceextents [ facenum ] ;
int i ;
for ( i = 0 ; i < 2 ; i + + )
{
mins_out [ i ] = e - > mins [ i ] ;
maxs_out [ i ] = e - > maxs [ i ] ;
}
}
# endif
# endif
//
// =====================================================================================
//
# ifdef ZHLT_CHART_AllocBlock
const int BLOCK_WIDTH = 128 ;
const int BLOCK_HEIGHT = 128 ;
typedef struct lightmapblock_s
{
lightmapblock_s * next ;
bool used ;
int allocated [ BLOCK_WIDTH ] ;
}
lightmapblock_t ;
void DoAllocBlock ( lightmapblock_t * blocks , int w , int h )
{
lightmapblock_t * block ;
// code from Quake
int i , j ;
int best , best2 ;
int x , y ;
if ( w < 1 | | h < 1 )
{
Error ( " DoAllocBlock: internal error. " ) ;
}
for ( block = blocks ; block ; block = block - > next )
{
best = BLOCK_HEIGHT ;
for ( i = 0 ; i < BLOCK_WIDTH - w ; i + + )
{
best2 = 0 ;
for ( j = 0 ; j < w ; j + + )
{
if ( block - > allocated [ i + j ] > = best )
break ;
if ( block - > allocated [ i + j ] > best2 )
best2 = block - > allocated [ i + j ] ;
}
if ( j = = w )
{
x = i ;
y = best = best2 ;
}
}
if ( best + h < = BLOCK_HEIGHT )
{
block - > used = true ;
for ( i = 0 ; i < w ; i + + )
{
block - > allocated [ x + i ] = best + h ;
}
return ;
}
if ( ! block - > next )
{ // need to allocate a new block
if ( ! block - > used )
{
Warning ( " CountBlocks: invalid extents %dx%d " , w , h ) ;
return ;
}
block - > next = ( lightmapblock_t * ) malloc ( sizeof ( lightmapblock_t ) ) ;
hlassume ( block - > next ! = NULL , assume_NoMemory ) ;
memset ( block - > next , 0 , sizeof ( lightmapblock_t ) ) ;
}
}
}
int CountBlocks ( )
{
# ifdef ZHLT_64BIT_FIX
# if !defined (PLATFORM_CAN_CALC_EXTENT) && !defined (HLRAD)
return - 1 ; // otherwise GetFaceExtents will error
# endif
# endif
lightmapblock_t * blocks ;
blocks = ( lightmapblock_t * ) malloc ( sizeof ( lightmapblock_t ) ) ;
hlassume ( blocks ! = NULL , assume_NoMemory ) ;
memset ( blocks , 0 , sizeof ( lightmapblock_t ) ) ;
int k ;
for ( k = 0 ; k < g_numfaces ; k + + )
{
dface_t * f = & g_dfaces [ k ] ;
# ifdef ZHLT_EMBEDLIGHTMAP
const char * texname = GetTextureByNumber ( ParseTexinfoForFace ( f ) ) ;
# else
const char * texname = GetTextureByNumber ( f - > texinfo ) ;
# endif
if ( ! strncmp ( texname , " sky " , 3 ) //sky, no lightmap allocation.
| | ! strncmp ( texname , " ! " , 1 ) | | ! strncasecmp ( texname , " water " , 5 ) | | ! strncasecmp ( texname , " laser " , 5 ) //water, no lightmap allocation.
# ifdef ZHLT_EMBEDLIGHTMAP
| | ( g_texinfo [ ParseTexinfoForFace ( f ) ] . flags & TEX_SPECIAL ) //aaatrigger, I don't know.
# else
| | ( g_texinfo [ f - > texinfo ] . flags & TEX_SPECIAL ) //aaatrigger, I don't know.
# endif
)
{
continue ;
}
int extents [ 2 ] ;
vec3_t point ;
{
# ifdef ZHLT_64BIT_FIX
int bmins [ 2 ] ;
int bmaxs [ 2 ] ;
int i ;
GetFaceExtents ( k , bmins , bmaxs ) ;
for ( i = 0 ; i < 2 ; i + + )
{
extents [ i ] = ( bmaxs [ i ] - bmins [ i ] ) * TEXTURE_STEP ;
}
VectorClear ( point ) ;
if ( f - > numedges > 0 )
{
int e = g_dsurfedges [ f - > firstedge ] ;
dvertex_t * v = & g_dvertexes [ g_dedges [ abs ( e ) ] . v [ e > = 0 ? 0 : 1 ] ] ;
VectorCopy ( v - > point , point ) ;
}
# else
float mins [ 2 ] , maxs [ 2 ] ;
int bmins [ 2 ] , bmaxs [ 2 ] ;
texinfo_t * tex ;
tex = & g_texinfo [ f - > texinfo ] ;
mins [ 0 ] = mins [ 1 ] = 999999 ;
maxs [ 0 ] = maxs [ 1 ] = - 99999 ;
VectorClear ( point ) ;
int i ;
for ( i = 0 ; i < f - > numedges ; i + + )
{
int e ;
dvertex_t * v ;
int j ;
e = g_dsurfedges [ f - > firstedge + i ] ;
if ( e > = 0 )
{
v = & g_dvertexes [ g_dedges [ e ] . v [ 0 ] ] ;
}
else
{
v = & g_dvertexes [ g_dedges [ - e ] . v [ 1 ] ] ;
}
if ( i = = 0 )
{
VectorCopy ( v - > point , point ) ;
}
for ( j = 0 ; j < 2 ; j + + )
{
float val = v - > point [ 0 ] * tex - > vecs [ j ] [ 0 ] + v - > point [ 1 ] * tex - > vecs [ j ] [ 1 ]
+ v - > point [ 2 ] * tex - > vecs [ j ] [ 2 ] + tex - > vecs [ j ] [ 3 ] ;
if ( val < mins [ j ] )
{
mins [ j ] = val ;
}
if ( val > maxs [ j ] )
{
maxs [ j ] = val ;
}
}
}
for ( i = 0 ; i < 2 ; i + + )
{
bmins [ i ] = floor ( mins [ i ] / TEXTURE_STEP ) ;
bmaxs [ i ] = ceil ( maxs [ i ] / TEXTURE_STEP ) ;
extents [ i ] = ( bmaxs [ i ] - bmins [ i ] ) * TEXTURE_STEP ;
}
# endif
}
if ( extents [ 0 ] < 0 | | extents [ 1 ] < 0 | | extents [ 0 ] > qmax ( 512 , MAX_SURFACE_EXTENT * TEXTURE_STEP ) | | extents [ 1 ] > qmax ( 512 , MAX_SURFACE_EXTENT * TEXTURE_STEP ) )
// the default restriction from the engine is 512, but place 'max (512, MAX_SURFACE_EXTENT * TEXTURE_STEP)' here in case someone raise the limit
{
Warning ( " Bad surface extents %d/%d at position (%.0f,%.0f,%.0f) " , extents [ 0 ] , extents [ 1 ] , point [ 0 ] , point [ 1 ] , point [ 2 ] ) ;
continue ;
}
DoAllocBlock ( blocks , ( extents [ 0 ] / TEXTURE_STEP ) + 1 , ( extents [ 1 ] / TEXTURE_STEP ) + 1 ) ;
}
int count = 0 ;
lightmapblock_t * next ;
for ( ; blocks ; blocks = next )
{
if ( blocks - > used )
{
count + + ;
}
next = blocks - > next ;
free ( blocks ) ;
}
return count ;
}
# endif
# ifdef ZHLT_CHART_WADFILES
bool NoWadTextures ( )
{
// copied from loadtextures.cpp
int numtextures = g_texdatasize ? ( ( dmiptexlump_t * ) g_dtexdata ) - > nummiptex : 0 ;
for ( int i = 0 ; i < numtextures ; i + + )
{
int offset = ( ( dmiptexlump_t * ) g_dtexdata ) - > dataofs [ i ] ;
int size = g_texdatasize - offset ;
if ( offset < 0 | | size < ( int ) sizeof ( miptex_t ) )
{
// missing textures have ofs -1
continue ;
}
miptex_t * mt = ( miptex_t * ) & g_dtexdata [ offset ] ;
if ( ! mt - > offsets [ 0 ] )
{
return false ;
}
}
return true ;
}
char * FindWadValue ( )
// return NULL for syntax error
// this function needs to be as stable as possible because it might be called from ripent
{
int linestart , lineend ;
bool inentity = false ;
for ( linestart = 0 ; linestart < g_entdatasize ; )
{
for ( lineend = linestart ; lineend < g_entdatasize ; lineend + + )
if ( g_dentdata [ lineend ] = = ' \r ' | | g_dentdata [ lineend ] = = ' \n ' )
break ;
if ( lineend = = linestart + 1 )
{
if ( g_dentdata [ linestart ] = = ' { ' )
{
if ( inentity )
return NULL ;
inentity = true ;
}
else if ( g_dentdata [ linestart ] = = ' } ' )
{
if ( ! inentity )
return NULL ;
inentity = false ;
return _strdup ( " " ) ; // only parse the first entity
}
else
return NULL ;
}
else
{
if ( ! inentity )
return NULL ;
int quotes [ 4 ] ;
int i , j ;
for ( i = 0 , j = linestart ; i < 4 ; i + + , j + + )
{
for ( ; j < lineend ; j + + )
if ( g_dentdata [ j ] = = ' \" ' )
break ;
if ( j > = lineend )
break ;
quotes [ i ] = j ;
}
if ( i ! = 4 | | quotes [ 0 ] ! = linestart | | quotes [ 3 ] ! = lineend - 1 )
{
return NULL ;
}
if ( quotes [ 1 ] - ( quotes [ 0 ] + 1 ) = = ( int ) strlen ( " wad " ) & & ! strncmp ( & g_dentdata [ quotes [ 0 ] + 1 ] , " wad " , strlen ( " wad " ) ) )
{
int len = quotes [ 3 ] - ( quotes [ 2 ] + 1 ) ;
char * value = ( char * ) malloc ( len + 1 ) ;
hlassume ( value ! = NULL , assume_NoMemory ) ;
memcpy ( value , & g_dentdata [ quotes [ 2 ] + 1 ] , len ) ;
value [ len ] = ' \0 ' ;
return value ;
}
}
for ( linestart = lineend ; linestart < g_entdatasize ; linestart + + )
if ( g_dentdata [ linestart ] ! = ' \r ' & & g_dentdata [ linestart ] ! = ' \n ' )
break ;
}
return NULL ;
}
# endif
# define ENTRIES(a) (sizeof(a) / sizeof(*(a)))
# define ENTRYSIZE(a) (sizeof(*(a)))
// =====================================================================================
// ArrayUsage
// blah
// =====================================================================================
static int ArrayUsage ( const char * const szItem , const int items , const int maxitems , const int itemsize )
{
float percentage = maxitems ? items * 100.0 / maxitems : 0.0 ;
# ifdef ZHLT_MAX_MAP_LEAFS
Log ( " %-13s %7i/%-7i %8i/%-8i (%4.1f%%) \n " , szItem , items , maxitems , items * itemsize , maxitems * itemsize , percentage ) ;
# else
Log ( " %-12s %7i/%-7i %7i/%-7i (%4.1f%%) \n " , szItem , items , maxitems , items * itemsize , maxitems * itemsize , percentage ) ;
# endif
return items * itemsize ;
}
// =====================================================================================
// GlobUsage
// pritn out global ussage line in chart
// =====================================================================================
static int GlobUsage ( const char * const szItem , const int itemstorage , const int maxstorage )
{
float percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0 ;
# ifdef ZHLT_MAX_MAP_LEAFS
Log ( " %-13s [variable] %8i/%-8i (%4.1f%%) \n " , szItem , itemstorage , maxstorage , percentage ) ;
# else
Log ( " %-12s [variable] %7i/%-7i (%4.1f%%) \n " , szItem , itemstorage , maxstorage , percentage ) ;
# endif
return itemstorage ;
}
// =====================================================================================
// PrintBSPFileSizes
// Dumps info about current file
// =====================================================================================
void PrintBSPFileSizes ( )
{
int numtextures = g_texdatasize ? ( ( dmiptexlump_t * ) g_dtexdata ) - > nummiptex : 0 ;
int totalmemory = 0 ;
# ifdef ZHLT_CHART_AllocBlock
int numallocblocks = CountBlocks ( ) ;
int maxallocblocks = 64 ;
# endif
# ifdef ZHLT_CHART_WADFILES
bool nowadtextures = NoWadTextures ( ) ; // We don't have this check at hlcsg, because only legacy compile tools don't empty "wad" value in "-nowadtextures" compiles.
char * wadvalue = FindWadValue ( ) ;
# endif
Log ( " \n " ) ;
Log ( " Object names Objects/Maxobjs Memory / Maxmem Fullness \n " ) ;
Log ( " ------------ --------------- --------------- -------- \n " ) ;
totalmemory + = ArrayUsage ( " models " , g_nummodels , ENTRIES ( g_dmodels ) , ENTRYSIZE ( g_dmodels ) ) ;
totalmemory + = ArrayUsage ( " planes " , g_numplanes , MAX_MAP_PLANES , ENTRYSIZE ( g_dplanes ) ) ;
totalmemory + = ArrayUsage ( " vertexes " , g_numvertexes , ENTRIES ( g_dvertexes ) , ENTRYSIZE ( g_dvertexes ) ) ;
totalmemory + = ArrayUsage ( " nodes " , g_numnodes , ENTRIES ( g_dnodes ) , ENTRYSIZE ( g_dnodes ) ) ;
# ifdef HLCSG_HLBSP_REDUCETEXTURE
totalmemory + = ArrayUsage ( " texinfos " , g_numtexinfo , MAX_MAP_TEXINFO , ENTRYSIZE ( g_texinfo ) ) ;
# else
totalmemory + = ArrayUsage ( " texinfos " , g_numtexinfo , ENTRIES ( g_texinfo ) , ENTRYSIZE ( g_texinfo ) ) ;
# endif
totalmemory + = ArrayUsage ( " faces " , g_numfaces , ENTRIES ( g_dfaces ) , ENTRYSIZE ( g_dfaces ) ) ;
# ifdef ZHLT_WARNWORLDFACES
totalmemory + = ArrayUsage ( " * worldfaces " , ( g_nummodels > 0 ? g_dmodels [ 0 ] . numfaces : 0 ) , MAX_MAP_WORLDFACES , 0 ) ;
# endif
# ifdef ZHLT_XASH2
for ( int hull = 1 ; hull < MAX_MAP_HULLS ; hull + + )
{
char buffer [ 32 ] ;
sprintf ( buffer , " clipnodes%d " , hull ) ;
totalmemory + = ArrayUsage ( buffer , g_numclipnodes [ hull - 1 ] , ENTRIES ( g_dclipnodes [ hull - 1 ] ) , ENTRYSIZE ( g_dclipnodes [ hull - 1 ] ) ) ;
}
# else
totalmemory + = ArrayUsage ( " clipnodes " , g_numclipnodes , ENTRIES ( g_dclipnodes ) , ENTRYSIZE ( g_dclipnodes ) ) ;
# endif
# ifdef ZHLT_MAX_MAP_LEAFS
totalmemory + = ArrayUsage ( " leaves " , g_numleafs , MAX_MAP_LEAFS , ENTRYSIZE ( g_dleafs ) ) ;
totalmemory + = ArrayUsage ( " * worldleaves " , ( g_nummodels > 0 ? g_dmodels [ 0 ] . visleafs : 0 ) , MAX_MAP_LEAFS_ENGINE , 0 ) ;
# else
totalmemory + = ArrayUsage ( " leaves " , g_numleafs , ENTRIES ( g_dleafs ) , ENTRYSIZE ( g_dleafs ) ) ;
# endif
totalmemory + = ArrayUsage ( " marksurfaces " , g_nummarksurfaces , ENTRIES ( g_dmarksurfaces ) , ENTRYSIZE ( g_dmarksurfaces ) ) ;
totalmemory + = ArrayUsage ( " surfedges " , g_numsurfedges , ENTRIES ( g_dsurfedges ) , ENTRYSIZE ( g_dsurfedges ) ) ;
totalmemory + = ArrayUsage ( " edges " , g_numedges , ENTRIES ( g_dedges ) , ENTRYSIZE ( g_dedges ) ) ;
totalmemory + = GlobUsage ( " texdata " , g_texdatasize , g_max_map_miptex ) ;
totalmemory + = GlobUsage ( " lightdata " , g_lightdatasize , g_max_map_lightdata ) ;
totalmemory + = GlobUsage ( " visdata " , g_visdatasize , sizeof ( g_dvisdata ) ) ;
totalmemory + = GlobUsage ( " entdata " , g_entdatasize , sizeof ( g_dentdata ) ) ;
# ifdef ZHLT_CHART_AllocBlock
# ifdef ZHLT_64BIT_FIX
if ( numallocblocks = = - 1 )
{
Log ( " * AllocBlock [ not available to the " PLATFORM_VERSIONSTRING " version ] \n " ) ;
}
else
{
# endif
totalmemory + = ArrayUsage ( " * AllocBlock " , numallocblocks , maxallocblocks , 0 ) ;
# ifdef ZHLT_64BIT_FIX
}
# endif
# endif
Log ( " %i textures referenced \n " , numtextures ) ;
Log ( " === Total BSP file data space used: %d bytes === \n " , totalmemory ) ;
# ifdef ZHLT_CHART_WADFILES
if ( nowadtextures )
{
Log ( " Wad files required to run the map: (None) \n " ) ;
}
else if ( wadvalue = = NULL )
{
Log ( " Wad files required to run the map: (Couldn't parse wad keyvalue from entity data) \n " ) ;
}
else
{
Log ( " Wad files required to run the map: \" %s \" \n " , wadvalue ) ;
}
if ( wadvalue )
{
free ( wadvalue ) ;
}
# endif
}
# ifdef ZHLT_EMBEDLIGHTMAP
// =====================================================================================
// ParseImplicitTexinfoFromTexture
// purpose: get the actual texinfo for a face. the tools shouldn't directly use f->texinfo after embedlightmap is done
// =====================================================================================
int ParseImplicitTexinfoFromTexture ( int miptex )
{
int texinfo ;
int numtextures = g_texdatasize ? ( ( dmiptexlump_t * ) g_dtexdata ) - > nummiptex : 0 ;
int offset ;
int size ;
miptex_t * mt ;
char name [ 16 ] ;
if ( miptex < 0 | | miptex > = numtextures )
{
Warning ( " ParseImplicitTexinfoFromTexture: internal error: invalid texture number %d. " , miptex ) ;
return - 1 ;
}
offset = ( ( dmiptexlump_t * ) g_dtexdata ) - > dataofs [ miptex ] ;
size = g_texdatasize - offset ;
if ( offset < 0 | | g_dtexdata + offset < ( byte * ) & ( ( dmiptexlump_t * ) g_dtexdata ) - > dataofs [ numtextures ] | |
size < ( int ) sizeof ( miptex_t ) )
{
return - 1 ;
}
mt = ( miptex_t * ) & g_dtexdata [ offset ] ;
safe_strncpy ( name , mt - > name , 16 ) ;
if ( ! ( strlen ( name ) > = 6 & & ! strncasecmp ( & name [ 1 ] , " _rad " , 4 ) & & ' 0 ' < = name [ 5 ] & & name [ 5 ] < = ' 9 ' ) )
{
return - 1 ;
}
texinfo = atoi ( & name [ 5 ] ) ;
if ( texinfo < 0 | | texinfo > = g_numtexinfo )
{
Warning ( " Invalid index of original texinfo: %d parsed from texture name '%s'. " , texinfo , name ) ;
return - 1 ;
}
return texinfo ;
}
int ParseTexinfoForFace ( const dface_t * f )
{
int texinfo ;
int miptex ;
int texinfo2 ;
texinfo = f - > texinfo ;
miptex = g_texinfo [ texinfo ] . miptex ;
if ( miptex ! = - 1 )
{
texinfo2 = ParseImplicitTexinfoFromTexture ( miptex ) ;
if ( texinfo2 ! = - 1 )
{
texinfo = texinfo2 ;
}
}
return texinfo ;
}
// =====================================================================================
// DeleteEmbeddedLightmaps
// removes all "?_rad*" textures that are created by hlrad
// this function does nothing if the map has no textures with name "?_rad*"
// =====================================================================================
void DeleteEmbeddedLightmaps ( )
{
int countrestoredfaces = 0 ;
int countremovedtexinfos = 0 ;
int countremovedtextures = 0 ;
int i ;
int numtextures = g_texdatasize ? ( ( dmiptexlump_t * ) g_dtexdata ) - > nummiptex : 0 ;
// Step 1: parse the original texinfo index stored in each "?_rad*" texture
// and restore the texinfo for the faces that have had their lightmap embedded
for ( i = 0 ; i < g_numfaces ; i + + )
{
dface_t * f = & g_dfaces [ i ] ;
int texinfo ;
texinfo = ParseTexinfoForFace ( f ) ;
if ( texinfo ! = f - > texinfo )
{
f - > texinfo = texinfo ;
countrestoredfaces + + ;
}
}
// Step 2: remove redundant texinfo
{
bool * texinfoused = ( bool * ) malloc ( g_numtexinfo * sizeof ( bool ) ) ;
hlassume ( texinfoused ! = NULL , assume_NoMemory ) ;
for ( i = 0 ; i < g_numtexinfo ; i + + )
{
texinfoused [ i ] = false ;
}
for ( i = 0 ; i < g_numfaces ; i + + )
{
dface_t * f = & g_dfaces [ i ] ;
if ( f - > texinfo < 0 | | f - > texinfo > = g_numtexinfo )
{
continue ;
}
texinfoused [ f - > texinfo ] = true ;
}
for ( i = g_numtexinfo - 1 ; i > - 1 ; i - - )
{
texinfo_t * info = & g_texinfo [ i ] ;
if ( texinfoused [ i ] )
{
break ; // still used by a face; should not remove this texinfo
}
if ( info - > miptex < 0 | | info - > miptex > = numtextures )
{
break ; // invalid; should not remove this texinfo
}
if ( ParseImplicitTexinfoFromTexture ( info - > miptex ) = = - 1 )
{
break ; // not added by hlrad; should not remove this texinfo
}
countremovedtexinfos + + ;
}
g_numtexinfo = i + 1 ; // shrink g_texinfo
free ( texinfoused ) ;
}
// Step 3: remove redundant textures
{
int numremaining ; // number of remaining textures
bool * textureused = ( bool * ) malloc ( numtextures * sizeof ( bool ) ) ;
hlassume ( textureused ! = NULL , assume_NoMemory ) ;
for ( i = 0 ; i < numtextures ; i + + )
{
textureused [ i ] = false ;
}
for ( i = 0 ; i < g_numtexinfo ; i + + )
{
texinfo_t * info = & g_texinfo [ i ] ;
if ( info - > miptex < 0 | | info - > miptex > = numtextures )
{
continue ;
}
textureused [ info - > miptex ] = true ;
}
for ( i = numtextures - 1 ; i > - 1 ; i - - )
{
if ( textureused [ i ] | | ParseImplicitTexinfoFromTexture ( i ) = = - 1 )
{
break ; // should not remove this texture
}
countremovedtextures + + ;
}
numremaining = i + 1 ;
free ( textureused ) ;
if ( numremaining < numtextures )
{
dmiptexlump_t * texdata = ( dmiptexlump_t * ) g_dtexdata ;
byte * dataaddr = ( byte * ) & texdata - > dataofs [ texdata - > nummiptex ] ;
int datasize = ( g_dtexdata + texdata - > dataofs [ numremaining ] ) - dataaddr ;
byte * newdataaddr = ( byte * ) & texdata - > dataofs [ numremaining ] ;
memmove ( newdataaddr , dataaddr , datasize ) ;
g_texdatasize = ( newdataaddr + datasize ) - g_dtexdata ;
texdata - > nummiptex = numremaining ;
for ( i = 0 ; i < numremaining ; i + + )
{
if ( texdata - > dataofs [ i ] < 0 ) // bad texture
{
continue ;
}
texdata - > dataofs [ i ] + = newdataaddr - dataaddr ;
}
numtextures = texdata - > nummiptex ;
}
}
if ( countrestoredfaces > 0 | | countremovedtexinfos > 0 | | countremovedtextures > 0 )
{
Log ( " DeleteEmbeddedLightmaps: restored %d faces, removed %d texinfos and %d textures. \n " ,
countrestoredfaces , countremovedtexinfos , countremovedtextures ) ;
}
}
# endif
// =====================================================================================
// ParseEpair
// entity key/value pairs
// =====================================================================================
epair_t * ParseEpair ( )
{
epair_t * e ;
e = ( epair_t * ) Alloc ( sizeof ( epair_t ) ) ;
if ( strlen ( g_token ) > = MAX_KEY - 1 )
Error ( " ParseEpair: Key token too long (%i > MAX_KEY) " , ( int ) strlen ( g_token ) ) ;
e - > key = _strdup ( g_token ) ;
GetToken ( false ) ;
if ( strlen ( g_token ) > = MAX_VAL - 1 ) //MAX_VALUE //vluzacn
Error ( " ParseEpar: Value token too long (%i > MAX_VALUE) " , ( int ) strlen ( g_token ) ) ;
e - > value = _strdup ( g_token ) ;
return e ;
}
/*
* = = = = = = = = = = = = = = = =
* ParseEntity
* = = = = = = = = = = = = = = = =
*/
# ifdef ZHLT_INFO_COMPILE_PARAMETERS
// AJM: each tool should have its own version of GetParamsFromEnt which parseentity calls
extern void GetParamsFromEnt ( entity_t * mapent ) ;
# endif
bool ParseEntity ( )
{
epair_t * e ;
entity_t * mapent ;
if ( ! GetToken ( true ) )
{
return false ;
}
if ( strcmp ( g_token , " { " ) )
{
Error ( " ParseEntity: { not found " ) ;
}
if ( g_numentities = = MAX_MAP_ENTITIES )
{
Error ( " g_numentities == MAX_MAP_ENTITIES " ) ;
}
mapent = & g_entities [ g_numentities ] ;
g_numentities + + ;
while ( 1 )
{
if ( ! GetToken ( true ) )
{
Error ( " ParseEntity: EOF without closing brace " ) ;
}
if ( ! strcmp ( g_token , " } " ) )
{
break ;
}
e = ParseEpair ( ) ;
e - > next = mapent - > epairs ;
mapent - > epairs = e ;
}
# ifdef ZHLT_INFO_COMPILE_PARAMETERS // AJM
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " info_compile_parameters " ) )
{
Log ( " Map entity info_compile_parameters detected, using compile settings \n " ) ;
GetParamsFromEnt ( mapent ) ;
}
# endif
# ifdef ZHLT_ENTITY_LIGHTSURFACE
// ugly code
if ( ! strncmp ( ValueForKey ( mapent , " classname " ) , " light " , 5 ) & & * ValueForKey ( mapent , " _tex " ) )
{
SetKeyValue ( mapent , " convertto " , ValueForKey ( mapent , " classname " ) ) ;
SetKeyValue ( mapent , " classname " , " light_surface " ) ;
}
# endif
# ifdef ZHLT_ENTITY_LIGHTSHADOW
if ( ! strcmp ( ValueForKey ( mapent , " convertfrom " ) , " light_shadow " )
# ifdef ZHLT_ENTITY_LIGHTBOUNCE
| | ! strcmp ( ValueForKey ( mapent , " convertfrom " ) , " light_bounce " )
# endif
)
{
SetKeyValue ( mapent , " convertto " , ValueForKey ( mapent , " classname " ) ) ;
SetKeyValue ( mapent , " classname " , ValueForKey ( mapent , " convertfrom " ) ) ;
SetKeyValue ( mapent , " convertfrom " , " " ) ;
}
# endif
# ifdef ZHLT_ENTITY_INFOSUNLIGHT
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " light_environment " ) & &
! strcmp ( ValueForKey ( mapent , " convertfrom " ) , " info_sunlight " ) )
{
while ( mapent - > epairs )
{
DeleteKey ( mapent , mapent - > epairs - > key ) ;
}
memset ( mapent , 0 , sizeof ( entity_t ) ) ;
g_numentities - - ;
return true ;
}
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " light_environment " ) & &
IntForKey ( mapent , " _fake " ) )
{
SetKeyValue ( mapent , " classname " , " info_sunlight " ) ;
}
# endif
return true ;
}
// =====================================================================================
// ParseEntities
// Parses the dentdata string into entities
// =====================================================================================
void ParseEntities ( )
{
g_numentities = 0 ;
ParseFromMemory ( g_dentdata , g_entdatasize ) ;
while ( ParseEntity ( ) )
{
}
}
// =====================================================================================
// UnparseEntities
// Generates the dentdata string from all the entities
// =====================================================================================
# ifdef ZHLT_ENTITY_INFOSUNLIGHT
int anglesforvector ( float angles [ 3 ] , const float vector [ 3 ] )
{
float z = vector [ 2 ] , r = sqrt ( vector [ 0 ] * vector [ 0 ] + vector [ 1 ] * vector [ 1 ] ) ;
float tmp ;
if ( sqrt ( z * z + r * r ) < NORMAL_EPSILON )
{
return - 1 ;
}
else
{
tmp = sqrt ( z * z + r * r ) ;
z / = tmp , r / = tmp ;
if ( r < NORMAL_EPSILON )
{
if ( z < 0 )
{
angles [ 0 ] = - 90 , angles [ 1 ] = 0 ;
}
else
{
angles [ 0 ] = 90 , angles [ 1 ] = 0 ;
}
}
else
{
angles [ 0 ] = atan ( z / r ) / Q_PI * 180 ;
float x = vector [ 0 ] , y = vector [ 1 ] ;
tmp = sqrt ( x * x + y * y ) ;
x / = tmp , y / = tmp ;
if ( x < - 1 + NORMAL_EPSILON )
{
angles [ 1 ] = - 180 ;
}
else
{
if ( y > = 0 )
{
angles [ 1 ] = 2 * atan ( y / ( 1 + x ) ) / Q_PI * 180 ;
}
else
{
angles [ 1 ] = 2 * atan ( y / ( 1 + x ) ) / Q_PI * 180 + 360 ;
}
}
}
}
angles [ 2 ] = 0 ;
return 0 ;
}
# endif
void UnparseEntities ( )
{
char * buf ;
char * end ;
epair_t * ep ;
char line [ MAXTOKEN ] ;
int i ;
buf = g_dentdata ;
end = buf ;
* end = 0 ;
# ifdef ZHLT_ENTITY_INFOSUNLIGHT
for ( i = 0 ; i < g_numentities ; i + + )
{
entity_t * mapent = & g_entities [ i ] ;
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " info_sunlight " ) | |
! strcmp ( ValueForKey ( mapent , " classname " ) , " light_environment " ) )
{
float vec [ 3 ] = { 0 , 0 , 0 } ;
{
sscanf ( ValueForKey ( mapent , " angles " ) , " %f %f %f " , & vec [ 0 ] , & vec [ 1 ] , & vec [ 2 ] ) ;
float pitch = FloatForKey ( mapent , " pitch " ) ;
if ( pitch )
vec [ 0 ] = pitch ;
const char * target = ValueForKey ( mapent , " target " ) ;
if ( target [ 0 ] )
{
entity_t * targetent = FindTargetEntity ( target ) ;
if ( targetent )
{
float origin1 [ 3 ] = { 0 , 0 , 0 } , origin2 [ 3 ] = { 0 , 0 , 0 } , normal [ 3 ] ;
sscanf ( ValueForKey ( mapent , " origin " ) , " %f %f %f " , & origin1 [ 0 ] , & origin1 [ 1 ] , & origin1 [ 2 ] ) ;
sscanf ( ValueForKey ( targetent , " origin " ) , " %f %f %f " , & origin2 [ 0 ] , & origin2 [ 1 ] , & origin2 [ 2 ] ) ;
VectorSubtract ( origin2 , origin1 , normal ) ;
anglesforvector ( vec , normal ) ;
}
}
}
char stmp [ 1024 ] ;
safe_snprintf ( stmp , 1024 , " %g %g %g " , vec [ 0 ] , vec [ 1 ] , vec [ 2 ] ) ;
SetKeyValue ( mapent , " angles " , stmp ) ;
DeleteKey ( mapent , " pitch " ) ;
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " info_sunlight " ) )
{
if ( g_numentities = = MAX_MAP_ENTITIES )
{
Error ( " g_numentities == MAX_MAP_ENTITIES " ) ;
}
entity_t * newent = & g_entities [ g_numentities + + ] ;
newent - > epairs = mapent - > epairs ;
SetKeyValue ( newent , " classname " , " light_environment " ) ;
SetKeyValue ( newent , " _fake " , " 1 " ) ;
mapent - > epairs = NULL ;
}
}
}
# endif
# ifdef ZHLT_ENTITY_LIGHTSHADOW
for ( i = 0 ; i < g_numentities ; i + + )
{
entity_t * mapent = & g_entities [ i ] ;
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " light_shadow " )
# ifdef ZHLT_ENTITY_LIGHTBOUNCE
| | ! strcmp ( ValueForKey ( mapent , " classname " ) , " light_bounce " )
# endif
)
{
SetKeyValue ( mapent , " convertfrom " , ValueForKey ( mapent , " classname " ) ) ;
SetKeyValue ( mapent , " classname " , ( * ValueForKey ( mapent , " convertto " ) ? ValueForKey ( mapent , " convertto " ) : " light " ) ) ;
SetKeyValue ( mapent , " convertto " , " " ) ;
}
}
# endif
# ifdef ZHLT_ENTITY_LIGHTSURFACE
// ugly code
for ( i = 0 ; i < g_numentities ; i + + )
{
entity_t * mapent = & g_entities [ i ] ;
if ( ! strcmp ( ValueForKey ( mapent , " classname " ) , " light_surface " ) )
{
if ( ! * ValueForKey ( mapent , " _tex " ) )
{
SetKeyValue ( mapent , " _tex " , " " ) ;
}
const char * newclassname = ValueForKey ( mapent , " convertto " ) ;
if ( ! * newclassname )
{
SetKeyValue ( mapent , " classname " , " light " ) ;
}
else if ( strncmp ( newclassname , " light " , 5 ) )
{
Error ( " New classname for 'light_surface' should begin with 'light' not '%s'. \n " , newclassname ) ;
}
else
{
SetKeyValue ( mapent , " classname " , newclassname ) ;
}
SetKeyValue ( mapent , " convertto " , " " ) ;
}
}
# endif
# ifdef HLCSG_OPTIMIZELIGHTENTITY
# ifdef HLCSG
extern bool g_nolightopt ;
if ( ! g_nolightopt )
{
int i , j ;
int count = 0 ;
bool * lightneedcompare = ( bool * ) malloc ( g_numentities * sizeof ( bool ) ) ;
hlassume ( lightneedcompare ! = NULL , assume_NoMemory ) ;
memset ( lightneedcompare , 0 , g_numentities * sizeof ( bool ) ) ;
for ( i = g_numentities - 1 ; i > - 1 ; i - - )
{
entity_t * ent = & g_entities [ i ] ;
const char * classname = ValueForKey ( ent , " classname " ) ;
const char * targetname = ValueForKey ( ent , " targetname " ) ;
int style = IntForKey ( ent , " style " ) ;
if ( ! targetname [ 0 ] | | strcmp ( classname , " light " ) & & strcmp ( classname , " light_spot " ) & & strcmp ( classname , " light_environment " ) )
continue ;
for ( j = i + 1 ; j < g_numentities ; j + + )
{
if ( ! lightneedcompare [ j ] )
continue ;
entity_t * ent2 = & g_entities [ j ] ;
const char * targetname2 = ValueForKey ( ent2 , " targetname " ) ;
int style2 = IntForKey ( ent2 , " style " ) ;
if ( style = = style2 & & ! strcmp ( targetname , targetname2 ) )
break ;
}
if ( j < g_numentities )
{
DeleteKey ( ent , " targetname " ) ;
count + + ;
}
else
{
lightneedcompare [ i ] = true ;
}
}
if ( count > 0 )
{
Log ( " %d redundant named lights optimized. \n " , count ) ;
}
free ( lightneedcompare ) ;
}
# endif
# endif
for ( i = 0 ; i < g_numentities ; i + + )
{
ep = g_entities [ i ] . epairs ;
if ( ! ep )
{
continue ; // ent got removed
}
strcat ( end , " { \n " ) ;
end + = 2 ;
for ( ep = g_entities [ i ] . epairs ; ep ; ep = ep - > next )
{
sprintf ( line , " \" %s \" \" %s \" \n " , ep - > key , ep - > value ) ;
strcat ( end , line ) ;
end + = strlen ( line ) ;
}
strcat ( end , " } \n " ) ;
end + = 2 ;
if ( end > buf + MAX_MAP_ENTSTRING )
{
Error ( " Entity text too long " ) ;
}
}
g_entdatasize = end - buf + 1 ;
}
// =====================================================================================
// SetKeyValue
// makes a keyvalue
// =====================================================================================
# ifdef ZHLT_DELETEKEY
void DeleteKey ( entity_t * ent , const char * const key )
{
epair_t * * pep ;
for ( pep = & ent - > epairs ; * pep ; pep = & ( * pep ) - > next )
{
if ( ! strcmp ( ( * pep ) - > key , key ) )
{
epair_t * ep = * pep ;
* pep = ep - > next ;
Free ( ep - > key ) ;
Free ( ep - > value ) ;
Free ( ep ) ;
return ;
}
}
}
# endif
void SetKeyValue ( entity_t * ent , const char * const key , const char * const value )
{
epair_t * ep ;
# ifdef ZHLT_DELETEKEY
if ( ! value [ 0 ] )
{
DeleteKey ( ent , key ) ;
return ;
}
# endif
for ( ep = ent - > epairs ; ep ; ep = ep - > next )
{
if ( ! strcmp ( ep - > key , key ) )
{
# ifdef ZHLT_DELETEKEY
char * value2 = strdup ( value ) ;
Free ( ep - > value ) ;
ep - > value = value2 ;
# else
Free ( ep - > value ) ;
ep - > value = strdup ( value ) ;
# endif
return ;
}
}
ep = ( epair_t * ) Alloc ( sizeof ( * ep ) ) ;
ep - > next = ent - > epairs ;
ent - > epairs = ep ;
ep - > key = strdup ( key ) ;
ep - > value = strdup ( value ) ;
}
// =====================================================================================
// ValueForKey
// returns the value for a passed entity and key
// =====================================================================================
const char * ValueForKey ( const entity_t * const ent , const char * const key )
{
epair_t * ep ;
for ( ep = ent - > epairs ; ep ; ep = ep - > next )
{
if ( ! strcmp ( ep - > key , key ) )
{
return ep - > value ;
}
}
return " " ;
}
// =====================================================================================
// IntForKey
// =====================================================================================
int IntForKey ( const entity_t * const ent , const char * const key )
{
return atoi ( ValueForKey ( ent , key ) ) ;
}
// =====================================================================================
// FloatForKey
// =====================================================================================
vec_t FloatForKey ( const entity_t * const ent , const char * const key )
{
return atof ( ValueForKey ( ent , key ) ) ;
}
// =====================================================================================
// GetVectorForKey
// returns value for key in vec[0-2]
// =====================================================================================
void GetVectorForKey ( const entity_t * const ent , const char * const key , vec3_t vec )
{
const char * k ;
double v1 , v2 , v3 ;
k = ValueForKey ( ent , key ) ;
// scanf into doubles, then assign, so it is vec_t size independent
v1 = v2 = v3 = 0 ;
sscanf ( k , " %lf %lf %lf " , & v1 , & v2 , & v3 ) ;
vec [ 0 ] = v1 ;
vec [ 1 ] = v2 ;
vec [ 2 ] = v3 ;
}
// =====================================================================================
// FindTargetEntity
//
// =====================================================================================
entity_t * FindTargetEntity ( const char * const target )
{
int i ;
const char * n ;
for ( i = 0 ; i < g_numentities ; i + + )
{
n = ValueForKey ( & g_entities [ i ] , " targetname " ) ;
if ( ! strcmp ( n , target ) )
{
return & g_entities [ i ] ;
}
}
return NULL ;
}
void dtexdata_init ( )
{
g_dtexdata = ( byte * ) AllocBlock ( g_max_map_miptex ) ;
hlassume ( g_dtexdata ! = NULL , assume_NoMemory ) ;
g_dlightdata = ( byte * ) AllocBlock ( g_max_map_lightdata ) ;
hlassume ( g_dlightdata ! = NULL , assume_NoMemory ) ;
}
void CDECL dtexdata_free ( )
{
FreeBlock ( g_dtexdata ) ;
g_dtexdata = NULL ;
FreeBlock ( g_dlightdata ) ;
g_dlightdata = NULL ;
}
// =====================================================================================
// GetTextureByNumber
// Touchy function, can fail with a page fault if all the data isnt kosher
// (i.e. map was compiled with missing textures)
// =====================================================================================
# ifdef HLCSG_HLBSP_VOIDTEXINFO
static char emptystring [ 1 ] = { ' \0 ' } ;
# endif
char * GetTextureByNumber ( int texturenumber )
{
# ifdef HLCSG_HLBSP_VOIDTEXINFO
if ( texturenumber = = - 1 )
return emptystring ;
# endif
texinfo_t * info ;
miptex_t * miptex ;
int ofs ;
info = & g_texinfo [ texturenumber ] ;
ofs = ( ( dmiptexlump_t * ) g_dtexdata ) - > dataofs [ info - > miptex ] ;
miptex = ( miptex_t * ) ( & g_dtexdata [ ofs ] ) ;
2024-03-04 22:32:51 +00:00
// cypress -- hacked-in support for __TB_empty
// just sorta replacing __TB_empty with null here, because
// ericw-tools does the same thing, and this is the best
// place to do it with the least amount of work required.
if ( ! strncasecmp ( miptex - > name , " __TB_empty " , 10 ) )
return " null " ;
2016-09-20 21:07:53 +00:00
return miptex - > name ;
}
// =====================================================================================
// EntityForModel
// returns entity addy for given modelnum
// =====================================================================================
entity_t * EntityForModel ( const int modnum )
{
int i ;
const char * s ;
char name [ 16 ] ;
sprintf ( name , " *%i " , modnum ) ;
// search the entities for one using modnum
for ( i = 0 ; i < g_numentities ; i + + )
{
s = ValueForKey ( & g_entities [ i ] , " model " ) ;
if ( ! strcmp ( s , name ) )
{
return & g_entities [ i ] ;
}
}
return & g_entities [ 0 ] ;
}