This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/common/model.c

1920 lines
44 KiB
C
Raw Normal View History

2010-05-22 22:00:00 +02:00
//=======================================================================
// Copyright XashXT Group 2007 <20>
2010-11-22 22:00:00 +01:00
// model.c - modelloader
2010-05-22 22:00:00 +02:00
//=======================================================================
#include "cm_local.h"
2010-09-10 22:00:00 +02:00
#include "sprite.h"
2010-05-22 22:00:00 +02:00
#include "mathlib.h"
2010-09-10 22:00:00 +02:00
#include "studio.h"
#include "wadfile.h"
2010-11-21 22:00:00 +01:00
#include "world.h"
2010-12-03 22:00:00 +01:00
#include "gl_local.h"
2010-05-22 22:00:00 +02:00
2010-12-09 22:00:00 +01:00
world_static_t world;
2010-05-22 22:00:00 +02:00
byte *mod_base;
2010-12-09 22:00:00 +01:00
byte *com_studiocache; // cache for submodels
2010-12-08 22:00:00 +01:00
static model_t *com_models[MAX_MODELS]; // shared replacement modeltable
2010-08-12 22:00:00 +02:00
static model_t cm_models[MAX_MODELS];
2010-12-08 22:00:00 +01:00
static int cm_nummodels = 0;
2010-12-12 22:00:00 +01:00
static byte visdata[MAX_MAP_LEAFS/8]; // intermediate buffer
2010-08-12 22:00:00 +02:00
model_t *loadmodel;
model_t *worldmodel;
2010-05-22 22:00:00 +02:00
2010-10-18 22:00:00 +02:00
// cvars
2010-12-09 22:00:00 +01:00
2010-10-18 22:00:00 +02:00
2010-10-20 22:00:00 +02:00
// default hullmins
static vec3_t cm_hullmins[4] =
{
{ -16, -16, -36 },
{ -16, -16, -18 },
{ 0, 0, 0 },
{ -32, -32, -32 },
};
// defualt hummaxs
static vec3_t cm_hullmaxs[4] =
{
{ 16, 16, 36 },
{ 16, 16, 18 },
{ 0, 0, 0 },
{ 32, 32, 32 },
};
2010-05-22 22:00:00 +02:00
/*
===============================================================================
2010-12-08 22:00:00 +01:00
MOD COMMON UTILS
2010-05-22 22:00:00 +02:00
===============================================================================
*/
2010-12-08 22:00:00 +01:00
/*
================
Mod_SetupHulls
================
*/
void Mod_SetupHulls( float mins[4][3], float maxs[4][3] )
2010-10-20 22:00:00 +02:00
{
2011-03-10 22:00:00 +01:00
Q_memcpy( mins, cm_hullmins, sizeof( cm_hullmins ));
Q_memcpy( maxs, cm_hullmaxs, sizeof( cm_hullmaxs ));
2010-10-20 22:00:00 +02:00
}
2010-12-12 22:00:00 +01:00
/*
===================
Mod_CompressVis
===================
*/
byte *Mod_CompressVis( const byte *in, size_t *size )
{
int j, rep;
int visrow;
byte *dest_p;
if( !worldmodel )
{
Host_Error( "Mod_CompressVis: no worldmodel\n" );
return NULL;
}
dest_p = visdata;
visrow = (worldmodel->numleafs + 7)>>3;
for( j = 0; j < visrow; j++ )
{
*dest_p++ = in[j];
if( in[j] ) continue;
rep = 1;
for( j++; j < visrow; j++ )
{
if( in[j] || rep == 255 )
break;
else rep++;
}
*dest_p++ = rep;
j--;
}
if( size ) *size = dest_p - visdata;
return visdata;
}
2010-12-08 22:00:00 +01:00
/*
===================
Mod_DecompressVis
===================
*/
byte *Mod_DecompressVis( const byte *in )
{
2010-12-12 22:00:00 +01:00
int c, row;
byte *out;
2010-12-08 22:00:00 +01:00
if( !worldmodel )
{
Host_Error( "Mod_DecompressVis: no worldmodel\n" );
return NULL;
}
row = (worldmodel->numleafs + 7)>>3;
2010-12-12 22:00:00 +01:00
out = visdata;
2010-12-08 22:00:00 +01:00
if( !in )
{
// no vis info, so make all visible
while( row )
{
*out++ = 0xff;
row--;
}
2010-12-12 22:00:00 +01:00
return visdata;
2010-12-08 22:00:00 +01:00
}
do
{
if( *in )
{
*out++ = *in++;
continue;
}
c = in[1];
in += 2;
while( c )
{
*out++ = 0;
c--;
}
2010-12-12 22:00:00 +01:00
} while( out - visdata < row );
2010-12-08 22:00:00 +01:00
2010-12-12 22:00:00 +01:00
return visdata;
2010-12-08 22:00:00 +01:00
}
2010-11-21 22:00:00 +01:00
/*
==================
Mod_PointInLeaf
==================
*/
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
{
2010-12-12 22:00:00 +01:00
ASSERT( node != NULL );
2010-12-06 22:00:00 +01:00
2010-12-12 22:00:00 +01:00
while( 1 )
2010-12-06 22:00:00 +01:00
{
2010-12-12 22:00:00 +01:00
if( node->contents < 0 )
return (mleaf_t *)node;
node = node->children[PlaneDiff( p, node->plane ) < 0];
}
2010-12-06 22:00:00 +01:00
2010-12-12 22:00:00 +01:00
// never reached
return NULL;
2010-12-06 22:00:00 +01:00
}
2010-11-21 22:00:00 +01:00
2010-12-06 22:00:00 +01:00
/*
==================
Mod_LeafPVS
2010-11-21 22:00:00 +01:00
2010-12-06 22:00:00 +01:00
==================
*/
byte *Mod_LeafPVS( mleaf_t *leaf, model_t *model )
{
if( !model || !leaf || leaf == model->leafs || !model->visdata )
2010-12-13 22:00:00 +01:00
return Mod_DecompressVis( NULL );
2010-12-06 22:00:00 +01:00
return Mod_DecompressVis( leaf->compressed_vis );
2010-11-21 22:00:00 +01:00
}
2010-12-12 22:00:00 +01:00
/*
==================
Mod_LeafPHS
==================
*/
byte *Mod_LeafPHS( mleaf_t *leaf, model_t *model )
{
if( !model || !leaf || leaf == model->leafs || !model->visdata )
2010-12-13 22:00:00 +01:00
return Mod_DecompressVis( NULL );
2010-12-12 22:00:00 +01:00
return Mod_DecompressVis( leaf->compressed_pas );
}
2010-12-06 22:00:00 +01:00
/*
==================
Mod_PointLeafnum
==================
*/
2010-11-21 22:00:00 +01:00
int Mod_PointLeafnum( const vec3_t p )
{
// map not loaded
if ( !worldmodel ) return 0;
2010-12-09 22:00:00 +01:00
return Mod_PointInLeaf( p, worldmodel->nodes ) - worldmodel->leafs;
2010-11-21 22:00:00 +01:00
}
/*
======================================================================
LEAF LISTING
======================================================================
*/
static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
{
mplane_t *plane;
int s;
while( 1 )
{
if( node->contents == CONTENTS_SOLID )
return;
if( node->contents < 0 )
{
mleaf_t *leaf = (mleaf_t *)node;
// it's a leaf!
if( ll->count >= ll->maxcount )
{
ll->overflowed = true;
return;
}
2010-12-12 22:00:00 +01:00
ll->list[ll->count++] = leaf - worldmodel->leafs - 1;
2010-11-21 22:00:00 +01:00
return;
}
plane = node->plane;
s = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, plane );
if( s == 1 )
{
node = node->children[0];
}
else if( s == 2 )
{
node = node->children[1];
}
else
{
// go down both
if( ll->topnode == -1 )
ll->topnode = node - worldmodel->nodes;
Mod_BoxLeafnums_r( ll, node->children[0] );
node = node->children[1];
}
}
}
/*
==================
Mod_BoxLeafnums
==================
*/
int Mod_BoxLeafnums( const vec3_t mins, const vec3_t maxs, short *list, int listsize, int *topnode )
{
leaflist_t ll;
if( !worldmodel ) return 0;
VectorCopy( mins, ll.mins );
VectorCopy( maxs, ll.maxs );
ll.count = 0;
ll.maxcount = listsize;
ll.list = list;
ll.topnode = -1;
ll.overflowed = false;
Mod_BoxLeafnums_r( &ll, worldmodel->nodes );
if( topnode ) *topnode = ll.topnode;
return ll.count;
}
/*
=============
Mod_BoxVisible
Returns true if any leaf in boxspace
is potentially visible
=============
*/
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits )
{
short leafList[MAX_BOX_LEAFS];
int i, count;
if( !visbits || !mins || !maxs )
return true;
count = Mod_BoxLeafnums( mins, maxs, leafList, MAX_BOX_LEAFS, NULL );
for( i = 0; i < count; i++ )
{
int leafnum = leafList[i];
if( visbits[leafnum>>3] & (1<<( leafnum & 7 )))
return true;
}
return false;
}
/*
==================
Mod_AmbientLevels
grab the ambient sound levels for current point
==================
*/
void Mod_AmbientLevels( const vec3_t p, byte *pvolumes )
{
mleaf_t *leaf;
if( !worldmodel || !p || !pvolumes )
return;
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
*(int *)pvolumes = *(int *)leaf->ambient_sound_level;
}
2010-05-22 22:00:00 +02:00
/*
================
2010-12-02 22:00:00 +01:00
Mod_FreeModel
2010-05-22 22:00:00 +02:00
================
*/
2010-12-02 22:00:00 +01:00
static void Mod_FreeModel( model_t *mod )
2010-05-22 22:00:00 +02:00
{
if( !mod || !mod->mempool )
return;
2010-12-06 22:00:00 +01:00
// select the properly unloader
2010-12-02 22:00:00 +01:00
switch( mod->type )
{
case mod_sprite:
Mod_UnloadSpriteModel( mod );
break;
case mod_studio:
2010-12-06 22:00:00 +01:00
Mod_UnloadStudioModel( mod );
break;
case mod_brush:
Mod_UnloadBrushModel( mod );
2010-12-02 22:00:00 +01:00
break;
}
2010-05-22 22:00:00 +02:00
}
2010-10-18 22:00:00 +02:00
/*
===============================================================================
2010-05-22 22:00:00 +02:00
2010-12-08 22:00:00 +01:00
MODEL INITALIZE\SHUTDOWN
2010-10-18 22:00:00 +02:00
===============================================================================
*/
2010-11-21 22:00:00 +01:00
void Mod_Init( void )
2010-05-22 22:00:00 +02:00
{
2010-12-09 22:00:00 +01:00
com_studiocache = Mem_AllocPool( "Studio Cache" );
2010-10-18 22:00:00 +02:00
}
2010-05-22 22:00:00 +02:00
2010-12-21 22:00:00 +01:00
void Mod_ClearAll( void )
2010-10-18 22:00:00 +02:00
{
int i;
2010-05-22 22:00:00 +02:00
2010-10-18 22:00:00 +02:00
for( i = 0; i < cm_nummodels; i++ )
2010-12-02 22:00:00 +01:00
Mod_FreeModel( &cm_models[i] );
2010-11-15 22:00:00 +01:00
2011-03-10 22:00:00 +01:00
Q_memset( cm_models, 0, sizeof( cm_models ));
2010-12-21 22:00:00 +01:00
cm_nummodels = 0;
}
void Mod_Shutdown( void )
{
Mod_ClearAll();
2010-12-09 22:00:00 +01:00
Mem_FreePool( &com_studiocache );
2010-05-22 22:00:00 +02:00
}
/*
===============================================================================
MAP LOADING
===============================================================================
*/
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadSubmodels
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadSubmodels( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dmodel_t *in;
dmodel_t *out;
int i, j, count;
in = (void *)(mod_base + l->fileofs);
2010-11-21 22:00:00 +01:00
if( l->filelen % sizeof( *in )) Host_Error( "Mod_LoadBModel: funny lump size\n" );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
if( count < 1 ) Host_Error( "Map %s without models\n", loadmodel->name );
if( count > MAX_MAP_MODELS ) Host_Error( "Map %s has too many models\n", loadmodel->name );
// allocate extradata
out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
loadmodel->submodels = out;
loadmodel->numsubmodels = count;
2010-12-13 22:00:00 +01:00
if( world.loading ) world.max_surfaces = 0;
2010-05-22 22:00:00 +02:00
for( i = 0; i < count; i++, in++, out++ )
{
for( j = 0; j < 3; j++ )
{
// spread the mins / maxs by a pixel
2010-11-21 22:00:00 +01:00
out->mins[j] = in->mins[j] - 1;
out->maxs[j] = in->maxs[j] + 1;
out->origin[j] = in->origin[j];
2010-05-22 22:00:00 +02:00
}
for( j = 0; j < MAX_MAP_HULLS; j++ )
2010-11-21 22:00:00 +01:00
out->headnode[j] = in->headnode[j];
2010-05-22 22:00:00 +02:00
2010-11-21 22:00:00 +01:00
out->visleafs = in->visleafs;
out->firstface = in->firstface;
out->numfaces = in->numfaces;
2010-12-13 22:00:00 +01:00
if( i == 0 || !world.loading )
continue; // skip the world
world.max_surfaces = max( world.max_surfaces, out->numfaces );
2010-05-22 22:00:00 +02:00
}
2010-12-13 22:00:00 +01:00
if( world.loading )
world.draw_surfaces = Mem_Alloc( loadmodel->mempool, world.max_surfaces * sizeof( msurface_t* ));
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadTextures
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadTextures( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dmiptexlump_t *in;
2010-12-06 22:00:00 +01:00
texture_t *tx, *tx2;
texture_t *anims[10];
texture_t *altanims[10];
int num, max, altmax;
char texname[32];
2010-05-22 22:00:00 +02:00
mip_t *mt;
2010-12-06 22:00:00 +01:00
int i, j;
// release old sky layers first
GL_FreeTexture( tr.solidskyTexture );
GL_FreeTexture( tr.alphaskyTexture );
tr.solidskyTexture = tr.alphaskyTexture = 0;
2010-05-22 22:00:00 +02:00
if( !l->filelen )
{
// no textures
loadmodel->textures = NULL;
return;
}
in = (void *)(mod_base + l->fileofs);
loadmodel->numtextures = in->nummiptex;
2010-11-21 22:00:00 +01:00
loadmodel->textures = (texture_t **)Mem_Alloc( loadmodel->mempool, loadmodel->numtextures * sizeof( texture_t* ));
2010-05-22 22:00:00 +02:00
for( i = 0; i < loadmodel->numtextures; i++ )
{
2010-11-22 22:00:00 +01:00
if( in->dataofs[i] == -1 ) continue; // missed
2010-05-22 22:00:00 +02:00
mt = (mip_t *)((byte *)in + in->dataofs[i] );
2010-12-06 22:00:00 +01:00
if( !mt->name[0] )
{
MsgDev( D_WARN, "unnamed texture in %s\n", loadmodel->name );
2011-03-09 22:00:00 +01:00
Q_snprintf( mt->name, sizeof( mt->name ), "miptex_%i", i );
2010-12-06 22:00:00 +01:00
}
2010-11-22 22:00:00 +01:00
tx = Mem_Alloc( loadmodel->mempool, sizeof( *tx ));
loadmodel->textures[i] = tx;
2010-05-22 22:00:00 +02:00
2010-12-06 22:00:00 +01:00
// convert to lowercase
2011-03-09 22:00:00 +01:00
Q_strnlwr( mt->name, mt->name, sizeof( mt->name ));
Q_strncpy( tx->name, mt->name, sizeof( tx->name ));
Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", mt->name );
2010-12-06 22:00:00 +01:00
2010-11-22 22:00:00 +01:00
tx->width = mt->width;
tx->height = mt->height;
2010-12-06 22:00:00 +01:00
// check for sky texture (quake1 only!)
2011-03-09 22:00:00 +01:00
if( world.version == Q1BSP_VERSION && !Q_strncmp( mt->name, "sky", 3 ))
2010-12-06 22:00:00 +01:00
{
R_InitSky( mt, tx );
}
else if( mt->offsets[0] > 0 )
{
// NOTE: imagelib detect miptex version by size
// 770 additional bytes is indicated custom palette
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
2010-12-09 22:00:00 +01:00
if( world.version == HLBSP_VERSION ) size += sizeof( short ) + 768;
2010-12-06 22:00:00 +01:00
tx->gl_texturenum = GL_LoadTexture( texname, (byte *)mt, size, 0 );
}
else
{
// okay, loading it from wad
tx->gl_texturenum = GL_LoadTexture( texname, NULL, 0, 0 );
}
// check for luma texture
if( R_GetTexture( tx->gl_texturenum )->flags & TF_HAS_LUMA )
{
2011-03-09 22:00:00 +01:00
Q_snprintf( texname, sizeof( texname ), "%s%s_luma.mip", mt->offsets[0] > 0 ? "#" : "", mt->name );
2010-12-06 22:00:00 +01:00
if( mt->offsets[0] > 0 )
{
// NOTE: imagelib detect miptex version by size
// 770 additional bytes is indicated custom palette
int size = (int)sizeof( mip_t ) + ((mt->width * mt->height * 85)>>6);
2010-12-09 22:00:00 +01:00
if( world.version == HLBSP_VERSION ) size += sizeof( short ) + 768;
2010-12-06 22:00:00 +01:00
2010-12-11 22:00:00 +01:00
tx->fb_texturenum = GL_LoadTexture( texname, (byte *)mt, size, TF_MAKELUMA|TF_NOMIPMAP );
2010-12-06 22:00:00 +01:00
}
else
{
// okay, loading it from wad
2010-12-11 22:00:00 +01:00
tx->fb_texturenum = GL_LoadTexture( texname, NULL, 0, TF_MAKELUMA|TF_NOMIPMAP );
2010-12-06 22:00:00 +01:00
}
}
// apply texture type (just for debug)
GL_SetTextureType( tx->gl_texturenum, TEX_BRUSH );
GL_SetTextureType( tx->fb_texturenum, TEX_BRUSH );
}
// sequence the animations
for( i = 0; i < loadmodel->numtextures; i++ )
{
tx = loadmodel->textures[i];
if( !tx || tx->name[0] != '+' )
continue;
if( tx->anim_next )
continue; // allready sequenced
// find the number of frames in the animation
2011-03-10 22:00:00 +01:00
Q_memset( anims, 0, sizeof( anims ));
Q_memset( altanims, 0, sizeof( altanims ));
2010-12-06 22:00:00 +01:00
max = tx->name[1];
altmax = 0;
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 Host_Error( "Mod_LoadTextures: bad animating texture %s\n", tx->name );
for( j = i + 1; j < loadmodel->numtextures; j++ )
{
tx2 = loadmodel->textures[j];
if( !tx2 || tx2->name[0] != '+' )
continue;
2011-03-09 22:00:00 +01:00
if( Q_strcmp( tx2->name + 2, tx->name + 2 ))
2010-12-06 22:00:00 +01:00
continue;
num = tx2->name[1];
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 Host_Error( "Mod_LoadTextures: bad animating texture %s\n", tx->name );
}
// link them all together
for( j = 0; j < max; j++ )
{
tx2 = anims[j];
if( !tx2 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", 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 ) Host_Error( "Mod_LoadTextures: missing frame %i of %s\n", 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];
}
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadTexInfo
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadTexInfo( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dtexinfo_t *in;
2010-08-12 22:00:00 +02:00
mtexinfo_t *out;
2010-05-22 22:00:00 +02:00
int miptex;
int i, j, count;
uint surfaceParm = 0;
2010-11-22 22:00:00 +01:00
float len1, len2;
2010-05-22 22:00:00 +02:00
in = (void *)(mod_base + l->fileofs);
if( l->filelen % sizeof( *in ))
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadTexInfo: funny lump size in %s\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
loadmodel->texinfo = out;
loadmodel->numtexinfo = count;
for( i = 0; i < count; i++, in++, out++ )
{
for( j = 0; j < 8; j++ )
2010-11-21 22:00:00 +01:00
out->vecs[0][j] = in->vecs[0][j];
2010-05-22 22:00:00 +02:00
2010-11-22 22:00:00 +01:00
len1 = VectorLength( out->vecs[0] );
len2 = VectorLength( out->vecs[1] );
len1 = ( len1 + len2 ) / 2;
// g-cont: can use this info for GL_TEXTURE_LOAD_BIAS_EXT ?
if( len1 < 0.32f ) out->mipadjust = 4;
else if( len1 < 0.49f ) out->mipadjust = 3;
else if( len1 < 0.99f ) out->mipadjust = 2;
else out->mipadjust = 1;
2010-11-21 22:00:00 +01:00
miptex = in->miptex;
2010-05-22 22:00:00 +02:00
if( miptex < 0 || miptex > loadmodel->numtextures )
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadTexInfo: bad miptex number in '%s'\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
out->texture = loadmodel->textures[miptex];
2010-12-02 22:00:00 +01:00
out->flags = in->flags;
2010-05-22 22:00:00 +02:00
}
}
2010-07-01 22:00:00 +02:00
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadLighting
2010-07-01 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadLighting( const dlump_t *l )
2010-07-01 22:00:00 +02:00
{
2010-11-21 22:00:00 +01:00
byte d, *in;
color24 *out;
2010-07-01 22:00:00 +02:00
int i;
if( !l->filelen ) return;
in = (void *)(mod_base + l->fileofs);
2010-12-09 22:00:00 +01:00
switch( world.version )
2010-07-01 22:00:00 +02:00
{
case Q1BSP_VERSION:
// expand the white lighting data
2010-11-21 22:00:00 +01:00
loadmodel->lightdata = (color24 *)Mem_Alloc( loadmodel->mempool, l->filelen * sizeof( color24 ));
2010-07-01 22:00:00 +02:00
out = loadmodel->lightdata;
2010-11-21 22:00:00 +01:00
for( i = 0; i < l->filelen; i++, out++ )
2010-07-01 22:00:00 +02:00
{
d = *in++;
2010-11-21 22:00:00 +01:00
out->r = d;
out->g = d;
out->b = d;
2010-07-01 22:00:00 +02:00
}
break;
case HLBSP_VERSION:
// load colored lighting
loadmodel->lightdata = Mem_Alloc( loadmodel->mempool, l->filelen );
2011-03-10 22:00:00 +01:00
Q_memcpy( loadmodel->lightdata, in, l->filelen );
2010-07-01 22:00:00 +02:00
break;
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_CalcSurfaceExtents
2010-07-01 22:00:00 +02:00
2010-11-22 22:00:00 +01:00
Fills in surf->texturemins[] and surf->extents[]
2010-07-01 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_CalcSurfaceExtents( msurface_t *surf )
2010-07-01 22:00:00 +02:00
{
2010-11-22 22:00:00 +01:00
float mins[2], maxs[2], val;
int bmins[2], bmaxs[2];
int i, j, e;
mtexinfo_t *tex;
mvertex_t *v;
2010-07-01 22:00:00 +02:00
2010-12-07 22:00:00 +01:00
if( surf->flags & ( SURF_DRAWSKY|SURF_DRAWTURB ))
2010-07-01 22:00:00 +02:00
{
surf->extents[0] = surf->extents[1] = 16384;
2010-08-12 22:00:00 +02:00
surf->texturemins[0] = surf->texturemins[1] = -8192;
2010-07-01 22:00:00 +02:00
return;
}
2010-11-22 22:00:00 +01:00
tex = surf->texinfo;
2010-07-01 22:00:00 +02:00
mins[0] = mins[1] = 999999;
maxs[0] = maxs[1] = -999999;
for( i = 0; i < surf->numedges; i++ )
{
e = loadmodel->surfedges[surf->firstedge + i];
2010-11-22 22:00:00 +01:00
if( e >= 0 ) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
2010-07-01 22:00:00 +02:00
for( j = 0; j < 2; j++ )
{
2010-11-22 22:00:00 +01:00
val = DotProduct( v->position, surf->texinfo->vecs[j] ) + surf->texinfo->vecs[j][3];
2010-07-01 22:00:00 +02:00
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] / LM_SAMPLE_SIZE );
bmaxs[i] = ceil( maxs[i] / LM_SAMPLE_SIZE );
2010-08-12 22:00:00 +02:00
surf->texturemins[i] = bmins[i] * LM_SAMPLE_SIZE;
2010-07-01 22:00:00 +02:00
surf->extents[i] = (bmaxs[i] - bmins[i]) * LM_SAMPLE_SIZE;
2010-11-22 22:00:00 +01:00
if(!( tex->flags & TEX_SPECIAL ) && surf->extents[i] > 4096 )
MsgDev( D_ERROR, "Bad surface extents %i\n", surf->extents[i] );
2010-07-01 22:00:00 +02:00
}
}
2010-12-12 22:00:00 +01:00
/*
=================
Mod_CalcSurfaceBounds
fills in surf->mins and surf->maxs
=================
*/
static void Mod_CalcSurfaceBounds( msurface_t *surf, mextrasurf_t *info )
{
int i, e;
mvertex_t *v;
2010-12-13 22:00:00 +01:00
ClearBounds( info->mins, info->maxs );
2010-12-12 22:00:00 +01:00
for( i = 0; i < surf->numedges; i++ )
{
e = loadmodel->surfedges[surf->firstedge + i];
if( e >= 0 ) v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
else v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
2010-12-13 22:00:00 +01:00
AddPointToBounds( v->position, info->mins, info->maxs );
2010-12-12 22:00:00 +01:00
}
2010-12-13 22:00:00 +01:00
VectorAverage( info->mins, info->maxs, info->origin );
2010-12-12 22:00:00 +01:00
}
2010-05-22 22:00:00 +02:00
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadSurfaces
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadSurfaces( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dface_t *in;
2010-08-12 22:00:00 +02:00
msurface_t *out;
2010-12-12 22:00:00 +01:00
mextrasurf_t *info;
2010-12-07 22:00:00 +01:00
int i, j;
int count;
2010-05-22 22:00:00 +02:00
in = (void *)(mod_base + l->fileofs);
if( l->filelen % sizeof( dface_t ))
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadSurfaces: funny lump size in '%s'\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( dface_t );
loadmodel->numsurfaces = count;
2010-08-12 22:00:00 +02:00
loadmodel->surfaces = Mem_Alloc( loadmodel->mempool, count * sizeof( msurface_t ));
2010-12-12 22:00:00 +01:00
loadmodel->cache.data = Mem_Alloc( loadmodel->mempool, count * sizeof( mextrasurf_t ));
2010-05-22 22:00:00 +02:00
out = loadmodel->surfaces;
2010-12-12 22:00:00 +01:00
info = loadmodel->cache.data;
2010-05-22 22:00:00 +02:00
2010-12-12 22:00:00 +01:00
for( i = 0; i < count; i++, in++, out++, info++ )
2010-05-22 22:00:00 +02:00
{
2010-12-07 22:00:00 +01:00
if(( in->firstedge + in->numedges ) > loadmodel->numsurfedges )
2010-11-22 22:00:00 +01:00
{
2010-12-07 22:00:00 +01:00
MsgDev( D_ERROR, "Bad surface %i from %i\n", i, count );
2010-11-22 22:00:00 +01:00
continue;
}
2010-12-07 22:00:00 +01:00
out->firstedge = in->firstedge;
out->numedges = in->numedges;
out->flags = 0;
2010-11-21 22:00:00 +01:00
if( in->side ) out->flags |= SURF_PLANEBACK;
out->plane = loadmodel->planes + in->planenum;
out->texinfo = loadmodel->texinfo + in->texinfo;
2010-07-01 22:00:00 +02:00
2010-10-23 22:00:00 +02:00
// some DMC maps have bad textures
if( out->texinfo->texture )
{
2010-12-02 22:00:00 +01:00
texture_t *tex = out->texinfo->texture;
2011-03-09 22:00:00 +01:00
if( !Q_strncmp( tex->name, "sky", 3 ))
2010-12-20 22:00:00 +01:00
out->flags |= (SURF_DRAWTILED|SURF_DRAWSKY);
2010-07-01 22:00:00 +02:00
2011-02-15 22:00:00 +01:00
if( tex->name[0] == '*' || tex->name[0] == '!' )
2010-10-23 22:00:00 +02:00
out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED);
2010-12-12 22:00:00 +01:00
2011-03-09 22:00:00 +01:00
if( !Q_strnicmp( tex->name, "water", 5 ))
2011-02-15 22:00:00 +01:00
out->flags |= (SURF_DRAWTURB|SURF_DRAWTILED|SURF_NOCULL);
2011-03-09 22:00:00 +01:00
if( !Q_strnicmp( tex->name, "scroll", 6 ))
2010-12-12 22:00:00 +01:00
out->flags |= SURF_CONVEYOR;
2010-12-20 22:00:00 +01:00
2010-12-27 22:00:00 +01:00
if( tex->name[0] == '{' )
out->flags |= SURF_TRANSPARENT;
2010-12-20 22:00:00 +01:00
if( out->texinfo->flags & TEX_SPECIAL )
out->flags |= SURF_DRAWTILED;
2010-10-23 22:00:00 +02:00
}
2010-07-01 22:00:00 +02:00
2010-12-12 22:00:00 +01:00
Mod_CalcSurfaceBounds( out, info );
2010-11-22 22:00:00 +01:00
Mod_CalcSurfaceExtents( out );
2010-07-01 22:00:00 +02:00
2010-12-07 22:00:00 +01:00
if( loadmodel->lightdata && in->lightofs != -1 )
2010-07-01 22:00:00 +02:00
{
2010-12-09 22:00:00 +01:00
if( world.version == HLBSP_VERSION )
2010-12-07 22:00:00 +01:00
out->samples = loadmodel->lightdata + (in->lightofs / 3);
else out->samples = loadmodel->lightdata + in->lightofs;
2010-11-22 22:00:00 +01:00
}
2010-12-07 22:00:00 +01:00
for( j = 0; j < MAXLIGHTMAPS; j++ )
out->styles[j] = in->styles[j];
2010-12-20 22:00:00 +01:00
if( out->flags & SURF_DRAWSKY && world.version == Q1BSP_VERSION )
GL_SubdivideSurface( out ); // cut up polygon for warps
if( out->flags & SURF_DRAWTURB )
2010-12-06 22:00:00 +01:00
GL_SubdivideSurface( out ); // cut up polygon for warps
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadVertexes
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadVertexes( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dvertex_t *in;
2010-11-21 22:00:00 +01:00
mvertex_t *out;
int i, count;
2010-05-22 22:00:00 +02:00
in = (void *)( mod_base + l->fileofs );
if( l->filelen % sizeof( *in ))
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadVertexes: funny lump size in %s\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
loadmodel->numvertexes = count;
2010-11-21 22:00:00 +01:00
out = loadmodel->vertexes = Mem_Alloc( loadmodel->mempool, count * sizeof( mvertex_t ));
2010-05-22 22:00:00 +02:00
2010-11-21 22:00:00 +01:00
for( i = 0; i < count; i++, in++, out++ )
2010-05-22 22:00:00 +02:00
{
2010-11-21 22:00:00 +01:00
VectorCopy( in->point, out->position );
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadEdges
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadEdges( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
2010-11-21 22:00:00 +01:00
dedge_t *in;
medge_t *out;
2010-05-22 22:00:00 +02:00
int i, count;
in = (void *)( mod_base + l->fileofs );
if( l->filelen % sizeof( *in ))
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadEdges: funny lump size in %s\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
2010-11-21 22:00:00 +01:00
count = l->filelen / sizeof( *in );
loadmodel->edges = out = Mem_Alloc( loadmodel->mempool, count * sizeof( medge_t ));
2010-05-22 22:00:00 +02:00
loadmodel->numedges = count;
for( i = 0; i < count; i++, in++, out++ )
{
2010-11-21 22:00:00 +01:00
out->v[0] = (word)in->v[0];
out->v[1] = (word)in->v[1];
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadSurfEdges
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadSurfEdges( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
2010-11-22 22:00:00 +01:00
dsurfedge_t *in;
2010-11-21 22:00:00 +01:00
int count;
2010-05-22 22:00:00 +02:00
in = (void *)( mod_base + l->fileofs );
if( l->filelen % sizeof( *in ))
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadSurfEdges: funny lump size in %s\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( dsurfedge_t );
2010-11-22 22:00:00 +01:00
loadmodel->surfedges = Mem_Alloc( loadmodel->mempool, count * sizeof( dsurfedge_t ));
2010-05-22 22:00:00 +02:00
loadmodel->numsurfedges = count;
2011-03-10 22:00:00 +01:00
Q_memcpy( loadmodel->surfedges, in, count * sizeof( dsurfedge_t ));
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadMarkSurfaces
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_LoadMarkSurfaces( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dmarkface_t *in;
int i, j, count;
2010-11-26 22:00:00 +01:00
msurface_t **out;
2010-05-22 22:00:00 +02:00
in = (void *)( mod_base + l->fileofs );
if( l->filelen % sizeof( *in ))
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadMarkFaces: funny lump size in %s\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
2010-11-26 22:00:00 +01:00
loadmodel->marksurfaces = out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
2010-12-14 22:00:00 +01:00
loadmodel->nummarksurfaces = count;
2010-05-22 22:00:00 +02:00
for( i = 0; i < count; i++ )
{
2010-11-21 22:00:00 +01:00
j = in[i];
2010-07-28 22:00:00 +02:00
if( j < 0 || j >= loadmodel->numsurfaces )
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadMarkFaces: bad surface number in '%s'\n", loadmodel->name );
2010-11-26 22:00:00 +01:00
out[i] = loadmodel->surfaces + j;
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_SetParent
2010-05-22 22:00:00 +02:00
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_SetParent( mnode_t *node, mnode_t *parent )
2010-05-22 22:00:00 +02:00
{
node->parent = parent;
if( node->contents < 0 ) return; // it's node
2010-11-22 22:00:00 +01:00
Mod_SetParent( node->children[0], node );
Mod_SetParent( node->children[1], node );
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadNodes
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadNodes( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dnode_t *in;
2010-08-12 22:00:00 +02:00
mnode_t *out;
2010-05-22 22:00:00 +02:00
int i, j, p;
in = (void *)(mod_base + l->fileofs);
2010-11-22 22:00:00 +01:00
if( l->filelen % sizeof( *in )) Host_Error( "Mod_LoadNodes: funny lump size\n" );
2010-05-22 22:00:00 +02:00
loadmodel->numnodes = l->filelen / sizeof( *in );
if( loadmodel->numnodes < 1 ) Host_Error( "Map %s has no nodes\n", loadmodel->name );
2010-08-12 22:00:00 +02:00
out = loadmodel->nodes = (mnode_t *)Mem_Alloc( loadmodel->mempool, loadmodel->numnodes * sizeof( *out ));
2010-05-22 22:00:00 +02:00
for( i = 0; i < loadmodel->numnodes; i++, out++, in++ )
{
2010-11-22 22:00:00 +01:00
for( j = 0; j < 3; j++ )
{
out->minmaxs[j] = in->mins[j];
out->minmaxs[3+j] = in->maxs[j];
}
2010-11-21 22:00:00 +01:00
p = in->planenum;
2010-05-22 22:00:00 +02:00
out->plane = loadmodel->planes + p;
2010-11-21 22:00:00 +01:00
out->firstsurface = in->firstface;
out->numsurfaces = in->numfaces;
2010-05-22 22:00:00 +02:00
for( j = 0; j < 2; j++ )
{
2010-11-21 22:00:00 +01:00
p = in->children[j];
2010-05-22 22:00:00 +02:00
if( p >= 0 ) out->children[j] = loadmodel->nodes + p;
2010-08-12 22:00:00 +02:00
else out->children[j] = (mnode_t *)(loadmodel->leafs + ( -1 - p ));
2010-05-22 22:00:00 +02:00
}
}
// sets nodes and leafs
2010-11-22 22:00:00 +01:00
Mod_SetParent( loadmodel->nodes, NULL );
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadLeafs
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadLeafs( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dleaf_t *in;
2010-08-12 22:00:00 +02:00
mleaf_t *out;
2010-05-22 22:00:00 +02:00
int i, j, p, count;
in = (void *)(mod_base + l->fileofs);
2010-11-22 22:00:00 +01:00
if( l->filelen % sizeof( *in )) Host_Error( "Mod_LoadLeafs: funny lump size\n" );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
if( count < 1 ) Host_Error( "Map %s with no leafs\n", loadmodel->name );
2010-08-12 22:00:00 +02:00
out = (mleaf_t *)Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
2010-05-22 22:00:00 +02:00
loadmodel->leafs = out;
loadmodel->numleafs = count;
for( i = 0; i < count; i++, in++, out++ )
{
2010-11-22 22:00:00 +01:00
for( j = 0; j < 3; j++ )
{
out->minmaxs[j] = in->mins[j];
out->minmaxs[3+j] = in->maxs[j];
}
out->contents = in->contents;
2010-05-22 22:00:00 +02:00
2010-11-21 22:00:00 +01:00
p = in->visofs;
2010-05-22 22:00:00 +02:00
2010-12-06 22:00:00 +01:00
if( p == -1 ) out->compressed_vis = NULL;
else out->compressed_vis = loadmodel->visdata + p;
2010-05-22 22:00:00 +02:00
for( j = 0; j < 4; j++ )
out->ambient_sound_level[j] = in->ambient_level[j];
2010-11-21 22:00:00 +01:00
out->firstmarksurface = loadmodel->marksurfaces + in->firstmarksurface;
out->nummarksurfaces = in->nummarksurfaces;
2010-11-22 22:00:00 +01:00
// gl underwater warp
if( out->contents != CONTENTS_EMPTY )
{
for( j = 0; j < out->nummarksurfaces; j++ )
out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
}
2010-05-22 22:00:00 +02:00
}
if( loadmodel->leafs[0].contents != CONTENTS_SOLID )
2010-11-22 22:00:00 +01:00
Host_Error( "Mod_LoadLeafs: Map %s has leaf 0 is not CONTENTS_SOLID\n", loadmodel->name );
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadPlanes
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadPlanes( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
dplane_t *in;
2010-08-12 22:00:00 +02:00
mplane_t *out;
2010-05-22 22:00:00 +02:00
int i, j, count;
in = (void *)(mod_base + l->fileofs);
2010-11-22 22:00:00 +01:00
if( l->filelen % sizeof( *in )) Host_Error( "Mod_LoadPlanes: funny lump size\n" );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
if( count < 1 ) Host_Error( "Map %s with no planes\n", loadmodel->name );
2010-08-12 22:00:00 +02:00
out = (mplane_t *)Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
2010-05-22 22:00:00 +02:00
loadmodel->planes = out;
loadmodel->numplanes = count;
for( i = 0; i < count; i++, in++, out++ )
{
for( j = 0; j < 3; j++ )
{
2010-11-21 22:00:00 +01:00
out->normal[j] = in->normal[j];
2010-12-02 22:00:00 +01:00
if( out->normal[j] < 0.0f )
out->signbits |= 1<<j;
2010-05-22 22:00:00 +02:00
}
2010-11-21 22:00:00 +01:00
out->dist = in->dist;
out->type = in->type;
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadVisibility
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadVisibility( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
if( !l->filelen )
{
2010-05-27 22:00:00 +02:00
MsgDev( D_WARN, "map ^2%s^7 has no visibility\n", loadmodel->name );
2010-12-08 22:00:00 +01:00
loadmodel->visdata = NULL;
2010-12-19 22:00:00 +01:00
world.visdatasize = 0;
2010-05-22 22:00:00 +02:00
return;
}
2010-12-06 22:00:00 +01:00
loadmodel->visdata = Mem_Alloc( loadmodel->mempool, l->filelen );
2011-03-10 22:00:00 +01:00
Q_memcpy( loadmodel->visdata, (void *)(mod_base + l->fileofs), l->filelen );
2010-12-19 22:00:00 +01:00
world.visdatasize = l->filelen; // save it for PHS allocation
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadEntities
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadEntities( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
byte *in;
in = (void *)(mod_base + l->fileofs);
2010-11-22 22:00:00 +01:00
loadmodel->entities = Mem_Alloc( loadmodel->mempool, l->filelen );
2011-03-10 22:00:00 +01:00
Q_memcpy( loadmodel->entities, mod_base + l->fileofs, l->filelen );
2010-05-22 22:00:00 +02:00
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_LoadClipnodes
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadClipnodes( const dlump_t *l )
2010-05-22 22:00:00 +02:00
{
2010-08-12 22:00:00 +02:00
dclipnode_t *in, *out;
2010-05-22 22:00:00 +02:00
int i, count;
2010-08-12 22:00:00 +02:00
hull_t *hull;
2010-05-22 22:00:00 +02:00
in = (void *)(mod_base + l->fileofs);
2010-11-22 22:00:00 +01:00
if( l->filelen % sizeof( *in )) Host_Error( "Mod_LoadClipnodes: funny lump size\n" );
2010-05-22 22:00:00 +02:00
count = l->filelen / sizeof( *in );
out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
loadmodel->clipnodes = out;
loadmodel->numclipnodes = count;
// hulls[0] is a point hull, always zeroed
hull = &loadmodel->hulls[1];
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count - 1;
hull->planes = loadmodel->planes;
VectorCopy( GI->client_mins[1], hull->clip_mins ); // copy human hull
VectorCopy( GI->client_maxs[1], hull->clip_maxs );
2010-12-09 22:00:00 +01:00
VectorSubtract( hull->clip_maxs, hull->clip_mins, world.hull_sizes[1] );
2010-05-22 22:00:00 +02:00
hull = &loadmodel->hulls[2];
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count - 1;
hull->planes = loadmodel->planes;
VectorCopy( GI->client_mins[2], hull->clip_mins ); // copy large hull
VectorCopy( GI->client_maxs[2], hull->clip_maxs );
2010-12-09 22:00:00 +01:00
VectorSubtract( hull->clip_maxs, hull->clip_mins, world.hull_sizes[2] );
2010-05-22 22:00:00 +02:00
hull = &loadmodel->hulls[3];
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count - 1;
hull->planes = loadmodel->planes;
VectorCopy( GI->client_mins[3], hull->clip_mins ); // copy head hull
VectorCopy( GI->client_maxs[3], hull->clip_maxs );
2010-12-09 22:00:00 +01:00
VectorSubtract( hull->clip_maxs, hull->clip_mins, world.hull_sizes[3] );
2010-05-22 22:00:00 +02:00
for( i = 0; i < count; i++, out++, in++ )
{
2010-11-21 22:00:00 +01:00
out->planenum = in->planenum;
out->children[0] = in->children[0];
out->children[1] = in->children[1];
2010-05-22 22:00:00 +02:00
}
}
/*
=================
2010-11-22 22:00:00 +01:00
Mod_MakeHull0
2010-05-22 22:00:00 +02:00
Duplicate the drawing hull structure as a clipping hull
=================
*/
2010-11-22 22:00:00 +01:00
static void Mod_MakeHull0( void )
2010-05-22 22:00:00 +02:00
{
2010-08-12 22:00:00 +02:00
mnode_t *in, *child;
dclipnode_t *out;
hull_t *hull;
2010-05-22 22:00:00 +02:00
int i, j, count;
hull = &loadmodel->hulls[0];
in = loadmodel->nodes;
count = loadmodel->numnodes;
out = Mem_Alloc( loadmodel->mempool, count * sizeof( *out ));
hull->clipnodes = out;
hull->firstclipnode = 0;
hull->lastclipnode = count - 1;
hull->planes = loadmodel->planes;
for( i = 0; i < count; i++, out++, in++ )
{
out->planenum = in->plane - loadmodel->planes;
for( j = 0; j < 2; j++ )
{
child = in->children[j];
2010-08-12 22:00:00 +02:00
if( child->contents < 0 )
out->children[j] = child->contents;
2010-05-22 22:00:00 +02:00
else out->children[j] = child - loadmodel->nodes;
}
}
}
2010-12-19 22:00:00 +01:00
/*
=================
Mod_CalcPHS
=================
*/
void Mod_CalcPHS( void )
{
int hcount, vcount;
int i, j, k, l, index, num;
int rowbytes, rowwords;
int bitbyte, rowsize;
int *visofs, total_size = 0;
byte *vismap, *vismap_p;
byte *uncompressed_vis;
byte *uncompressed_pas;
byte *compressed_pas;
byte *scan, *comp;
uint *dest, *src;
double timestart;
size_t phsdatasize;
// no worldmodel or no visdata
if( !worldmodel || !worldmodel->visdata )
return;
MsgDev( D_NOTE, "Building PAS...\n" );
timestart = Sys_DoubleTime();
// NOTE: first leaf is skipped becuase is a outside leaf. Now all leafs have shift up by 1.
// and last leaf (which equal worldmodel->numleafs) has no visdata! Add extra one leaf
2011-02-20 22:00:00 +01:00
// to avoid this situation.
2010-12-19 22:00:00 +01:00
num = worldmodel->numleafs + 1;
rowwords = (num + 31)>>5;
rowbytes = rowwords * 4;
// typycally PHS enough more room because RLE fails on multiple 1 not 0
phsdatasize = world.visdatasize * 4;
// allocate pvs and phs data single array
visofs = Mem_Alloc( worldmodel->mempool, num * sizeof( int ));
uncompressed_vis = Mem_Alloc( worldmodel->mempool, rowbytes * num * 2 );
uncompressed_pas = uncompressed_vis + rowbytes * num;
compressed_pas = Mem_Alloc( worldmodel->mempool, phsdatasize );
vismap = vismap_p = compressed_pas; // compressed PHS buffer
scan = uncompressed_vis;
vcount = 0;
// uncompress pvs first
for( i = 0; i < num; i++, scan += rowbytes )
{
2011-03-10 22:00:00 +01:00
Q_memcpy( scan, Mod_LeafPVS( worldmodel->leafs + i, worldmodel ), rowbytes );
2010-12-19 22:00:00 +01:00
if( i == 0 ) continue;
for( j = 0; j < num; j++ )
{
if( scan[j>>3] & (1<<( j & 7 )))
vcount++;
}
}
scan = uncompressed_vis;
hcount = 0;
dest = (uint *)uncompressed_pas;
for( i = 0; i < num; i++, dest += rowwords, scan += rowbytes )
{
2011-03-10 22:00:00 +01:00
Q_memcpy( dest, scan, rowbytes );
2010-12-19 22:00:00 +01:00
for( j = 0; j < rowbytes; j++ )
{
bitbyte = scan[j];
if( !bitbyte ) continue;
for( k = 0; k < 8; k++ )
{
if(!( bitbyte & ( 1<<k )))
continue;
// or this pvs row into the phs
// +1 because pvs is 1 based
index = ((j<<3) + k + 1);
if( index >= num ) continue;
src = (uint *)uncompressed_vis + index * rowwords;
for( l = 0; l < rowwords; l++ )
dest[l] |= src[l];
}
}
// compress PHS data back
comp = Mod_CompressVis( (byte *)dest, &rowsize );
visofs[i] = vismap_p - vismap; // leaf 0 is a common solid
total_size += rowsize;
if( total_size > phsdatasize )
2011-03-09 22:00:00 +01:00
{
Host_Error( "CalcPHS: vismap expansion overflow %s > %s\n",
Q_memprint( total_size ), Q_memprint( phsdatasize ));
}
2010-12-19 22:00:00 +01:00
2011-03-10 22:00:00 +01:00
Q_memcpy( vismap_p, comp, rowsize );
2010-12-19 22:00:00 +01:00
vismap_p += rowsize; // move pointer
if( i == 0 ) continue;
for( j = 0; j < num; j++ )
{
if(((byte *)dest)[j>>3] & (1<<( j & 7 )))
hcount++;
}
}
// adjust compressed pas data to fit the size
compressed_pas = Mem_Realloc( worldmodel->mempool, compressed_pas, total_size );
// apply leaf pointers
for( i = 0; i < worldmodel->numleafs; i++ )
worldmodel->leafs[i].compressed_pas = compressed_pas + visofs[i];
// release uncompressed data
Mem_Free( uncompressed_vis );
Mem_Free( visofs ); // release vis offsets
// NOTE: we don't need to store off pointer to compressed pas-data
// because this is will be automatiaclly frees by mempool internal pointer
// and we not use this pointer any time after this point
MsgDev( D_NOTE, "Average leaves visible / audible / total: %i / %i / %i\n", vcount / num, hcount / num, num );
MsgDev( D_NOTE, "PAS building time: %g secs\n", Sys_DoubleTime() - timestart );
}
2010-12-06 22:00:00 +01:00
/*
=================
Mod_UnloadBrushModel
Release all uploaded textures
=================
*/
void Mod_UnloadBrushModel( model_t *mod )
{
texture_t *tx;
int i;
ASSERT( mod != NULL );
if( mod->type != mod_brush )
return; // not a bmodel
2010-12-08 22:00:00 +01:00
if( mod->name[0] != '*' )
2010-12-06 22:00:00 +01:00
{
2010-12-08 22:00:00 +01:00
for( i = 0; i < mod->numtextures; i++ )
{
tx = mod->textures[i];
if( !tx ) continue; // free slot
GL_FreeTexture( tx->gl_texturenum ); // main texture
GL_FreeTexture( tx->fb_texturenum ); // luma texture
}
2010-12-06 22:00:00 +01:00
2010-12-08 22:00:00 +01:00
Mem_FreePool( &mod->mempool );
2010-12-06 22:00:00 +01:00
}
2011-03-10 22:00:00 +01:00
Q_memset( mod, 0, sizeof( *mod ));
2010-12-06 22:00:00 +01:00
}
2010-05-22 22:00:00 +02:00
/*
=================
2010-12-08 22:00:00 +01:00
Mod_LoadBrushModel
2010-05-22 22:00:00 +02:00
=================
*/
2010-12-08 22:00:00 +01:00
static void Mod_LoadBrushModel( model_t *mod, const void *buffer )
2010-05-22 22:00:00 +02:00
{
2010-12-08 22:00:00 +01:00
int i, j;
2010-05-22 22:00:00 +02:00
dheader_t *header;
dmodel_t *bm;
header = (dheader_t *)buffer;
2010-11-21 22:00:00 +01:00
i = header->version;
2010-05-22 22:00:00 +02:00
switch( i )
{
2010-12-06 22:00:00 +01:00
case 28: // get support for quake1 beta
i = Q1BSP_VERSION;
break;
2010-05-22 22:00:00 +02:00
case Q1BSP_VERSION:
case HLBSP_VERSION:
break;
default:
2010-12-08 22:00:00 +01:00
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i)", loadmodel->name, i, HLBSP_VERSION );
2010-05-22 22:00:00 +02:00
return;
}
// will be merged later
loadmodel->type = mod_brush;
2010-12-13 22:00:00 +01:00
if( world.loading ) world.version = i;
2010-05-22 22:00:00 +02:00
// swap all the lumps
mod_base = (byte *)header;
2010-05-27 22:00:00 +02:00
loadmodel->mempool = Mem_AllocPool( va( "sv: ^2%s^7", loadmodel->name ));
2010-05-22 22:00:00 +02:00
// load into heap
2011-01-09 22:00:00 +01:00
if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 )
2010-05-31 22:00:00 +02:00
{
// blue-shift swapped lumps
2010-11-22 22:00:00 +01:00
Mod_LoadEntities( &header->lumps[LUMP_PLANES] );
Mod_LoadPlanes( &header->lumps[LUMP_ENTITIES] );
2010-05-31 22:00:00 +02:00
}
else
{
// normal half-life lumps
2010-11-22 22:00:00 +01:00
Mod_LoadEntities( &header->lumps[LUMP_ENTITIES] );
Mod_LoadPlanes( &header->lumps[LUMP_PLANES] );
2010-05-31 22:00:00 +02:00
}
2010-11-22 22:00:00 +01:00
Mod_LoadVertexes( &header->lumps[LUMP_VERTEXES] );
Mod_LoadEdges( &header->lumps[LUMP_EDGES] );
Mod_LoadSurfEdges( &header->lumps[LUMP_SURFEDGES] );
Mod_LoadTextures( &header->lumps[LUMP_TEXTURES] );
Mod_LoadLighting( &header->lumps[LUMP_LIGHTING] );
Mod_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
Mod_LoadTexInfo( &header->lumps[LUMP_TEXINFO] );
Mod_LoadSurfaces( &header->lumps[LUMP_FACES] );
Mod_LoadMarkSurfaces( &header->lumps[LUMP_MARKSURFACES] );
Mod_LoadLeafs( &header->lumps[LUMP_LEAFS] );
Mod_LoadNodes( &header->lumps[LUMP_NODES] );
Mod_LoadClipnodes( &header->lumps[LUMP_CLIPNODES] );
2010-11-21 22:00:00 +01:00
Mod_LoadSubmodels( &header->lumps[LUMP_MODELS] );
2010-05-22 22:00:00 +02:00
2010-11-22 22:00:00 +01:00
Mod_MakeHull0 ();
2010-05-22 22:00:00 +02:00
loadmodel->numframes = 2; // regular and alternate animation
2011-02-20 22:00:00 +01:00
// set up the submodels
2010-05-22 22:00:00 +02:00
for( i = 0; i < mod->numsubmodels; i++ )
{
bm = &mod->submodels[i];
2010-12-08 22:00:00 +01:00
mod->hulls[0].firstclipnode = bm->headnode[0];
2010-05-22 22:00:00 +02:00
for( j = 1; j < MAX_MAP_HULLS; j++ )
{
2010-12-08 22:00:00 +01:00
mod->hulls[j].firstclipnode = bm->headnode[j];
mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2010-05-22 22:00:00 +02:00
}
2010-12-08 22:00:00 +01:00
mod->firstmodelsurface = bm->firstface;
mod->nummodelsurfaces = bm->numfaces;
2010-12-09 22:00:00 +01:00
VectorCopy( bm->mins, mod->mins );
2010-12-08 22:00:00 +01:00
VectorCopy( bm->maxs, mod->maxs );
2010-05-22 22:00:00 +02:00
2010-12-08 22:00:00 +01:00
mod->radius = RadiusFromBounds( mod->mins, mod->maxs );
mod->numleafs = bm->visleafs;
2010-12-15 22:00:00 +01:00
mod->flags = 0; // clear flags
2010-05-22 22:00:00 +02:00
2010-12-12 22:00:00 +01:00
for( j = 0; i != 0 && j < mod->nummodelsurfaces; j++ )
{
msurface_t *surf = mod->surfaces + mod->firstmodelsurface + j;
mextrasurf_t *info = SURF_INFO( surf, mod );
vec3_t normal, vup = { 0, 0, 1 };
2010-12-15 22:00:00 +01:00
if( surf->flags & SURF_CONVEYOR )
mod->flags |= MODEL_CONVEYOR;
2010-12-12 22:00:00 +01:00
// kill water backplanes for submodels (half-life rules)
if( surf->flags & SURF_DRAWTURB )
{
if( surf->flags & SURF_PLANEBACK )
VectorNegate( surf->plane->normal, normal );
else VectorCopy( surf->plane->normal, normal );
if( surf->plane->type == PLANE_Z )
{
// kill bottom plane too
2010-12-13 22:00:00 +01:00
if( info->mins[2] == bm->mins[2] + 1 )
2010-12-12 22:00:00 +01:00
surf->flags |= SURF_WATERCSG;
}
else
{
// kill side planes
surf->flags |= SURF_WATERCSG;
}
}
}
2010-12-08 22:00:00 +01:00
if( i < mod->numsubmodels - 1 )
{
char name[8];
// duplicate the basic information
2011-03-09 22:00:00 +01:00
Q_snprintf( name, sizeof( name ), "*%i", i + 1 );
2010-12-08 22:00:00 +01:00
loadmodel = Mod_FindName( name, true );
*loadmodel = *mod;
2011-03-09 22:00:00 +01:00
Q_strncpy( loadmodel->name, name, sizeof( loadmodel->name ));
2010-12-08 22:00:00 +01:00
loadmodel->mempool = NULL;
mod = loadmodel;
}
2010-05-22 22:00:00 +02:00
}
}
2010-12-08 22:00:00 +01:00
/*
==================
Mod_FindName
2010-08-25 22:00:00 +02:00
2010-12-08 22:00:00 +01:00
==================
*/
model_t *Mod_FindName( const char *name, qboolean create )
2010-10-18 22:00:00 +02:00
{
model_t *mod;
2010-12-08 22:00:00 +01:00
int i;
2010-10-18 22:00:00 +02:00
if( !name || !name[0] )
return NULL;
2010-12-08 22:00:00 +01:00
2010-10-18 22:00:00 +02:00
// search the currently loaded models
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
2010-12-08 22:00:00 +01:00
{
2010-10-18 22:00:00 +02:00
if( !mod->name[0] ) continue;
2011-03-09 22:00:00 +01:00
if( !Q_stricmp( mod->name, name ))
2010-10-18 22:00:00 +02:00
{
// prolonge registration
2010-12-09 22:00:00 +01:00
mod->needload = world.load_sequence;
2010-10-18 22:00:00 +02:00
return mod;
}
}
2010-12-08 22:00:00 +01:00
if( !create ) return NULL;
2010-10-18 22:00:00 +02:00
// find a free model slot spot
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
2010-12-08 22:00:00 +01:00
if( !mod->name[0] ) break; // this is a valid spot
2010-10-18 22:00:00 +02:00
if( i == cm_nummodels )
{
if( cm_nummodels == MAX_MODELS )
Host_Error( "Mod_ForName: MAX_MODELS limit exceeded\n" );
cm_nummodels++;
}
2010-12-08 22:00:00 +01:00
// copy name, so model loader can find model file
2011-03-09 22:00:00 +01:00
Q_strncpy( mod->name, name, sizeof( mod->name ));
2010-12-08 22:00:00 +01:00
return mod;
}
/*
==================
Mod_LoadModel
Loads a model into the cache
==================
*/
2010-12-27 22:00:00 +01:00
model_t *Mod_LoadModel( model_t *mod, qboolean crash )
2010-12-08 22:00:00 +01:00
{
byte *buf;
if( !mod )
{
2010-12-27 22:00:00 +01:00
if( crash ) Host_Error( "Mod_ForName: NULL model\n" );
2010-12-08 22:00:00 +01:00
else MsgDev( D_ERROR, "Mod_ForName: NULL model\n" );
return NULL;
}
// check if already loaded (or inline bmodel)
if( mod->mempool || mod->name[0] == '*' )
return mod;
2011-03-08 22:00:00 +01:00
buf = FS_LoadFile( mod->name, NULL, false );
2010-10-18 22:00:00 +02:00
if( !buf )
{
2010-12-27 22:00:00 +01:00
if( crash ) Host_Error( "Mod_ForName: %s couldn't load\n", mod->name );
2010-12-08 22:00:00 +01:00
else MsgDev( D_ERROR, "Mod_ForName: %s couldn't load\n", mod->name );
2011-03-10 22:00:00 +01:00
Q_memset( mod, 0, sizeof( model_t ));
2010-10-18 22:00:00 +02:00
return NULL;
}
2010-12-08 22:00:00 +01:00
MsgDev( D_NOTE, "Mod_LoadModel: %s\n", mod->name );
2010-12-09 22:00:00 +01:00
mod->needload = world.load_sequence; // register mod
2010-10-18 22:00:00 +02:00
mod->type = mod_bad;
loadmodel = mod;
// call the apropriate loader
2010-11-21 22:00:00 +01:00
switch( *(uint *)buf )
2010-10-18 22:00:00 +02:00
{
case IDSTUDIOHEADER:
2010-12-08 22:00:00 +01:00
Mod_LoadStudioModel( mod, buf );
2010-10-18 22:00:00 +02:00
break;
case IDSPRITEHEADER:
2010-12-08 22:00:00 +01:00
Mod_LoadSpriteModel( mod, buf );
2010-10-18 22:00:00 +02:00
break;
2010-12-08 22:00:00 +01:00
case Q1BSP_VERSION:
case HLBSP_VERSION:
Mod_LoadBrushModel( mod, buf );
2010-10-18 22:00:00 +02:00
break;
}
Mem_Free( buf );
if( mod->type == mod_bad )
{
2010-12-02 22:00:00 +01:00
Mod_FreeModel( mod );
2010-10-18 22:00:00 +02:00
// check for loading problems
2010-12-27 22:00:00 +01:00
if( crash ) Host_Error( "Mod_ForName: %s unknown format\n", mod->name );
2010-12-08 22:00:00 +01:00
else MsgDev( D_ERROR, "Mod_ForName: %s unknown format\n", mod->name );
2010-10-18 22:00:00 +02:00
return NULL;
}
return mod;
}
2010-12-08 22:00:00 +01:00
/*
==================
Mod_ForName
2010-08-12 22:00:00 +02:00
2010-12-08 22:00:00 +01:00
Loads in a model for the given name
==================
*/
2010-12-27 22:00:00 +01:00
model_t *Mod_ForName( const char *name, qboolean crash )
2010-12-08 22:00:00 +01:00
{
model_t *mod;
mod = Mod_FindName( name, true );
2010-12-27 22:00:00 +01:00
return Mod_LoadModel( mod, crash );
2010-05-22 22:00:00 +02:00
}
/*
==================
2010-12-08 22:00:00 +01:00
Mod_LoadWorld
2010-05-22 22:00:00 +02:00
Loads in the map and all submodels
==================
*/
2010-12-08 22:00:00 +01:00
void Mod_LoadWorld( const char *name, uint *checksum )
2010-05-22 22:00:00 +02:00
{
2010-12-19 22:00:00 +01:00
int i;
2010-05-22 22:00:00 +02:00
// now replacement table is invalidate
2011-03-10 22:00:00 +01:00
Q_memset( com_models, 0, sizeof( com_models ));
2010-05-22 22:00:00 +02:00
2011-03-09 22:00:00 +01:00
if( !Q_stricmp( cm_models[0].name, name ))
2010-05-22 22:00:00 +02:00
{
// singleplayer mode: server already loading map
2010-12-08 22:00:00 +01:00
com_models[1] = cm_models; // make link to world
2010-12-09 22:00:00 +01:00
if( checksum ) *checksum = world.checksum;
2010-05-22 22:00:00 +02:00
// still have the right version
return;
}
2010-12-19 22:00:00 +01:00
// clear all studio submodels on restart
for( i = 0; i < cm_nummodels; i++ )
{
if( cm_models[i].type != mod_studio )
continue;
cm_models[i].submodels = NULL;
}
2010-12-08 22:00:00 +01:00
// purge all submodels
2010-12-09 22:00:00 +01:00
Mem_EmptyPool( com_studiocache );
2010-12-08 22:00:00 +01:00
Mod_FreeModel( &cm_models[0] );
2010-12-09 22:00:00 +01:00
world.load_sequence++; // now all models are invalid
2010-05-22 22:00:00 +02:00
// load the newmap
2010-12-27 22:00:00 +01:00
world.loading = true;
2010-12-08 22:00:00 +01:00
worldmodel = Mod_ForName( name, true );
com_models[1] = cm_models; // make link to world
2010-12-27 22:00:00 +01:00
CRC32_MapFile( &world.checksum, worldmodel->name );
world.loading = false;
2010-12-19 22:00:00 +01:00
2010-12-27 22:00:00 +01:00
if( checksum ) *checksum = world.checksum;
2010-12-19 22:00:00 +01:00
// calc Potentially Hearable Set and compress it
Mod_CalcPHS();
2010-05-22 22:00:00 +02:00
}
2010-12-08 22:00:00 +01:00
/*
==================
Mod_FreeUnused
Purge all unused models
==================
*/
void Mod_FreeUnused( void )
2010-05-22 22:00:00 +02:00
{
2010-08-12 22:00:00 +02:00
model_t *mod;
2010-05-22 22:00:00 +02:00
int i;
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
{
if( !mod->name[0] ) continue;
2010-12-09 22:00:00 +01:00
if( mod->needload != world.load_sequence )
2010-12-02 22:00:00 +01:00
Mod_FreeModel( mod );
2010-05-22 22:00:00 +02:00
}
}
/*
2010-12-08 22:00:00 +01:00
===================
Mod_GetType
===================
2010-05-22 22:00:00 +02:00
*/
2010-12-08 22:00:00 +01:00
modtype_t Mod_GetType( int handle )
2010-05-22 22:00:00 +02:00
{
2011-02-20 22:00:00 +01:00
model_t *mod = Mod_Handle( handle );
2010-12-08 22:00:00 +01:00
if( !mod ) return mod_bad;
return mod->type;
2010-05-22 22:00:00 +02:00
}
2010-11-10 22:00:00 +01:00
2010-05-22 22:00:00 +02:00
/*
===================
2010-08-12 22:00:00 +02:00
Mod_GetFrames
2010-05-22 22:00:00 +02:00
===================
*/
2010-08-12 22:00:00 +02:00
void Mod_GetFrames( int handle, int *numFrames )
2010-05-22 22:00:00 +02:00
{
2011-02-20 22:00:00 +01:00
model_t *mod = Mod_Handle( handle );
2010-05-22 22:00:00 +02:00
if( !numFrames ) return;
if( !mod )
{
*numFrames = 1;
return;
}
2010-12-17 22:00:00 +01:00
*numFrames = mod->numframes;
2010-05-22 22:00:00 +02:00
if( *numFrames < 1 ) *numFrames = 1;
}
/*
===================
2010-08-12 22:00:00 +02:00
Mod_GetBounds
2010-05-22 22:00:00 +02:00
===================
*/
2010-08-12 22:00:00 +02:00
void Mod_GetBounds( int handle, vec3_t mins, vec3_t maxs )
2010-05-22 22:00:00 +02:00
{
2010-12-29 22:00:00 +01:00
model_t *cmod;
if( handle <= 0 ) return;
2011-02-20 22:00:00 +01:00
cmod = Mod_Handle( handle );
2010-05-22 22:00:00 +02:00
if( cmod )
{
if( mins ) VectorCopy( cmod->mins, mins );
if( maxs ) VectorCopy( cmod->maxs, maxs );
}
else
{
MsgDev( D_ERROR, "Mod_GetBounds: NULL model %i\n", handle );
if( mins ) VectorClear( mins );
if( maxs ) VectorClear( maxs );
}
}
2010-11-15 22:00:00 +01:00
/*
===============
Mod_Calloc
===============
*/
void *Mod_Calloc( int number, size_t size )
{
if( number <= 0 || size <= 0 ) return NULL;
2010-12-09 22:00:00 +01:00
return Mem_Alloc( com_studiocache, number * size );
2010-11-15 22:00:00 +01:00
}
/*
===============
Mod_CacheCheck
===============
*/
void *Mod_CacheCheck( cache_user_t *c )
{
2010-12-09 22:00:00 +01:00
return Cache_Check( com_studiocache, c );
2010-11-15 22:00:00 +01:00
}
/*
===============
Mod_LoadCacheFile
===============
*/
void Mod_LoadCacheFile( const char *path, cache_user_t *cu )
{
byte *buf;
string filepath;
size_t i, size;
ASSERT( cu != NULL );
if( !path || !path[0] ) return;
// replace all '\' with '/'
for( i = ( path[0] == '/' ||path[0] == '\\' ), size = 0; path[i] && ( size < sizeof( filepath )-1 ); i++ )
{
if( path[i] == '\\' ) filepath[size++] = '/';
else filepath[size++] = path[i];
}
if( !size ) return;
filepath[size] = 0;
2011-03-08 22:00:00 +01:00
buf = FS_LoadFile( filepath, &size, false );
2010-12-09 22:00:00 +01:00
cu->data = Mem_Alloc( com_studiocache, size );
2011-03-10 22:00:00 +01:00
Q_memcpy( cu->data, buf, size );
2010-11-15 22:00:00 +01:00
Mem_Free( buf );
}
2010-12-08 22:00:00 +01:00
/*
===================
Mod_RegisterModel
register model with shared index
===================
*/
qboolean Mod_RegisterModel( const char *name, int index )
{
model_t *mod;
if( index < 0 || index > MAX_MODELS )
return false;
// this array used for acess to servermodels
mod = Mod_ForName( name, false );
com_models[index] = mod;
return ( mod != NULL );
}
2010-11-15 22:00:00 +01:00
/*
===============
Mod_Extradata
===============
*/
void *Mod_Extradata( model_t *mod )
{
if( mod && mod->type == mod_studio )
2010-11-21 22:00:00 +01:00
return mod->cache.data;
2010-11-15 22:00:00 +01:00
return NULL;
2010-12-08 22:00:00 +01:00
}
/*
==================
2011-02-20 22:00:00 +01:00
Mod_Handle
2010-12-08 22:00:00 +01:00
==================
*/
2011-02-20 22:00:00 +01:00
model_t *Mod_Handle( int handle )
2010-12-08 22:00:00 +01:00
{
if( handle < 0 || handle > MAX_MODELS )
{
2011-02-20 22:00:00 +01:00
Host_Error( "Mod_Handle: bad handle #%i\n", handle );
2010-12-08 22:00:00 +01:00
return NULL;
}
return com_models[handle];
2010-05-22 22:00:00 +02:00
}