2014-04-12 12:19:49 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
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 2
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 , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// model.c -- model loading and caching
// models are the only shared resource between a client and server running
// on the same machine.
# include "quakedef.h"
extern cvar_t * gl_glowmap ; // 1999-12-28 OpenGL fullbright fix by Neal White III
2014-04-12 12:29:30 +00:00
# ifdef QSB
# define MAX_MOD_KNOWN 4096
# else
2014-04-12 12:19:49 +00:00
# define MAX_MOD_KNOWN 512
2014-04-12 12:29:30 +00:00
# endif
2014-04-12 12:19:49 +00:00
model_t mod_known [ MAX_MOD_KNOWN ] ;
int mod_numknown ;
/*
= = = = = = = = = = = = = = = = = = =
Mod_ClearAll
= = = = = = = = = = = = = = = = = = =
*/
void Mod_ClearAll ( void )
{
int i ;
model_t * mod ;
for ( i = 0 , mod = mod_known ; i < mod_numknown ; i + + , mod + + )
if ( mod - > type ! = mod_alias )
mod - > needload = true ;
}
/*
= = = = = = = = = = = = = = = = = =
Mod_FindName
= = = = = = = = = = = = = = = = = =
*/
model_t * Mod_FindName ( char * name )
{
int i ;
model_t * mod ;
if ( ! name [ 0 ] )
Sys_Error ( " Mod_ForName: NULL name " ) ;
//
// search the currently loaded models
//
for ( i = 0 , mod = mod_known ; i < mod_numknown ; i + + , mod + + )
if ( ! strcmp ( mod - > name , name ) )
break ;
if ( i = = mod_numknown )
{
if ( mod_numknown = = MAX_MOD_KNOWN )
Sys_Error ( " mod_numknown == MAX_MOD_KNOWN " ) ;
strcpy ( mod - > name , name ) ;
mod - > needload = true ;
mod_numknown + + ;
}
return mod ;
}
/*
= = = = = = = = = = = = = = = = = =
Mod_TouchModel
= = = = = = = = = = = = = = = = = =
*/
void Mod_TouchModel ( char * name )
{
model_t * mod ;
mod = Mod_FindName ( name ) ;
if ( ! mod - > needload )
{
if ( mod - > type = = mod_alias )
Cache_Check ( & mod - > cache ) ;
}
}
/*
= = = = = = = = = = = = = = = = = =
Mod_LoadModel
Loads a model into the cache
= = = = = = = = = = = = = = = = = =
*/
model_t * Mod_LoadModel ( model_t * mod , qboolean crash )
{
void * d ;
unsigned * buf ;
byte stackbuf [ 1024 ] ; // avoid dirtying the cache heap
loadedfile_t * fileinfo ; // 2001-09-12 Returning information about loaded file by Maddes
if ( ! mod - > needload )
{
if ( mod - > type = = mod_alias )
{
d = Cache_Check ( & mod - > cache ) ;
if ( d )
return mod ;
}
else
return mod ; // not cached at all
}
//
// because the world is so huge, load it one piece at a time
//
if ( ! crash )
{
}
//
// load the file
//
// 2001-09-12 Returning information about loaded file by Maddes start
/*
buf = ( unsigned * ) COM_LoadStackFile ( mod - > name , stackbuf , sizeof ( stackbuf ) ) ;
if ( ! buf )
*/
fileinfo = COM_LoadStackFile ( mod - > name , stackbuf , sizeof ( stackbuf ) ) ;
if ( ! fileinfo )
// 2001-09-12 Returning information about loaded file by Maddes end
{
if ( crash )
Sys_Error ( " Mod_NumForName: %s not found " , mod - > name ) ;
return NULL ;
}
buf = ( unsigned * ) fileinfo - > data ; // 2001-09-12 Returning information about loaded file by Maddes
//
// allocate a new model
//
COM_FileBase ( mod - > name , loadname ) ;
loadmodel = mod ;
//
// fill it in
//
// call the apropriate loader
mod - > needload = false ;
switch ( LittleLong ( * ( unsigned * ) buf ) )
{
case IDPOLYHEADER :
Mod_LoadAliasModel ( mod , buf ) ;
break ;
case IDSPRITEHEADER :
Mod_LoadSpriteModel ( mod , buf ) ;
break ;
default :
Mod_LoadBrushModel ( mod , buf , fileinfo ) ; // 2001-09-12 .ENT support by Maddes
break ;
}
return mod ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BRUSHMODEL LOADING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = =
Mod_LoadTextures
= = = = = = = = = = = = = = = = =
*/
void Mod_LoadTextures ( lump_t * l )
{
// 1999-12-28 OpenGL fullbright fix by Neal White III start
// Neal White III - 12-28-1999 - OpenGL fullbright bugfix
// nwhite@softblox.com
// http://home.telefragged.com/wally/
//
// Problem:
//
// There was a problem in the original glquake with fullbright texels.
// In the software renderer, fullbrights glow brightly in the dark.
// Essentially, the fullbrights were ignored. I've fixed it by
// adding another rendering pass and creating a new glowmap texture.
//
// Fix:
//
// When a texture with fullbright (FB) texels is loaded, a copy is made,
// then the FB pixels are cleared to black in the original texture. In
// the copy, all normal colors are cleared and only the FBs remain. When
// it comes time to render the polygons, I do an additional pass and ADD
// the glowmap on top of the current polygon.
byte * ptexel ;
qboolean hasfullbrights ;
// qboolean noglow = COM_CheckParm("-noglow");
// int i, j, pixels, num, max, altmax;
int i , num , max , altmax ;
unsigned long j , pixels ;
// 1999-12-28 OpenGL fullbright fix by Neal White III end
miptex_t * mt ;
texture_t * tx , * tx2 ;
texture_t * anims [ 10 ] ;
texture_t * altanims [ 10 ] ;
dmiptexlump_t * m ;
if ( ! l - > filelen )
{
loadmodel - > textures = NULL ;
return ;
}
m = ( dmiptexlump_t * ) ( mod_base + l - > fileofs ) ;
m - > nummiptex = LittleLong ( m - > nummiptex ) ;
loadmodel - > numtextures = m - > nummiptex ;
loadmodel - > textures = Hunk_AllocName ( m - > nummiptex * sizeof ( * loadmodel - > textures ) , loadname ) ;
for ( i = 0 ; i < m - > nummiptex ; i + + )
{
m - > dataofs [ i ] = LittleLong ( m - > dataofs [ i ] ) ;
if ( m - > dataofs [ i ] = = - 1 )
continue ;
mt = ( miptex_t * ) ( ( byte * ) m + m - > dataofs [ i ] ) ;
mt - > width = LittleLong ( mt - > width ) ;
mt - > height = LittleLong ( mt - > height ) ;
for ( j = 0 ; j < MIPLEVELS ; j + + )
mt - > offsets [ j ] = LittleLong ( mt - > offsets [ j ] ) ;
if ( ( mt - > width & 15 ) | | ( mt - > height & 15 ) )
Sys_Error ( " Texture %s is not 16 aligned " , mt - > name ) ;
pixels = mt - > width * mt - > height / 64 * 85 ;
// 1999-12-28 OpenGL fullbright fix by Neal White III start
hasfullbrights = false ;
if ( ( ! strncmp ( mt - > name , " sky " , 3 ) ) | |
( ! strncmp ( mt - > name , " * " , 1 ) ) | | // turbulent (liquid)
( ! gl_glowmap - > value ) | | ( ! gl_mtexable ) )
{
// sky has no lightmap, nor do liquids (so never needs a glowmap),
// -noglow command line parameter, or no multi-texture support
//
// hasfullbrights is already false
}
else // check this texture for fullbright texels
{
ptexel = ( byte * ) ( mt + 1 ) ;
for ( j = 0 ; j < pixels ; j + + )
{
if ( ptexel [ j ] > = 256 - 32 ) // 32 fullbright colors
{
hasfullbrights = true ;
break ;
}
}
}
if ( hasfullbrights )
{
tx = Hunk_AllocName ( sizeof ( texture_t ) + pixels * 2 , loadname ) ;
}
else
{
// 1999-12-28 OpenGL fullbright fix by Neal White III end
tx = Hunk_AllocName ( sizeof ( texture_t ) + pixels , loadname ) ;
} // 1999-12-28 OpenGL fullbright fix by Neal White III
loadmodel - > textures [ i ] = tx ;
memcpy ( tx - > name , mt - > name , sizeof ( tx - > name ) ) ;
tx - > width = mt - > width ;
tx - > height = mt - > height ;
for ( j = 0 ; j < MIPLEVELS ; j + + )
{ // 1999-12-28 OpenGL fullbright fix by Neal White III
tx - > offsets [ j ] = mt - > offsets [ j ] + sizeof ( texture_t ) - sizeof ( miptex_t ) ;
// 1999-12-28 OpenGL fullbright fix by Neal White III start
if ( hasfullbrights )
{
tx - > glowoffsets [ j ] = mt - > offsets [ j ] + sizeof ( texture_t ) - sizeof ( miptex_t ) + pixels ;
}
else
{
tx - > glowoffsets [ j ] = 0 ;
}
}
// 1999-12-28 OpenGL fullbright fix by Neal White III end
// the pixels immediately follow the structures
memcpy ( tx + 1 , mt + 1 , pixels ) ;
// 1999-12-28 OpenGL fullbright fix by Neal White III start
if ( hasfullbrights )
{
ptexel = ( byte * ) ( tx + 1 ) ;
memcpy ( ptexel + pixels , mt + 1 , pixels ) ;
}
tx - > flags = 0 ;
// 1999-12-28 OpenGL fullbright fix by Neal White III end
if ( ! strncmp ( mt - > name , " sky " , 3 ) )
// 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline start
{
if ( cls . state ! = ca_dedicated )
{
// 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline end
R_InitSky ( tx ) ;
// 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline start
}
}
// 2000-07-09 Dedicated server bug in GLQuake fix by Nathan Cline end
else
{
texture_mode = GL_LINEAR_MIPMAP_NEAREST ; //_LINEAR;
// 1999-12-28 OpenGL fullbright fix by Neal White III start
// remove glowing fullbright colors from base texture (make black)
if ( hasfullbrights )
{
# ifdef _DEBUG
qboolean bColorUsed [ 256 ] ;
Con_DPrintf ( " *** Fullbright Texture: \" %s \" , %dx%d, %d pixels \n " , mt - > name , mt - > width , mt - > height , pixels ) ;
for ( j = 0 ; j < 256 ; j + + ) bColorUsed [ j ] = false ;
# endif
ptexel = ( byte * ) ( tx + 1 ) ;
for ( j = 0 ; j < pixels ; j + + )
{
# ifdef _DEBUG
bColorUsed [ ptexel [ j ] ] = true ;
# endif
if ( ptexel [ j ] > = 256 - 32 ) // 32 fullbright colors
{
ptexel [ j ] = 0 ; // make fullbrights black
}
}
# ifdef _DEBUG
Con_DPrintf ( " *** Normal colors: " ) ;
for ( j = 0 ; j < 256 - 32 ; j + + )
{
if ( bColorUsed [ j ] )
Con_DPrintf ( " %d " , j ) ;
}
Con_DPrintf ( " \n " ) ;
Con_DPrintf ( " *** Fullbrights: " ) ;
for ( j = 256 - 32 ; j < 256 ; j + + )
{
if ( bColorUsed [ j ] )
Con_DPrintf ( " %d " , j ) ;
}
Con_DPrintf ( " \n " ) ;
# endif
}
# ifdef _DEBUG
else
{
Con_DPrintf ( " *** Normal Texture: \" %s \" , %dx%d \n " , mt - > name , mt - > width , mt - > height ) ;
}
# endif
// 1999-12-28 OpenGL fullbright fix by Neal White III end
tx - > gl_texturenum = GL_LoadTexture ( mt - > name , tx - > width , tx - > height , ( byte * ) ( tx + 1 ) , true , false ) ;
// 1999-12-28 OpenGL fullbright fix by Neal White III start
// create glowmap texture (all black except for glowing fullbright colors)
if ( hasfullbrights )
{
# ifdef _DEBUG
qboolean bGlowDoubleCheck = false ;
# endif
char glowname [ 32 ] ;
memcpy ( glowname , mt - > name , sizeof ( mt - > name ) ) ;
glowname [ 16 ] = ' \0 ' ;
for ( j = 0 ; glowname [ j ] ! = ' \0 ' ; j + + )
;
glowname [ j + + ] = ' < ' ;
glowname [ j + + ] = ' G ' ;
glowname [ j + + ] = ' L ' ;
glowname [ j + + ] = ' O ' ;
glowname [ j + + ] = ' W ' ;
glowname [ j + + ] = ' > ' ;
glowname [ j + + ] = ' \0 ' ;
ptexel = ( byte * ) ( tx + 1 ) + pixels ;
for ( j = 0 ; j < pixels ; j + + )
{
if ( ptexel [ j ] < 256 - 32 ) // build glowmap
{
ptexel [ j ] = 0 ; // make non-fullbrights black
}
# ifdef _DEBUG
else
{
bGlowDoubleCheck = true ;
}
# endif
}
tx - > gl_glowtexnum = GL_LoadTexture ( glowname , tx - > width , tx - > height , ptexel , true , false ) ;
tx - > flags | = FLAG_HAS_GLOWMAP ;
# ifdef _DEBUG
if ( ! bGlowDoubleCheck )
Con_DPrintf ( " INTERNAL ERROR: Mod_LoadTextures - FullBright texture \" %s \" has no FullBright colors! \n " , glowname ) ;
# endif
}
// 1999-12-28 OpenGL fullbright fix by Neal White III end
texture_mode = GL_LINEAR ;
}
}
//
// sequence the animations
//
for ( i = 0 ; i < m - > nummiptex ; i + + )
{
tx = loadmodel - > textures [ i ] ;
if ( ! tx | | tx - > name [ 0 ] ! = ' + ' )
continue ;
if ( tx - > anim_next )
continue ; // already sequenced
// find the number of frames in the animation
memset ( anims , 0 , sizeof ( anims ) ) ;
memset ( altanims , 0 , sizeof ( altanims ) ) ;
max = tx - > name [ 1 ] ;
altmax = 0 ;
if ( max > = ' a ' & & max < = ' z ' )
max - = ' a ' - ' A ' ;
if ( max > = ' 0 ' & & max < = ' 9 ' )
{
max - = ' 0 ' ;
altmax = 0 ;
anims [ max ] = tx ;
max + + ;
}
else if ( max > = ' A ' & & max < = ' J ' )
{
altmax = max - ' A ' ;
max = 0 ;
altanims [ altmax ] = tx ;
altmax + + ;
}
else
Sys_Error ( " Bad animating texture %s " , tx - > name ) ;
for ( j = i + 1 ; j < m - > nummiptex ; j + + )
{
tx2 = loadmodel - > textures [ j ] ;
if ( ! tx2 | | tx2 - > name [ 0 ] ! = ' + ' )
continue ;
if ( strcmp ( tx2 - > name + 2 , tx - > name + 2 ) )
continue ;
num = tx2 - > name [ 1 ] ;
if ( num > = ' a ' & & num < = ' z ' )
num - = ' a ' - ' A ' ;
if ( num > = ' 0 ' & & num < = ' 9 ' )
{
num - = ' 0 ' ;
anims [ num ] = tx2 ;
if ( num + 1 > max )
max = num + 1 ;
}
else if ( num > = ' A ' & & num < = ' J ' )
{
num = num - ' A ' ;
altanims [ num ] = tx2 ;
if ( num + 1 > altmax )
altmax = num + 1 ;
}
else
Sys_Error ( " Bad animating texture %s " , tx - > name ) ;
}
# define ANIM_CYCLE 2
// link them all together
for ( j = 0 ; j < max ; j + + )
{
tx2 = anims [ j ] ;
if ( ! tx2 )
Sys_Error ( " Missing frame %i of %s " , j , tx - > name ) ;
tx2 - > anim_total = max * ANIM_CYCLE ;
tx2 - > anim_min = j * ANIM_CYCLE ;
tx2 - > anim_max = ( j + 1 ) * ANIM_CYCLE ;
tx2 - > anim_next = anims [ ( j + 1 ) % max ] ;
if ( altmax )
tx2 - > alternate_anims = altanims [ 0 ] ;
}
for ( j = 0 ; j < altmax ; j + + )
{
tx2 = altanims [ j ] ;
if ( ! tx2 )
Sys_Error ( " Missing frame %i of %s " , j , tx - > name ) ;
tx2 - > anim_total = altmax * ANIM_CYCLE ;
tx2 - > anim_min = j * ANIM_CYCLE ;
tx2 - > anim_max = ( j + 1 ) * ANIM_CYCLE ;
tx2 - > anim_next = altanims [ ( j + 1 ) % altmax ] ;
if ( max )
tx2 - > alternate_anims = anims [ 0 ] ;
}
}
}
/*
= = = = = = = = = = = = = = = = =
Mod_LoadLighting
= = = = = = = = = = = = = = = = =
*/
void Mod_LoadLighting ( lump_t * l )
{
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes start
/*
if ( ! l - > filelen )
{
loadmodel - > lightdata = NULL ;
return ;
}
loadmodel - > lightdata = Hunk_AllocName ( l - > filelen , loadname ) ;
memcpy ( loadmodel - > lightdata , mod_base + l - > fileofs , l - > filelen ) ;
*/
int i ;
byte * in , * out , * data ;
byte d ;
char litfilename [ 1024 ] ;
loadedfile_t * fileinfo ; // 2001-09-12 Returning information about loaded file by Maddes
loadmodel - > lightdata = NULL ;
if ( external_lit - > value )
{
// check for a .LIT file
strcpy ( litfilename , loadmodel - > name ) ;
COM_StripExtension ( litfilename , litfilename ) ;
strcat ( litfilename , " .lit " ) ;
// 2001-09-12 Returning information about loaded file by Maddes start
/*
data = ( byte * ) COM_LoadHunkFile ( litfilename ) ;
if ( data )
*/
fileinfo = COM_LoadHunkFile ( litfilename ) ;
if ( fileinfo )
// 2001-09-12 Returning information about loaded file by Maddes end
{
2014-04-12 12:29:30 +00:00
Con_DPrintf ( " %s loaded from %s \n " , litfilename , fileinfo - > path - > pack ? fileinfo - > path - > pack - > filename : fileinfo - > path - > filename ) ; // 2001-09-12 Displaying where .LIT file is loaded from by Maddes
2014-04-12 12:19:49 +00:00
data = fileinfo - > data ; // 2001-09-12 Returning information about loaded file by Maddes
if ( data [ 0 ] = = ' Q ' & & data [ 1 ] = = ' L ' & & data [ 2 ] = = ' I ' & & data [ 3 ] = = ' T ' )
{
i = LittleLong ( ( ( int * ) data ) [ 1 ] ) ;
if ( i = = 1 )
{
loadmodel - > lightdata = data + 8 ;
return ;
}
else
Con_Printf ( " Unknown .LIT file version (%d) \n " , i ) ;
}
else
Con_Printf ( " Corrupt .LIT file (old version?), ignoring \n " ) ;
}
// no .LIT found, expand the white lighting data to color
}
if ( ! l - > filelen )
return ;
loadmodel - > lightdata = Hunk_AllocName ( l - > filelen * 3 , loadname ) ;
in = loadmodel - > lightdata + l - > filelen * 2 ; // place the file at the end, so it will not be overwritten until the very last write
out = loadmodel - > lightdata ;
memcpy ( in , mod_base + l - > fileofs , l - > filelen ) ;
for ( i = 0 ; i < l - > filelen ; i + + )
{
d = * in + + ;
* out + + = d ;
* out + + = d ;
* out + + = d ;
}
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes end
}
/*
= = = = = = = = = = = = = = = =
CalcSurfaceExtents
Fills in s - > texturemins [ ] and s - > extents [ ]
= = = = = = = = = = = = = = = =
*/
void CalcSurfaceExtents ( msurface_t * s )
{
float mins [ 2 ] , maxs [ 2 ] , val ;
int i , j , e ;
mvertex_t * v ;
mtexinfo_t * tex ;
int bmins [ 2 ] , bmaxs [ 2 ] ;
mins [ 0 ] = mins [ 1 ] = 999999 ;
maxs [ 0 ] = maxs [ 1 ] = - 99999 ;
tex = s - > texinfo ;
for ( i = 0 ; i < s - > numedges ; i + + )
{
e = loadmodel - > surfedges [ s - > firstedge + i ] ;
if ( e > = 0 )
v = & loadmodel - > vertexes [ loadmodel - > edges [ e ] . v [ 0 ] ] ;
else
v = & loadmodel - > vertexes [ loadmodel - > edges [ - e ] . v [ 1 ] ] ;
for ( j = 0 ; j < 2 ; j + + )
{
val = v - > position [ 0 ] * tex - > vecs [ j ] [ 0 ] +
v - > position [ 1 ] * tex - > vecs [ j ] [ 1 ] +
v - > position [ 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 ] / 16 ) ;
bmaxs [ i ] = ceil ( maxs [ i ] / 16 ) ;
s - > texturemins [ i ] = bmins [ i ] * 16 ;
s - > extents [ i ] = ( bmaxs [ i ] - bmins [ i ] ) * 16 ;
if ( ! ( tex - > flags & TEX_SPECIAL ) & & s - > extents [ i ] > 512 /* 256 */ )
Sys_Error ( " Bad surface extents " ) ;
}
}
/*
= = = = = = = = = = = = = = = = =
Mod_LoadFaces
= = = = = = = = = = = = = = = = =
*/
void Mod_LoadFaces ( lump_t * l )
{
dface_t * in ;
msurface_t * out ;
int i , count , surfnum ;
int planenum , side ;
in = ( void * ) ( mod_base + l - > fileofs ) ;
if ( l - > filelen % sizeof ( * in ) )
Sys_Error ( " MOD_LoadBmodel: funny lump size in %s " , loadmodel - > name ) ;
count = l - > filelen / sizeof ( * in ) ;
out = Hunk_AllocName ( count * sizeof ( * out ) , loadname ) ;
loadmodel - > surfaces = out ;
loadmodel - > numsurfaces = count ;
for ( surfnum = 0 ; surfnum < count ; surfnum + + , in + + , out + + )
{
out - > firstedge = LittleLong ( in - > firstedge ) ;
out - > numedges = LittleShort ( in - > numedges ) ;
out - > flags = 0 ;
planenum = LittleShort ( in - > planenum ) ;
side = LittleShort ( in - > side ) ;
if ( side )
out - > flags | = SURF_PLANEBACK ;
out - > plane = loadmodel - > planes + planenum ;
out - > texinfo = loadmodel - > texinfo + LittleShort ( in - > texinfo ) ;
CalcSurfaceExtents ( out ) ;
// lighting info
for ( i = 0 ; i < MAXLIGHTMAPS ; i + + )
out - > styles [ i ] = in - > styles [ i ] ;
i = LittleLong ( in - > lightofs ) ;
if ( i = = - 1 )
out - > samples = NULL ;
else
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes start
// out->samples = loadmodel->lightdata + i;
out - > samples = loadmodel - > lightdata + ( i * 3 ) ; // expand white lighting
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes end
// set the drawing flags flag
if ( ! strncmp ( out - > texinfo - > texture - > name , " sky " , 3 ) ) // sky
{
out - > flags | = ( SURF_DRAWSKY | SURF_DRAWTILED ) ;
# ifndef QUAKE2
GL_SubdivideSurface ( out ) ; // cut up polygon for warps
# endif
continue ;
}
if ( ! strncmp ( out - > texinfo - > texture - > name , " * " , 1 ) ) // turbulent
{
out - > flags | = ( SURF_DRAWTURB | SURF_DRAWTILED ) ;
for ( i = 0 ; i < 2 ; i + + )
{
out - > extents [ i ] = 16384 ;
out - > texturemins [ i ] = - 8192 ;
}
GL_SubdivideSurface ( out ) ; // cut up polygon for warps
continue ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ALIAS MODELS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
aliashdr_t * pheader ;
stvert_t stverts [ MAXALIASVERTS ] ;
mtriangle_t triangles [ MAXALIASTRIS ] ;
// a pose is a single set of vertexes. a frame may be
// an animating sequence of poses
trivertx_t * poseverts [ MAXALIASFRAMES ] ;
int posenum ;
byte * * player_8bit_texels_tbl ;
byte * player_8bit_texels ;
int aliasbboxmins [ 3 ] , aliasbboxmaxs [ 3 ] ; // 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz
/*
= = = = = = = = = = = = = = = = =
Mod_LoadAliasFrame
= = = = = = = = = = = = = = = = =
*/
void * Mod_LoadAliasFrame ( void * pin , maliasframedesc_t * frame )
{
trivertx_t * pframe , * pinframe ;
int i , j ;
daliasframe_t * pdaliasframe ;
pdaliasframe = ( daliasframe_t * ) pin ;
strcpy ( frame - > name , pdaliasframe - > name ) ;
frame - > firstpose = posenum ;
frame - > numposes = 1 ;
for ( i = 0 ; i < 3 ; i + + )
{
// these are byte values, so we don't have to worry about
// endianness
frame - > bboxmin . v [ i ] = pdaliasframe - > bboxmin . v [ i ] ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz start
// frame->bboxmin.v[i] = pdaliasframe->bboxmax.v[i];
frame - > bboxmax . v [ i ] = pdaliasframe - > bboxmax . v [ i ] ;
aliasbboxmins [ i ] = min ( frame - > bboxmin . v [ i ] , aliasbboxmins [ i ] ) ;
aliasbboxmaxs [ i ] = max ( frame - > bboxmax . v [ i ] , aliasbboxmaxs [ i ] ) ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz end
}
pinframe = ( trivertx_t * ) ( pdaliasframe + 1 ) ;
poseverts [ posenum ] = pinframe ;
posenum + + ;
pinframe + = pheader - > numverts ;
return ( void * ) pinframe ;
}
/*
= = = = = = = = = = = = = = = = =
Mod_LoadAliasGroup
= = = = = = = = = = = = = = = = =
*/
void * Mod_LoadAliasGroup ( void * pin , maliasframedesc_t * frame )
{
daliasgroup_t * pingroup ;
int i , numframes ;
daliasinterval_t * pin_intervals ;
void * ptemp ;
pingroup = ( daliasgroup_t * ) pin ;
numframes = LittleLong ( pingroup - > numframes ) ;
frame - > firstpose = posenum ;
frame - > numposes = numframes ;
for ( i = 0 ; i < 3 ; i + + )
{
// these are byte values, so we don't have to worry about endianness
frame - > bboxmin . v [ i ] = pingroup - > bboxmin . v [ i ] ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz start
// frame->bboxmin.v[i] = pingroup->bboxmax.v[i];
frame - > bboxmax . v [ i ] = pingroup - > bboxmax . v [ i ] ;
aliasbboxmins [ i ] = min ( frame - > bboxmin . v [ i ] , aliasbboxmins [ i ] ) ;
aliasbboxmaxs [ i ] = max ( frame - > bboxmax . v [ i ] , aliasbboxmaxs [ i ] ) ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz end
}
pin_intervals = ( daliasinterval_t * ) ( pingroup + 1 ) ;
frame - > interval = LittleFloat ( pin_intervals - > interval ) ;
pin_intervals + = numframes ;
ptemp = ( void * ) pin_intervals ;
for ( i = 0 ; i < numframes ; i + + )
{
poseverts [ posenum ] = ( trivertx_t * ) ( ( daliasframe_t * ) ptemp + 1 ) ;
posenum + + ;
ptemp = ( trivertx_t * ) ( ( daliasframe_t * ) ptemp + 1 ) + pheader - > numverts ;
}
return ptemp ;
}
//=========================================================
/*
= = = = = = = = = = = = = = = = =
Mod_FloodFillSkin
Fill background pixels so mipmapping doesn ' t have haloes - Ed
= = = = = = = = = = = = = = = = =
*/
typedef struct
{
short x , y ;
} floodfill_t ;
extern unsigned d_8to24table [ ] ;
// must be a power of 2
# define FLOODFILL_FIFO_SIZE 0x1000
# define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
# define FLOODFILL_STEP( off, dx, dy ) \
{ \
if ( pos [ off ] = = fillcolor ) \
{ \
pos [ off ] = 255 ; \
fifo [ inpt ] . x = x + ( dx ) , fifo [ inpt ] . y = y + ( dy ) ; \
inpt = ( inpt + 1 ) & FLOODFILL_FIFO_MASK ; \
} \
else if ( pos [ off ] ! = 255 ) fdc = pos [ off ] ; \
}
void Mod_FloodFillSkin ( byte * skin , int skinwidth , int skinheight )
{
byte fillcolor = * skin ; // assume this is the pixel to fill
floodfill_t fifo [ FLOODFILL_FIFO_SIZE ] ;
int inpt = 0 , outpt = 0 ;
int filledcolor = - 1 ;
int i ;
if ( filledcolor = = - 1 )
{
filledcolor = 0 ;
// attempt to find opaque black
for ( i = 0 ; i < 256 ; + + i )
if ( d_8to24table [ i ] = = ( 255 < < 0 ) ) // alpha 1.0
{
filledcolor = i ;
break ;
}
}
// can't fill to filled color or to transparent color (used as visited marker)
if ( ( fillcolor = = filledcolor ) | | ( fillcolor = = 255 ) )
{
//printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
return ;
}
fifo [ inpt ] . x = 0 , fifo [ inpt ] . y = 0 ;
inpt = ( inpt + 1 ) & FLOODFILL_FIFO_MASK ;
while ( outpt ! = inpt )
{
int x = fifo [ outpt ] . x , y = fifo [ outpt ] . y ;
int fdc = filledcolor ;
byte * pos = & skin [ x + skinwidth * y ] ;
outpt = ( outpt + 1 ) & FLOODFILL_FIFO_MASK ;
if ( x > 0 ) FLOODFILL_STEP ( - 1 , - 1 , 0 ) ;
if ( x < skinwidth - 1 ) FLOODFILL_STEP ( 1 , 1 , 0 ) ;
if ( y > 0 ) FLOODFILL_STEP ( - skinwidth , 0 , - 1 ) ;
if ( y < skinheight - 1 ) FLOODFILL_STEP ( skinwidth , 0 , 1 ) ;
skin [ x + skinwidth * y ] = fdc ;
}
}
/*
= = = = = = = = = = = = = = =
Mod_LoadAllSkins
= = = = = = = = = = = = = = =
*/
void * Mod_LoadAllSkins ( int numskins , daliasskintype_t * pskintype )
{
int i , j , k ;
char name [ 32 ] ;
int s ;
byte * copy ;
byte * skin ;
byte * texels ;
daliasskingroup_t * pinskingroup ;
int groupskins ;
daliasskininterval_t * pinskinintervals ;
skin = ( byte * ) ( pskintype + 1 ) ;
if ( numskins < 1 | | numskins > MAX_SKINS )
Sys_Error ( " Mod_LoadAliasModel: Invalid # of skins: %d \n " , numskins ) ;
s = pheader - > skinwidth * pheader - > skinheight ;
for ( i = 0 ; i < numskins ; i + + )
{
if ( pskintype - > type = = ALIAS_SKIN_SINGLE ) {
Mod_FloodFillSkin ( skin , pheader - > skinwidth , pheader - > skinheight ) ;
// save 8 bit texels for the player model to remap
// if (!strcmp(loadmodel->name,"progs/player.mdl")) {
texels = Hunk_AllocName ( s , loadname ) ;
pheader - > texels [ i ] = texels - ( byte * ) pheader ;
memcpy ( texels , ( byte * ) ( pskintype + 1 ) , s ) ;
// }
sprintf ( name , " %s_%i " , loadmodel - > name , i ) ;
pheader - > gl_texturenum [ i ] [ 0 ] =
pheader - > gl_texturenum [ i ] [ 1 ] =
pheader - > gl_texturenum [ i ] [ 2 ] =
pheader - > gl_texturenum [ i ] [ 3 ] =
GL_LoadTexture ( name , pheader - > skinwidth ,
pheader - > skinheight , ( byte * ) ( pskintype + 1 ) , true , false ) ;
pskintype = ( daliasskintype_t * ) ( ( byte * ) ( pskintype + 1 ) + s ) ;
} else {
// animating skin group. yuck.
pskintype + + ;
pinskingroup = ( daliasskingroup_t * ) pskintype ;
groupskins = LittleLong ( pinskingroup - > numskins ) ;
pinskinintervals = ( daliasskininterval_t * ) ( pinskingroup + 1 ) ;
pskintype = ( void * ) ( pinskinintervals + groupskins ) ;
for ( j = 0 ; j < groupskins ; j + + )
{
Mod_FloodFillSkin ( skin , pheader - > skinwidth , pheader - > skinheight ) ;
if ( j = = 0 ) {
texels = Hunk_AllocName ( s , loadname ) ;
pheader - > texels [ i ] = texels - ( byte * ) pheader ;
memcpy ( texels , ( byte * ) ( pskintype ) , s ) ;
}
sprintf ( name , " %s_%i_%i " , loadmodel - > name , i , j ) ;
pheader - > gl_texturenum [ i ] [ j & 3 ] =
GL_LoadTexture ( name , pheader - > skinwidth ,
pheader - > skinheight , ( byte * ) ( pskintype ) , true , false ) ;
pskintype = ( daliasskintype_t * ) ( ( byte * ) ( pskintype ) + s ) ;
}
k = j ;
for ( /* */ ; j < 4 ; j + + )
pheader - > gl_texturenum [ i ] [ j & 3 ] =
pheader - > gl_texturenum [ i ] [ j - k ] ;
}
}
return ( void * ) pskintype ;
}
//=========================================================================
/*
= = = = = = = = = = = = = = = = =
Mod_LoadAliasModel
= = = = = = = = = = = = = = = = =
*/
void Mod_LoadAliasModel ( model_t * mod , void * buffer )
{
int i , j ;
mdl_t * pinmodel ;
stvert_t * pinstverts ;
dtriangle_t * pintriangles ;
int version , numframes , numskins ;
int size ;
daliasframetype_t * pframetype ;
daliasskintype_t * pskintype ;
int start , end , total ;
start = Hunk_LowMark ( ) ;
pinmodel = ( mdl_t * ) buffer ;
version = LittleLong ( pinmodel - > version ) ;
if ( version ! = ALIAS_VERSION )
Sys_Error ( " %s has wrong version number (%i should be %i) " ,
mod - > name , version , ALIAS_VERSION ) ;
//
// allocate space for a working header, plus all the data except the frames,
// skin and group info
//
size = sizeof ( aliashdr_t )
+ ( LittleLong ( pinmodel - > numframes ) - 1 ) *
sizeof ( pheader - > frames [ 0 ] ) ;
pheader = Hunk_AllocName ( size , loadname ) ;
mod - > flags = LittleLong ( pinmodel - > flags ) ;
//
// endian-adjust and copy the data, starting with the alias model header
//
pheader - > boundingradius = LittleFloat ( pinmodel - > boundingradius ) ;
pheader - > numskins = LittleLong ( pinmodel - > numskins ) ;
pheader - > skinwidth = LittleLong ( pinmodel - > skinwidth ) ;
pheader - > skinheight = LittleLong ( pinmodel - > skinheight ) ;
if ( pheader - > skinheight > MAX_LBM_HEIGHT )
Sys_Error ( " model %s has a skin taller than %d " , mod - > name ,
MAX_LBM_HEIGHT ) ;
pheader - > numverts = LittleLong ( pinmodel - > numverts ) ;
if ( pheader - > numverts < = 0 )
Sys_Error ( " model %s has no vertices " , mod - > name ) ;
if ( pheader - > numverts > MAXALIASVERTS )
Sys_Error ( " model %s has too many vertices " , mod - > name ) ;
pheader - > numtris = LittleLong ( pinmodel - > numtris ) ;
if ( pheader - > numtris < = 0 )
Sys_Error ( " model %s has no triangles " , mod - > name ) ;
pheader - > numframes = LittleLong ( pinmodel - > numframes ) ;
numframes = pheader - > numframes ;
if ( numframes < 1 )
Sys_Error ( " Mod_LoadAliasModel: Invalid # of frames: %d \n " , numframes ) ;
pheader - > size = LittleFloat ( pinmodel - > size ) * ALIAS_BASE_SIZE_RATIO ;
mod - > synctype = LittleLong ( pinmodel - > synctype ) ;
mod - > numframes = pheader - > numframes ;
for ( i = 0 ; i < 3 ; i + + )
{
pheader - > scale [ i ] = LittleFloat ( pinmodel - > scale [ i ] ) ;
pheader - > scale_origin [ i ] = LittleFloat ( pinmodel - > scale_origin [ i ] ) ;
pheader - > eyeposition [ i ] = LittleFloat ( pinmodel - > eyeposition [ i ] ) ;
}
//
// load the skins
//
pskintype = ( daliasskintype_t * ) & pinmodel [ 1 ] ;
pskintype = Mod_LoadAllSkins ( pheader - > numskins , pskintype ) ;
//
// load base s and t vertices
//
pinstverts = ( stvert_t * ) pskintype ;
for ( i = 0 ; i < pheader - > numverts ; i + + )
{
stverts [ i ] . onseam = LittleLong ( pinstverts [ i ] . onseam ) ;
stverts [ i ] . s = LittleLong ( pinstverts [ i ] . s ) ;
stverts [ i ] . t = LittleLong ( pinstverts [ i ] . t ) ;
}
//
// load triangle lists
//
pintriangles = ( dtriangle_t * ) & pinstverts [ pheader - > numverts ] ;
for ( i = 0 ; i < pheader - > numtris ; i + + )
{
triangles [ i ] . facesfront = LittleLong ( pintriangles [ i ] . facesfront ) ;
for ( j = 0 ; j < 3 ; j + + )
{
triangles [ i ] . vertindex [ j ] =
LittleLong ( pintriangles [ i ] . vertindex [ j ] ) ;
}
}
//
// load the frames
//
posenum = 0 ;
pframetype = ( daliasframetype_t * ) & pintriangles [ pheader - > numtris ] ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz start
aliasbboxmins [ 0 ] = aliasbboxmins [ 1 ] = aliasbboxmins [ 2 ] = 99999 ;
aliasbboxmaxs [ 0 ] = aliasbboxmaxs [ 1 ] = aliasbboxmaxs [ 2 ] = - 99999 ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz end
for ( i = 0 ; i < numframes ; i + + )
{
aliasframetype_t frametype ;
frametype = LittleLong ( pframetype - > type ) ;
if ( frametype = = ALIAS_SINGLE )
{
pframetype = ( daliasframetype_t * )
Mod_LoadAliasFrame ( pframetype + 1 , & pheader - > frames [ i ] ) ;
}
else
{
pframetype = ( daliasframetype_t * )
Mod_LoadAliasGroup ( pframetype + 1 , & pheader - > frames [ i ] ) ;
}
}
pheader - > numposes = posenum ;
mod - > type = mod_alias ;
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz start
/*
// FIXME: do this right
mod - > mins [ 0 ] = mod - > mins [ 1 ] = mod - > mins [ 2 ] = - 16 ;
mod - > maxs [ 0 ] = mod - > maxs [ 1 ] = mod - > maxs [ 2 ] = 16 ;
*/
for ( i = 0 ; i < 3 ; i + + )
{
mod - > mins [ i ] = aliasbboxmins [ i ] * pheader - > scale [ i ] + pheader - > scale_origin [ i ] ;
mod - > maxs [ i ] = aliasbboxmaxs [ i ] * pheader - > scale [ i ] + pheader - > scale_origin [ i ] ;
// Keep necessary minimum bounding box by Maddes start
if ( mod - > mins [ i ] > - 16 )
{
mod - > mins [ i ] = - 16 ;
}
if ( mod - > maxs [ i ] < 16 )
{
mod - > maxs [ i ] = 16 ;
}
// Keep necessary minimum bounding box by Maddes end
}
// 2001-11-31 Vanishing entity in screen corners fix by LordHavoc/Tomaz end
//
// build the draw lists
//
GL_MakeAliasModelDisplayLists ( mod , pheader ) ;
//
// move the complete, relocatable alias model to the cache
//
end = Hunk_LowMark ( ) ;
total = end - start ;
Cache_Alloc ( & mod - > cache , total , loadname ) ;
if ( ! mod - > cache . data )
return ;
memcpy ( mod - > cache . data , pheader , total ) ;
Hunk_FreeToLowMark ( start ) ;
}
//=============================================================================
/*
= = = = = = = = = = = = = = = = =
Mod_LoadSpriteFrame
= = = = = = = = = = = = = = = = =
*/
void * Mod_LoadSpriteFrame ( void * pin , mspriteframe_t * * ppframe , int framenum )
{
dspriteframe_t * pinframe ;
mspriteframe_t * pspriteframe ;
int i , width , height , size , origin [ 2 ] ;
unsigned short * ppixout ;
byte * ppixin ;
char name [ 64 ] ;
pinframe = ( dspriteframe_t * ) pin ;
width = LittleLong ( pinframe - > width ) ;
height = LittleLong ( pinframe - > height ) ;
size = width * height ;
pspriteframe = Hunk_AllocName ( sizeof ( mspriteframe_t ) , loadname ) ;
Q_memset ( pspriteframe , 0 , sizeof ( mspriteframe_t ) ) ;
* ppframe = pspriteframe ;
pspriteframe - > width = width ;
pspriteframe - > height = height ;
origin [ 0 ] = LittleLong ( pinframe - > origin [ 0 ] ) ;
origin [ 1 ] = LittleLong ( pinframe - > origin [ 1 ] ) ;
pspriteframe - > up = origin [ 1 ] ;
pspriteframe - > down = origin [ 1 ] - height ;
pspriteframe - > left = origin [ 0 ] ;
pspriteframe - > right = width + origin [ 0 ] ;
sprintf ( name , " %s_%i " , loadmodel - > name , framenum ) ;
pspriteframe - > gl_texturenum = GL_LoadTexture ( name , width , height , ( byte * ) ( pinframe + 1 ) , true , true ) ;
return ( void * ) ( ( byte * ) pinframe + sizeof ( dspriteframe_t ) + size ) ;
}
/*
= = = = = = = = = = = = = = = = =
Mod_LoadSpriteGroup
= = = = = = = = = = = = = = = = =
*/
void * Mod_LoadSpriteGroup ( void * pin , mspriteframe_t * * ppframe , int framenum )
{
dspritegroup_t * pingroup ;
mspritegroup_t * pspritegroup ;
int i , numframes ;
dspriteinterval_t * pin_intervals ;
float * poutintervals ;
void * ptemp ;
pingroup = ( dspritegroup_t * ) pin ;
numframes = LittleLong ( pingroup - > numframes ) ;
pspritegroup = Hunk_AllocName ( sizeof ( mspritegroup_t ) +
( numframes - 1 ) * sizeof ( pspritegroup - > frames [ 0 ] ) , loadname ) ;
pspritegroup - > numframes = numframes ;
* ppframe = ( mspriteframe_t * ) pspritegroup ;
pin_intervals = ( dspriteinterval_t * ) ( pingroup + 1 ) ;
poutintervals = Hunk_AllocName ( numframes * sizeof ( float ) , loadname ) ;
pspritegroup - > intervals = poutintervals ;
for ( i = 0 ; i < numframes ; i + + )
{
* poutintervals = LittleFloat ( pin_intervals - > interval ) ;
if ( * poutintervals < = 0.0 )
Sys_Error ( " Mod_LoadSpriteGroup: interval<=0 " ) ;
poutintervals + + ;
pin_intervals + + ;
}
ptemp = ( void * ) pin_intervals ;
for ( i = 0 ; i < numframes ; i + + )
{
ptemp = Mod_LoadSpriteFrame ( ptemp , & pspritegroup - > frames [ i ] , framenum * 100 + i ) ;
}
return ptemp ;
}
/*
= = = = = = = = = = = = = = = = =
Mod_LoadSpriteModel
= = = = = = = = = = = = = = = = =
*/
void Mod_LoadSpriteModel ( model_t * mod , void * buffer )
{
int i ;
int version ;
dsprite_t * pin ;
msprite_t * psprite ;
int numframes ;
int size ;
dspriteframetype_t * pframetype ;
pin = ( dsprite_t * ) buffer ;
version = LittleLong ( pin - > version ) ;
if ( version ! = SPRITE_VERSION )
Sys_Error ( " %s has wrong version number "
" (%i should be %i) " , mod - > name , version , SPRITE_VERSION ) ;
numframes = LittleLong ( pin - > numframes ) ;
size = sizeof ( msprite_t ) + ( numframes - 1 ) * sizeof ( psprite - > frames ) ;
psprite = Hunk_AllocName ( size , loadname ) ;
mod - > cache . data = psprite ;
psprite - > type = LittleLong ( pin - > type ) ;
psprite - > maxwidth = LittleLong ( pin - > width ) ;
psprite - > maxheight = LittleLong ( pin - > height ) ;
psprite - > beamlength = LittleFloat ( pin - > beamlength ) ;
mod - > synctype = LittleLong ( pin - > synctype ) ;
psprite - > numframes = numframes ;
mod - > mins [ 0 ] = mod - > mins [ 1 ] = - psprite - > maxwidth / 2 ;
mod - > maxs [ 0 ] = mod - > maxs [ 1 ] = psprite - > maxwidth / 2 ;
mod - > mins [ 2 ] = - psprite - > maxheight / 2 ;
mod - > maxs [ 2 ] = psprite - > maxheight / 2 ;
//
// load the frames
//
if ( numframes < 1 )
Sys_Error ( " Mod_LoadSpriteModel: Invalid # of frames: %d \n " , numframes ) ;
mod - > numframes = numframes ;
pframetype = ( dspriteframetype_t * ) ( pin + 1 ) ;
for ( i = 0 ; i < numframes ; i + + )
{
spriteframetype_t frametype ;
frametype = LittleLong ( pframetype - > type ) ;
psprite - > frames [ i ] . type = frametype ;
if ( frametype = = SPR_SINGLE )
{
pframetype = ( dspriteframetype_t * )
Mod_LoadSpriteFrame ( pframetype + 1 ,
& psprite - > frames [ i ] . frameptr , i ) ;
}
else
{
pframetype = ( dspriteframetype_t * )
Mod_LoadSpriteGroup ( pframetype + 1 ,
& psprite - > frames [ i ] . frameptr , i ) ;
}
}
mod - > type = mod_sprite ;
}
//=============================================================================
/*
= = = = = = = = = = = = = = = =
Mod_Print
= = = = = = = = = = = = = = = =
*/
void Mod_Print ( void )
{
int i ;
model_t * mod ;
Con_Printf ( " Cached models: \n " ) ;
for ( i = 0 , mod = mod_known ; i < mod_numknown ; i + + , mod + + )
{
Con_Printf ( " %8p : %s \n " , mod - > cache . data , mod - > name ) ;
}
}