2005-09-08 02:02:09 +00:00
//a note about dedicated servers:
//In the server-side gamecode, a couple of q1 extensions require knowing something about models.
//So we load models serverside, if required.
//things we need:
//tag/bone names and indexes so we can have reasonable modding with tags. :)
//tag/bone positions so we can shoot from the actual gun or other funky stuff
//vertex positions so we can trace against the mesh rather than the bbox.
//we use the gl renderer's model code because it supports more sorts of models than the sw renderer. Sad but true.
2004-08-22 22:29:09 +00:00
# include "quakedef.h"
2005-08-03 22:35:11 +00:00
# ifdef RGLQUAKE
2004-08-22 22:29:09 +00:00
# include "glquake.h"
2005-08-03 22:35:11 +00:00
# endif
# if defined(RGLQUAKE) || defined(SERVERONLY)
2004-08-22 22:29:09 +00:00
# include "shader.h"
# include "hash.h"
2005-08-19 16:35:49 +00:00
# if defined(ZYMOTICMODELS) || defined(MD5MODELS)
2004-11-29 01:21:00 +00:00
# define SKELETALMODELS
2005-09-08 02:02:09 +00:00
# include "malloc.h"
2004-11-29 01:21:00 +00:00
# endif
2005-06-14 04:52:10 +00:00
# define MAX_BONES 256
2005-07-16 00:53:08 +00:00
static model_t * loadmodel ;
2004-08-22 22:29:09 +00:00
//FIXME
typedef struct
{
float scale [ 3 ] ; // multiply qbyte verts by this
float translate [ 3 ] ; // then add this
char name [ 16 ] ; // frame name from grabbing
dtrivertx_t verts [ 1 ] ; // variable sized
} dmd2aliasframe_t ;
// entity_state_t->renderfx flags
2005-07-28 15:33:27 +00:00
# define Q2RF_MINLIGHT 1 // always have some light (viewmodel)
2004-08-22 22:29:09 +00:00
# define Q2RF_VIEWERMODEL 2 // don't draw through eyes, only mirrors
# define Q2RF_WEAPONMODEL 4 // only draw through eyes
2005-07-28 15:33:27 +00:00
# define Q2RF_FULLBRIGHT 8 // always draw full intensity
2004-08-22 22:29:09 +00:00
# define Q2RF_DEPTHHACK 16 // for view weapon Z crunching
# define Q2RF_TRANSLUCENT 32
# define Q2RF_FRAMELERP 64
# define Q2RF_BEAM 128
# define Q2RF_CUSTOMSKIN 256 // skin is an index in image_precache
# define Q2RF_GLOW 512 // pulse lighting for bonus items
# define Q2RF_SHELL_RED 1024
# define Q2RF_SHELL_GREEN 2048
# define Q2RF_SHELL_BLUE 4096
//ROGUE
# define Q2RF_IR_VISIBLE 0x00008000 // 32768
# define Q2RF_SHELL_DOUBLE 0x00010000 // 65536
# define Q2RF_SHELL_HALF_DAM 0x00020000
# define Q2RF_USE_DISGUISE 0x00040000
//ROGUE
2005-08-06 22:39:28 +00:00
extern cvar_t gl_part_flame , r_fullbrightSkins , r_fb_models ;
2004-08-22 22:29:09 +00:00
extern cvar_t r_noaliasshadows ;
void R_TorchEffect ( vec3_t pos , int type ) ;
void GLMod_FloodFillSkin ( qbyte * skin , int skinwidth , int skinheight ) ;
extern char loadname [ 32 ] ; // for hunk tags
int numTempColours ;
byte_vec4_t * tempColours ;
int numTempVertexCoords ;
2005-05-13 10:42:48 +00:00
vec3_t * tempVertexCoords ;
2004-08-22 22:29:09 +00:00
int numTempNormals ;
vec3_t * tempNormals ;
extern cvar_t gl_ati_truform ;
2004-11-18 17:55:04 +00:00
extern cvar_t r_vertexdlights ;
2005-09-08 02:02:09 +00:00
extern cvar_t mod_md3flags ;
2004-08-22 22:29:09 +00:00
typedef struct {
int ofs_indexes ;
int numindexes ;
int ofs_trineighbours ;
int numskins ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
int ofsskins ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
2005-09-08 02:02:09 +00:00
qboolean sharesverts ; //used with models with two shaders using the same vertex - use last mesh's verts
qboolean sharesbones ; //use last mesh's bones (please, never set this on the first mesh!)
2004-08-22 22:29:09 +00:00
int numverts ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
int ofs_st_array ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
int groups ;
int groupofs ;
int nextsurf ;
2004-11-17 18:13:33 +00:00
2005-08-19 16:35:49 +00:00
# ifdef SKELETALMODELS
2004-11-23 01:23:45 +00:00
int numbones ;
int ofsbones ;
int numtransforms ;
int ofstransforms ;
2005-08-19 16:35:49 +00:00
# endif
2004-11-23 01:23:45 +00:00
//these exist only in the root mesh.
2004-12-24 08:45:56 +00:00
int numtagframes ;
2004-11-17 18:13:33 +00:00
int numtags ;
int ofstags ;
2004-08-22 22:29:09 +00:00
} galiasinfo_t ;
//frame is an index into this
typedef struct {
2004-11-29 01:21:00 +00:00
# ifdef SKELETALMODELS
2005-08-03 23:14:59 +00:00
qboolean isheirachical ; //for models with transforms, states that bones need to be transformed from thier parent.
//this is actually bad, and can result in bones shortening as they interpolate.
2004-11-29 01:21:00 +00:00
# endif
2005-11-14 01:31:14 +00:00
qboolean loop ;
2004-08-22 22:29:09 +00:00
int numposes ;
float rate ;
int poseofs ;
2006-02-27 00:42:25 +00:00
char name [ 64 ] ;
2004-08-22 22:29:09 +00:00
} galiasgroup_t ;
typedef struct {
int ofsverts ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
int ofsnormals ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
vec3_t scale ;
vec3_t scale_origin ;
} galiaspose_t ;
2004-11-29 01:21:00 +00:00
# ifdef SKELETALMODELS
2004-11-23 01:23:45 +00:00
typedef struct {
2005-06-14 04:52:10 +00:00
char name [ 32 ] ;
2004-11-23 01:23:45 +00:00
int parent ;
} galiasbone_t ;
typedef struct {
//skeletal poses refer to this.
int vertexindex ;
int boneindex ;
vec4_t org ;
} galisskeletaltransforms_t ;
2004-11-29 01:21:00 +00:00
# endif
2004-11-23 01:23:45 +00:00
2004-08-22 22:29:09 +00:00
//we can't be bothered with animating skins.
//We'll load up to four of them but after that you're on your own
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
typedef struct {
int skinwidth ;
int skinheight ;
int ofstexels ; //this is 8bit for frame 0 only. only valid in q1 models without replacement textures, used for colourising player skins.
float skinspeed ;
int texnums ;
int ofstexnums ;
2005-08-03 23:14:59 +00:00
char name [ MAX_QPATH ] ;
2004-08-22 22:29:09 +00:00
} galiasskin_t ;
typedef struct {
int base ;
int bump ;
int fullbright ;
2004-10-19 16:10:14 +00:00
2006-01-28 02:35:40 +00:00
# ifdef Q3SHADERS
2004-10-19 16:10:14 +00:00
shader_t * shader ;
2006-01-28 02:35:40 +00:00
# endif
2004-08-22 22:29:09 +00:00
} galiastexnum_t ;
typedef struct {
char name [ MAX_QPATH ] ;
galiastexnum_t texnum ;
int colour ;
int skinnum ;
bucket_t bucket ;
} galiascolourmapped_t ;
2005-07-16 00:53:08 +00:00
# endif
2005-08-19 16:35:49 +00:00
# ifdef SKELETALMODELS
2005-07-16 00:53:08 +00:00
static void R_LerpBones ( float * plerp , float * * pose , int poses , galiasbone_t * bones , int bonecount , float bonepose [ MAX_BONES ] [ 12 ] ) ;
static void R_TransformVerticies ( float bonepose [ MAX_BONES ] [ 12 ] , galisskeletaltransforms_t * weights , int numweights , float * xyzout ) ;
2005-08-19 16:35:49 +00:00
# endif
2005-07-16 00:53:08 +00:00
void Mod_DoCRC ( model_t * mod , char * buffer , int buffersize )
{
# ifndef SERVERONLY
//we've got to have this bit
2006-03-06 00:19:46 +00:00
if ( loadmodel - > engineflags & MDLF_DOCRC )
2005-07-16 00:53:08 +00:00
{
unsigned short crc ;
qbyte * p ;
int len ;
char st [ 40 ] ;
2005-09-08 02:02:09 +00:00
QCRC_Init ( & crc ) ;
2005-07-16 00:53:08 +00:00
for ( len = buffersize , p = buffer ; len ; len - - , p + + )
2005-09-08 02:02:09 +00:00
QCRC_ProcessByte ( & crc , * p ) ;
2005-11-26 03:02:55 +00:00
2005-07-16 00:53:08 +00:00
sprintf ( st , " %d " , ( int ) crc ) ;
2005-11-26 03:02:55 +00:00
Info_SetValueForKey ( cls . userinfo ,
2006-03-06 00:19:46 +00:00
( loadmodel - > engineflags & MDLF_PLAYER ) ? pmodel_name : emodel_name ,
2005-07-16 00:53:08 +00:00
st , MAX_INFO_STRING ) ;
if ( cls . state > = ca_connected )
{
2005-11-26 03:02:55 +00:00
CL_SendClientCommand ( true , " setinfo %s %d " ,
2006-03-06 00:19:46 +00:00
( loadmodel - > engineflags & MDLF_PLAYER ) ? pmodel_name : emodel_name ,
2005-07-16 00:53:08 +00:00
( int ) crc ) ;
}
}
# endif
}
qboolean GLMod_Trace ( model_t * model , int forcehullnum , int frame , vec3_t start , vec3_t end , vec3_t mins , vec3_t maxs , trace_t * trace )
{
galiasinfo_t * mod = Mod_Extradata ( model ) ;
galiasgroup_t * group ;
galiaspose_t * pose ;
int i ;
float * p1 , * p2 , * p3 ;
vec3_t edge1 , edge2 , edge3 ;
vec3_t normal ;
vec3_t edgenormal ;
float planedist ;
float diststart , distend ;
float frac ;
2005-08-19 16:35:49 +00:00
// float temp;
2005-07-16 00:53:08 +00:00
vec3_t impactpoint ;
float * posedata ;
int * indexes ;
while ( mod )
{
indexes = ( int * ) ( ( char * ) mod + mod - > ofs_indexes ) ;
group = ( galiasgroup_t * ) ( ( char * ) mod + mod - > groupofs ) ;
pose = ( galiaspose_t * ) ( ( char * ) & group [ 0 ] + group [ 0 ] . poseofs ) ;
posedata = ( float * ) ( ( char * ) pose + pose - > ofsverts ) ;
2005-08-19 16:35:49 +00:00
# ifdef SKELETALMODELS
2005-08-03 23:14:59 +00:00
if ( mod - > numbones & & ! mod - > sharesverts )
2005-07-16 00:53:08 +00:00
{
float bonepose [ MAX_BONES ] [ 12 ] ;
posedata = alloca ( mod - > numverts * sizeof ( vec3_t ) ) ;
frac = 1 ;
2005-08-03 23:14:59 +00:00
if ( group - > isheirachical )
{
2005-09-08 02:02:09 +00:00
if ( ! mod - > sharesbones )
R_LerpBones ( & frac , ( float * * ) posedata , 1 , ( galiasbone_t * ) ( ( char * ) mod + mod - > ofsbones ) , mod - > numbones , bonepose ) ;
2005-08-03 23:14:59 +00:00
R_TransformVerticies ( bonepose , ( galisskeletaltransforms_t * ) ( ( char * ) mod + mod - > ofstransforms ) , mod - > numtransforms , posedata ) ;
}
else
R_TransformVerticies ( ( void * ) posedata , ( galisskeletaltransforms_t * ) ( ( char * ) mod + mod - > ofstransforms ) , mod - > numtransforms , posedata ) ;
2005-07-16 00:53:08 +00:00
}
2005-08-19 16:35:49 +00:00
# endif
2005-07-16 00:53:08 +00:00
for ( i = 0 ; i < mod - > numindexes ; i + = 3 )
{
p1 = posedata + 3 * indexes [ i + 0 ] ;
p2 = posedata + 3 * indexes [ i + 1 ] ;
p3 = posedata + 3 * indexes [ i + 2 ] ;
VectorSubtract ( p1 , p2 , edge1 ) ;
VectorSubtract ( p3 , p2 , edge2 ) ;
CrossProduct ( edge1 , edge2 , normal ) ;
planedist = DotProduct ( p1 , normal ) ;
diststart = DotProduct ( start , normal ) ;
if ( diststart < = planedist )
continue ; //start on back side.
distend = DotProduct ( end , normal ) ;
if ( distend > = planedist )
continue ; //end on front side (as must start - doesn't cross).
frac = ( diststart - planedist ) / ( diststart - distend ) ;
if ( frac > = trace - > fraction ) //already found one closer.
continue ;
impactpoint [ 0 ] = start [ 0 ] + frac * ( end [ 0 ] - start [ 0 ] ) ;
impactpoint [ 1 ] = start [ 1 ] + frac * ( end [ 1 ] - start [ 1 ] ) ;
impactpoint [ 2 ] = start [ 2 ] + frac * ( end [ 2 ] - start [ 2 ] ) ;
2005-08-19 16:35:49 +00:00
// temp = DotProduct(impactpoint, normal)-planedist;
2005-07-16 00:53:08 +00:00
CrossProduct ( edge1 , normal , edgenormal ) ;
2005-08-19 16:35:49 +00:00
// temp = DotProduct(impactpoint, edgenormal)-DotProduct(p2, edgenormal);
2005-07-16 00:53:08 +00:00
if ( DotProduct ( impactpoint , edgenormal ) > DotProduct ( p2 , edgenormal ) )
continue ;
CrossProduct ( normal , edge2 , edgenormal ) ;
if ( DotProduct ( impactpoint , edgenormal ) > DotProduct ( p3 , edgenormal ) )
continue ;
VectorSubtract ( p1 , p3 , edge3 ) ;
CrossProduct ( normal , edge3 , edgenormal ) ;
if ( DotProduct ( impactpoint , edgenormal ) > DotProduct ( p1 , edgenormal ) )
continue ;
trace - > fraction = frac ;
VectorCopy ( impactpoint , trace - > endpos ) ;
VectorCopy ( normal , trace - > plane . normal ) ;
}
if ( mod - > nextsurf )
mod = ( galiasinfo_t * ) ( ( char * ) mod + mod - > nextsurf ) ;
else
mod = NULL ;
}
trace - > allsolid = false ;
2004-08-22 22:29:09 +00:00
2005-07-16 00:53:08 +00:00
return trace - > fraction ! = 1 ;
}
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
static hashtable_t skincolourmapped ;
static vec3_t shadevector ;
static vec3_t shadelight , ambientlight ;
2006-06-08 06:24:07 +00:00
static void R_LerpFrames ( mesh_t * mesh , galiaspose_t * p1 , galiaspose_t * p2 , float lerp , qbyte alpha , float expand , qboolean nolightdir )
2004-08-22 22:29:09 +00:00
{
extern cvar_t r_nolerp , r_nolightdir ;
float blerp = 1 - lerp ;
int i ;
float l ;
int temp ;
vec3_t * p1v , * p2v ;
vec3_t * p1n , * p2n ;
2004-09-20 23:25:38 +00:00
p1v = ( vec3_t * ) ( ( char * ) p1 + p1 - > ofsverts ) ;
p2v = ( vec3_t * ) ( ( char * ) p2 + p2 - > ofsverts ) ;
2004-08-22 22:29:09 +00:00
2004-09-20 23:25:38 +00:00
p1n = ( vec3_t * ) ( ( char * ) p1 + p1 - > ofsnormals ) ;
p2n = ( vec3_t * ) ( ( char * ) p2 + p2 - > ofsnormals ) ;
2004-08-22 22:29:09 +00:00
if ( p1v = = p2v | | r_nolerp . value )
{
2004-09-20 23:25:38 +00:00
mesh - > normals_array = ( vec3_t * ) ( ( char * ) p1 + p1 - > ofsnormals ) ;
2005-05-13 10:42:48 +00:00
mesh - > xyz_array = p1v ;
2006-06-08 06:24:07 +00:00
if ( r_nolightdir . value | | nolightdir )
2004-08-22 22:29:09 +00:00
{
2005-06-04 04:20:20 +00:00
mesh - > colors_array = NULL ;
2004-08-22 22:29:09 +00:00
}
else
{
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
l = DotProduct ( mesh - > normals_array [ i ] , shadevector ) ;
temp = l * ambientlight [ 0 ] + shadelight [ 0 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
mesh - > colors_array [ i ] [ 0 ] = temp ;
temp = l * ambientlight [ 1 ] + shadelight [ 1 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
mesh - > colors_array [ i ] [ 1 ] = temp ;
temp = l * ambientlight [ 2 ] + shadelight [ 2 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
mesh - > colors_array [ i ] [ 2 ] = temp ;
mesh - > colors_array [ i ] [ 3 ] = alpha ;
}
}
}
else
{
2006-06-08 06:24:07 +00:00
if ( r_nolightdir . value | | nolightdir )
2004-08-22 22:29:09 +00:00
{
2006-02-27 00:42:25 +00:00
mesh - > colors_array = NULL ;
2004-08-22 22:29:09 +00:00
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
mesh - > normals_array [ i ] [ 0 ] = p1n [ i ] [ 0 ] * lerp + p2n [ i ] [ 0 ] * blerp ;
mesh - > normals_array [ i ] [ 1 ] = p1n [ i ] [ 1 ] * lerp + p2n [ i ] [ 1 ] * blerp ;
mesh - > normals_array [ i ] [ 2 ] = p1n [ i ] [ 2 ] * lerp + p2n [ i ] [ 2 ] * blerp ;
mesh - > xyz_array [ i ] [ 0 ] = p1v [ i ] [ 0 ] * lerp + p2v [ i ] [ 0 ] * blerp ;
mesh - > xyz_array [ i ] [ 1 ] = p1v [ i ] [ 1 ] * lerp + p2v [ i ] [ 1 ] * blerp ;
mesh - > xyz_array [ i ] [ 2 ] = p1v [ i ] [ 2 ] * lerp + p2v [ i ] [ 2 ] * blerp ;
}
}
else
{
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
mesh - > normals_array [ i ] [ 0 ] = p1n [ i ] [ 0 ] * lerp + p2n [ i ] [ 0 ] * blerp ;
mesh - > normals_array [ i ] [ 1 ] = p1n [ i ] [ 1 ] * lerp + p2n [ i ] [ 1 ] * blerp ;
mesh - > normals_array [ i ] [ 2 ] = p1n [ i ] [ 2 ] * lerp + p2n [ i ] [ 2 ] * blerp ;
mesh - > xyz_array [ i ] [ 0 ] = p1v [ i ] [ 0 ] * lerp + p2v [ i ] [ 0 ] * blerp ;
mesh - > xyz_array [ i ] [ 1 ] = p1v [ i ] [ 1 ] * lerp + p2v [ i ] [ 1 ] * blerp ;
mesh - > xyz_array [ i ] [ 2 ] = p1v [ i ] [ 2 ] * lerp + p2v [ i ] [ 2 ] * blerp ;
l = DotProduct ( mesh - > normals_array [ i ] , shadevector ) ;
temp = l * ambientlight [ 0 ] + shadelight [ 0 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
mesh - > colors_array [ i ] [ 0 ] = temp ;
temp = l * ambientlight [ 1 ] + shadelight [ 1 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
mesh - > colors_array [ i ] [ 1 ] = temp ;
temp = l * ambientlight [ 2 ] + shadelight [ 2 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
mesh - > colors_array [ i ] [ 2 ] = temp ;
mesh - > colors_array [ i ] [ 3 ] = alpha ;
}
}
}
if ( expand )
{
2005-05-13 10:42:48 +00:00
if ( mesh - > xyz_array = = p1v )
2004-08-22 22:29:09 +00:00
{
2005-05-13 10:42:48 +00:00
mesh - > xyz_array = tempVertexCoords ;
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
mesh - > xyz_array [ i ] [ 0 ] = p1v [ i ] [ 0 ] + mesh - > normals_array [ i ] [ 0 ] * expand ;
mesh - > xyz_array [ i ] [ 1 ] = p1v [ i ] [ 1 ] + mesh - > normals_array [ i ] [ 1 ] * expand ;
mesh - > xyz_array [ i ] [ 2 ] = p1v [ i ] [ 2 ] + mesh - > normals_array [ i ] [ 2 ] * expand ;
}
}
else
{
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
mesh - > xyz_array [ i ] [ 0 ] + = mesh - > normals_array [ i ] [ 0 ] * expand ;
mesh - > xyz_array [ i ] [ 1 ] + = mesh - > normals_array [ i ] [ 1 ] * expand ;
mesh - > xyz_array [ i ] [ 2 ] + = mesh - > normals_array [ i ] [ 2 ] * expand ;
}
2004-08-22 22:29:09 +00:00
}
}
}
2005-07-16 00:53:08 +00:00
# endif
2004-11-29 01:21:00 +00:00
# ifdef SKELETALMODELS
2005-07-16 00:53:08 +00:00
static void R_LerpBones ( float * plerp , float * * pose , int poses , galiasbone_t * bones , int bonecount , float bonepose [ MAX_BONES ] [ 12 ] )
2004-11-23 01:23:45 +00:00
{
int i , k , b ;
2005-07-16 00:53:08 +00:00
float * matrix , m [ 12 ] ;
2004-11-23 01:23:45 +00:00
2005-08-03 23:14:59 +00:00
if ( poses = = 1 )
2004-11-23 01:23:45 +00:00
{
2005-08-03 23:14:59 +00:00
// vertex weighted skeletal
// interpolate matrices and concatenate them to their parents
for ( i = 0 ; i < bonecount ; i + + )
{
matrix = pose [ 0 ] + i * 12 ;
if ( bones [ i ] . parent > = 0 )
R_ConcatTransforms ( ( void * ) bonepose [ bones [ i ] . parent ] , ( void * ) matrix , ( void * ) bonepose [ i ] ) ;
else
for ( k = 0 ; k < 12 ; k + + ) //parentless
bonepose [ i ] [ k ] = matrix [ k ] ;
}
}
else
{
// vertex weighted skeletal
// interpolate matrices and concatenate them to their parents
for ( i = 0 ; i < bonecount ; i + + )
2004-11-23 01:23:45 +00:00
{
for ( k = 0 ; k < 12 ; k + + )
2005-08-03 23:14:59 +00:00
m [ k ] = 0 ;
for ( b = 0 ; b < poses ; b + + )
{
matrix = pose [ b ] + i * 12 ;
2005-11-26 03:02:55 +00:00
2005-08-03 23:14:59 +00:00
for ( k = 0 ; k < 12 ; k + + )
m [ k ] + = matrix [ k ] * plerp [ b ] ;
}
if ( bones [ i ] . parent > = 0 )
R_ConcatTransforms ( ( void * ) bonepose [ bones [ i ] . parent ] , ( void * ) m , ( void * ) bonepose [ i ] ) ;
else
for ( k = 0 ; k < 12 ; k + + ) //parentless
bonepose [ i ] [ k ] = m [ k ] ;
2004-11-23 01:23:45 +00:00
}
}
2005-07-16 00:53:08 +00:00
}
static void R_TransformVerticies ( float bonepose [ MAX_BONES ] [ 12 ] , galisskeletaltransforms_t * weights , int numweights , float * xyzout )
{
int i ;
float * out , * matrix ;
galisskeletaltransforms_t * v = weights ;
for ( i = 0 ; i < numweights ; i + + , v + + )
{
out = xyzout + v - > vertexindex * 3 ;
matrix = bonepose [ v - > boneindex ] ;
// FIXME: this can very easily be optimized with SSE or 3DNow
out [ 0 ] + = v - > org [ 0 ] * matrix [ 0 ] + v - > org [ 1 ] * matrix [ 1 ] + v - > org [ 2 ] * matrix [ 2 ] + v - > org [ 3 ] * matrix [ 3 ] ;
out [ 1 ] + = v - > org [ 0 ] * matrix [ 4 ] + v - > org [ 1 ] * matrix [ 5 ] + v - > org [ 2 ] * matrix [ 6 ] + v - > org [ 3 ] * matrix [ 7 ] ;
out [ 2 ] + = v - > org [ 0 ] * matrix [ 8 ] + v - > org [ 1 ] * matrix [ 9 ] + v - > org [ 2 ] * matrix [ 10 ] + v - > org [ 3 ] * matrix [ 11 ] ;
}
}
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
static void R_BuildSkeletalMesh ( mesh_t * mesh , float * plerp , float * * pose , int poses , galiasbone_t * bones , int bonecount , galisskeletaltransforms_t * weights , int numweights , qboolean usehierarchy )
2005-07-16 00:53:08 +00:00
{
float bonepose [ MAX_BONES ] [ 12 ] ;
2005-08-03 23:14:59 +00:00
int i , k , l ;
2005-07-16 00:53:08 +00:00
2005-08-03 23:14:59 +00:00
if ( usehierarchy )
R_LerpBones ( plerp , pose , poses , bones , bonecount , bonepose ) ;
else
{
if ( poses = = 1 )
memcpy ( bonepose , pose [ 0 ] , sizeof ( float ) * 12 * bonecount ) ;
else if ( poses = = 2 )
{
for ( i = 0 ; i < bonecount * 12 ; i + + )
{
( ( float * ) bonepose ) [ i ] = pose [ 0 ] [ i ] * plerp [ 0 ] + pose [ 1 ] [ i ] * plerp [ 1 ] ;
}
}
else
{
for ( i = 0 ; i < bonecount ; i + + )
{
for ( l = 0 ; l < 12 ; l + + )
bonepose [ i ] [ l ] = 0 ;
for ( k = 0 ; k < poses ; k + + )
{
for ( l = 0 ; l < 12 ; l + + )
bonepose [ i ] [ l ] + = pose [ k ] [ i * 12 + l ] * plerp [ k ] ;
}
}
}
}
2004-11-23 01:23:45 +00:00
// blend the vertex bone weights
2005-07-16 00:53:08 +00:00
// memset(outhead, 0, mesh->numvertexes * sizeof(mesh->xyz_array[0]));
2004-11-23 01:23:45 +00:00
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
mesh - > normals_array [ i ] [ 0 ] = 0 ;
mesh - > normals_array [ i ] [ 1 ] = 0 ;
mesh - > normals_array [ i ] [ 2 ] = 1 ;
2006-02-27 00:42:25 +00:00
/*
2004-11-23 01:23:45 +00:00
mesh - > colors_array [ i ] [ 0 ] = ambientlight [ 0 ] ;
mesh - > colors_array [ i ] [ 1 ] = ambientlight [ 1 ] ;
mesh - > colors_array [ i ] [ 2 ] = ambientlight [ 2 ] ;
mesh - > colors_array [ i ] [ 3 ] = 255 ; //alpha;
2006-02-27 00:42:25 +00:00
*/
2004-11-23 01:23:45 +00:00
/*
mesh - > xyz_array [ i ] [ 0 ] = 0 ;
mesh - > xyz_array [ i ] [ 1 ] = 0 ;
mesh - > xyz_array [ i ] [ 2 ] = 0 ;
mesh - > xyz_array [ i ] [ 3 ] = 1 ;
*/
}
2006-02-27 00:42:25 +00:00
mesh - > colors_array = NULL ;
2004-11-23 01:23:45 +00:00
2005-08-03 23:14:59 +00:00
memset ( mesh - > xyz_array , 0 , mesh - > numvertexes * sizeof ( vec3_t ) ) ;
2005-07-16 00:53:08 +00:00
R_TransformVerticies ( bonepose , weights , numweights , ( float * ) mesh - > xyz_array ) ;
2005-08-03 23:14:59 +00:00
#if 0 //draws the bones
qglColor3f ( 1 , 0 , 0 ) ;
{
int i ;
int p ;
vec3_t org , dest ;
qglBegin ( GL_LINES ) ;
for ( i = 0 ; i < bonecount ; i + + )
{
p = bones [ i ] . parent ;
if ( p < 0 )
p = 0 ;
qglVertex3f ( bonepose [ i ] [ 3 ] , bonepose [ i ] [ 7 ] , bonepose [ i ] [ 11 ] ) ;
qglVertex3f ( bonepose [ p ] [ 3 ] , bonepose [ p ] [ 7 ] , bonepose [ p ] [ 11 ] ) ;
}
qglEnd ( ) ;
qglBegin ( GL_LINES ) ;
for ( i = 0 ; i < bonecount ; i + + )
{
p = bones [ i ] . parent ;
if ( p < 0 )
p = 0 ;
org [ 0 ] = bonepose [ i ] [ 3 ] ; org [ 1 ] = bonepose [ i ] [ 7 ] ; org [ 2 ] = bonepose [ i ] [ 11 ] ;
qglVertex3fv ( org ) ;
qglVertex3f ( bonepose [ p ] [ 3 ] , bonepose [ p ] [ 7 ] , bonepose [ p ] [ 11 ] ) ;
dest [ 0 ] = org [ 0 ] + bonepose [ i ] [ 0 ] ; dest [ 1 ] = org [ 1 ] + bonepose [ i ] [ 1 ] ; dest [ 2 ] = org [ 2 ] + bonepose [ i ] [ 2 ] ;
qglVertex3fv ( org ) ;
qglVertex3fv ( dest ) ;
qglVertex3fv ( dest ) ;
qglVertex3f ( bonepose [ p ] [ 3 ] , bonepose [ p ] [ 7 ] , bonepose [ p ] [ 11 ] ) ;
dest [ 0 ] = org [ 0 ] + bonepose [ i ] [ 4 ] ; dest [ 1 ] = org [ 1 ] + bonepose [ i ] [ 5 ] ; dest [ 2 ] = org [ 2 ] + bonepose [ i ] [ 6 ] ;
qglVertex3fv ( org ) ;
qglVertex3fv ( dest ) ;
qglVertex3fv ( dest ) ;
qglVertex3f ( bonepose [ p ] [ 3 ] , bonepose [ p ] [ 7 ] , bonepose [ p ] [ 11 ] ) ;
dest [ 0 ] = org [ 0 ] + bonepose [ i ] [ 8 ] ; dest [ 1 ] = org [ 1 ] + bonepose [ i ] [ 9 ] ; dest [ 2 ] = org [ 2 ] + bonepose [ i ] [ 10 ] ;
qglVertex3fv ( org ) ;
qglVertex3fv ( dest ) ;
qglVertex3fv ( dest ) ;
qglVertex3f ( bonepose [ p ] [ 3 ] , bonepose [ p ] [ 7 ] , bonepose [ p ] [ 11 ] ) ;
}
qglEnd ( ) ;
2005-09-08 02:02:09 +00:00
// mesh->numindexes = 0; //don't draw this mesh, as that would obscure the bones. :(
2005-08-03 23:14:59 +00:00
}
# endif
2004-11-23 01:23:45 +00:00
}
2004-11-29 01:21:00 +00:00
# endif
2005-07-16 00:53:08 +00:00
# endif
2004-11-23 01:23:45 +00:00
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2006-02-27 00:42:25 +00:00
void R_LightArrays ( byte_vec4_t * colours , int vertcount , vec3_t * normals )
{
int i ;
float l ;
int temp ;
for ( i = vertcount - 1 ; i > = 0 ; i - - )
{
l = DotProduct ( normals [ i ] , shadevector ) ;
temp = l * ambientlight [ 0 ] + shadelight [ 0 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
colours [ i ] [ 0 ] = temp ;
temp = l * ambientlight [ 1 ] + shadelight [ 1 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
colours [ i ] [ 1 ] = temp ;
temp = l * ambientlight [ 2 ] + shadelight [ 2 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
colours [ i ] [ 2 ] = temp ;
}
}
2005-09-08 02:02:09 +00:00
//changes vertex lighting values
2006-02-27 00:42:25 +00:00
static void R_GAliasApplyLighting ( mesh_t * mesh , vec3_t org , vec3_t angles , float * colormod )
2004-09-07 23:09:15 +00:00
{
int l , v ;
vec3_t rel ;
vec3_t dir ;
float dot , d , a , f ;
2006-02-27 00:42:25 +00:00
if ( mesh - > colors_array )
2004-09-07 23:09:15 +00:00
{
2006-02-27 00:42:25 +00:00
float l ;
int temp ;
int i ;
byte_vec4_t * colours = mesh - > colors_array ;
vec3_t * normals = mesh - > normals_array ;
vec3_t ambient , shade ;
qbyte alphab = bound ( 0 , colormod [ 3 ] * 255 , 255 ) ;
if ( ! mesh - > normals_array )
2004-09-07 23:09:15 +00:00
{
2006-02-27 00:42:25 +00:00
mesh - > colors_array = NULL ;
return ;
}
2004-09-07 23:09:15 +00:00
2006-02-27 00:42:25 +00:00
VectorCopy ( ambientlight , ambient ) ;
VectorCopy ( shadelight , shade ) ;
for ( i = 0 ; i < 3 ; i + + )
{
ambient [ i ] * = colormod [ i ] ;
shade [ i ] * = colormod [ i ] ;
}
for ( i = mesh - > numvertexes - 1 ; i > = 0 ; i - - )
{
l = DotProduct ( normals [ i ] , shadevector ) ;
temp = l * ambient [ 0 ] + shade [ 0 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
colours [ i ] [ 0 ] = temp ;
temp = l * ambient [ 1 ] + shade [ 1 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
colours [ i ] [ 1 ] = temp ;
temp = l * ambient [ 2 ] + shade [ 2 ] ;
if ( temp < 0 ) temp = 0 ;
else if ( temp > 255 ) temp = 255 ;
colours [ i ] [ 2 ] = temp ;
colours [ i ] [ 3 ] = alphab ;
}
}
if ( r_vertexdlights . value & & mesh - > colors_array )
{
2006-05-11 03:14:41 +00:00
for ( l = 0 ; l < dlights_running ; l + + )
2006-02-27 00:42:25 +00:00
{
if ( cl_dlights [ l ] . radius )
2004-09-07 23:09:15 +00:00
{
2006-02-27 00:42:25 +00:00
VectorSubtract ( cl_dlights [ l ] . origin ,
org ,
dir ) ;
if ( Length ( dir ) > cl_dlights [ l ] . radius + mesh - > radius ) //far out man!
continue ;
rel [ 0 ] = - DotProduct ( dir , currententity - > axis [ 0 ] ) ;
rel [ 1 ] = - DotProduct ( dir , currententity - > axis [ 1 ] ) ; //quake's crazy.
rel [ 2 ] = - DotProduct ( dir , currententity - > axis [ 2 ] ) ;
/*
glBegin ( GL_LINES ) ;
glVertex3f ( 0 , 0 , 0 ) ;
glVertex3f ( rel [ 0 ] , rel [ 1 ] , rel [ 2 ] ) ;
glEnd ( ) ;
*/
for ( v = 0 ; v < mesh - > numvertexes ; v + + )
2004-09-07 23:09:15 +00:00
{
2006-02-27 00:42:25 +00:00
VectorSubtract ( mesh - > xyz_array [ v ] , rel , dir ) ;
dot = DotProduct ( dir , mesh - > normals_array [ v ] ) ;
if ( dot > 0 )
2004-09-07 23:09:15 +00:00
{
2006-02-27 00:42:25 +00:00
d = DotProduct ( dir , dir ) ;
a = 1 / d ;
if ( a > 0 )
{
a * = 10000000 * dot / sqrt ( d ) ;
f = mesh - > colors_array [ v ] [ 0 ] + a * cl_dlights [ l ] . color [ 0 ] ;
if ( f > 255 )
f = 255 ;
else if ( f < 0 )
f = 0 ;
mesh - > colors_array [ v ] [ 0 ] = f ;
f = mesh - > colors_array [ v ] [ 1 ] + a * cl_dlights [ l ] . color [ 1 ] ;
if ( f > 255 )
f = 255 ;
else if ( f < 0 )
f = 0 ;
mesh - > colors_array [ v ] [ 1 ] = f ;
f = mesh - > colors_array [ v ] [ 2 ] + a * cl_dlights [ l ] . color [ 2 ] ;
if ( f > 255 )
f = 255 ;
else if ( f < 0 )
f = 0 ;
mesh - > colors_array [ v ] [ 2 ] = f ;
}
// else
// mesh->colors_array[v][1] =255;
2004-09-07 23:09:15 +00:00
}
2006-02-27 00:42:25 +00:00
// else
// mesh->colors_array[v][2] =255;
2004-09-07 23:09:15 +00:00
}
}
}
}
}
2006-06-08 06:24:07 +00:00
static qboolean R_GAliasBuildMesh ( mesh_t * mesh , galiasinfo_t * inf , int frame1 , int frame2 , float lerp , float alpha , float fg1time , float fg2time , qboolean nolightdir )
2004-08-22 22:29:09 +00:00
{
galiasgroup_t * g1 , * g2 ;
2005-05-15 18:49:04 +00:00
2004-08-22 22:29:09 +00:00
if ( ! inf - > groups )
{
2004-10-26 14:54:59 +00:00
Con_DPrintf ( " Model with no frames (%s) \n " , currententity - > model - > name ) ;
2004-11-23 01:23:45 +00:00
return false ;
2004-08-22 22:29:09 +00:00
}
if ( frame1 < 0 )
{
2004-10-26 14:54:59 +00:00
Con_DPrintf ( " Negative frame (%s) \n " , currententity - > model - > name ) ;
2004-08-22 22:29:09 +00:00
frame1 = 0 ;
}
if ( frame2 < 0 )
{
2004-10-26 14:54:59 +00:00
Con_DPrintf ( " Negative frame (%s) \n " , currententity - > model - > name ) ;
2004-08-22 22:29:09 +00:00
frame2 = frame1 ;
}
if ( frame1 > = inf - > groups )
{
2004-10-26 14:54:59 +00:00
Con_DPrintf ( " Too high frame %i (%s) \n " , frame1 , currententity - > model - > name ) ;
2005-08-03 23:14:59 +00:00
frame1 % = inf - > groups ;
2004-08-22 22:29:09 +00:00
}
if ( frame2 > = inf - > groups )
{
2004-10-26 14:54:59 +00:00
Con_DPrintf ( " Too high frame %i (%s) \n " , frame2 , currententity - > model - > name ) ;
2004-08-22 22:29:09 +00:00
frame2 = frame1 ;
}
if ( lerp < = 0 )
frame2 = frame1 ;
2004-11-23 01:23:45 +00:00
else if ( lerp > = 1 )
2004-08-22 22:29:09 +00:00
frame1 = frame2 ;
if ( numTempColours < inf - > numverts )
{
if ( tempColours )
BZ_Free ( tempColours ) ;
tempColours = BZ_Malloc ( sizeof ( * tempColours ) * inf - > numverts ) ;
numTempColours = inf - > numverts ;
}
if ( numTempNormals < inf - > numverts )
{
if ( tempNormals )
BZ_Free ( tempNormals ) ;
tempNormals = BZ_Malloc ( sizeof ( * tempNormals ) * inf - > numverts ) ;
numTempNormals = inf - > numverts ;
}
if ( numTempVertexCoords < inf - > numverts )
{
if ( tempVertexCoords )
BZ_Free ( tempVertexCoords ) ;
tempVertexCoords = BZ_Malloc ( sizeof ( * tempVertexCoords ) * inf - > numverts ) ;
numTempVertexCoords = inf - > numverts ;
}
2005-05-15 18:49:04 +00:00
mesh - > numvertexes = inf - > numverts ;
2004-10-19 16:10:14 +00:00
mesh - > indexes = ( index_t * ) ( ( char * ) inf + inf - > ofs_indexes ) ;
2004-08-22 22:29:09 +00:00
mesh - > numindexes = inf - > numindexes ;
2005-05-15 18:49:04 +00:00
if ( inf - > sharesverts )
return false ; //don't generate the new vertex positions. We still have them all.
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-09-20 23:25:38 +00:00
mesh - > st_array = ( vec2_t * ) ( ( char * ) inf + inf - > ofs_st_array ) ;
2004-08-22 22:29:09 +00:00
mesh - > lmst_array = NULL ;
mesh - > colors_array = tempColours ;
2004-09-20 23:25:38 +00:00
mesh - > trneighbors = ( int * ) ( ( char * ) inf + inf - > ofs_trineighbours ) ;
2004-11-23 01:23:45 +00:00
mesh - > normals_array = tempNormals ;
2005-07-16 00:53:08 +00:00
# endif
mesh - > xyz_array = tempVertexCoords ;
2004-11-23 01:23:45 +00:00
2004-09-20 23:25:38 +00:00
g1 = ( galiasgroup_t * ) ( ( char * ) inf + inf - > groupofs + sizeof ( galiasgroup_t ) * frame1 ) ;
g2 = ( galiasgroup_t * ) ( ( char * ) inf + inf - > groupofs + sizeof ( galiasgroup_t ) * frame2 ) ;
2004-08-22 22:29:09 +00:00
2004-11-23 01:23:45 +00:00
//we don't support meshes with one pose skeletal and annother not.
//we don't support meshes with one group skeletal and annother not.
2004-11-29 01:21:00 +00:00
# ifdef SKELETALMODELS
2005-08-03 23:14:59 +00:00
if ( inf - > numbones )
2004-11-23 01:23:45 +00:00
{
int l = 0 ;
float plerp [ 4 ] ;
float * pose [ 4 ] ;
float mlerp ; //minor lerp, poses within a group.
2005-08-03 23:14:59 +00:00
qboolean hirachy ;
2006-01-12 22:25:15 +00:00
if ( g1 - > isheirachical ! = g2 - > isheirachical | | lerp < 0 )
2005-08-03 23:14:59 +00:00
lerp = 0 ;
hirachy = g1 - > isheirachical ;
2004-11-23 01:23:45 +00:00
2005-07-01 19:23:00 +00:00
mlerp = ( fg1time ) * g1 - > rate ;
2004-11-23 01:23:45 +00:00
frame1 = mlerp ;
frame2 = frame1 + 1 ;
mlerp - = frame1 ;
2005-11-14 01:31:14 +00:00
if ( g1 - > loop )
{
frame1 = frame1 % g1 - > numposes ;
frame2 = frame2 % g1 - > numposes ;
}
else
{
frame1 = ( frame1 > g1 - > numposes - 1 ) ? g1 - > numposes - 1 : frame1 ;
frame2 = ( frame2 > g1 - > numposes - 1 ) ? g1 - > numposes - 1 : frame2 ;
}
2004-11-23 01:23:45 +00:00
2004-11-23 15:30:34 +00:00
plerp [ l ] = ( 1 - mlerp ) * ( 1 - lerp ) ;
2004-11-23 01:23:45 +00:00
if ( plerp [ l ] > 0 )
pose [ l + + ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame1 ) ;
2004-11-23 15:30:34 +00:00
plerp [ l ] = ( mlerp ) * ( 1 - lerp ) ;
2004-11-23 01:23:45 +00:00
if ( plerp [ l ] > 0 )
pose [ l + + ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame2 ) ;
2005-07-01 19:23:00 +00:00
if ( lerp )
{
mlerp = ( fg2time ) * g2 - > rate ;
frame1 = mlerp ;
frame2 = frame1 + 1 ;
mlerp - = frame1 ;
2005-11-14 01:31:14 +00:00
if ( g2 - > loop )
{
frame1 = frame1 % g2 - > numposes ;
frame2 = frame2 % g2 - > numposes ;
}
else
{
frame1 = ( frame1 > g2 - > numposes - 1 ) ? g2 - > numposes - 1 : frame1 ;
frame2 = ( frame2 > g2 - > numposes - 1 ) ? g2 - > numposes - 1 : frame2 ;
}
2005-07-01 19:23:00 +00:00
plerp [ l ] = ( 1 - mlerp ) * ( lerp ) ;
if ( plerp [ l ] > 0 )
pose [ l + + ] = ( float * ) ( ( char * ) g2 + g2 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame1 ) ;
plerp [ l ] = ( mlerp ) * ( lerp ) ;
if ( plerp [ l ] > 0 )
pose [ l + + ] = ( float * ) ( ( char * ) g2 + g2 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame2 ) ;
}
2004-11-23 14:58:32 +00:00
/*
pose [ 0 ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs ) ;
2004-11-23 01:23:45 +00:00
plerp [ 0 ] = 1 ;
plerp [ 1 ] = 0 ;
plerp [ 3 ] = 0 ;
plerp [ 4 ] = 0 ;
l = 1 ;
*/
2005-08-03 23:14:59 +00:00
R_BuildSkeletalMesh ( mesh , plerp , pose , l , ( galiasbone_t * ) ( ( char * ) inf + inf - > ofsbones ) , inf - > numbones , ( galisskeletaltransforms_t * ) ( ( char * ) inf + inf - > ofstransforms ) , inf - > numtransforms , hirachy ) ;
2004-11-23 01:23:45 +00:00
return false ;
}
2004-11-29 01:21:00 +00:00
# endif
2004-11-23 01:23:45 +00:00
2004-08-22 22:29:09 +00:00
if ( g1 = = g2 ) //lerping within group is only done if not changing group
{
2005-07-01 19:23:00 +00:00
lerp = fg1time * g1 - > rate ;
2005-11-30 01:20:53 +00:00
if ( lerp < 0 ) lerp = 0 ; //hrm
2004-08-22 22:29:09 +00:00
frame1 = lerp ;
frame2 = frame1 + 1 ;
lerp - = frame1 ;
2005-11-14 01:31:14 +00:00
if ( g1 - > loop )
{
frame1 = frame1 % g1 - > numposes ;
frame2 = frame2 % g1 - > numposes ;
}
else
{
frame1 = ( frame1 > g1 - > numposes - 1 ) ? g1 - > numposes - 1 : frame1 ;
frame2 = ( frame2 > g1 - > numposes - 1 ) ? g1 - > numposes - 1 : frame2 ;
}
2004-08-22 22:29:09 +00:00
}
2004-11-23 01:23:45 +00:00
else //don't bother with a four way lerp. Yeah, this will produce jerkyness with models with just framegroups.
2004-08-22 22:29:09 +00:00
{
frame1 = 0 ;
frame2 = 0 ;
}
R_LerpFrames ( mesh , ( galiaspose_t * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( galiaspose_t ) * frame1 ) ,
( galiaspose_t * ) ( ( char * ) g2 + g2 - > poseofs + sizeof ( galiaspose_t ) * frame2 ) ,
2006-06-08 06:24:07 +00:00
1 - lerp , ( qbyte ) ( alpha * 255 ) , currententity - > fatness , nolightdir ) ;
2004-11-23 01:23:45 +00:00
return true ; //to allow the mesh to be dlighted.
2004-08-22 22:29:09 +00:00
}
void GL_GAliasFlushSkinCache ( void )
{
int i ;
bucket_t * b ;
for ( i = 0 ; i < skincolourmapped . numbuckets ; i + + )
{
while ( ( b = skincolourmapped . bucket [ i ] ) )
{
skincolourmapped . bucket [ i ] = b - > next ;
BZ_Free ( b - > data ) ;
}
}
if ( skincolourmapped . bucket )
BZ_Free ( skincolourmapped . bucket ) ;
skincolourmapped . bucket = NULL ;
skincolourmapped . numbuckets = 0 ;
}
2005-08-07 13:16:20 +00:00
static galiastexnum_t * GL_ChooseSkin ( galiasinfo_t * inf , char * modelname , int surfnum , entity_t * e )
2004-08-22 22:29:09 +00:00
{
galiasskin_t * skins ;
galiastexnum_t * texnums ;
int frame ;
int tc , bc ;
2005-06-14 04:52:10 +00:00
int local ;
2004-08-22 22:29:09 +00:00
2005-03-20 02:57:11 +00:00
if ( ! gl_nocolors . value )
2004-08-22 22:29:09 +00:00
{
2005-02-06 02:47:36 +00:00
if ( e - > scoreboard )
2004-09-26 00:30:42 +00:00
{
2005-02-06 02:47:36 +00:00
if ( ! e - > scoreboard - > skin )
Skin_Find ( e - > scoreboard ) ;
tc = e - > scoreboard - > topcolor ;
bc = e - > scoreboard - > bottomcolor ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
//colour forcing
if ( cl . splitclients < 2 & & ! ( cl . fpd & FPD_NO_FORCE_COLOR ) ) //no colour/skin forcing in splitscreen.
2004-09-26 00:30:42 +00:00
{
2005-06-14 04:52:10 +00:00
if ( cl . teamplay & & cl . spectator )
{
local = Cam_TrackNum ( 0 ) ;
if ( local < 0 )
local = cl . playernum [ 0 ] ;
}
else
local = cl . playernum [ 0 ] ;
if ( cl . teamplay & & ! strcmp ( e - > scoreboard - > team , cl . players [ local ] . team ) )
2005-02-06 02:47:36 +00:00
{
if ( cl_teamtopcolor > = 0 )
tc = cl_teamtopcolor ;
if ( cl_teambottomcolor > = 0 )
bc = cl_teambottomcolor ;
}
else
{
if ( cl_enemytopcolor > = 0 )
tc = cl_enemytopcolor ;
if ( cl_enemybottomcolor > = 0 )
bc = cl_enemybottomcolor ;
}
2004-09-26 00:30:42 +00:00
}
}
2004-08-22 22:29:09 +00:00
else
{
2005-02-06 02:47:36 +00:00
tc = 1 ;
bc = 1 ;
2004-08-22 22:29:09 +00:00
}
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
if ( tc ! = 1 | | bc ! = 1 | | ( e - > scoreboard & & e - > scoreboard - > skin ) )
2004-08-22 22:29:09 +00:00
{
2005-02-06 02:47:36 +00:00
int inwidth , inheight ;
int tinwidth , tinheight ;
char * skinname ;
qbyte * original ;
int cc ;
galiascolourmapped_t * cm ;
2005-03-20 02:57:11 +00:00
char hashname [ 512 ] ;
2005-02-06 02:47:36 +00:00
cc = ( tc < < 4 ) | bc ;
2005-03-20 02:57:11 +00:00
if ( e - > scoreboard & & e - > scoreboard - > skin & & ! gl_nocolors . value )
2004-08-22 22:29:09 +00:00
{
2006-03-06 01:41:09 +00:00
snprintf ( hashname , sizeof ( hashname ) , " %s$%s$%i " , modelname , e - > scoreboard - > skin - > name , surfnum ) ;
2005-08-07 13:16:20 +00:00
skinname = hashname ;
}
else if ( surfnum )
{
2006-03-06 01:41:09 +00:00
snprintf ( hashname , sizeof ( hashname ) , " %s$%i " , modelname , surfnum ) ;
2005-03-20 02:57:11 +00:00
skinname = hashname ;
2004-08-22 22:29:09 +00:00
}
2005-03-20 02:57:11 +00:00
else
skinname = modelname ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
if ( ! skincolourmapped . numbuckets )
Hash_InitTable ( & skincolourmapped , 256 , BZ_Malloc ( Hash_BytesForBuckets ( 256 ) ) ) ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
for ( cm = Hash_Get ( & skincolourmapped , skinname ) ; cm ; cm = Hash_GetNext ( & skincolourmapped , skinname , cm ) )
{
if ( cm - > colour = = cc & & cm - > skinnum = = e - > skinnum )
{
return & cm - > texnum ;
}
}
2005-11-26 03:02:55 +00:00
2005-03-20 02:57:11 +00:00
if ( ! inf - > numskins )
{
skins = NULL ;
texnums = NULL ;
}
else
{
skins = ( galiasskin_t * ) ( ( char * ) inf + inf - > ofsskins ) ;
if ( ! skins - > texnums )
return NULL ;
if ( e - > skinnum > = 0 & & e - > skinnum < inf - > numskins )
skins + = e - > skinnum ;
texnums = ( galiastexnum_t * ) ( ( char * ) skins + skins - > ofstexnums ) ;
}
2005-02-06 02:47:36 +00:00
//colourmap isn't present yet.
cm = BZ_Malloc ( sizeof ( * cm ) ) ;
Q_strncpyz ( cm - > name , skinname , sizeof ( cm - > name ) ) ;
2005-02-09 19:32:09 +00:00
Hash_Add ( & skincolourmapped , cm - > name , cm , & cm - > bucket ) ;
2005-02-06 02:47:36 +00:00
cm - > colour = cc ;
cm - > skinnum = e - > skinnum ;
cm - > texnum . fullbright = 0 ;
cm - > texnum . base = 0 ;
2005-03-20 02:57:11 +00:00
if ( ! texnums )
{ //load just the skin
if ( e - > scoreboard & & e - > scoreboard - > skin )
2005-11-26 03:02:55 +00:00
{
2006-02-22 23:49:35 +00:00
if ( cls . protocol = = CP_QUAKE2 )
{
original = Skin_Cache32 ( e - > scoreboard - > skin ) ;
if ( original )
{
inwidth = e - > scoreboard - > skin - > width ;
inheight = e - > scoreboard - > skin - > height ;
cm - > texnum . base = cm - > texnum . fullbright = GL_LoadTexture32 ( e - > scoreboard - > skin - > name , inwidth , inheight , ( unsigned int * ) original , true , false ) ;
return & cm - > texnum ;
}
}
else
{
original = Skin_Cache8 ( e - > scoreboard - > skin ) ;
if ( original )
{
inwidth = e - > scoreboard - > skin - > width ;
inheight = e - > scoreboard - > skin - > height ;
cm - > texnum . base = cm - > texnum . fullbright = GL_LoadTexture ( e - > scoreboard - > skin - > name , inwidth , inheight , original , true , false ) ;
return & cm - > texnum ;
}
}
cm - > texnum . base = Mod_LoadHiResTexture ( e - > scoreboard - > skin - > name , " skins " , true , false , true ) ;
2005-03-20 02:57:11 +00:00
return & cm - > texnum ;
}
return NULL ;
}
2005-02-06 02:47:36 +00:00
cm - > texnum . bump = texnums [ cm - > skinnum ] . bump ; //can't colour bumpmapping
2006-02-22 23:49:35 +00:00
if ( cls . protocol ! = CP_QUAKE2 & & ( ( ! texnums | | ! strcmp ( modelname , " progs/player.mdl " ) ) & & e - > scoreboard & & e - > scoreboard - > skin ) )
2004-12-09 23:45:14 +00:00
{
2005-02-06 02:47:36 +00:00
original = Skin_Cache8 ( e - > scoreboard - > skin ) ;
inwidth = e - > scoreboard - > skin - > width ;
inheight = e - > scoreboard - > skin - > height ;
2004-12-09 23:45:14 +00:00
}
else
{
original = NULL ;
inwidth = 0 ;
2005-03-28 00:11:59 +00:00
inheight = 0 ;
2004-12-09 23:45:14 +00:00
}
2005-02-06 02:47:36 +00:00
if ( ! original )
2004-08-22 22:29:09 +00:00
{
2005-02-06 02:47:36 +00:00
if ( skins - > ofstexels )
{
original = ( qbyte * ) skins + skins - > ofstexels ;
inwidth = skins - > skinwidth ;
inheight = skins - > skinheight ;
}
2004-08-22 22:29:09 +00:00
else
{
2005-02-06 02:47:36 +00:00
original = NULL ;
inwidth = 0 ;
inheight = 0 ;
2004-08-22 22:29:09 +00:00
}
}
2005-02-06 02:47:36 +00:00
tinwidth = skins - > skinwidth ;
tinheight = skins - > skinheight ;
if ( original )
2004-08-22 22:29:09 +00:00
{
2005-02-06 02:47:36 +00:00
int i , j ;
qbyte translate [ 256 ] ;
unsigned translate32 [ 256 ] ;
static unsigned pixels [ 512 * 512 ] ;
unsigned * out ;
unsigned frac , fracstep ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
unsigned scaled_width , scaled_height ;
qbyte * inrow ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
texnums = & cm - > texnum ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
texnums - > base = 0 ;
texnums - > fullbright = 0 ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
scaled_width = gl_max_size . value < 512 ? gl_max_size . value : 512 ;
scaled_height = gl_max_size . value < 512 ? gl_max_size . value : 512 ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
for ( i = 0 ; i < 256 ; i + + )
translate [ i ] = i ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
tc < < = 4 ;
bc < < = 4 ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
for ( i = 0 ; i < 16 ; i + + )
{
if ( tc < 128 ) // the artists made some backwards ranges. sigh.
translate [ TOP_RANGE + i ] = tc + i ;
else
translate [ TOP_RANGE + i ] = tc + 15 - i ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
if ( bc < 128 )
translate [ BOTTOM_RANGE + i ] = bc + i ;
else
translate [ BOTTOM_RANGE + i ] = bc + 15 - i ;
}
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
for ( i = 0 ; i < 256 ; i + + )
translate32 [ i ] = d_8to24rgbtable [ translate [ i ] ] ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
out = pixels ;
fracstep = tinwidth * 0x10000 / scaled_width ;
for ( i = 0 ; i < scaled_height ; i + + , out + = scaled_width )
2004-08-22 22:29:09 +00:00
{
2005-03-28 00:11:59 +00:00
inrow = original + inwidth * ( i * inheight / scaled_height ) ;
2005-02-06 02:47:36 +00:00
frac = fracstep > > 1 ;
for ( j = 0 ; j < scaled_width ; j + = 4 )
{
out [ j ] = translate32 [ inrow [ frac > > 16 ] ] ;
frac + = fracstep ;
out [ j + 1 ] = translate32 [ inrow [ frac > > 16 ] ] ;
frac + = fracstep ;
out [ j + 2 ] = translate32 [ inrow [ frac > > 16 ] ] ;
frac + = fracstep ;
out [ j + 3 ] = translate32 [ inrow [ frac > > 16 ] ] ;
frac + = fracstep ;
}
2004-08-22 22:29:09 +00:00
}
2005-02-06 02:47:36 +00:00
texnums - > base = texture_extension_number + + ;
GL_Bind ( texnums - > base ) ;
qglTexImage2D ( GL_TEXTURE_2D , 0 , gl_solid_format , scaled_width , scaled_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
//now do the fullbrights.
out = pixels ;
fracstep = tinwidth * 0x10000 / scaled_width ;
for ( i = 0 ; i < scaled_height ; i + + , out + = scaled_width )
{
2005-03-28 00:11:59 +00:00
inrow = original + inwidth * ( i * inheight / scaled_height ) ;
2005-02-06 02:47:36 +00:00
frac = fracstep > > 1 ;
for ( j = 0 ; j < scaled_width ; j + = 1 )
{
if ( inrow [ frac > > 16 ] < 255 - vid . fullbright )
( ( char * ) ( & out [ j ] ) ) [ 3 ] = 0 ; //alpha 0
frac + = fracstep ;
}
}
texnums - > fullbright = texture_extension_number + + ;
GL_Bind ( texnums - > fullbright ) ;
qglTexImage2D ( GL_TEXTURE_2D , 0 , gl_alpha_format , scaled_width , scaled_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
qglTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
2004-08-22 22:29:09 +00:00
}
2005-02-06 02:47:36 +00:00
else
{
skins = ( galiasskin_t * ) ( ( char * ) inf + inf - > ofsskins ) ;
if ( e - > skinnum > = 0 & & e - > skinnum < inf - > numskins )
skins + = e - > skinnum ;
2005-11-26 03:02:55 +00:00
2006-02-22 23:49:35 +00:00
if ( ! inf - > numskins | | ! skins - > texnums )
2005-02-06 02:47:36 +00:00
return NULL ;
2005-11-26 03:02:55 +00:00
2005-02-06 02:47:36 +00:00
frame = cl . time * skins - > skinspeed ;
frame = frame % skins - > texnums ;
texnums = ( galiastexnum_t * ) ( ( char * ) skins + skins - > ofstexnums + frame * sizeof ( galiastexnum_t ) ) ;
memcpy ( & cm - > texnum , texnums , sizeof ( cm - > texnum ) ) ;
}
return & cm - > texnum ;
2004-08-22 22:29:09 +00:00
}
}
2005-03-18 06:14:33 +00:00
if ( ! inf - > numskins )
return NULL ;
2004-09-13 04:16:52 +00:00
skins = ( galiasskin_t * ) ( ( char * ) inf + inf - > ofsskins ) ;
2004-08-22 22:29:09 +00:00
if ( e - > skinnum > = 0 & & e - > skinnum < inf - > numskins )
skins + = e - > skinnum ;
2005-08-03 23:14:59 +00:00
else
2006-03-15 20:07:43 +00:00
{
2005-08-03 23:14:59 +00:00
Con_DPrintf ( " Skin number out of range \n " ) ;
2006-03-15 20:07:43 +00:00
if ( ! inf - > numskins )
return NULL ;
}
2004-08-22 22:29:09 +00:00
if ( ! skins - > texnums )
return NULL ;
frame = cl . time * skins - > skinspeed ;
frame = frame % skins - > texnums ;
2004-09-13 04:16:52 +00:00
texnums = ( galiastexnum_t * ) ( ( char * ) skins + skins - > ofstexnums + frame * sizeof ( galiastexnum_t ) ) ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
return texnums ;
}
static int numFacing ;
static qbyte * triangleFacing ;
static void R_CalcFacing ( mesh_t * mesh , vec3_t lightpos )
{
float * v1 , * v2 , * v3 ;
vec3_t d1 , d2 , norm ;
int i ;
2004-10-19 16:10:14 +00:00
index_t * indexes = mesh - > indexes ;
2004-08-22 22:29:09 +00:00
int numtris = mesh - > numindexes / 3 ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
if ( numFacing < numtris )
{
if ( triangleFacing )
BZ_Free ( triangleFacing ) ;
triangleFacing = BZ_Malloc ( sizeof ( * triangleFacing ) * numtris ) ;
numFacing = numtris ;
}
for ( i = 0 ; i < numtris ; i + + , indexes + = 3 )
{
v1 = ( float * ) ( mesh - > xyz_array + indexes [ 0 ] ) ;
v2 = ( float * ) ( mesh - > xyz_array + indexes [ 1 ] ) ;
v3 = ( float * ) ( mesh - > xyz_array + indexes [ 2 ] ) ;
VectorSubtract ( v1 , v2 , d1 ) ;
VectorSubtract ( v3 , v2 , d2 ) ;
CrossProduct ( d1 , d2 , norm ) ;
triangleFacing [ i ] = ( ( lightpos [ 0 ] - v1 [ 0 ] ) * norm [ 0 ] + ( lightpos [ 1 ] - v1 [ 1 ] ) * norm [ 1 ] + ( lightpos [ 2 ] - v1 [ 2 ] ) * norm [ 2 ] ) > 0 ;
}
}
# define PROJECTION_DISTANCE 30000
static int numProjectedShadowVerts ;
static vec3_t * ProjectedShadowVerts ;
static void R_ProjectShadowVolume ( mesh_t * mesh , vec3_t lightpos )
{
int numverts = mesh - > numvertexes ;
int i ;
2005-05-13 10:42:48 +00:00
vec3_t * input = mesh - > xyz_array ;
2004-08-22 22:29:09 +00:00
vec3_t * projected ;
if ( numProjectedShadowVerts < numverts )
{
if ( ProjectedShadowVerts )
BZ_Free ( ProjectedShadowVerts ) ;
ProjectedShadowVerts = BZ_Malloc ( sizeof ( * ProjectedShadowVerts ) * numverts ) ;
numProjectedShadowVerts = numverts ;
}
projected = ProjectedShadowVerts ;
for ( i = 0 ; i < numverts ; i + + )
{
projected [ i ] [ 0 ] = input [ i ] [ 0 ] + ( input [ i ] [ 0 ] - lightpos [ 0 ] ) * PROJECTION_DISTANCE ;
projected [ i ] [ 1 ] = input [ i ] [ 1 ] + ( input [ i ] [ 1 ] - lightpos [ 1 ] ) * PROJECTION_DISTANCE ;
projected [ i ] [ 2 ] = input [ i ] [ 2 ] + ( input [ i ] [ 2 ] - lightpos [ 2 ] ) * PROJECTION_DISTANCE ;
}
}
static void R_DrawShadowVolume ( mesh_t * mesh )
{
int t ;
vec3_t * proj = ProjectedShadowVerts ;
2005-05-13 10:42:48 +00:00
vec3_t * verts = mesh - > xyz_array ;
2004-10-19 16:10:14 +00:00
index_t * indexes = mesh - > indexes ;
2004-08-22 22:29:09 +00:00
int * neighbours = mesh - > trneighbors ;
int numtris = mesh - > numindexes / 3 ;
2005-01-07 02:54:22 +00:00
qglBegin ( GL_TRIANGLES ) ;
2004-08-22 22:29:09 +00:00
for ( t = 0 ; t < numtris ; t + + )
{
if ( triangleFacing [ t ] )
{
//draw front
2005-01-07 02:54:22 +00:00
qglVertex3fv ( verts [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 2 ] ] ) ;
2004-08-22 22:29:09 +00:00
//draw back
2005-01-07 02:54:22 +00:00
qglVertex3fv ( proj [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 2 ] ] ) ;
2004-08-22 22:29:09 +00:00
//draw side caps
if ( neighbours [ t * 3 + 0 ] < 0 | | ! triangleFacing [ neighbours [ t * 3 + 0 ] ] )
{
2005-01-07 02:54:22 +00:00
qglVertex3fv ( verts [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 1 ] ] ) ;
2004-08-22 22:29:09 +00:00
}
if ( neighbours [ t * 3 + 1 ] < 0 | | ! triangleFacing [ neighbours [ t * 3 + 1 ] ] )
{
2005-01-07 02:54:22 +00:00
qglVertex3fv ( verts [ indexes [ t * 3 + 2 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 2 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 1 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 2 ] ] ) ;
2004-08-22 22:29:09 +00:00
}
if ( neighbours [ t * 3 + 2 ] < 0 | | ! triangleFacing [ neighbours [ t * 3 + 2 ] ] )
{
2005-01-07 02:54:22 +00:00
qglVertex3fv ( verts [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 2 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 2 ] ] ) ;
qglVertex3fv ( verts [ indexes [ t * 3 + 0 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 2 ] ] ) ;
qglVertex3fv ( proj [ indexes [ t * 3 + 0 ] ] ) ;
2004-08-22 22:29:09 +00:00
}
}
}
2005-01-07 02:54:22 +00:00
qglEnd ( ) ;
2004-08-22 22:29:09 +00:00
}
2005-02-09 19:32:09 +00:00
void GL_DrawAliasMesh_Sketch ( mesh_t * mesh )
2004-12-11 03:45:47 +00:00
{
int i ;
extern int gldepthfunc ;
# ifdef Q3SHADERS
R_UnlockArrays ( ) ;
# endif
2005-01-07 02:54:22 +00:00
qglDepthFunc ( gldepthfunc ) ;
qglDepthMask ( 1 ) ;
2004-12-11 03:45:47 +00:00
2005-11-26 03:02:55 +00:00
if ( gldepthmin = = 0.5 )
2004-12-11 03:45:47 +00:00
qglCullFace ( GL_BACK ) ;
else
qglCullFace ( GL_FRONT ) ;
GL_TexEnv ( GL_MODULATE ) ;
2005-01-07 02:54:22 +00:00
qglDisable ( GL_TEXTURE_2D ) ;
2004-12-11 03:45:47 +00:00
2005-05-13 10:42:48 +00:00
qglVertexPointer ( 3 , GL_FLOAT , 0 , mesh - > xyz_array ) ;
2005-01-07 02:54:22 +00:00
qglEnableClientState ( GL_VERTEX_ARRAY ) ;
2004-12-11 03:45:47 +00:00
2005-01-07 02:54:22 +00:00
if ( mesh - > normals_array & & qglNormalPointer ) //d3d wrapper doesn't support normals, and this is only really needed for truform
2004-12-11 03:45:47 +00:00
{
2005-01-07 02:54:22 +00:00
qglNormalPointer ( GL_FLOAT , 0 , mesh - > normals_array ) ;
qglEnableClientState ( GL_NORMAL_ARRAY ) ;
2004-12-11 03:45:47 +00:00
}
2005-08-03 23:14:59 +00:00
qglColor3f ( 1 , 1 , 1 ) ;
/* if (mesh->colors_array)
2004-12-11 03:45:47 +00:00
{
2005-01-07 02:54:22 +00:00
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , mesh - > colors_array ) ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
2004-12-11 03:45:47 +00:00
}
else
2005-08-03 23:14:59 +00:00
*/ qglDisableClientState ( GL_COLOR_ARRAY ) ;
2004-12-11 03:45:47 +00:00
2005-01-07 02:54:22 +00:00
qglDrawElements ( GL_TRIANGLES , mesh - > numindexes , GL_UNSIGNED_INT , mesh - > indexes ) ;
2004-12-11 03:45:47 +00:00
2005-01-07 02:54:22 +00:00
qglDisableClientState ( GL_VERTEX_ARRAY ) ;
qglDisableClientState ( GL_COLOR_ARRAY ) ;
qglDisableClientState ( GL_NORMAL_ARRAY ) ;
2004-12-11 03:45:47 +00:00
2005-08-03 23:14:59 +00:00
if ( mesh - > colors_array )
qglColor4ub ( 0 , 0 , 0 , mesh - > colors_array [ 0 ] [ 3 ] ) ;
else
qglColor3f ( 0 , 0 , 0 ) ;
2005-01-07 02:54:22 +00:00
qglBegin ( GL_LINES ) ;
2004-12-11 03:45:47 +00:00
for ( i = 0 ; i < mesh - > numindexes ; i + = 3 )
{
float * v1 , * v2 , * v3 ;
int n ;
v1 = mesh - > xyz_array [ mesh - > indexes [ i + 0 ] ] ;
v2 = mesh - > xyz_array [ mesh - > indexes [ i + 1 ] ] ;
v3 = mesh - > xyz_array [ mesh - > indexes [ i + 2 ] ] ;
for ( n = 0 ; n < 3 ; n + + ) //rember we do this triangle AND the neighbours
{
2005-01-07 02:54:22 +00:00
qglVertex3f ( v1 [ 0 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
2004-12-11 03:45:47 +00:00
v1 [ 1 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
v1 [ 2 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( v2 [ 0 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
2004-12-15 19:53:30 +00:00
v2 [ 1 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
v2 [ 2 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( v2 [ 0 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
2004-12-11 03:45:47 +00:00
v2 [ 1 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
v2 [ 2 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( v3 [ 0 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
2004-12-11 03:45:47 +00:00
v3 [ 1 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
v3 [ 2 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ) ;
2004-12-15 19:53:30 +00:00
2005-01-07 02:54:22 +00:00
qglVertex3f ( v3 [ 0 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
2004-12-15 19:53:30 +00:00
v3 [ 1 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
v3 [ 2 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( v1 [ 0 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
2004-12-15 19:53:30 +00:00
v1 [ 1 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ,
v1 [ 2 ] + 0.5 * ( rand ( ) / ( float ) RAND_MAX - 0.5 ) ) ;
2004-12-11 03:45:47 +00:00
}
}
2005-01-07 02:54:22 +00:00
qglEnd ( ) ;
2004-12-11 03:45:47 +00:00
# ifdef Q3SHADERS
R_IBrokeTheArrays ( ) ;
# endif
}
2005-05-17 02:36:54 +00:00
//called from sprite code.
/*
void GL_KnownState ( void )
{
extern int gldepthfunc ;
qglDepthFunc ( gldepthfunc ) ;
qglDepthMask ( 1 ) ;
2005-11-26 03:02:55 +00:00
if ( gldepthmin = = 0.5 )
2005-05-17 02:36:54 +00:00
qglCullFace ( GL_BACK ) ;
else
qglCullFace ( GL_FRONT ) ;
GL_TexEnv ( GL_MODULATE ) ;
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
}
*/
2004-10-19 16:10:14 +00:00
void GL_DrawAliasMesh ( mesh_t * mesh , int texnum )
{
extern int gldepthfunc ;
# ifdef Q3SHADERS
R_UnlockArrays ( ) ;
# endif
2005-01-07 02:54:22 +00:00
qglDepthFunc ( gldepthfunc ) ;
qglDepthMask ( 1 ) ;
2005-04-26 16:04:12 +00:00
2004-10-19 16:10:14 +00:00
GL_Bind ( texnum ) ;
2005-11-26 03:02:55 +00:00
if ( gldepthmin = = 0.5 )
2004-12-09 23:45:14 +00:00
qglCullFace ( GL_BACK ) ;
else
qglCullFace ( GL_FRONT ) ;
2004-10-19 16:10:14 +00:00
2004-11-13 17:31:04 +00:00
GL_TexEnv ( GL_MODULATE ) ;
2005-05-13 10:42:48 +00:00
qglVertexPointer ( 3 , GL_FLOAT , 0 , mesh - > xyz_array ) ;
2005-01-07 02:54:22 +00:00
qglEnableClientState ( GL_VERTEX_ARRAY ) ;
2004-10-19 16:10:14 +00:00
2005-01-07 02:54:22 +00:00
if ( mesh - > normals_array & & qglNormalPointer ) //d3d wrapper doesn't support normals, and this is only really needed for truform
2004-10-19 16:10:14 +00:00
{
2005-01-07 02:54:22 +00:00
qglNormalPointer ( GL_FLOAT , 0 , mesh - > normals_array ) ;
qglEnableClientState ( GL_NORMAL_ARRAY ) ;
2004-10-19 16:10:14 +00:00
}
if ( mesh - > colors_array )
{
2005-01-07 02:54:22 +00:00
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , mesh - > colors_array ) ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
2004-10-19 16:10:14 +00:00
}
2004-11-13 17:31:04 +00:00
else
2005-01-07 02:54:22 +00:00
qglDisableClientState ( GL_COLOR_ARRAY ) ;
2004-10-19 16:10:14 +00:00
2005-01-07 02:54:22 +00:00
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , mesh - > st_array ) ;
2004-10-19 16:10:14 +00:00
2005-09-29 23:28:08 +00:00
qglDrawRangeElements ( GL_TRIANGLES , 0 , mesh - > numvertexes , mesh - > numindexes , GL_UNSIGNED_INT , mesh - > indexes ) ;
2004-10-19 16:10:14 +00:00
2005-01-07 02:54:22 +00:00
qglDisableClientState ( GL_VERTEX_ARRAY ) ;
qglDisableClientState ( GL_COLOR_ARRAY ) ;
qglDisableClientState ( GL_NORMAL_ARRAY ) ;
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
2004-10-19 16:10:14 +00:00
# ifdef Q3SHADERS
R_IBrokeTheArrays ( ) ;
# endif
}
2005-11-26 03:02:55 +00:00
qboolean R_CullEntityBox ( entity_t * e , vec3_t modmins , vec3_t modmaxs )
{
int i ;
vec3_t wmin , wmax ;
float fmin , fmax ;
//convert the model's bbox to the expanded maximum size of the entity, as drawn with this model.
//The result is an axial box, which we pass to R_CullBox
for ( i = 0 ; i < 3 ; i + + )
{
fmin = DotProduct ( modmins , e - > axis [ i ] ) ;
fmax = DotProduct ( modmaxs , e - > axis [ i ] ) ;
if ( fmin > - 16 )
fmin = - 16 ;
if ( fmax < 16 )
fmax = 16 ;
if ( fmin < fmax )
{
wmin [ i ] = e - > origin [ i ] + fmin ;
wmax [ i ] = e - > origin [ i ] + fmax ;
}
else
{ //box went inside out
wmin [ i ] = e - > origin [ i ] + fmax ;
wmax [ i ] = e - > origin [ i ] + fmin ;
}
}
return R_CullBox ( wmin , wmax ) ;
}
2006-01-28 02:43:10 +00:00
# ifdef Q3SHADERS
mfog_t * CM_FogForOrigin ( vec3_t org ) ;
# endif
2004-08-22 22:29:09 +00:00
void R_DrawGAliasModel ( entity_t * e )
{
2004-12-11 03:45:47 +00:00
extern cvar_t r_drawflat ;
2004-11-27 08:16:25 +00:00
model_t * clmodel ;
2004-08-22 22:29:09 +00:00
vec3_t dist ;
vec_t add ;
int i ;
galiasinfo_t * inf ;
mesh_t mesh ;
galiastexnum_t * skin ;
float entScale ;
vec3_t lightdir ;
2005-05-26 12:55:34 +00:00
vec3_t saveorg ;
# ifdef Q3SHADERS
mfog_t * fog ;
# endif
2005-08-07 13:16:20 +00:00
int surfnum ;
2005-05-26 12:55:34 +00:00
2004-08-22 22:29:09 +00:00
float tmatrix [ 3 ] [ 4 ] ;
2006-02-27 00:42:25 +00:00
qboolean needrecolour ;
2006-06-08 06:24:07 +00:00
qboolean nolightdir ;
2006-02-27 00:42:25 +00:00
2004-10-26 14:54:59 +00:00
currententity = e ;
2005-02-28 07:16:19 +00:00
// if (e->flags & Q2RF_VIEWERMODEL && e->keynum == cl.playernum[r_refdef.currentplayernum]+1)
// return;
2004-08-22 22:29:09 +00:00
2005-04-16 16:21:27 +00:00
if ( r_secondaryview & & e - > flags & Q2RF_WEAPONMODEL )
return ;
2004-11-27 08:16:25 +00:00
{
extern int cl_playerindex ;
if ( e - > scoreboard & & e - > model = = cl . model_precache [ cl_playerindex ] )
{
clmodel = e - > scoreboard - > model ;
if ( ! clmodel | | clmodel - > type ! = mod_alias )
clmodel = e - > model ;
}
else
clmodel = e - > model ;
}
2005-03-12 23:40:42 +00:00
if ( ! ( e - > flags & Q2RF_WEAPONMODEL ) )
2005-11-26 03:02:55 +00:00
if ( R_CullEntityBox ( e , clmodel - > mins , clmodel - > maxs ) )
2005-03-12 23:40:42 +00:00
return ;
2004-08-22 22:29:09 +00:00
2005-04-18 17:12:18 +00:00
if ( ! ( r_refdef . flags & Q2RDF_NOWORLDMODEL ) )
2004-08-22 22:29:09 +00:00
{
2005-04-18 17:12:18 +00:00
if ( e - > flags & Q2RF_WEAPONMODEL )
2006-09-17 00:59:22 +00:00
cl . worldmodel - > funcs . LightPointValues ( cl . worldmodel , r_refdef . vieworg , shadelight , ambientlight , lightdir ) ;
2005-04-18 17:12:18 +00:00
else
2006-09-17 00:59:22 +00:00
cl . worldmodel - > funcs . LightPointValues ( cl . worldmodel , e - > origin , shadelight , ambientlight , lightdir ) ;
2004-08-22 22:29:09 +00:00
}
else
{
ambientlight [ 0 ] = ambientlight [ 1 ] = ambientlight [ 2 ] = shadelight [ 0 ] = shadelight [ 1 ] = shadelight [ 2 ] = 255 ;
lightdir [ 0 ] = 0 ;
lightdir [ 1 ] = 1 ;
lightdir [ 2 ] = 1 ;
}
2004-11-18 17:55:04 +00:00
if ( ! r_vertexdlights . value )
2004-08-22 22:29:09 +00:00
{
2006-05-11 03:14:41 +00:00
for ( i = 0 ; i < dlights_running ; i + + )
2004-08-22 22:29:09 +00:00
{
2004-11-27 08:16:25 +00:00
if ( cl_dlights [ i ] . radius )
2004-09-07 23:09:15 +00:00
{
VectorSubtract ( e - > origin ,
cl_dlights [ i ] . origin ,
dist ) ;
add = cl_dlights [ i ] . radius - Length ( dist ) ;
if ( add > 0 ) {
add * = 5 ;
ambientlight [ 0 ] + = add * cl_dlights [ i ] . color [ 0 ] ;
ambientlight [ 1 ] + = add * cl_dlights [ i ] . color [ 1 ] ;
ambientlight [ 2 ] + = add * cl_dlights [ i ] . color [ 2 ] ;
//ZOID models should be affected by dlights as well
shadelight [ 0 ] + = add * cl_dlights [ i ] . color [ 0 ] ;
shadelight [ 1 ] + = add * cl_dlights [ i ] . color [ 1 ] ;
shadelight [ 2 ] + = add * cl_dlights [ i ] . color [ 2 ] ;
}
2004-08-22 22:29:09 +00:00
}
}
}
2004-09-07 23:09:15 +00:00
else
{
}
2004-08-22 22:29:09 +00:00
for ( i = 0 ; i < 3 ; i + + ) //clamp light so it doesn't get vulgar.
{
if ( ambientlight [ i ] > 128 )
ambientlight [ i ] = 128 ;
if ( ambientlight [ i ] + shadelight [ i ] > 192 )
shadelight [ i ] = 192 - ambientlight [ i ] ;
}
if ( e - > flags & Q2RF_WEAPONMODEL )
{
for ( i = 0 ; i < 3 ; i + + )
{
if ( ambientlight [ i ] < 24 )
ambientlight [ i ] = shadelight [ i ] = 24 ;
}
}
//MORE HUGE HACKS! WHEN WILL THEY CEASE!
// clamp lighting so it doesn't overbright as much
// ZOID: never allow players to go totally black
2006-06-08 06:24:07 +00:00
nolightdir = false ;
2006-03-06 00:19:46 +00:00
if ( clmodel - > engineflags & MDLF_PLAYER )
2004-08-22 22:29:09 +00:00
{
float fb = r_fullbrightSkins . value ;
if ( fb > cls . allow_fbskins )
fb = cls . allow_fbskins ;
if ( fb < 0 )
fb = 0 ;
if ( fb )
{
2006-05-11 02:30:13 +00:00
extern cvar_t r_fb_models ;
if ( fb > = 1 & & r_fb_models . value )
{
2006-06-08 06:24:07 +00:00
ambientlight [ 0 ] = ambientlight [ 1 ] = ambientlight [ 2 ] = 4096 ;
shadelight [ 0 ] = shadelight [ 1 ] = shadelight [ 2 ] = 4096 ;
nolightdir = true ;
2006-05-11 02:30:13 +00:00
}
else
2004-08-22 22:29:09 +00:00
{
2006-05-11 02:30:13 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
ambientlight [ i ] = max ( ambientlight [ i ] , 8 + fb * 120 ) ;
shadelight [ i ] = max ( shadelight [ i ] , 8 + fb * 120 ) ;
}
2004-08-22 22:29:09 +00:00
}
}
for ( i = 0 ; i < 3 ; i + + )
{
if ( ambientlight [ i ] < 8 )
ambientlight [ i ] = shadelight [ i ] = 8 ;
}
}
2006-06-08 06:24:07 +00:00
if ( clmodel - > engineflags & MDLF_FLAME )
2004-08-22 22:29:09 +00:00
{
2006-06-08 06:24:07 +00:00
shadelight [ 0 ] = shadelight [ 1 ] = shadelight [ 2 ] = 4096 ;
ambientlight [ 0 ] = ambientlight [ 1 ] = ambientlight [ 2 ] = 4096 ;
nolightdir = true ;
}
else
{
for ( i = 0 ; i < 3 ; i + + )
{
if ( ambientlight [ i ] > 128 )
ambientlight [ i ] = 128 ;
2004-08-22 22:29:09 +00:00
2006-06-08 06:24:07 +00:00
shadelight [ i ] / = 200.0 / 255 ;
ambientlight [ i ] / = 200.0 / 255 ;
}
2004-08-22 22:29:09 +00:00
}
if ( ( e - > drawflags & MLS_MASKIN ) = = MLS_ABSLIGHT )
{
shadelight [ 0 ] = shadelight [ 1 ] = shadelight [ 2 ] = e - > abslight ;
ambientlight [ 0 ] = ambientlight [ 1 ] = ambientlight [ 2 ] = 0 ;
}
2006-06-08 06:24:07 +00:00
if ( ( e - > drawflags & MLS_MASKIN ) = = MLS_FULLBRIGHT | | ( e - > flags & Q2RF_FULLBRIGHT ) )
2005-05-19 02:43:11 +00:00
{
shadelight [ 0 ] = shadelight [ 1 ] = shadelight [ 2 ] = 255 ;
ambientlight [ 0 ] = ambientlight [ 1 ] = ambientlight [ 2 ] = 0 ;
2006-06-08 06:24:07 +00:00
nolightdir = true ;
2005-05-19 02:43:11 +00:00
}
2004-08-22 22:29:09 +00:00
//#define SHOWLIGHTDIR
{ //lightdir is absolute, shadevector is relative
2005-02-28 07:16:19 +00:00
shadevector [ 0 ] = DotProduct ( lightdir , e - > axis [ 0 ] ) ;
shadevector [ 1 ] = DotProduct ( lightdir , e - > axis [ 1 ] ) ;
shadevector [ 2 ] = DotProduct ( lightdir , e - > axis [ 2 ] ) ;
2006-02-27 00:42:25 +00:00
if ( e - > flags & Q2RF_WEAPONMODEL )
{
vec3_t temp ;
temp [ 0 ] = DotProduct ( shadevector , vpn ) ;
temp [ 1 ] = DotProduct ( shadevector , vright ) ;
temp [ 2 ] = DotProduct ( shadevector , vup ) ;
VectorCopy ( temp , shadevector ) ;
}
2004-08-22 22:29:09 +00:00
VectorNormalize ( shadevector ) ;
VectorCopy ( shadevector , mesh . lightaxis [ 2 ] ) ;
VectorVectors ( mesh . lightaxis [ 2 ] , mesh . lightaxis [ 1 ] , mesh . lightaxis [ 0 ] ) ;
2005-02-28 07:16:19 +00:00
VectorInverse ( mesh . lightaxis [ 1 ] ) ;
2004-08-22 22:29:09 +00:00
}
2005-08-03 23:14:59 +00:00
if ( e - > flags & Q2RF_GLOW )
{
shadelight [ 0 ] + = sin ( cl . time ) * 0.25 ;
shadelight [ 1 ] + = sin ( cl . time ) * 0.25 ;
shadelight [ 2 ] + = sin ( cl . time ) * 0.25 ;
}
2005-11-26 03:02:55 +00:00
/*
2005-08-03 23:14:59 +00:00
VectorClear ( ambientlight ) ;
VectorClear ( shadelight ) ;
*/
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
/*
an = e - > angles [ 1 ] / 180 * M_PI ;
shadevector [ 0 ] = cos ( - an ) ;
shadevector [ 1 ] = sin ( - an ) ;
shadevector [ 2 ] = 1 ;
VectorNormalize ( shadevector ) ;
*/
GL_DisableMultitexture ( ) ;
2004-11-13 17:31:04 +00:00
GL_TexEnv ( GL_MODULATE ) ;
2004-08-22 22:29:09 +00:00
if ( gl_smoothmodels . value )
2005-01-07 02:54:22 +00:00
qglShadeModel ( GL_SMOOTH ) ;
2004-08-22 22:29:09 +00:00
if ( gl_affinemodels . value )
2005-01-07 02:54:22 +00:00
qglHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_FASTEST ) ;
2004-08-22 22:29:09 +00:00
2005-01-07 02:54:22 +00:00
qglDisable ( GL_ALPHA_TEST ) ;
2004-08-22 22:29:09 +00:00
if ( e - > flags & Q2RF_DEPTHHACK )
2005-01-07 02:54:22 +00:00
qglDepthRange ( gldepthmin , gldepthmin + 0.3 * ( gldepthmax - gldepthmin ) ) ;
2004-08-22 22:29:09 +00:00
// glColor3f( 1,1,1);
2005-05-17 02:36:54 +00:00
if ( e - > flags & Q2RF_ADDATIVE )
{
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( GL_ONE , GL_ONE ) ;
}
else if ( ( e - > model - > flags & EF_SPECIAL_TRANS ) ) //hexen2 flags.
2004-08-22 22:29:09 +00:00
{
2005-01-07 02:54:22 +00:00
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( GL_ONE_MINUS_SRC_ALPHA , GL_SRC_ALPHA ) ;
2004-08-22 22:29:09 +00:00
// glColor3f( 1,1,1);
2005-01-07 02:54:22 +00:00
qglDisable ( GL_CULL_FACE ) ;
2004-08-22 22:29:09 +00:00
}
else if ( e - > drawflags & DRF_TRANSLUCENT )
{
2005-01-07 02:54:22 +00:00
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2006-02-27 00:42:25 +00:00
e - > shaderRGBAf [ 3 ] = r_wateralpha . value ;
2004-08-22 22:29:09 +00:00
}
else if ( ( e - > model - > flags & EF_TRANSPARENT ) )
{
2005-01-07 02:54:22 +00:00
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2004-08-22 22:29:09 +00:00
}
else if ( ( e - > model - > flags & EF_HOLEY ) )
{
2005-01-07 02:54:22 +00:00
qglEnable ( GL_ALPHA_TEST ) ;
// qglEnable (GL_BLEND);
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2004-08-22 22:29:09 +00:00
}
2006-02-27 00:42:25 +00:00
else if ( e - > shaderRGBAf [ 3 ] < 1 )
2004-08-22 22:29:09 +00:00
{
2005-01-07 02:54:22 +00:00
qglEnable ( GL_BLEND ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2004-08-22 22:29:09 +00:00
}
else
{
2005-01-07 02:54:22 +00:00
qglDisable ( GL_BLEND ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2004-08-22 22:29:09 +00:00
}
2005-01-07 02:54:22 +00:00
// qglEnable (GL_ALPHA_TEST);
2004-08-22 22:29:09 +00:00
2005-01-07 02:54:22 +00:00
qglPushMatrix ( ) ;
2004-08-22 22:29:09 +00:00
R_RotateForEntity ( e ) ;
if ( e - > scale ! = 1 & & e - > scale ! = 0 ) //hexen 2 stuff
{
vec3_t scale ;
vec3_t scale_origin ;
float xyfact , zfact ;
scale [ 0 ] = ( clmodel - > maxs [ 0 ] - clmodel - > mins [ 0 ] ) / 255 ;
scale [ 1 ] = ( clmodel - > maxs [ 1 ] - clmodel - > mins [ 1 ] ) / 255 ;
scale [ 2 ] = ( clmodel - > maxs [ 2 ] - clmodel - > mins [ 2 ] ) / 255 ;
scale_origin [ 0 ] = clmodel - > mins [ 0 ] ;
scale_origin [ 1 ] = clmodel - > mins [ 1 ] ;
scale_origin [ 2 ] = clmodel - > mins [ 2 ] ;
2005-01-07 02:54:22 +00:00
/* qglScalef( 1/scale[0],
2004-08-22 22:29:09 +00:00
1 / scale [ 1 ] ,
1 / scale [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglTranslatef ( - scale_origin [ 0 ] ,
2004-08-22 22:29:09 +00:00
- scale_origin [ 1 ] ,
- scale_origin [ 2 ] ) ;
*/
if ( e - > scale ! = 0 & & e - > scale ! = 1 )
{
entScale = ( float ) e - > scale ;
switch ( e - > drawflags & SCALE_TYPE_MASKIN )
{
default :
case SCALE_TYPE_UNIFORM :
tmatrix [ 0 ] [ 0 ] = scale [ 0 ] * entScale ;
tmatrix [ 1 ] [ 1 ] = scale [ 1 ] * entScale ;
tmatrix [ 2 ] [ 2 ] = scale [ 2 ] * entScale ;
xyfact = zfact = ( entScale - 1.0 ) * 127.95 ;
break ;
case SCALE_TYPE_XYONLY :
tmatrix [ 0 ] [ 0 ] = scale [ 0 ] * entScale ;
tmatrix [ 1 ] [ 1 ] = scale [ 1 ] * entScale ;
tmatrix [ 2 ] [ 2 ] = scale [ 2 ] ;
xyfact = ( entScale - 1.0 ) * 127.95 ;
zfact = 1.0 ;
break ;
case SCALE_TYPE_ZONLY :
tmatrix [ 0 ] [ 0 ] = scale [ 0 ] ;
tmatrix [ 1 ] [ 1 ] = scale [ 1 ] ;
tmatrix [ 2 ] [ 2 ] = scale [ 2 ] * entScale ;
xyfact = 1.0 ;
zfact = ( entScale - 1.0 ) * 127.95 ;
break ;
}
switch ( currententity - > drawflags & SCALE_ORIGIN_MASKIN )
{
default :
case SCALE_ORIGIN_CENTER :
tmatrix [ 0 ] [ 3 ] = scale_origin [ 0 ] - scale [ 0 ] * xyfact ;
tmatrix [ 1 ] [ 3 ] = scale_origin [ 1 ] - scale [ 1 ] * xyfact ;
tmatrix [ 2 ] [ 3 ] = scale_origin [ 2 ] - scale [ 2 ] * zfact ;
break ;
case SCALE_ORIGIN_BOTTOM :
tmatrix [ 0 ] [ 3 ] = scale_origin [ 0 ] - scale [ 0 ] * xyfact ;
tmatrix [ 1 ] [ 3 ] = scale_origin [ 1 ] - scale [ 1 ] * xyfact ;
tmatrix [ 2 ] [ 3 ] = scale_origin [ 2 ] ;
break ;
case SCALE_ORIGIN_TOP :
tmatrix [ 0 ] [ 3 ] = scale_origin [ 0 ] - scale [ 0 ] * xyfact ;
tmatrix [ 1 ] [ 3 ] = scale_origin [ 1 ] - scale [ 1 ] * xyfact ;
tmatrix [ 2 ] [ 3 ] = scale_origin [ 2 ] - scale [ 2 ] * zfact * 2.0 ;
break ;
}
}
else
{
tmatrix [ 0 ] [ 0 ] = scale [ 0 ] ;
tmatrix [ 1 ] [ 1 ] = scale [ 1 ] ;
tmatrix [ 2 ] [ 2 ] = scale [ 2 ] ;
tmatrix [ 0 ] [ 3 ] = scale_origin [ 0 ] ;
tmatrix [ 1 ] [ 3 ] = scale_origin [ 1 ] ;
tmatrix [ 2 ] [ 3 ] = scale_origin [ 2 ] ;
}
/* if(clmodel->flags&EF_ROTATE)
{ // Floating motion
tmatrix [ 2 ] [ 3 ] + = sin ( currententity - > origin [ 0 ]
+ currententity - > origin [ 1 ] + ( cl . time * 3 ) ) * 5.5 ;
} */
2005-01-07 02:54:22 +00:00
qglTranslatef ( tmatrix [ 0 ] [ 3 ] , tmatrix [ 1 ] [ 3 ] , tmatrix [ 2 ] [ 3 ] ) ;
qglScalef ( tmatrix [ 0 ] [ 0 ] , tmatrix [ 1 ] [ 1 ] , tmatrix [ 2 ] [ 2 ] ) ;
2005-11-26 03:02:55 +00:00
2005-01-07 02:54:22 +00:00
qglScalef ( 1 / scale [ 0 ] ,
2004-08-22 22:29:09 +00:00
1 / scale [ 1 ] ,
1 / scale [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglTranslatef ( - scale_origin [ 0 ] ,
2004-08-22 22:29:09 +00:00
- scale_origin [ 1 ] ,
- scale_origin [ 2 ] ) ;
}
inf = GLMod_Extradata ( clmodel ) ;
if ( qglPNTrianglesfATI & & gl_ati_truform . value )
2005-01-07 02:54:22 +00:00
qglEnable ( GL_PN_TRIANGLES_ATI ) ;
2004-08-22 22:29:09 +00:00
2005-05-26 12:55:34 +00:00
if ( e - > flags & Q2RF_WEAPONMODEL )
{
VectorCopy ( currententity - > origin , saveorg ) ;
VectorCopy ( r_refdef . vieworg , currententity - > origin ) ;
}
# ifdef Q3SHADERS
fog = CM_FogForOrigin ( currententity - > origin ) ;
# endif
2006-02-27 00:42:25 +00:00
qglColor4f ( shadelight [ 0 ] / 255 , shadelight [ 1 ] / 255 , shadelight [ 2 ] / 255 , e - > shaderRGBAf [ 3 ] ) ;
2005-06-04 04:20:20 +00:00
2004-11-13 17:31:04 +00:00
memset ( & mesh , 0 , sizeof ( mesh ) ) ;
2005-08-07 13:16:20 +00:00
for ( surfnum = 0 ; inf ; ( ( inf - > nextsurf ) ? ( inf = ( galiasinfo_t * ) ( ( char * ) inf + inf - > nextsurf ) ) : ( inf = NULL ) ) , surfnum + + )
2004-08-22 22:29:09 +00:00
{
2006-06-08 06:24:07 +00:00
needrecolour = R_GAliasBuildMesh ( & mesh , inf , e - > frame , e - > oldframe , e - > lerpfrac , e - > shaderRGBAf [ 3 ] , e - > frame1time , e - > frame2time , nolightdir ) ;
2005-02-09 19:32:09 +00:00
2004-08-22 22:29:09 +00:00
c_alias_polys + = mesh . numindexes / 3 ;
2004-10-19 16:10:14 +00:00
2004-12-11 03:45:47 +00:00
if ( r_drawflat . value = = 2 )
2005-02-09 19:32:09 +00:00
{
2006-02-27 00:42:25 +00:00
if ( needrecolour )
R_GAliasApplyLighting ( & mesh , e - > origin , e - > angles , e - > shaderRGBAf ) ;
2005-02-09 19:32:09 +00:00
GL_DrawAliasMesh_Sketch ( & mesh ) ;
continue ;
}
# ifdef Q3SHADERS
else if ( currententity - > forcedshader )
{
meshbuffer_t mb ;
R_IBrokeTheArrays ( ) ;
mb . entity = & r_worldentity ;
mb . shader = currententity - > forcedshader ;
2005-05-26 12:55:34 +00:00
mb . fog = fog ;
2005-02-09 19:32:09 +00:00
mb . mesh = & mesh ;
2005-08-26 22:56:51 +00:00
mb . infokey = - 1 ; //currententity->keynum;
2005-02-09 19:32:09 +00:00
mb . dlightbits = 0 ;
R_PushMesh ( & mesh , mb . shader - > features | MF_NONBATCHED | MF_COLORS ) ;
R_RenderMeshBuffer ( & mb , false ) ;
continue ;
}
# endif
2005-08-07 13:16:20 +00:00
skin = GL_ChooseSkin ( inf , clmodel - > name , surfnum , e ) ;
2005-02-09 19:32:09 +00:00
2006-02-28 00:46:04 +00:00
if ( ! skin | | ( ( void * ) skin - > base = = NULL
2006-02-22 23:49:35 +00:00
# ifdef Q3SHADERS
& & skin - > shader = = NULL
# endif
) )
2004-10-19 16:10:14 +00:00
{
2006-02-27 00:42:25 +00:00
if ( needrecolour )
R_GAliasApplyLighting ( & mesh , e - > origin , e - > angles , e - > shaderRGBAf ) ;
2005-02-09 19:32:09 +00:00
GL_DrawAliasMesh_Sketch ( & mesh ) ;
2004-10-19 16:10:14 +00:00
}
# ifdef Q3SHADERS
else if ( skin - > shader )
{
meshbuffer_t mb ;
2005-05-17 02:36:54 +00:00
int olddst = skin - > shader - > numpasses ? skin - > shader - > passes [ 0 ] . blenddst : 0 ;
if ( e - > flags & Q2RF_ADDATIVE & & skin - > shader - > numpasses )
{ //hack the shader into submition.
skin - > shader - > passes [ 0 ] . blenddst = GL_ONE ;
2005-07-14 01:57:34 +00:00
skin - > shader - > passes [ 0 ] . flags & = ~ SHADER_PASS_DEPTHWRITE ;
2005-05-17 02:36:54 +00:00
}
2004-10-19 16:10:14 +00:00
mb . entity = & r_worldentity ;
mb . shader = skin - > shader ;
2005-05-26 12:55:34 +00:00
mb . fog = fog ;
2004-10-19 16:10:14 +00:00
mb . mesh = & mesh ;
2005-08-26 22:56:51 +00:00
mb . infokey = - 1 ; //currententity->keynum;
2004-10-19 16:10:14 +00:00
mb . dlightbits = 0 ;
R_IBrokeTheArrays ( ) ;
2004-11-13 17:31:04 +00:00
R_PushMesh ( & mesh , skin - > shader - > features | MF_NONBATCHED | MF_COLORS ) ;
2004-10-19 16:10:14 +00:00
R_RenderMeshBuffer ( & mb , false ) ;
2005-05-17 02:36:54 +00:00
if ( e - > flags & Q2RF_ADDATIVE & & skin - > shader - > numpasses )
{ //hack the shader into submition.
skin - > shader - > passes [ 0 ] . blenddst = olddst ;
}
2004-10-19 16:10:14 +00:00
}
# endif
2004-08-22 22:29:09 +00:00
else
{
2006-02-27 00:42:25 +00:00
if ( needrecolour )
R_GAliasApplyLighting ( & mesh , e - > origin , e - > angles , e - > shaderRGBAf ) ;
2005-01-07 02:54:22 +00:00
qglEnable ( GL_TEXTURE_2D ) ;
2004-10-19 16:10:14 +00:00
// if (skin->bump)
// GL_DrawMeshBump(&mesh, skin->base, 0, skin->bump, 0);
// else
GL_DrawAliasMesh ( & mesh , skin - > base ) ;
2004-08-22 22:29:09 +00:00
if ( skin - > fullbright & & r_fb_models . value & & cls . allow_luma )
{
mesh . colors_array = NULL ;
2005-01-07 02:54:22 +00:00
qglEnable ( GL_BLEND ) ;
2006-02-27 00:42:25 +00:00
qglColor4f ( e - > shaderRGBAf [ 0 ] , e - > shaderRGBAf [ 1 ] , e - > shaderRGBAf [ 2 ] , e - > shaderRGBAf [ 3 ] * r_fb_models . value ) ;
2004-08-22 22:29:09 +00:00
c_alias_polys + = mesh . numindexes / 3 ;
2005-08-03 23:14:59 +00:00
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE ) ;
2004-10-19 16:10:14 +00:00
GL_DrawAliasMesh ( & mesh , skin - > fullbright ) ;
2005-08-03 23:14:59 +00:00
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2004-08-22 22:29:09 +00:00
}
2006-01-13 06:27:18 +00:00
# ifdef Q3BSPS
2006-01-02 23:01:54 +00:00
if ( fog )
{
meshbuffer_t mb ;
shader_t dummyshader = { 0 } ;
R_IBrokeTheArrays ( ) ;
mb . entity = currententity ;
mb . shader = & dummyshader ;
mb . fog = fog ;
mb . mesh = & mesh ;
mb . infokey = - 1 ; //currententity->keynum;
mb . dlightbits = 0 ;
R_PushMesh ( & mesh , mb . shader - > features | MF_NONBATCHED | MF_COLORS ) ;
R_RenderMeshBuffer ( & mb , false ) ;
R_ClearArrays ( ) ;
}
2006-01-13 06:27:18 +00:00
# endif
2004-08-22 22:29:09 +00:00
}
}
2005-05-26 12:55:34 +00:00
if ( e - > flags & Q2RF_WEAPONMODEL )
VectorCopy ( saveorg , currententity - > origin ) ;
2004-08-22 22:29:09 +00:00
if ( qglPNTrianglesfATI & & gl_ati_truform . value )
2005-01-07 02:54:22 +00:00
qglDisable ( GL_PN_TRIANGLES_ATI ) ;
2004-08-22 22:29:09 +00:00
# ifdef SHOWLIGHTDIR //testing
2005-01-07 02:54:22 +00:00
qglDisable ( GL_TEXTURE_2D ) ;
qglBegin ( GL_LINES ) ;
qglColor3f ( 1 , 0 , 0 ) ;
qglVertex3f ( 0 ,
2004-08-22 22:29:09 +00:00
0 ,
0 ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( 100 * mesh . lightaxis [ 0 ] [ 0 ] ,
2004-08-22 22:29:09 +00:00
100 * mesh . lightaxis [ 0 ] [ 1 ] ,
100 * mesh . lightaxis [ 0 ] [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglColor3f ( 0 , 1 , 0 ) ;
qglVertex3f ( 0 ,
2004-08-22 22:29:09 +00:00
0 ,
0 ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( 100 * mesh . lightaxis [ 1 ] [ 0 ] ,
2004-08-22 22:29:09 +00:00
100 * mesh . lightaxis [ 1 ] [ 1 ] ,
100 * mesh . lightaxis [ 1 ] [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglColor3f ( 0 , 0 , 1 ) ;
qglVertex3f ( 0 ,
2004-08-22 22:29:09 +00:00
0 ,
0 ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( 100 * mesh . lightaxis [ 2 ] [ 0 ] ,
2004-08-22 22:29:09 +00:00
100 * mesh . lightaxis [ 2 ] [ 1 ] ,
100 * mesh . lightaxis [ 2 ] [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglEnd ( ) ;
qglEnable ( GL_TEXTURE_2D ) ;
2004-08-22 22:29:09 +00:00
# endif
2005-01-07 02:54:22 +00:00
qglPopMatrix ( ) ;
2004-08-22 22:29:09 +00:00
2005-01-07 02:54:22 +00:00
qglDisable ( GL_BLEND ) ;
2004-08-22 22:29:09 +00:00
2005-01-07 02:54:22 +00:00
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2004-11-13 17:31:04 +00:00
GL_TexEnv ( GL_REPLACE ) ;
2004-08-22 22:29:09 +00:00
2005-01-07 02:54:22 +00:00
qglEnable ( GL_TEXTURE_2D ) ;
2004-08-22 22:29:09 +00:00
2005-01-07 02:54:22 +00:00
qglShadeModel ( GL_FLAT ) ;
2004-08-22 22:29:09 +00:00
if ( gl_affinemodels . value )
2005-11-26 03:02:55 +00:00
qglHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ;
2004-08-22 22:29:09 +00:00
if ( e - > flags & Q2RF_DEPTHHACK )
2005-01-07 02:54:22 +00:00
qglDepthRange ( gldepthmin , gldepthmax ) ;
2004-08-22 22:29:09 +00:00
if ( ( currententity - > model - > flags & EF_SPECIAL_TRANS ) & & gl_cull . value )
2005-01-07 02:54:22 +00:00
qglEnable ( GL_CULL_FACE ) ;
2004-08-22 22:29:09 +00:00
if ( ( currententity - > model - > flags & EF_HOLEY ) )
2005-01-07 02:54:22 +00:00
qglDisable ( GL_ALPHA_TEST ) ;
2004-08-22 22:29:09 +00:00
# ifdef SHOWLIGHTDIR //testing
2005-01-07 02:54:22 +00:00
qglDisable ( GL_TEXTURE_2D ) ;
qglColor3f ( 1 , 1 , 1 ) ;
qglBegin ( GL_LINES ) ;
qglVertex3f ( currententity - > origin [ 0 ] ,
2004-08-22 22:29:09 +00:00
currententity - > origin [ 1 ] ,
currententity - > origin [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglVertex3f ( currententity - > origin [ 0 ] + 100 * lightdir [ 0 ] ,
2004-08-22 22:29:09 +00:00
currententity - > origin [ 1 ] + 100 * lightdir [ 1 ] ,
currententity - > origin [ 2 ] + 100 * lightdir [ 2 ] ) ;
2005-01-07 02:54:22 +00:00
qglEnd ( ) ;
qglEnable ( GL_TEXTURE_2D ) ;
2004-08-22 22:29:09 +00:00
# endif
}
2004-12-09 23:45:14 +00:00
//returns result in the form of the result vector
2005-08-03 23:14:59 +00:00
void RotateLightVector ( vec3_t * axis , vec3_t origin , vec3_t lightpoint , vec3_t result )
2004-08-22 22:29:09 +00:00
{
2005-08-03 23:14:59 +00:00
vec3_t offs ;
2004-12-09 23:45:14 +00:00
offs [ 0 ] = lightpoint [ 0 ] - origin [ 0 ] ;
offs [ 1 ] = lightpoint [ 1 ] - origin [ 1 ] ;
offs [ 2 ] = lightpoint [ 2 ] - origin [ 2 ] ;
2005-08-03 23:14:59 +00:00
result [ 0 ] = DotProduct ( offs , axis [ 0 ] ) ;
result [ 1 ] = DotProduct ( offs , axis [ 1 ] ) ;
result [ 2 ] = DotProduct ( offs , axis [ 2 ] ) ;
2004-12-09 23:45:14 +00:00
}
void GL_LightMesh ( mesh_t * mesh , vec3_t lightpos , vec3_t colours , float radius )
{
vec3_t dir ;
int i ;
2005-08-03 23:14:59 +00:00
float dot , d , f , a ;
vec3_t bcolours ;
2005-05-13 10:42:48 +00:00
vec3_t * xyz = mesh - > xyz_array ;
2004-12-09 23:45:14 +00:00
vec3_t * normals = mesh - > normals_array ;
byte_vec4_t * out = mesh - > colors_array ;
2005-08-03 23:14:59 +00:00
bcolours [ 0 ] = colours [ 0 ] * 255 ;
bcolours [ 1 ] = colours [ 1 ] * 255 ;
bcolours [ 2 ] = colours [ 2 ] * 255 ;
if ( ! out )
return ; //urm..
2004-12-09 23:45:14 +00:00
if ( normals )
{
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
VectorSubtract ( lightpos , xyz [ i ] , dir ) ;
dot = DotProduct ( dir , normals [ i ] ) ;
2005-08-03 23:14:59 +00:00
if ( dot > 0 )
{
d = DotProduct ( dir , dir ) / radius ;
a = 1 / d ;
if ( a > 0 )
{
a * = dot / sqrt ( d ) ;
f = a * bcolours [ 0 ] ;
if ( f > 255 )
f = 255 ;
else if ( f < 0 )
f = 0 ;
out [ i ] [ 0 ] = f ;
f = a * bcolours [ 1 ] ;
if ( f > 255 )
f = 255 ;
else if ( f < 0 )
f = 0 ;
out [ i ] [ 1 ] = f ;
f = a * bcolours [ 2 ] ;
if ( f > 255 )
f = 255 ;
else if ( f < 0 )
f = 0 ;
out [ i ] [ 2 ] = f ;
}
else
{
out [ i ] [ 0 ] = 0 ;
out [ i ] [ 1 ] = 0 ;
out [ i ] [ 2 ] = 0 ;
}
}
else
{
out [ i ] [ 0 ] = 0 ;
out [ i ] [ 1 ] = 0 ;
out [ i ] [ 2 ] = 0 ;
}
2004-12-09 23:45:14 +00:00
out [ i ] [ 3 ] = 255 ;
}
}
else
{
2005-08-03 23:14:59 +00:00
if ( bcolours [ 0 ] > 255 )
bcolours [ 0 ] = 255 ;
if ( bcolours [ 1 ] > 255 )
bcolours [ 1 ] = 255 ;
if ( bcolours [ 2 ] > 255 )
bcolours [ 2 ] = 255 ;
2004-12-09 23:45:14 +00:00
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
VectorSubtract ( lightpos , xyz [ i ] , dir ) ;
2005-08-03 23:14:59 +00:00
out [ i ] [ 0 ] = bcolours [ 0 ] ;
out [ i ] [ 1 ] = bcolours [ 1 ] ;
out [ i ] [ 2 ] = bcolours [ 2 ] ;
2004-12-09 23:45:14 +00:00
out [ i ] [ 3 ] = 255 ;
}
}
}
2005-09-08 02:02:09 +00:00
//courtesy of DP
void R_BuildBumpVectors ( const float * v0 , const float * v1 , const float * v2 , const float * tc0 , const float * tc1 , const float * tc2 , float * svector3f , float * tvector3f , float * normal3f )
{
float f , tangentcross [ 3 ] , v10 [ 3 ] , v20 [ 3 ] , tc10 [ 2 ] , tc20 [ 2 ] ;
// 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
// 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
// 6 multiply, 9 subtract
VectorSubtract ( v1 , v0 , v10 ) ;
VectorSubtract ( v2 , v0 , v20 ) ;
normal3f [ 0 ] = v10 [ 1 ] * v20 [ 2 ] - v10 [ 2 ] * v20 [ 1 ] ;
normal3f [ 1 ] = v10 [ 2 ] * v20 [ 0 ] - v10 [ 0 ] * v20 [ 2 ] ;
normal3f [ 2 ] = v10 [ 0 ] * v20 [ 1 ] - v10 [ 1 ] * v20 [ 0 ] ;
// 12 multiply, 10 subtract
tc10 [ 1 ] = tc1 [ 1 ] - tc0 [ 1 ] ;
tc20 [ 1 ] = tc2 [ 1 ] - tc0 [ 1 ] ;
svector3f [ 0 ] = tc10 [ 1 ] * v20 [ 0 ] - tc20 [ 1 ] * v10 [ 0 ] ;
svector3f [ 1 ] = tc10 [ 1 ] * v20 [ 1 ] - tc20 [ 1 ] * v10 [ 1 ] ;
svector3f [ 2 ] = tc10 [ 1 ] * v20 [ 2 ] - tc20 [ 1 ] * v10 [ 2 ] ;
tc10 [ 0 ] = tc1 [ 0 ] - tc0 [ 0 ] ;
tc20 [ 0 ] = tc2 [ 0 ] - tc0 [ 0 ] ;
tvector3f [ 0 ] = tc10 [ 0 ] * v20 [ 0 ] - tc20 [ 0 ] * v10 [ 0 ] ;
tvector3f [ 1 ] = tc10 [ 0 ] * v20 [ 1 ] - tc20 [ 0 ] * v10 [ 1 ] ;
tvector3f [ 2 ] = tc10 [ 0 ] * v20 [ 2 ] - tc20 [ 0 ] * v10 [ 2 ] ;
// 12 multiply, 4 add, 6 subtract
f = DotProduct ( svector3f , normal3f ) ;
svector3f [ 0 ] - = f * normal3f [ 0 ] ;
svector3f [ 1 ] - = f * normal3f [ 1 ] ;
svector3f [ 2 ] - = f * normal3f [ 2 ] ;
f = DotProduct ( tvector3f , normal3f ) ;
tvector3f [ 0 ] - = f * normal3f [ 0 ] ;
tvector3f [ 1 ] - = f * normal3f [ 1 ] ;
tvector3f [ 2 ] - = f * normal3f [ 2 ] ;
// if texture is mapped the wrong way (counterclockwise), the tangents
// have to be flipped, this is detected by calculating a normal from the
// two tangents, and seeing if it is opposite the surface normal
// 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
CrossProduct ( tvector3f , svector3f , tangentcross ) ;
if ( DotProduct ( tangentcross , normal3f ) < 0 )
{
VectorNegate ( svector3f , svector3f ) ;
VectorNegate ( tvector3f , tvector3f ) ;
}
}
//courtesy of DP
void R_AliasGenerateTextureVectors ( mesh_t * mesh , float * normal3f , float * svector3f , float * tvector3f )
{
int i ;
float sdir [ 3 ] , tdir [ 3 ] , normal [ 3 ] , * v ;
int * e ;
float * vertex3f = ( float * ) mesh - > xyz_array ;
float * texcoord2f = ( float * ) mesh - > st_array ;
// clear the vectors
// if (svector3f)
memset ( svector3f , 0 , mesh - > numvertexes * sizeof ( float [ 3 ] ) ) ;
// if (tvector3f)
memset ( tvector3f , 0 , mesh - > numvertexes * sizeof ( float [ 3 ] ) ) ;
// if (normal3f)
memset ( normal3f , 0 , mesh - > numvertexes * sizeof ( float [ 3 ] ) ) ;
// process each vertex of each triangle and accumulate the results
for ( e = mesh - > indexes ; e < mesh - > indexes + mesh - > numindexes ; e + = 3 )
{
R_BuildBumpVectors ( vertex3f + e [ 0 ] * 3 , vertex3f + e [ 1 ] * 3 , vertex3f + e [ 2 ] * 3 , texcoord2f + e [ 0 ] * 2 , texcoord2f + e [ 1 ] * 2 , texcoord2f + e [ 2 ] * 2 , sdir , tdir , normal ) ;
// if (!areaweighting)
// {
// VectorNormalize(sdir);
// VectorNormalize(tdir);
// VectorNormalize(normal);
// }
// if (svector3f)
for ( i = 0 ; i < 3 ; i + + )
VectorAdd ( svector3f + e [ i ] * 3 , sdir , svector3f + e [ i ] * 3 ) ;
// if (tvector3f)
for ( i = 0 ; i < 3 ; i + + )
VectorAdd ( tvector3f + e [ i ] * 3 , tdir , tvector3f + e [ i ] * 3 ) ;
// if (normal3f)
for ( i = 0 ; i < 3 ; i + + )
VectorAdd ( normal3f + e [ i ] * 3 , normal , normal3f + e [ i ] * 3 ) ;
}
// now we could divide the vectors by the number of averaged values on
// each vertex... but instead normalize them
// 4 assignments, 1 divide, 1 sqrt, 2 adds, 6 multiplies
if ( svector3f )
for ( i = 0 , v = svector3f ; i < mesh - > numvertexes ; i + + , v + = 3 )
VectorNormalize ( v ) ;
// 4 assignments, 1 divide, 1 sqrt, 2 adds, 6 multiplies
if ( tvector3f )
for ( i = 0 , v = tvector3f ; i < mesh - > numvertexes ; i + + , v + = 3 )
VectorNormalize ( v ) ;
// 4 assignments, 1 divide, 1 sqrt, 2 adds, 6 multiplies
if ( normal3f )
for ( i = 0 , v = normal3f ; i < mesh - > numvertexes ; i + + , v + = 3 )
VectorNormalize ( v ) ;
}
void R_AliasGenerateVertexLightDirs ( mesh_t * mesh , vec3_t lightdir , vec3_t * results , vec3_t * normal3f , vec3_t * svector3f , vec3_t * tvector3f )
{
int i ;
R_AliasGenerateTextureVectors ( mesh , ( float * ) normal3f , ( float * ) svector3f , ( float * ) tvector3f ) ;
for ( i = 0 ; i < mesh - > numvertexes ; i + + )
{
results [ i ] [ 0 ] = - DotProduct ( lightdir , tvector3f [ i ] ) ;
results [ i ] [ 1 ] = - DotProduct ( lightdir , svector3f [ i ] ) ;
results [ i ] [ 2 ] = - DotProduct ( lightdir , normal3f [ i ] ) ;
}
}
void R_DrawMeshBumpmap ( mesh_t * mesh , galiastexnum_t * skin , vec3_t lightdir )
{
extern int gldepthfunc ;
static vec3_t * lightdirs ;
static int maxlightdirs ;
extern int normalisationCubeMap ;
# ifdef Q3SHADERS
R_UnlockArrays ( ) ;
# endif
//(bumpmap dot cubemap)*texture
//why no luma?
//that's thrown on last.
//why a cubemap?
//we need to pass colours as a normal somehow
//we could use the fragment colour for it, however, we then wouldn't be able to colour the light.
//so we use a cubemap, which has the added advantage of normalizing the light dir for us.
//the bumpmap we use is tangent-space (so I'm told)
2005-09-08 22:52:46 +00:00
qglDepthFunc ( gldepthfunc ) ;
2005-09-08 02:02:09 +00:00
qglDepthMask ( 0 ) ;
2005-11-26 03:02:55 +00:00
if ( gldepthmin = = 0.5 )
2005-09-08 02:02:09 +00:00
qglCullFace ( GL_BACK ) ;
else
qglCullFace ( GL_FRONT ) ;
2005-10-20 20:02:33 +00:00
qglEnable ( GL_BLEND ) ;
2005-09-08 02:02:09 +00:00
qglVertexPointer ( 3 , GL_FLOAT , 0 , mesh - > xyz_array ) ;
qglEnableClientState ( GL_VERTEX_ARRAY ) ;
if ( mesh - > normals_array & & qglNormalPointer ) //d3d wrapper doesn't support normals, and this is only really needed for truform
{
qglNormalPointer ( GL_FLOAT , 0 , mesh - > normals_array ) ;
qglEnableClientState ( GL_NORMAL_ARRAY ) ;
}
if ( mesh - > colors_array )
{
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , mesh - > colors_array ) ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
}
else
qglDisableClientState ( GL_COLOR_ARRAY ) ;
if ( maxlightdirs < mesh - > numvertexes )
{
maxlightdirs = mesh - > numvertexes ;
lightdirs = BZ_Malloc ( sizeof ( vec3_t ) * maxlightdirs * 4 ) ;
}
R_AliasGenerateVertexLightDirs ( mesh , lightdir ,
lightdirs + maxlightdirs * 0 ,
lightdirs + maxlightdirs * 1 ,
lightdirs + maxlightdirs * 2 ,
lightdirs + maxlightdirs * 3 ) ;
GL_MBind ( mtexid0 , skin - > bump ) ;
GL_TexEnv ( GL_REPLACE ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , mesh - > st_array ) ;
qglEnable ( GL_TEXTURE_2D ) ;
GL_SelectTexture ( mtexid1 ) ;
GL_BindType ( GL_TEXTURE_CUBE_MAP_ARB , normalisationCubeMap ) ;
qglEnable ( GL_TEXTURE_CUBE_MAP_ARB ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE0_RGB_ARB , GL_TEXTURE ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_SOURCE1_RGB_ARB , GL_PREVIOUS_ARB ) ;
qglTexEnvi ( GL_TEXTURE_ENV , GL_COMBINE_RGB_ARB , GL_DOT3_RGB_ARB ) ;
GL_TexEnv ( GL_COMBINE_ARB ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 3 , GL_FLOAT , 0 , lightdirs ) ;
if ( gl_mtexarbable > = 3 )
{
GL_MBind ( mtexid0 + 2 , skin - > base ) ;
qglEnable ( GL_TEXTURE_2D ) ;
}
else
{ //we don't support 3tmus, so draw the bumps, and multiply the rest over the top
qglDrawElements ( GL_TRIANGLES , mesh - > numindexes , GL_UNSIGNED_INT , mesh - > indexes ) ;
2005-09-09 23:40:55 +00:00
qglDisable ( GL_TEXTURE_CUBE_MAP_ARB ) ;
2005-09-08 02:02:09 +00:00
GL_MBind ( mtexid0 , skin - > base ) ;
}
GL_TexEnv ( GL_MODULATE ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , mesh - > st_array ) ;
qglDrawElements ( GL_TRIANGLES , mesh - > numindexes , GL_UNSIGNED_INT , mesh - > indexes ) ;
// GL_SelectTexture(mtexid2);
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglDisable ( GL_TEXTURE_2D ) ;
GL_SelectTexture ( mtexid1 ) ;
2005-09-09 23:40:55 +00:00
qglDisable ( GL_TEXTURE_CUBE_MAP_ARB ) ;
2005-09-08 02:02:09 +00:00
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
GL_TexEnv ( GL_MODULATE ) ;
GL_SelectTexture ( mtexid0 ) ;
qglEnable ( GL_TEXTURE_2D ) ;
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglDisableClientState ( GL_VERTEX_ARRAY ) ;
qglDisableClientState ( GL_COLOR_ARRAY ) ;
qglDisableClientState ( GL_NORMAL_ARRAY ) ;
# ifdef Q3SHADERS
R_IBrokeTheArrays ( ) ;
# endif
}
2004-12-09 23:45:14 +00:00
void R_DrawGAliasModelLighting ( entity_t * e , vec3_t lightpos , vec3_t colours , float radius )
{
2005-10-20 20:02:33 +00:00
#if 0 //glitches, no attenuation... :(
2004-12-09 23:45:14 +00:00
2004-08-22 22:29:09 +00:00
model_t * clmodel = e - > model ;
vec3_t mins , maxs ;
vec3_t lightdir ;
galiasinfo_t * inf ;
2005-08-03 23:14:59 +00:00
galiastexnum_t * tex ;
2004-08-22 22:29:09 +00:00
mesh_t mesh ;
2005-08-07 13:16:20 +00:00
int surfnum ;
2005-10-20 20:02:33 +00:00
extern cvar_t r_nolightdir ;
2004-08-22 22:29:09 +00:00
if ( e - > flags & Q2RF_VIEWERMODEL )
return ;
2005-10-20 20:02:33 +00:00
if ( r_nolightdir . value ) //are you crazy?
return ;
2004-08-22 22:29:09 +00:00
//Total insanity with r_shadows 2...
// if (!strcmp (clmodel->name, "progs/flame2.mdl"))
// CL_NewDlight (e, e->origin[0]-1, e->origin[1]+1, e->origin[2]+24, 200 + (rand()&31), host_frametime*2, 3);
// if (!strcmp (clmodel->name, "progs/armor.mdl"))
// CL_NewDlight (e->keynum, e->origin[0]-1, e->origin[1]+1, e->origin[2]+25, 200 + (rand()&31), host_frametime*2, 3);
VectorAdd ( e - > origin , clmodel - > mins , mins ) ;
VectorAdd ( e - > origin , clmodel - > maxs , maxs ) ;
2005-08-03 23:14:59 +00:00
// if (!(e->flags & Q2RF_WEAPONMODEL))
// if (R_CullBox (mins, maxs))
// return;
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
RotateLightVector ( e - > axis , e - > origin , lightpos , lightdir ) ;
2004-08-22 22:29:09 +00:00
GL_DisableMultitexture ( ) ;
2004-11-13 17:31:04 +00:00
GL_TexEnv ( GL_MODULATE ) ;
2004-08-22 22:29:09 +00:00
if ( gl_smoothmodels . value )
2005-08-03 23:14:59 +00:00
qglShadeModel ( GL_SMOOTH ) ;
2004-08-22 22:29:09 +00:00
if ( gl_affinemodels . value )
2005-08-03 23:14:59 +00:00
qglHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_FASTEST ) ;
2004-08-22 22:29:09 +00:00
if ( e - > flags & Q2RF_DEPTHHACK )
2005-08-03 23:14:59 +00:00
qglDepthRange ( gldepthmin , gldepthmin + 0.3 * ( gldepthmax - gldepthmin ) ) ;
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
qglColor3f ( colours [ 0 ] , colours [ 1 ] , colours [ 2 ] ) ;
qglColor4f ( 1 , 1 , 1 , 1 ) ;
2004-12-09 23:45:14 +00:00
2005-08-03 23:14:59 +00:00
qglPushMatrix ( ) ;
2004-08-22 22:29:09 +00:00
R_RotateForEntity ( e ) ;
inf = GLMod_Extradata ( clmodel ) ;
if ( gl_ati_truform . value )
2005-08-03 23:14:59 +00:00
qglEnable ( GL_PN_TRIANGLES_ATI ) ;
qglEnable ( GL_TEXTURE_2D ) ;
qglEnable ( GL_POLYGON_OFFSET_FILL ) ;
GL_TexEnv ( GL_REPLACE ) ;
// qglDisable(GL_STENCIL_TEST);
qglEnable ( GL_BLEND ) ;
2005-09-08 02:02:09 +00:00
qglDisable ( GL_ALPHA_TEST ) ; //if you used an alpha channel where you shouldn't have, more fool you.
2005-08-03 23:14:59 +00:00
qglBlendFunc ( GL_ONE , GL_ONE ) ;
// qglDepthFunc(GL_ALWAYS);
2005-08-07 13:16:20 +00:00
for ( surfnum = 0 ; inf ; surfnum + + )
2004-08-22 22:29:09 +00:00
{
2006-06-08 06:24:07 +00:00
R_GAliasBuildMesh ( & mesh , inf , e - > frame , e - > oldframe , e - > lerpfrac , e - > alpha , e - > frame1time , e - > frame2time , false ) ;
2005-08-03 23:14:59 +00:00
mesh . colors_array = tempColours ;
2004-12-09 23:45:14 +00:00
2005-08-07 13:16:20 +00:00
tex = GL_ChooseSkin ( inf , clmodel - > name , surfnum , e ) ;
2004-12-09 23:45:14 +00:00
2005-09-08 02:02:09 +00:00
if ( tex - > bump & & e - > alpha = = 1 )
{
R_DrawMeshBumpmap ( & mesh , tex , lightdir ) ;
}
else
{
GL_LightMesh ( & mesh , lightdir , colours , radius ) ;
GL_DrawAliasMesh ( & mesh , tex - > base ) ;
}
2004-08-22 22:29:09 +00:00
if ( inf - > nextsurf )
2004-09-20 23:25:38 +00:00
inf = ( galiasinfo_t * ) ( ( char * ) inf + inf - > nextsurf ) ;
2004-08-22 22:29:09 +00:00
else
inf = NULL ;
}
2005-08-03 23:14:59 +00:00
currententity - > fatness = 0 ;
qglPopMatrix ( ) ;
2004-08-22 22:29:09 +00:00
if ( gl_ati_truform . value )
2005-08-03 23:14:59 +00:00
qglDisable ( GL_PN_TRIANGLES_ATI ) ;
2004-08-22 22:29:09 +00:00
2004-11-13 17:31:04 +00:00
GL_TexEnv ( GL_REPLACE ) ;
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
qglShadeModel ( GL_FLAT ) ;
2004-08-22 22:29:09 +00:00
if ( gl_affinemodels . value )
2005-11-26 03:02:55 +00:00
qglHint ( GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST ) ;
2005-08-03 23:14:59 +00:00
qglDisable ( GL_POLYGON_OFFSET_FILL ) ;
2004-08-22 22:29:09 +00:00
if ( e - > flags & Q2RF_DEPTHHACK )
2005-08-03 23:14:59 +00:00
qglDepthRange ( gldepthmin , gldepthmax ) ;
qglBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
qglDisable ( GL_BLEND ) ;
qglDisable ( GL_TEXTURE_2D ) ;
R_IBrokeTheArrays ( ) ;
2004-12-09 23:45:14 +00:00
# endif
2004-08-22 22:29:09 +00:00
}
//FIXME: Be less agressive.
//This function will have to be called twice (for geforce cards), with the same data, so do the building once and rendering twice.
void R_DrawGAliasShadowVolume ( entity_t * e , vec3_t lightpos , float radius )
{
model_t * clmodel = e - > model ;
galiasinfo_t * inf ;
mesh_t mesh ;
vec3_t lightorg ;
2006-06-08 06:24:07 +00:00
if ( clmodel - > engineflags & ( MDLF_FLAME | MDLF_BOLT ) )
2004-08-22 22:29:09 +00:00
return ;
if ( r_noaliasshadows . value )
return ;
2006-02-27 00:42:25 +00:00
if ( e - > shaderRGBAf [ 3 ] < 0.5 )
return ;
2005-08-03 23:14:59 +00:00
RotateLightVector ( e - > axis , e - > origin , lightpos , lightorg ) ;
2004-08-22 22:29:09 +00:00
if ( Length ( lightorg ) > radius + clmodel - > radius )
return ;
2005-01-07 02:54:22 +00:00
qglPushMatrix ( ) ;
2004-08-22 22:29:09 +00:00
R_RotateForEntity ( e ) ;
inf = GLMod_Extradata ( clmodel ) ;
while ( inf )
{
if ( inf - > ofs_trineighbours )
{
2006-06-08 06:24:07 +00:00
R_GAliasBuildMesh ( & mesh , inf , e - > frame , e - > oldframe , e - > lerpfrac , 1 , e - > frame1time , e - > frame2time , true ) ;
2004-08-22 22:29:09 +00:00
R_CalcFacing ( & mesh , lightorg ) ;
R_ProjectShadowVolume ( & mesh , lightorg ) ;
R_DrawShadowVolume ( & mesh ) ;
}
if ( inf - > nextsurf )
2004-09-20 23:25:38 +00:00
inf = ( galiasinfo_t * ) ( ( char * ) inf + inf - > nextsurf ) ;
2004-08-22 22:29:09 +00:00
else
inf = NULL ;
}
2005-01-07 02:54:22 +00:00
qglPopMatrix ( ) ;
2004-08-22 22:29:09 +00:00
}
static int R_FindTriangleWithEdge ( int * indexes , int numtris , int start , int end , int ignore )
{
int i ;
int match , count ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
count = 0 ;
match = - 1 ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
for ( i = 0 ; i < numtris ; i + + , indexes + = 3 )
{
if ( ( indexes [ 0 ] = = start & & indexes [ 1 ] = = end )
| | ( indexes [ 1 ] = = start & & indexes [ 2 ] = = end )
| | ( indexes [ 2 ] = = start & & indexes [ 0 ] = = end ) ) {
if ( i ! = ignore )
match = i ;
count + + ;
} else if ( ( indexes [ 1 ] = = start & & indexes [ 0 ] = = end )
| | ( indexes [ 2 ] = = start & & indexes [ 1 ] = = end )
| | ( indexes [ 0 ] = = start & & indexes [ 2 ] = = end ) ) {
count + + ;
}
}
// detect edges shared by three triangles and make them seams
if ( count > 2 )
match = - 1 ;
return match ;
}
static void R_BuildTriangleNeighbours ( int * neighbours , int * indexes , int numtris )
{
int i , * n ;
int * index ;
for ( i = 0 , index = indexes , n = neighbours ; i < numtris ; i + + , index + = 3 , n + = 3 )
{
n [ 0 ] = R_FindTriangleWithEdge ( indexes , numtris , index [ 1 ] , index [ 0 ] , i ) ;
n [ 1 ] = R_FindTriangleWithEdge ( indexes , numtris , index [ 2 ] , index [ 1 ] , i ) ;
n [ 2 ] = R_FindTriangleWithEdge ( indexes , numtris , index [ 0 ] , index [ 2 ] , i ) ;
}
}
void GL_GenerateNormals ( float * orgs , float * normals , int * indicies , int numtris , int numverts )
{
vec3_t d1 , d2 ;
vec3_t norm ;
int t , i , v1 , v2 , v3 ;
int tricounts [ MD2MAX_VERTS ] ;
vec3_t combined [ MD2MAX_VERTS ] ;
int triremap [ MD2MAX_VERTS ] ;
if ( numverts > MD2MAX_VERTS )
return ; //not an issue, you just loose the normals.
memset ( triremap , 0 , numverts * sizeof ( triremap [ 0 ] ) ) ;
v2 = 0 ;
for ( i = 0 ; i < numverts ; i + + ) //weld points
{
for ( v1 = 0 ; v1 < v2 ; v1 + + )
{
if ( orgs [ i * 3 + 0 ] = = combined [ v1 ] [ 0 ] & &
orgs [ i * 3 + 1 ] = = combined [ v1 ] [ 1 ] & &
orgs [ i * 3 + 2 ] = = combined [ v1 ] [ 2 ] )
{
triremap [ i ] = v1 ;
break ;
}
}
if ( v1 = = v2 )
{
combined [ v1 ] [ 0 ] = orgs [ i * 3 + 0 ] ;
combined [ v1 ] [ 1 ] = orgs [ i * 3 + 1 ] ;
combined [ v1 ] [ 2 ] = orgs [ i * 3 + 2 ] ;
v2 + + ;
triremap [ i ] = v1 ;
}
}
memset ( tricounts , 0 , v2 * sizeof ( tricounts [ 0 ] ) ) ;
memset ( combined , 0 , v2 * sizeof ( * combined ) ) ;
for ( t = 0 ; t < numtris ; t + + )
{
v1 = triremap [ indicies [ t * 3 ] ] ;
v2 = triremap [ indicies [ t * 3 + 1 ] ] ;
v3 = triremap [ indicies [ t * 3 + 2 ] ] ;
VectorSubtract ( ( orgs + v2 * 3 ) , ( orgs + v1 * 3 ) , d1 ) ;
VectorSubtract ( ( orgs + v3 * 3 ) , ( orgs + v1 * 3 ) , d2 ) ;
CrossProduct ( d1 , d2 , norm ) ;
VectorNormalize ( norm ) ;
VectorAdd ( norm , combined [ v1 ] , combined [ v1 ] ) ;
VectorAdd ( norm , combined [ v2 ] , combined [ v2 ] ) ;
VectorAdd ( norm , combined [ v3 ] , combined [ v3 ] ) ;
tricounts [ v1 ] + + ;
tricounts [ v2 ] + + ;
tricounts [ v3 ] + + ;
}
for ( i = 0 ; i < numverts ; i + + )
{
if ( tricounts [ triremap [ i ] ] )
{
VectorScale ( combined [ triremap [ i ] ] , 1.0f / tricounts [ triremap [ i ] ] , normals + i * 3 ) ;
}
}
}
2005-08-03 23:14:59 +00:00
char * * skinfilelist ;
2005-05-15 18:49:04 +00:00
int skinfilecount ;
2005-08-03 23:14:59 +00:00
static qboolean VARGS TryAddSkin ( char * skinname , . . . )
2005-05-15 18:49:04 +00:00
{
2005-08-03 23:14:59 +00:00
va_list argptr ;
char string [ MAX_QPATH ] ;
//make sure we don't add it twice
int i ;
2005-11-26 03:02:55 +00:00
2005-08-03 23:14:59 +00:00
va_start ( argptr , skinname ) ;
2006-03-06 01:41:09 +00:00
vsnprintf ( string , sizeof ( string ) - 1 , skinname , argptr ) ;
2005-08-03 23:14:59 +00:00
va_end ( argptr ) ;
string [ MAX_QPATH - 1 ] = ' \0 ' ;
for ( i = 0 ; i < skinfilecount ; i + + )
2005-05-15 18:49:04 +00:00
{
2005-08-03 23:14:59 +00:00
if ( ! strcmp ( skinfilelist [ i ] , string ) )
return true ; //already added
2005-05-15 18:49:04 +00:00
}
2005-08-03 23:14:59 +00:00
if ( ! COM_FCheckExists ( string ) )
return false ;
skinfilelist = BZ_Realloc ( skinfilelist , sizeof ( * skinfilelist ) * ( skinfilecount + 1 ) ) ;
skinfilelist [ skinfilecount ] = Z_Malloc ( strlen ( string ) + 1 ) ;
strcpy ( skinfilelist [ skinfilecount ] , string ) ;
skinfilecount + + ;
return true ;
2005-05-15 18:49:04 +00:00
}
2005-08-03 23:14:59 +00:00
int GL_EnumerateSkins ( char * name , int size , void * param )
2005-05-15 18:49:04 +00:00
{
2005-08-03 23:14:59 +00:00
TryAddSkin ( name ) ;
return true ;
}
2005-05-15 18:49:04 +00:00
2005-08-03 23:14:59 +00:00
int GL_BuildSkinFileList ( char * modelname )
{
int i ;
char skinfilename [ MAX_QPATH ] ;
//flush the old list
for ( i = 0 ; i < skinfilecount ; i + + )
2005-05-19 02:43:11 +00:00
{
2005-08-03 23:14:59 +00:00
Z_Free ( skinfilelist [ i ] ) ;
skinfilelist [ i ] = NULL ;
2005-05-19 02:43:11 +00:00
}
2005-08-03 23:14:59 +00:00
skinfilecount = 0 ;
2006-03-11 03:12:10 +00:00
COM_StripExtension ( modelname , skinfilename , sizeof ( skinfilename ) ) ;
2005-05-19 02:43:11 +00:00
2005-08-03 23:14:59 +00:00
//try and add numbered skins, and then try fixed names.
for ( i = 0 ; ; i + + )
2005-05-19 02:43:11 +00:00
{
2005-08-03 23:14:59 +00:00
if ( ! TryAddSkin ( " %s_%i.skin " , modelname , i ) )
2005-05-19 02:43:11 +00:00
{
2005-08-03 23:14:59 +00:00
if ( i = = 0 )
{
if ( ! TryAddSkin ( " %s_default.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 1 )
{
if ( ! TryAddSkin ( " %s_blue.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 2 )
{
if ( ! TryAddSkin ( " %s_red.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 3 )
{
if ( ! TryAddSkin ( " %s_green.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 4 )
{
if ( ! TryAddSkin ( " %s_yellow.skin " , skinfilename , i ) )
break ;
}
else
break ;
2005-05-19 02:43:11 +00:00
}
}
2006-03-15 20:07:43 +00:00
// if (strstr(modelname, "lower") || strstr(modelname, "upper") || strstr(modelname, "head"))
// {
COM_EnumerateFiles ( va ( " %s_*.skin " , modelname ) , GL_EnumerateSkins , NULL ) ;
COM_EnumerateFiles ( va ( " %s_*.skin " , skinfilename ) , GL_EnumerateSkins , NULL ) ;
// }
// else
// COM_EnumerateFiles("*.skin", GL_EnumerateSkins, NULL);
2005-08-03 23:14:59 +00:00
return skinfilecount ;
}
//This is a hack. It uses an assuption about q3 player models.
void GL_ParseQ3SkinFile ( char * out , char * surfname , char * modelname , int skinnum , char * skinfilename )
{
const char * f = NULL , * p ;
int len ;
if ( skinnum > = skinfilecount )
return ;
if ( skinfilename )
strcpy ( skinfilename , skinfilelist [ skinnum ] ) ;
f = COM_LoadTempFile2 ( skinfilelist [ skinnum ] ) ;
2005-05-15 18:49:04 +00:00
while ( f )
{
2005-08-26 22:56:51 +00:00
f = COM_ParseToken ( f , NULL ) ;
2005-05-15 18:49:04 +00:00
if ( ! f )
return ;
2005-05-19 02:43:11 +00:00
if ( ! strcmp ( com_token , " replace " ) )
2005-05-15 18:49:04 +00:00
{
2005-08-26 22:56:51 +00:00
f = COM_ParseToken ( f , NULL ) ;
2005-05-19 02:43:11 +00:00
len = strlen ( com_token ) ;
//copy surfname -> out, until we meet the part we need to replace
while ( * surfname )
2005-05-15 18:49:04 +00:00
{
2005-05-19 02:43:11 +00:00
if ( ! strncmp ( com_token , surfname , len ) )
//found it
{
surfname + = len ;
2005-08-26 22:56:51 +00:00
f = COM_ParseToken ( f , NULL ) ;
2005-05-19 02:43:11 +00:00
p = com_token ;
while ( * p ) //copy the replacement
* out + + = * p + + ;
while ( * surfname ) //copy the remaining
* out + + = * surfname + + ;
* out + + = ' \0 ' ; //we didn't find it.
return ;
}
* out + + = * surfname + + ;
}
* out + + = ' \0 ' ; //we didn't find it.
return ;
}
else
{
while ( * f = = ' ' | | * f = = ' \t ' )
2005-05-15 18:49:04 +00:00
f + + ;
2005-05-19 02:43:11 +00:00
if ( * f = = ' , ' )
{
if ( ! strcmp ( com_token , surfname ) )
{
f + + ;
2005-08-26 22:56:51 +00:00
COM_ParseToken ( f , NULL ) ;
2005-05-19 02:43:11 +00:00
strcpy ( out , com_token ) ;
return ;
}
2005-05-15 18:49:04 +00:00
}
}
p = strchr ( f , ' \n ' ) ;
if ( ! p )
f = f + strlen ( f ) ;
else
f = p + 1 ;
if ( ! * f )
break ;
}
}
2005-05-19 02:43:11 +00:00
void GL_LoadSkinFile ( galiastexnum_t * texnum , char * surfacename , int skinnumber , unsigned char * rawdata , int width , int height , unsigned char * palette )
2005-05-15 18:49:04 +00:00
{
2005-05-19 02:43:11 +00:00
char shadername [ MAX_QPATH ] ;
Q_strncpyz ( shadername , surfacename , sizeof ( shadername ) ) ;
2005-05-15 18:49:04 +00:00
2005-08-03 23:14:59 +00:00
GL_ParseQ3SkinFile ( shadername , surfacename , loadmodel - > name , skinnumber , NULL ) ;
2005-05-15 18:49:04 +00:00
2006-01-13 06:27:18 +00:00
# ifdef Q3SHADERS
2005-11-14 01:31:14 +00:00
texnum - > shader = R_RegisterSkin ( shadername ) ;
2006-01-13 06:27:18 +00:00
# endif
2005-11-14 01:31:14 +00:00
2005-05-19 02:43:11 +00:00
texnum - > base = Mod_LoadHiResTexture ( shadername , " models " , true , true , true ) ;
2005-05-15 18:49:04 +00:00
}
2005-07-16 00:53:08 +00:00
# endif //SERVERONLY
2004-08-22 22:29:09 +00:00
//Q1 model loading
# if 1
static galiasinfo_t * galias ;
static dmdl_t * pq1inmodel ;
# define NUMVERTEXNORMALS 162
extern float r_avertexnormals [ NUMVERTEXNORMALS ] [ 3 ] ;
2006-03-13 23:20:49 +00:00
static void * QTest_LoadFrameGroup ( daliasframetype_t * pframetype , int * seamremaps )
{
galiaspose_t * pose ;
galiasgroup_t * frame ;
dtrivertx_t * pinframe ;
qtestaliasframe_t * frameinfo ;
int i , j ;
vec3_t * normals ;
vec3_t * verts ;
frame = ( galiasgroup_t * ) ( ( char * ) galias + galias - > groupofs ) ;
for ( i = 0 ; i < pq1inmodel - > numframes ; i + + )
{
switch ( LittleLong ( pframetype - > type ) )
{
case ALIAS_SINGLE :
frameinfo = ( qtestaliasframe_t * ) ( ( char * ) ( pframetype + 1 ) ) ;
pinframe = ( dtrivertx_t * ) ( ( char * ) frameinfo + sizeof ( qtestaliasframe_t ) ) ;
pose = ( galiaspose_t * ) Hunk_Alloc ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * 2 * galias - > numverts ) ;
frame - > poseofs = ( char * ) pose - ( char * ) frame ;
frame - > numposes = 1 ;
galias - > groups + + ;
frame - > name [ 0 ] = ' \0 ' ;
verts = ( vec3_t * ) ( pose + 1 ) ;
normals = & verts [ galias - > numverts ] ;
pose - > ofsverts = ( char * ) verts - ( char * ) pose ;
# ifndef SERVERONLY
pose - > ofsnormals = ( char * ) normals - ( char * ) pose ;
# endif
for ( j = 0 ; j < pq1inmodel - > numverts ; j + + )
{
verts [ j ] [ 0 ] = pinframe [ j ] . v [ 0 ] * pq1inmodel - > scale [ 0 ] + pq1inmodel - > scale_origin [ 0 ] ;
verts [ j ] [ 1 ] = pinframe [ j ] . v [ 1 ] * pq1inmodel - > scale [ 1 ] + pq1inmodel - > scale_origin [ 1 ] ;
verts [ j ] [ 2 ] = pinframe [ j ] . v [ 2 ] * pq1inmodel - > scale [ 2 ] + pq1inmodel - > scale_origin [ 2 ] ;
# ifndef SERVERONLY
VectorCopy ( r_avertexnormals [ pinframe [ j ] . lightnormalindex ] , normals [ j ] ) ;
# endif
if ( seamremaps [ j ] ! = j )
{
VectorCopy ( verts [ j ] , verts [ seamremaps [ j ] ] ) ;
VectorCopy ( normals [ j ] , normals [ seamremaps [ j ] ] ) ;
}
}
// GL_GenerateNormals((float*)verts, (float*)normals, (int *)((char *)galias + galias->ofs_indexes), galias->numindexes/3, galias->numverts);
pframetype = ( daliasframetype_t * ) & pinframe [ pq1inmodel - > numverts ] ;
break ;
default :
Con_Printf ( S_ERROR " Bad frame type for QTest model in %s \n " , loadmodel - > name ) ;
return NULL ;
}
frame + + ;
}
return pframetype ;
}
2004-08-22 22:29:09 +00:00
static void * Q1_LoadFrameGroup ( daliasframetype_t * pframetype , int * seamremaps )
{
galiaspose_t * pose ;
galiasgroup_t * frame ;
dtrivertx_t * pinframe ;
2006-02-27 00:42:25 +00:00
daliasframe_t * frameinfo ;
2004-08-22 22:29:09 +00:00
int i , j , k ;
daliasgroup_t * ingroup ;
daliasinterval_t * intervals ;
2006-03-06 02:02:17 +00:00
float sinter ;
2004-08-22 22:29:09 +00:00
vec3_t * normals ;
vec3_t * verts ;
2004-09-13 04:16:52 +00:00
frame = ( galiasgroup_t * ) ( ( char * ) galias + galias - > groupofs ) ;
2004-08-22 22:29:09 +00:00
for ( i = 0 ; i < pq1inmodel - > numframes ; i + + )
{
switch ( LittleLong ( pframetype - > type ) )
{
case ALIAS_SINGLE :
2006-02-27 00:42:25 +00:00
frameinfo = ( daliasframe_t * ) ( ( char * ) ( pframetype + 1 ) ) ;
pinframe = ( dtrivertx_t * ) ( ( char * ) frameinfo + sizeof ( daliasframe_t ) ) ;
2004-08-22 22:29:09 +00:00
pose = ( galiaspose_t * ) Hunk_Alloc ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * 2 * galias - > numverts ) ;
frame - > poseofs = ( char * ) pose - ( char * ) frame ;
frame - > numposes = 1 ;
galias - > groups + + ;
2006-02-27 00:42:25 +00:00
Q_strncpyz ( frame - > name , frameinfo - > name , sizeof ( frame - > name ) ) ;
2004-08-22 22:29:09 +00:00
verts = ( vec3_t * ) ( pose + 1 ) ;
normals = & verts [ galias - > numverts ] ;
pose - > ofsverts = ( char * ) verts - ( char * ) pose ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
pose - > ofsnormals = ( char * ) normals - ( char * ) pose ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
for ( j = 0 ; j < pq1inmodel - > numverts ; j + + )
{
verts [ j ] [ 0 ] = pinframe [ j ] . v [ 0 ] * pq1inmodel - > scale [ 0 ] + pq1inmodel - > scale_origin [ 0 ] ;
verts [ j ] [ 1 ] = pinframe [ j ] . v [ 1 ] * pq1inmodel - > scale [ 1 ] + pq1inmodel - > scale_origin [ 1 ] ;
verts [ j ] [ 2 ] = pinframe [ j ] . v [ 2 ] * pq1inmodel - > scale [ 2 ] + pq1inmodel - > scale_origin [ 2 ] ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
VectorCopy ( r_avertexnormals [ pinframe [ j ] . lightnormalindex ] , normals [ j ] ) ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
if ( seamremaps [ j ] ! = j )
{
VectorCopy ( verts [ j ] , verts [ seamremaps [ j ] ] ) ;
VectorCopy ( normals [ j ] , normals [ seamremaps [ j ] ] ) ;
}
}
// GL_GenerateNormals((float*)verts, (float*)normals, (int *)((char *)galias + galias->ofs_indexes), galias->numindexes/3, galias->numverts);
2004-09-13 04:16:52 +00:00
pframetype = ( daliasframetype_t * ) & pinframe [ pq1inmodel - > numverts ] ;
2004-08-22 22:29:09 +00:00
break ;
2005-05-13 10:42:48 +00:00
2004-08-22 22:29:09 +00:00
case ALIAS_GROUP :
2005-05-08 03:41:24 +00:00
case ALIAS_GROUP_SWAPPED : // prerelease
2004-09-13 04:16:52 +00:00
ingroup = ( daliasgroup_t * ) ( pframetype + 1 ) ;
2004-08-22 22:29:09 +00:00
2005-04-19 21:09:29 +00:00
pose = ( galiaspose_t * ) Hunk_Alloc ( LittleLong ( ingroup - > numframes ) * ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * 2 * galias - > numverts ) ) ;
2004-08-22 22:29:09 +00:00
frame - > poseofs = ( char * ) pose - ( char * ) frame ;
frame - > numposes = LittleLong ( ingroup - > numframes ) ;
2006-03-06 01:41:09 +00:00
frame - > loop = true ;
2004-08-22 22:29:09 +00:00
galias - > groups + + ;
verts = ( vec3_t * ) ( pose + frame - > numposes ) ;
normals = & verts [ galias - > numverts ] ;
intervals = ( daliasinterval_t * ) ( ingroup + 1 ) ;
2006-03-06 02:02:17 +00:00
sinter = LittleFloat ( intervals - > interval ) ;
if ( sinter < = 0 )
sinter = 0.1 ;
frame - > rate = 1 / sinter ;
2004-08-22 22:29:09 +00:00
pinframe = ( dtrivertx_t * ) ( intervals + frame - > numposes ) ;
for ( k = 0 ; k < frame - > numposes ; k + + )
{
pose - > ofsverts = ( char * ) verts - ( char * ) pose ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
pose - > ofsnormals = ( char * ) normals - ( char * ) pose ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
2006-02-27 00:42:25 +00:00
frameinfo = ( daliasframe_t * ) pinframe ;
pinframe = ( dtrivertx_t * ) ( ( char * ) frameinfo + sizeof ( daliasframe_t ) ) ;
if ( k = = 0 )
Q_strncpyz ( frame - > name , frameinfo - > name , sizeof ( frame - > name ) ) ;
2004-08-22 22:29:09 +00:00
for ( j = 0 ; j < pq1inmodel - > numverts ; j + + )
{
verts [ j ] [ 0 ] = pinframe [ j ] . v [ 0 ] * pq1inmodel - > scale [ 0 ] + pq1inmodel - > scale_origin [ 0 ] ;
verts [ j ] [ 1 ] = pinframe [ j ] . v [ 1 ] * pq1inmodel - > scale [ 1 ] + pq1inmodel - > scale_origin [ 1 ] ;
verts [ j ] [ 2 ] = pinframe [ j ] . v [ 2 ] * pq1inmodel - > scale [ 2 ] + pq1inmodel - > scale_origin [ 2 ] ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
VectorCopy ( r_avertexnormals [ pinframe [ j ] . lightnormalindex ] , normals [ j ] ) ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
if ( seamremaps [ j ] ! = j )
{
VectorCopy ( verts [ j ] , verts [ seamremaps [ j ] ] ) ;
VectorCopy ( normals [ j ] , normals [ seamremaps [ j ] ] ) ;
}
}
verts = & normals [ galias - > numverts ] ;
normals = & verts [ galias - > numverts ] ;
pose + + ;
pinframe + = pq1inmodel - > numverts ;
}
// GL_GenerateNormals((float*)verts, (float*)normals, (int *)((char *)galias + galias->ofs_indexes), galias->numindexes/3, galias->numverts);
2004-09-13 04:16:52 +00:00
pframetype = ( daliasframetype_t * ) pinframe ;
2004-08-22 22:29:09 +00:00
break ;
default :
2006-03-12 08:01:48 +00:00
Con_Printf ( S_ERROR " Bad frame type in %s \n " , loadmodel - > name ) ;
return NULL ;
2004-08-22 22:29:09 +00:00
}
frame + + ;
}
return pframetype ;
}
2005-07-16 00:53:08 +00:00
# ifdef SERVERONLY //greatly reduced version of Q1_LoadSkins (too many #ifdefs
static void * Q1_LoadSkins ( daliasskintype_t * pskintype , qboolean alpha )
{
int i ;
int s ;
int * count ;
float * intervals ;
qbyte * data ;
s = pq1inmodel - > skinwidth * pq1inmodel - > skinheight ;
for ( i = 0 ; i < pq1inmodel - > numskins ; i + + )
{
switch ( LittleLong ( pskintype - > type ) )
{
case ALIAS_SKIN_SINGLE :
pskintype = ( daliasskintype_t * ) ( ( char * ) ( pskintype + 1 ) + s ) ;
break ;
default :
count = ( int * ) ( pskintype + 1 ) ;
intervals = ( float * ) ( count + 1 ) ;
data = ( qbyte * ) ( intervals + LittleLong ( * count ) ) ;
data + = s * LittleLong ( * count ) ;
pskintype = ( daliasskintype_t * ) data ;
break ;
}
}
galias - > numskins = pq1inmodel - > numskins ;
return pskintype ;
}
# else
2004-08-22 22:29:09 +00:00
static void * Q1_LoadSkins ( daliasskintype_t * pskintype , qboolean alpha )
{
2005-09-08 02:02:09 +00:00
extern cvar_t gl_bump ;
2004-08-22 22:29:09 +00:00
galiastexnum_t * texnums ;
char skinname [ MAX_QPATH ] ;
int i ;
int s , t ;
2006-03-06 02:02:17 +00:00
float sinter ;
2006-03-01 20:47:24 +00:00
daliasskingroup_t * count ;
daliasskininterval_t * intervals ;
2004-08-22 22:29:09 +00:00
qbyte * data , * saved ;
galiasskin_t * outskin = ( galiasskin_t * ) ( ( char * ) galias + galias - > ofsskins ) ;
int texture ;
int fbtexture ;
2005-09-08 02:02:09 +00:00
int bumptexture ;
2004-08-22 22:29:09 +00:00
s = pq1inmodel - > skinwidth * pq1inmodel - > skinheight ;
for ( i = 0 ; i < pq1inmodel - > numskins ; i + + )
{
switch ( LittleLong ( pskintype - > type ) )
{
case ALIAS_SKIN_SINGLE :
outskin - > skinwidth = pq1inmodel - > skinwidth ;
outskin - > skinheight = pq1inmodel - > skinheight ;
2005-04-26 16:04:12 +00:00
//LH's naming scheme ("models" is likly to be ignored)
2005-05-13 10:42:48 +00:00
fbtexture = 0 ;
2005-09-08 02:02:09 +00:00
bumptexture = 0 ;
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s_%i. " , loadmodel - > name , i ) ;
2005-04-26 16:04:12 +00:00
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
if ( texture )
2004-08-22 22:29:09 +00:00
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_luma. " , loadmodel - > name , i ) ;
2005-07-28 00:13:06 +00:00
fbtexture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
2005-09-08 02:02:09 +00:00
if ( gl_bump . value )
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_bump " , loadmodel - > name , i ) ;
2005-09-08 02:02:09 +00:00
bumptexture = Mod_LoadBumpmapTexture ( skinname , " models " ) ;
}
2005-04-26 16:04:12 +00:00
}
else
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s_%i " , loadname , i ) ;
2005-04-26 16:04:12 +00:00
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
2004-08-22 22:29:09 +00:00
if ( texture & & r_fb_models . value )
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_luma " , loadname , i ) ;
2005-04-26 16:04:12 +00:00
fbtexture = Mod_LoadReplacementTexture ( skinname , " models " , true , true , true ) ;
2004-08-22 22:29:09 +00:00
}
2005-09-08 02:02:09 +00:00
if ( texture & & gl_bump . value )
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_bump " , loadname , i ) ;
2005-09-08 02:02:09 +00:00
bumptexture = Mod_LoadBumpmapTexture ( skinname , " models " ) ;
}
2004-08-22 22:29:09 +00:00
}
2005-08-26 22:56:51 +00:00
//but only preload it if we have no replacement.
2004-08-22 22:29:09 +00:00
if ( ! texture )
{
2005-08-26 22:56:51 +00:00
//we're not using 24bits
texnums = Hunk_Alloc ( sizeof ( * texnums ) + s ) ;
saved = ( qbyte * ) ( texnums + 1 ) ;
outskin - > ofstexels = ( qbyte * ) ( saved ) - ( qbyte * ) outskin ;
memcpy ( saved , pskintype + 1 , s ) ;
GLMod_FloodFillSkin ( saved , outskin - > skinwidth , outskin - > skinheight ) ;
//the extra underscore is to stop
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s__%i " , loadname , i ) ;
2004-08-22 22:29:09 +00:00
texture = GL_LoadTexture ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , alpha ) ;
if ( r_fb_models . value )
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s__%i_luma " , loadname , i ) ;
2004-08-22 22:29:09 +00:00
fbtexture = GL_LoadTextureFB ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , true ) ;
}
2005-09-08 02:02:09 +00:00
if ( gl_bump . value )
{
2006-03-06 01:41:09 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s__%i_bump " , loadname , i ) ;
2005-09-08 02:02:09 +00:00
bumptexture = GL_LoadTexture8Bump ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , true ) ;
}
2004-08-22 22:29:09 +00:00
}
2005-08-26 22:56:51 +00:00
else
texnums = Hunk_Alloc ( sizeof ( * texnums ) ) ;
2004-08-22 22:29:09 +00:00
outskin - > texnums = 1 ;
outskin - > ofstexnums = ( char * ) texnums - ( char * ) outskin ;
2006-03-11 03:12:10 +00:00
2005-05-26 12:55:34 +00:00
# ifdef Q3SHADERS
2006-03-11 03:12:10 +00:00
if ( cls . allow_shaders )
{
sprintf ( skinname , " %s_%i " , loadname , i ) ;
texnums - > shader = R_RegisterCustom ( skinname , NULL ) ;
}
2005-05-26 12:55:34 +00:00
# endif
2006-03-11 03:12:10 +00:00
2005-05-26 12:55:34 +00:00
2004-08-22 22:29:09 +00:00
texnums - > base = texture ;
texnums - > fullbright = fbtexture ;
2005-09-08 02:02:09 +00:00
texnums - > bump = bumptexture ;
2004-08-22 22:29:09 +00:00
2004-09-13 04:16:52 +00:00
pskintype = ( daliasskintype_t * ) ( ( char * ) ( pskintype + 1 ) + s ) ;
2004-08-22 22:29:09 +00:00
break ;
default :
outskin - > skinwidth = pq1inmodel - > skinwidth ;
outskin - > skinheight = pq1inmodel - > skinheight ;
2006-03-01 20:47:24 +00:00
count = ( daliasskingroup_t * ) ( pskintype + 1 ) ;
intervals = ( daliasskininterval_t * ) ( count + 1 ) ;
outskin - > texnums = LittleLong ( count - > numskins ) ;
2004-08-22 22:29:09 +00:00
data = ( qbyte * ) ( intervals + outskin - > texnums ) ;
texnums = Hunk_Alloc ( sizeof ( * texnums ) * outskin - > texnums ) ;
outskin - > ofstexnums = ( char * ) texnums - ( char * ) outskin ;
outskin - > ofstexels = 0 ;
2006-03-06 02:02:17 +00:00
sinter = LittleFloat ( intervals [ 0 ] . interval ) ;
if ( sinter < = 0 )
sinter = 0.1 ;
outskin - > skinspeed = 1 / sinter ;
2006-03-01 20:47:24 +00:00
2004-08-22 22:29:09 +00:00
for ( t = 0 ; t < outskin - > texnums ; t + + , data + = s , texnums + + )
{
2005-04-26 16:04:12 +00:00
texture = 0 ;
fbtexture = 0 ;
//LH naming scheme
if ( ! texture )
2004-08-22 22:29:09 +00:00
{
2005-08-03 23:14:59 +00:00
sprintf ( skinname , " %s_%i_%i. " , loadmodel - > name , i , t ) ;
2005-04-26 16:04:12 +00:00
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
2004-08-22 22:29:09 +00:00
}
2005-04-26 16:04:12 +00:00
if ( ! fbtexture & & r_fb_models . value )
{
2005-08-03 23:14:59 +00:00
sprintf ( skinname , " %s_%i_%i_luma. " , loadmodel - > name , i , t ) ;
2005-04-26 16:04:12 +00:00
fbtexture = Mod_LoadReplacementTexture ( skinname , " models " , true , true , true ) ;
}
//Fuhquake naming scheme
if ( ! texture )
{
sprintf ( skinname , " %s_%i_%i " , loadname , i , t ) ;
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
}
if ( ! fbtexture & & r_fb_models . value )
{
sprintf ( skinname , " %s_%i_%i_luma " , loadname , i , t ) ;
fbtexture = Mod_LoadReplacementTexture ( skinname , " models " , true , true , true ) ;
}
if ( ! texture | | ( ! fbtexture & & r_fb_models . value ) )
2004-08-22 22:29:09 +00:00
{
if ( t = = 0 )
{
saved = Hunk_Alloc ( s ) ;
outskin - > ofstexels = ( qbyte * ) ( saved ) - ( qbyte * ) outskin ;
}
else
saved = BZ_Malloc ( s ) ;
2006-03-01 20:47:24 +00:00
memcpy ( saved , data , s ) ;
2004-08-22 22:29:09 +00:00
GLMod_FloodFillSkin ( saved , outskin - > skinwidth , outskin - > skinheight ) ;
2005-04-26 16:04:12 +00:00
if ( ! texture )
2004-08-22 22:29:09 +00:00
{
2005-04-26 16:04:12 +00:00
sprintf ( skinname , " %s_%i_%i " , loadname , i , t ) ;
texture = GL_LoadTexture ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , alpha ) ;
2004-08-22 22:29:09 +00:00
}
2005-04-26 16:04:12 +00:00
if ( ! fbtexture & & r_fb_models . value )
2004-08-22 22:29:09 +00:00
{
2005-04-26 16:04:12 +00:00
sprintf ( skinname , " %s_%i_%i_luma " , loadname , i , t ) ;
fbtexture = GL_LoadTextureFB ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , true ) ;
2004-08-22 22:29:09 +00:00
}
if ( t ! = 0 ) //only keep the first.
BZ_Free ( saved ) ;
}
2006-03-11 03:12:10 +00:00
2005-05-26 12:55:34 +00:00
# ifdef Q3SHADERS
2006-03-11 03:12:10 +00:00
if ( cls . allow_shaders )
{
sprintf ( skinname , " %s_%i_%i " , loadname , i , t ) ;
texnums - > shader = R_RegisterCustom ( skinname , NULL ) ;
}
2005-05-26 12:55:34 +00:00
# endif
2006-03-11 03:12:10 +00:00
2005-04-26 16:04:12 +00:00
texnums - > base = texture ;
texnums - > fullbright = fbtexture ;
2005-11-26 03:02:55 +00:00
}
2004-09-13 04:16:52 +00:00
pskintype = ( daliasskintype_t * ) data ;
2004-08-22 22:29:09 +00:00
break ;
}
outskin + + ;
}
galias - > numskins = pq1inmodel - > numskins ;
return pskintype ;
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
2006-03-12 08:01:48 +00:00
qboolean GL_LoadQ1Model ( model_t * mod , void * buffer )
2004-08-22 22:29:09 +00:00
{
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
vec2_t * st_array ;
2005-07-16 00:53:08 +00:00
int j ;
# endif
2004-08-22 22:29:09 +00:00
int hunkstart , hunkend , hunktotal ;
int version ;
2005-07-16 00:53:08 +00:00
int i , onseams ;
2004-08-22 22:29:09 +00:00
dstvert_t * pinstverts ;
dtriangle_t * pintriangles ;
int * seamremap ;
2004-10-19 16:10:14 +00:00
index_t * indexes ;
2006-03-13 23:20:49 +00:00
qboolean qtest = false ;
2004-08-22 22:29:09 +00:00
int size ;
loadmodel = mod ;
2005-07-16 00:53:08 +00:00
Mod_DoCRC ( loadmodel , buffer , com_filesize ) ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
hunkstart = Hunk_LowMark ( ) ;
pq1inmodel = ( dmdl_t * ) buffer ;
2006-04-16 06:03:58 +00:00
loadmodel - > engineflags | = MDLF_NEEDOVERBRIGHT ;
2006-04-03 18:52:28 +00:00
version = LittleLong ( pq1inmodel - > version ) ;
2006-03-13 23:20:49 +00:00
if ( version = = QTESTALIAS_VERSION )
qtest = true ;
else if ( version ! = ALIAS_VERSION )
2006-03-12 08:01:48 +00:00
{
2006-03-12 09:19:31 +00:00
Con_Printf ( S_ERROR " %s has wrong version number (%i should be %i) \n " ,
2004-08-22 22:29:09 +00:00
mod - > name , version , ALIAS_VERSION ) ;
2006-03-12 08:01:48 +00:00
return false ;
}
2004-08-22 22:29:09 +00:00
2006-03-13 23:20:49 +00:00
seamremap = ( int * ) pq1inmodel ; //I like overloading locals.
if ( qtest )
i = sizeof ( dmdl_t ) / 4 - sizeof ( int ) * 2 - 1 ;
else
i = sizeof ( dmdl_t ) / 4 - 1 ;
for ( ; i > = 0 ; i - - )
seamremap [ i ] = LittleLong ( seamremap [ i ] ) ;
2004-08-22 22:29:09 +00:00
if ( pq1inmodel - > numframes < 1 | |
pq1inmodel - > numskins < 1 | |
pq1inmodel - > numtris < 1 | |
pq1inmodel - > numverts < 3 | |
pq1inmodel - > skinheight < 1 | |
pq1inmodel - > skinwidth < 1 )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " Model %s has an invalid quantity \n " , mod - > name ) ;
return false ;
}
2004-08-22 22:29:09 +00:00
2006-03-13 23:20:49 +00:00
if ( qtest )
mod - > flags = 0 ; // Qtest has no flags in header
else
mod - > flags = pq1inmodel - > flags ;
2004-08-22 22:29:09 +00:00
size = sizeof ( galiasinfo_t )
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
+ pq1inmodel - > numskins * sizeof ( galiasskin_t )
# endif
+ pq1inmodel - > numframes * sizeof ( galiasgroup_t ) ;
2004-08-22 22:29:09 +00:00
galias = Hunk_Alloc ( size ) ;
galias - > groupofs = sizeof ( * galias ) ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
galias - > ofsskins = sizeof ( * galias ) + pq1inmodel - > numframes * sizeof ( galiasgroup_t ) ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
galias - > nextsurf = 0 ;
//skins
2006-03-13 23:20:49 +00:00
if ( qtest )
pinstverts = ( dstvert_t * ) Q1_LoadSkins ( ( daliasskintype_t * ) ( ( char * ) buffer + sizeof ( dmdl_t ) - sizeof ( int ) * 2 ) , 0 ) ;
else if ( mod - > flags & EF_HOLEY )
2004-08-22 22:29:09 +00:00
pinstverts = ( dstvert_t * ) Q1_LoadSkins ( ( daliasskintype_t * ) ( pq1inmodel + 1 ) , 3 ) ;
else if ( mod - > flags & EF_TRANSPARENT )
pinstverts = ( dstvert_t * ) Q1_LoadSkins ( ( daliasskintype_t * ) ( pq1inmodel + 1 ) , 2 ) ;
else if ( mod - > flags & EF_SPECIAL_TRANS )
pinstverts = ( dstvert_t * ) Q1_LoadSkins ( ( daliasskintype_t * ) ( pq1inmodel + 1 ) , 4 ) ;
else
pinstverts = ( dstvert_t * ) Q1_LoadSkins ( ( daliasskintype_t * ) ( pq1inmodel + 1 ) , 0 ) ;
// pinstverts = (dstvert_t *)Q1_LoadSkins((daliasskintype_t *)(pq1inmodel+1));
//count number of verts that are onseam.
for ( onseams = 0 , i = 0 ; i < pq1inmodel - > numverts ; i + + )
{
if ( pinstverts [ i ] . onseam )
onseams + + ;
}
seamremap = BZ_Malloc ( sizeof ( int ) * pq1inmodel - > numverts ) ;
galias - > numverts = pq1inmodel - > numverts + onseams ;
2005-07-16 00:53:08 +00:00
2004-08-22 22:29:09 +00:00
//st
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
st_array = Hunk_Alloc ( sizeof ( * st_array ) * ( pq1inmodel - > numverts + onseams ) ) ;
galias - > ofs_st_array = ( char * ) st_array - ( char * ) galias ;
for ( j = pq1inmodel - > numverts , i = 0 ; i < pq1inmodel - > numverts ; i + + )
{
2006-03-01 20:47:24 +00:00
st_array [ i ] [ 0 ] = ( LittleLong ( pinstverts [ i ] . s ) + 0.5 ) / ( float ) pq1inmodel - > skinwidth ;
st_array [ i ] [ 1 ] = ( LittleLong ( pinstverts [ i ] . t ) + 0.5 ) / ( float ) pq1inmodel - > skinheight ;
2004-08-22 22:29:09 +00:00
if ( pinstverts [ i ] . onseam )
{
st_array [ j ] [ 0 ] = st_array [ i ] [ 0 ] + 0.5 ;
st_array [ j ] [ 1 ] = st_array [ i ] [ 1 ] ;
seamremap [ i ] = j ;
j + + ;
}
else
seamremap [ i ] = i ;
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
//trianglelists;
pintriangles = ( dtriangle_t * ) & pinstverts [ pq1inmodel - > numverts ] ;
galias - > numindexes = pq1inmodel - > numtris * 3 ;
indexes = Hunk_Alloc ( galias - > numindexes * sizeof ( * indexes ) ) ;
galias - > ofs_indexes = ( char * ) indexes - ( char * ) galias ;
for ( i = 0 ; i < pq1inmodel - > numtris ; i + + )
{
if ( ! pintriangles [ i ] . facesfront )
{
indexes [ i * 3 + 0 ] = seamremap [ LittleLong ( pintriangles [ i ] . vertindex [ 0 ] ) ] ;
indexes [ i * 3 + 1 ] = seamremap [ LittleLong ( pintriangles [ i ] . vertindex [ 1 ] ) ] ;
indexes [ i * 3 + 2 ] = seamremap [ LittleLong ( pintriangles [ i ] . vertindex [ 2 ] ) ] ;
}
else
{
indexes [ i * 3 + 0 ] = LittleLong ( pintriangles [ i ] . vertindex [ 0 ] ) ;
indexes [ i * 3 + 1 ] = LittleLong ( pintriangles [ i ] . vertindex [ 1 ] ) ;
indexes [ i * 3 + 2 ] = LittleLong ( pintriangles [ i ] . vertindex [ 2 ] ) ;
}
}
//frames
2006-03-13 23:20:49 +00:00
if ( qtest )
2006-03-12 08:01:48 +00:00
{
2006-03-13 23:20:49 +00:00
if ( QTest_LoadFrameGroup ( ( daliasframetype_t * ) & pintriangles [ pq1inmodel - > numtris ] , seamremap ) = = NULL )
{
BZ_Free ( seamremap ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
}
else
{
if ( Q1_LoadFrameGroup ( ( daliasframetype_t * ) & pintriangles [ pq1inmodel - > numtris ] , seamremap ) = = NULL )
{
BZ_Free ( seamremap ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2006-03-12 08:01:48 +00:00
}
2004-08-22 22:29:09 +00:00
BZ_Free ( seamremap ) ;
2006-03-12 08:01:48 +00:00
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
if ( r_shadows . value )
{
int * neighbours ;
neighbours = Hunk_Alloc ( sizeof ( int ) * 3 * pq1inmodel - > numtris ) ;
galias - > ofs_trineighbours = ( qbyte * ) neighbours - ( qbyte * ) galias ;
R_BuildTriangleNeighbours ( neighbours , indexes , pq1inmodel - > numtris ) ;
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
VectorCopy ( pq1inmodel - > scale_origin , mod - > mins ) ;
VectorMA ( mod - > mins , 255 , pq1inmodel - > scale , mod - > maxs ) ;
//
// move the complete, relocatable alias model to the cache
2005-11-26 03:02:55 +00:00
//
2004-08-22 22:29:09 +00:00
hunkend = Hunk_LowMark ( ) ;
2004-10-10 06:32:29 +00:00
Hunk_Alloc ( 0 ) ;
2004-08-22 22:29:09 +00:00
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-12 08:01:48 +00:00
return false ;
2004-08-22 22:29:09 +00:00
}
memcpy ( mod - > cache . data , galias , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
2005-07-16 00:53:08 +00:00
mod - > funcs . Trace = GLMod_Trace ;
2006-03-12 08:01:48 +00:00
return true ;
2004-08-22 22:29:09 +00:00
}
# endif
int Mod_ReadFlagsFromMD1 ( char * name , int md3version )
{
dmdl_t * pinmodel ;
char fname [ MAX_QPATH ] ;
2006-03-11 03:12:10 +00:00
COM_StripExtension ( name , fname , sizeof ( fname ) ) ;
COM_DefaultExtension ( fname , " .mdl " , sizeof ( fname ) ) ;
2004-08-22 22:29:09 +00:00
2004-10-19 16:10:14 +00:00
if ( strcmp ( name , fname ) ) //md3 renamed as mdl
2004-08-22 22:29:09 +00:00
{
2006-03-11 03:12:10 +00:00
COM_StripExtension ( name , fname , sizeof ( fname ) ) ; //seeing as the md3 is named over the mdl,
COM_DefaultExtension ( fname , " .md1 " , sizeof ( fname ) ) ; //read from a file with md1 (one, not an ell)
2004-08-22 22:29:09 +00:00
return 0 ;
}
pinmodel = ( dmdl_t * ) COM_LoadTempFile ( fname ) ;
if ( ! pinmodel ) //not found
return 0 ;
2004-12-11 16:44:36 +00:00
if ( LittleLong ( pinmodel - > ident ) ! = IDPOLYHEADER )
2004-08-22 22:29:09 +00:00
return 0 ;
2004-12-11 16:44:36 +00:00
if ( LittleLong ( pinmodel - > version ) ! = ALIAS_VERSION )
2004-08-22 22:29:09 +00:00
return 0 ;
2004-12-11 16:44:36 +00:00
return LittleLong ( pinmodel - > flags ) ;
2004-08-22 22:29:09 +00:00
}
# ifdef MD2MODELS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Q2 model loading
static galiasinfo_t * galias ;
static model_t * loadmodel ;
static md2_t * pq2inmodel ;
# define Q2NUMVERTEXNORMALS 162
extern vec3_t bytedirs [ Q2NUMVERTEXNORMALS ] ;
static void Q2_LoadSkins ( char * skins )
{
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
int i ;
galiastexnum_t * texnums ;
galiasskin_t * outskin = ( galiasskin_t * ) ( ( char * ) galias + galias - > ofsskins ) ;
2005-11-29 11:57:02 +00:00
for ( i = 0 ; i < LittleLong ( pq2inmodel - > num_skins ) ; i + + , outskin + + )
2004-08-22 22:29:09 +00:00
{
texnums = Hunk_Alloc ( sizeof ( * texnums ) ) ;
outskin - > ofstexnums = ( char * ) texnums - ( char * ) outskin ;
outskin - > texnums = 1 ;
2005-03-18 06:14:33 +00:00
COM_CleanUpPath ( skins ) ; //blooming tanks.
2005-04-26 16:04:12 +00:00
texnums - > base = Mod_LoadReplacementTexture ( skins , " models " , true , false , true ) ;
2006-02-22 23:49:35 +00:00
texnums - > shader = R_RegisterCustom ( skins , NULL ) ;
if ( ! texnums - > base & & ! texnums - > shader )
Con_Printf ( " Couldn't load %s \n " , skins ) ;
2004-08-22 22:29:09 +00:00
outskin - > skinwidth = 0 ;
outskin - > skinheight = 0 ;
outskin - > skinspeed = 0 ;
skins + = MD2MAX_SKINNAME ;
}
2005-07-16 00:53:08 +00:00
# endif
2005-11-29 11:57:02 +00:00
galias - > numskins = LittleLong ( pq2inmodel - > num_skins ) ;
2006-02-22 23:49:35 +00:00
# ifndef SERVERONLY
2006-02-28 00:46:04 +00:00
outskin = ( galiasskin_t * ) ( ( char * ) galias + galias - > ofsskins ) ;
outskin + = galias - > numskins - 1 ;
if ( galias - > numskins )
2006-02-22 23:49:35 +00:00
{
2006-02-28 00:46:04 +00:00
texnums = ( galiastexnum_t * ) ( ( char * ) outskin + outskin - > ofstexnums ) ;
2006-02-22 23:49:35 +00:00
if ( texnums - > base )
2006-02-28 00:46:04 +00:00
return ;
2006-02-22 23:49:35 +00:00
if ( texnums - > shader )
2006-02-28 00:46:04 +00:00
return ;
2006-02-22 23:49:35 +00:00
galias - > numskins - - ;
}
# endif
2004-08-22 22:29:09 +00:00
}
# define MD2_MAX_TRIANGLES 4096
2006-03-12 08:01:48 +00:00
qboolean GL_LoadQ2Model ( model_t * mod , void * buffer )
2004-08-22 22:29:09 +00:00
{
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
dmd2stvert_t * pinstverts ;
vec2_t * st_array ;
vec3_t * normals ;
# endif
2004-08-22 22:29:09 +00:00
int hunkstart , hunkend , hunktotal ;
int version ;
int i , j ;
dmd2triangle_t * pintri ;
2004-10-19 16:10:14 +00:00
index_t * indexes ;
2004-08-22 22:29:09 +00:00
int numindexes ;
vec3_t min ;
vec3_t max ;
galiaspose_t * pose ;
galiasgroup_t * poutframe ;
dmd2aliasframe_t * pinframe ;
int framesize ;
vec3_t * verts ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
int indremap [ MD2_MAX_TRIANGLES * 3 ] ;
unsigned short ptempindex [ MD2_MAX_TRIANGLES * 3 ] , ptempstindex [ MD2_MAX_TRIANGLES * 3 ] ;
int numverts ;
int size ;
loadmodel = mod ;
2006-04-16 06:03:58 +00:00
loadmodel - > engineflags | = MDLF_NEEDOVERBRIGHT ;
2005-07-16 00:53:08 +00:00
Mod_DoCRC ( mod , buffer , com_filesize ) ;
2004-08-22 22:29:09 +00:00
hunkstart = Hunk_LowMark ( ) ;
pq2inmodel = ( md2_t * ) buffer ;
version = LittleLong ( pq2inmodel - > version ) ;
if ( version ! = MD2ALIAS_VERSION )
2006-03-12 08:01:48 +00:00
{
2006-03-12 09:19:31 +00:00
Con_Printf ( S_ERROR " %s has wrong version number (%i should be %i) \n " ,
2004-08-22 22:29:09 +00:00
mod - > name , version , MD2ALIAS_VERSION ) ;
2006-03-12 08:01:48 +00:00
return false ;
}
2004-08-22 22:29:09 +00:00
2005-11-29 11:57:02 +00:00
if ( LittleLong ( pq2inmodel - > num_frames ) < 1 | |
LittleLong ( pq2inmodel - > num_skins ) < 0 | |
LittleLong ( pq2inmodel - > num_tris ) < 1 | |
LittleLong ( pq2inmodel - > num_xyz ) < 3 | |
LittleLong ( pq2inmodel - > num_st ) < 3 | |
LittleLong ( pq2inmodel - > skinheight ) < 1 | |
LittleLong ( pq2inmodel - > skinwidth ) < 1 )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " Model %s has an invalid quantity \n " , mod - > name ) ;
return false ;
}
2004-08-22 22:29:09 +00:00
mod - > flags = 0 ;
2005-11-29 11:57:02 +00:00
loadmodel - > numframes = LittleLong ( pq2inmodel - > num_frames ) ;
2005-03-18 06:14:33 +00:00
2004-08-22 22:29:09 +00:00
size = sizeof ( galiasinfo_t )
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-11-29 11:57:02 +00:00
+ LittleLong ( pq2inmodel - > num_skins ) * sizeof ( galiasskin_t )
2005-07-16 00:53:08 +00:00
# endif
2005-11-29 11:57:02 +00:00
+ LittleLong ( pq2inmodel - > num_frames ) * sizeof ( galiasgroup_t ) ;
2004-08-22 22:29:09 +00:00
galias = Hunk_Alloc ( size ) ;
galias - > groupofs = sizeof ( * galias ) ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-11-29 11:57:02 +00:00
galias - > ofsskins = sizeof ( * galias ) + LittleLong ( pq2inmodel - > num_frames ) * sizeof ( galiasgroup_t ) ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
galias - > nextsurf = 0 ;
//skins
2005-11-29 11:57:02 +00:00
Q2_LoadSkins ( ( ( char * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_skins ) ) ) ;
2004-08-22 22:29:09 +00:00
//trianglelists;
2005-11-29 11:57:02 +00:00
pintri = ( dmd2triangle_t * ) ( ( char * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_tris ) ) ;
2004-08-22 22:29:09 +00:00
2005-11-29 11:57:02 +00:00
for ( i = 0 ; i < LittleLong ( pq2inmodel - > num_tris ) ; i + + , pintri + + )
2004-08-22 22:29:09 +00:00
{
for ( j = 0 ; j < 3 ; j + + )
{
ptempindex [ i * 3 + j ] = ( unsigned short ) LittleShort ( pintri - > xyz_index [ j ] ) ;
ptempstindex [ i * 3 + j ] = ( unsigned short ) LittleShort ( pintri - > st_index [ j ] ) ;
}
}
2005-11-29 11:57:02 +00:00
numindexes = galias - > numindexes = LittleLong ( pq2inmodel - > num_tris ) * 3 ;
2004-08-22 22:29:09 +00:00
indexes = Hunk_Alloc ( galias - > numindexes * sizeof ( * indexes ) ) ;
galias - > ofs_indexes = ( char * ) indexes - ( char * ) galias ;
memset ( indremap , - 1 , sizeof ( indremap ) ) ;
numverts = 0 ;
for ( i = 0 ; i < numindexes ; i + + )
{
if ( indremap [ i ] ! = - 1 ) {
continue ;
}
for ( j = 0 ; j < numindexes ; j + + )
{
if ( j = = i ) {
continue ;
}
if ( ( ptempindex [ i ] = = ptempindex [ j ] ) & & ( ptempstindex [ i ] = = ptempstindex [ j ] ) ) {
indremap [ j ] = i ;
}
}
}
// count unique vertexes
for ( i = 0 ; i < numindexes ; i + + )
{
if ( indremap [ i ] ! = - 1 ) {
continue ;
}
indexes [ i ] = numverts + + ;
indremap [ i ] = i ;
}
2005-11-29 11:57:02 +00:00
Con_DPrintf ( " %s: remapped %i verts to %i \n " , mod - > name , LittleLong ( pq2inmodel - > num_xyz ) , numverts ) ;
2004-08-22 22:29:09 +00:00
galias - > numverts = numverts ;
// remap remaining indexes
2005-11-26 03:02:55 +00:00
for ( i = 0 ; i < numindexes ; i + + )
2004-08-22 22:29:09 +00:00
{
if ( indremap [ i ] ! = i ) {
indexes [ i ] = indexes [ indremap [ i ] ] ;
}
}
// s and t vertices
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
pinstverts = ( dmd2stvert_t * ) ( ( qbyte * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_st ) ) ;
st_array = Hunk_Alloc ( sizeof ( * st_array ) * ( numverts ) ) ;
galias - > ofs_st_array = ( char * ) st_array - ( char * ) galias ;
for ( j = 0 ; j < numindexes ; j + + )
{
2005-11-29 11:57:02 +00:00
st_array [ indexes [ j ] ] [ 0 ] = ( float ) ( ( ( double ) LittleShort ( pinstverts [ ptempstindex [ indremap [ j ] ] ] . s ) + 0.5f ) / LittleLong ( pq2inmodel - > skinwidth ) ) ;
st_array [ indexes [ j ] ] [ 1 ] = ( float ) ( ( ( double ) LittleShort ( pinstverts [ ptempstindex [ indremap [ j ] ] ] . t ) + 0.5f ) / LittleLong ( pq2inmodel - > skinheight ) ) ;
2004-08-22 22:29:09 +00:00
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
//frames
ClearBounds ( mod - > mins , mod - > maxs ) ;
poutframe = ( galiasgroup_t * ) ( ( char * ) galias + galias - > groupofs ) ;
framesize = LittleLong ( pq2inmodel - > framesize ) ;
2005-11-29 11:57:02 +00:00
for ( i = 0 ; i < LittleLong ( pq2inmodel - > num_frames ) ; i + + )
2004-08-22 22:29:09 +00:00
{
2005-07-16 00:53:08 +00:00
pose = ( galiaspose_t * ) Hunk_Alloc ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * numverts
# ifndef SERVERONLY
+ sizeof ( vec3_t ) * numverts
# endif
) ;
2004-08-22 22:29:09 +00:00
poutframe - > poseofs = ( char * ) pose - ( char * ) poutframe ;
poutframe - > numposes = 1 ;
galias - > groups + + ;
verts = ( vec3_t * ) ( pose + 1 ) ;
pose - > ofsverts = ( char * ) verts - ( char * ) pose ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
normals = & verts [ galias - > numverts ] ;
2004-08-22 22:29:09 +00:00
pose - > ofsnormals = ( char * ) normals - ( char * ) pose ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
pinframe = ( dmd2aliasframe_t * ) ( ( qbyte * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_frames ) + i * framesize ) ;
2006-02-27 00:42:25 +00:00
Q_strncpyz ( poutframe - > name , pinframe - > name , sizeof ( poutframe - > name ) ) ;
2004-08-22 22:29:09 +00:00
for ( j = 0 ; j < 3 ; j + + )
{
pose - > scale [ j ] = LittleFloat ( pinframe - > scale [ j ] ) ;
pose - > scale_origin [ j ] = LittleFloat ( pinframe - > translate [ j ] ) ;
}
for ( j = 0 ; j < numindexes ; j + + )
{
// verts are all 8 bit, so no swapping needed
verts [ indexes [ j ] ] [ 0 ] = pose - > scale_origin [ 0 ] + pose - > scale [ 0 ] * pinframe - > verts [ ptempindex [ indremap [ j ] ] ] . v [ 0 ] ;
verts [ indexes [ j ] ] [ 1 ] = pose - > scale_origin [ 1 ] + pose - > scale [ 1 ] * pinframe - > verts [ ptempindex [ indremap [ j ] ] ] . v [ 1 ] ;
verts [ indexes [ j ] ] [ 2 ] = pose - > scale_origin [ 2 ] + pose - > scale [ 2 ] * pinframe - > verts [ ptempindex [ indremap [ j ] ] ] . v [ 2 ] ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
VectorCopy ( bytedirs [ pinframe - > verts [ ptempindex [ indremap [ j ] ] ] . lightnormalindex ] , normals [ indexes [ j ] ] ) ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
}
// Mod_AliasCalculateVertexNormals ( numindexes, poutindex, numverts, poutvertex, qfalse );
VectorCopy ( pose - > scale_origin , min ) ;
VectorMA ( pose - > scale_origin , 255 , pose - > scale , max ) ;
// poutframe->radius = RadiusFromBounds ( min, max );
// mod->radius = max ( mod->radius, poutframe->radius );
AddPointToBounds ( min , mod - > mins , mod - > maxs ) ;
AddPointToBounds ( max , mod - > mins , mod - > maxs ) ;
// GL_GenerateNormals((float*)verts, (float*)normals, indexes, numindexes/3, numverts);
poutframe + + ;
}
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
if ( r_shadows . value )
{
int * neighbours ;
2005-11-29 11:57:02 +00:00
neighbours = Hunk_Alloc ( sizeof ( int ) * 3 * LittleLong ( pq2inmodel - > num_tris ) ) ;
2004-08-22 22:29:09 +00:00
galias - > ofs_trineighbours = ( qbyte * ) neighbours - ( qbyte * ) galias ;
2005-11-29 11:57:02 +00:00
R_BuildTriangleNeighbours ( neighbours , indexes , LittleLong ( pq2inmodel - > num_tris ) ) ;
2004-08-22 22:29:09 +00:00
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
/*
VectorCopy ( pq2inmodel - > scale_origin , mod - > mins ) ;
VectorMA ( mod - > mins , 255 , pq2inmodel - > scale , mod - > maxs ) ;
*/
//
// move the complete, relocatable alias model to the cache
2005-11-26 03:02:55 +00:00
//
2004-08-22 22:29:09 +00:00
hunkend = Hunk_LowMark ( ) ;
2004-10-19 16:10:14 +00:00
Hunk_Alloc ( 0 ) ;
2004-08-22 22:29:09 +00:00
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-12 08:01:48 +00:00
return false ;
2004-08-22 22:29:09 +00:00
}
memcpy ( mod - > cache . data , galias , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
2005-07-16 00:53:08 +00:00
mod - > funcs . Trace = GLMod_Trace ;
2006-03-12 08:01:48 +00:00
return true ;
2004-08-22 22:29:09 +00:00
}
# endif
2004-11-17 18:13:33 +00:00
typedef struct {
char name [ MAX_QPATH ] ;
vec3_t org ;
float ang [ 3 ] [ 3 ] ;
} md3tag_t ;
2004-08-22 22:29:09 +00:00
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-06-14 04:52:10 +00:00
qboolean GLMod_GetTag ( model_t * model , int tagnum , int frame1 , int frame2 , float f2ness , float f1time , float f2time , float * result )
2005-07-16 00:53:08 +00:00
# else
qboolean Mod_GetTag ( model_t * model , int tagnum , int frame1 , int frame2 , float f2ness , float f1time , float f2time , float * result )
# endif
2004-11-17 18:13:33 +00:00
{
galiasinfo_t * inf ;
2004-08-22 22:29:09 +00:00
2005-06-14 04:52:10 +00:00
2004-11-17 18:13:33 +00:00
if ( ! model | | model - > type ! = mod_alias )
2005-06-14 04:52:10 +00:00
return false ;
2004-08-22 22:29:09 +00:00
2004-11-17 18:13:33 +00:00
inf = Mod_Extradata ( model ) ;
2005-06-14 04:52:10 +00:00
# ifdef SKELETALMODELS
if ( inf - > numbones )
{
galiasbone_t * bone ;
galiasgroup_t * g1 , * g2 ;
float tempmatrix [ 12 ] ; //flipped between this and bonematrix
float * matrix ; //the matrix for a single bone in a single pose.
float m [ 12 ] ; //combined interpolated version of 'matrix'.
int b , k ; //counters
float * pose [ 4 ] ; //the per-bone matricies (one for each pose)
float plerp [ 4 ] ; //the ammount of that pose to use (must combine to 1)
int numposes = 0 ;
if ( tagnum < = 0 | | tagnum > inf - > numbones )
return false ;
tagnum - - ; //tagnum 0 is 'use my angles/org'
if ( frame1 < 0 | | frame1 > = inf - > groups )
return false ;
if ( frame2 < 0 | | frame2 > = inf - > groups )
{
f2ness = 0 ;
frame2 = frame1 ;
}
bone = ( galiasbone_t * ) ( ( char * ) inf + inf - > ofsbones ) ;
//the higher level merges old/new anims, but we still need to blend between automated frame-groups.
g1 = ( galiasgroup_t * ) ( ( char * ) inf + inf - > groupofs + sizeof ( galiasgroup_t ) * frame1 ) ;
g2 = ( galiasgroup_t * ) ( ( char * ) inf + inf - > groupofs + sizeof ( galiasgroup_t ) * frame2 ) ;
2005-07-01 19:23:00 +00:00
f1time * = g1 - > rate ;
2005-06-14 04:52:10 +00:00
frame1 = ( int ) f1time % g1 - > numposes ;
frame2 = ( ( int ) f1time + 1 ) % g1 - > numposes ;
f1time = f1time - ( int ) f1time ;
pose [ numposes ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame1 ) ;
plerp [ numposes ] = ( 1 - f1time ) * ( 1 - f2ness ) ;
numposes + + ;
if ( frame1 ! = frame2 )
{
pose [ numposes ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame2 ) ;
plerp [ numposes ] = f1time * ( 1 - f2ness ) ;
numposes + + ;
}
if ( f2ness )
{
2005-07-01 19:23:00 +00:00
f2time * = g2 - > rate ;
2005-06-14 04:52:10 +00:00
frame1 = ( int ) f2time % g2 - > numposes ;
frame2 = ( ( int ) f2time + 1 ) % g2 - > numposes ;
f2time = f2time - ( int ) f2time ;
pose [ numposes ] = ( float * ) ( ( char * ) g2 + g2 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame1 ) ;
plerp [ numposes ] = ( 1 - f2time ) * f2ness ;
numposes + + ;
if ( frame1 ! = frame2 )
{
pose [ numposes ] = ( float * ) ( ( char * ) g2 + g2 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame2 ) ;
plerp [ numposes ] = f2time * f2ness ;
numposes + + ;
}
}
//set up the identity matrix
for ( k = 0 ; k < 12 ; k + + )
result [ k ] = 0 ;
result [ 0 ] = 1 ;
result [ 5 ] = 1 ;
result [ 10 ] = 1 ;
while ( tagnum > = 0 )
{
//set up the per-bone transform matrix
for ( k = 0 ; k < 12 ; k + + )
m [ k ] = 0 ;
for ( b = 0 ; b < numposes ; b + + )
{
matrix = pose [ b ] + tagnum * 12 ;
2005-11-26 03:02:55 +00:00
2005-06-14 04:52:10 +00:00
for ( k = 0 ; k < 12 ; k + + )
m [ k ] + = matrix [ k ] * plerp [ b ] ;
}
memcpy ( tempmatrix , result , sizeof ( tempmatrix ) ) ;
R_ConcatTransforms ( ( void * ) m , ( void * ) tempmatrix , ( void * ) result ) ;
2004-08-22 22:29:09 +00:00
2005-06-14 04:52:10 +00:00
tagnum = bone [ tagnum ] . parent ;
}
return true ;
}
# endif
if ( inf - > numtags )
{
md3tag_t * t1 , * t2 ;
if ( tagnum < = 0 | | tagnum > inf - > numtags )
return false ;
2005-08-26 22:56:51 +00:00
if ( frame1 < 0 )
2005-06-14 04:52:10 +00:00
return false ;
2005-08-26 22:56:51 +00:00
if ( frame1 > = inf - > numtagframes )
frame1 = inf - > numtagframes - 1 ;
2005-06-14 04:52:10 +00:00
if ( frame2 < 0 | | frame2 > = inf - > numtagframes )
frame2 = frame1 ;
tagnum - - ; //tagnum 0 is 'use my angles/org'
t1 = ( md3tag_t * ) ( ( char * ) inf + inf - > ofstags ) ;
t1 + = tagnum ;
t1 + = inf - > numtags * frame1 ;
2005-11-26 03:02:55 +00:00
2005-06-14 04:52:10 +00:00
t2 = ( md3tag_t * ) ( ( char * ) inf + inf - > ofstags ) ;
t2 + = tagnum ;
t2 + = inf - > numtags * frame2 ;
if ( t1 = = t2 )
{
result [ 0 ] = t1 - > ang [ 0 ] [ 0 ] ;
2005-08-03 23:14:59 +00:00
result [ 1 ] = t1 - > ang [ 0 ] [ 1 ] ;
result [ 2 ] = t1 - > ang [ 0 ] [ 2 ] ;
2005-06-14 04:52:10 +00:00
result [ 3 ] = t1 - > org [ 0 ] ;
2005-08-03 23:14:59 +00:00
result [ 4 ] = t1 - > ang [ 1 ] [ 0 ] ;
2005-06-14 04:52:10 +00:00
result [ 5 ] = t1 - > ang [ 1 ] [ 1 ] ;
2005-08-03 23:14:59 +00:00
result [ 6 ] = t1 - > ang [ 1 ] [ 2 ] ;
2005-06-14 04:52:10 +00:00
result [ 7 ] = t1 - > org [ 1 ] ;
2005-08-03 23:14:59 +00:00
result [ 8 ] = t1 - > ang [ 2 ] [ 0 ] ;
result [ 9 ] = t1 - > ang [ 2 ] [ 1 ] ;
2005-06-14 04:52:10 +00:00
result [ 10 ] = t1 - > ang [ 2 ] [ 2 ] ;
result [ 11 ] = t1 - > org [ 2 ] ;
}
else
{
float f1ness = 1 - f2ness ;
result [ 0 ] = t1 - > ang [ 0 ] [ 0 ] * f1ness + t2 - > ang [ 0 ] [ 0 ] * f2ness ;
2005-08-03 23:14:59 +00:00
result [ 1 ] = t1 - > ang [ 0 ] [ 1 ] * f1ness + t2 - > ang [ 0 ] [ 1 ] * f2ness ;
result [ 2 ] = t1 - > ang [ 0 ] [ 2 ] * f1ness + t2 - > ang [ 0 ] [ 2 ] * f2ness ;
2005-06-14 04:52:10 +00:00
result [ 3 ] = t1 - > org [ 0 ] * f1ness + t2 - > org [ 0 ] * f2ness ;
2005-08-03 23:14:59 +00:00
result [ 4 ] = t1 - > ang [ 1 ] [ 0 ] * f1ness + t2 - > ang [ 1 ] [ 0 ] * f2ness ;
2005-06-14 04:52:10 +00:00
result [ 5 ] = t1 - > ang [ 1 ] [ 1 ] * f1ness + t2 - > ang [ 1 ] [ 1 ] * f2ness ;
2005-08-03 23:14:59 +00:00
result [ 6 ] = t1 - > ang [ 1 ] [ 2 ] * f1ness + t2 - > ang [ 1 ] [ 2 ] * f2ness ;
2005-06-14 04:52:10 +00:00
result [ 7 ] = t1 - > org [ 1 ] * f1ness + t2 - > org [ 1 ] * f2ness ;
2005-08-03 23:14:59 +00:00
result [ 8 ] = t1 - > ang [ 2 ] [ 0 ] * f1ness + t2 - > ang [ 2 ] [ 0 ] * f2ness ;
result [ 9 ] = t1 - > ang [ 2 ] [ 1 ] * f1ness + t2 - > ang [ 2 ] [ 1 ] * f2ness ;
2005-06-14 04:52:10 +00:00
result [ 10 ] = t1 - > ang [ 2 ] [ 2 ] * f1ness + t2 - > ang [ 2 ] [ 2 ] * f2ness ;
result [ 11 ] = t1 - > org [ 2 ] * f1ness + t2 - > org [ 2 ] * f2ness ;
}
return true ;
}
return false ;
2004-11-17 18:13:33 +00:00
}
2004-08-22 22:29:09 +00:00
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-12-21 04:32:34 +00:00
int GLMod_TagNumForName ( model_t * model , char * name )
2005-07-16 00:53:08 +00:00
# else
int Mod_TagNumForName ( model_t * model , char * name )
# endif
2004-12-21 04:32:34 +00:00
{
int i ;
galiasinfo_t * inf ;
md3tag_t * t ;
if ( ! model | | model - > type ! = mod_alias )
return 0 ;
inf = Mod_Extradata ( model ) ;
2005-06-14 04:52:10 +00:00
# ifdef SKELETALMODELS
if ( inf - > numbones )
{
galiasbone_t * b ;
b = ( galiasbone_t * ) ( ( char * ) inf + inf - > ofsbones ) ;
for ( i = 0 ; i < inf - > numbones ; i + + )
{
if ( ! strcmp ( b [ i ] . name , name ) )
return i + 1 ;
}
}
# endif
2004-12-21 04:32:34 +00:00
t = ( md3tag_t * ) ( ( char * ) inf + inf - > ofstags ) ;
for ( i = 0 ; i < inf - > numtags ; i + + )
{
2004-12-24 08:45:56 +00:00
if ( ! strcmp ( t [ i ] . name , name ) )
2004-12-21 04:32:34 +00:00
return i + 1 ;
}
2005-06-14 04:52:10 +00:00
2004-12-21 04:32:34 +00:00
return 0 ;
}
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
int GLMod_SkinNumForName ( model_t * model , char * name )
{
int i ;
galiasinfo_t * inf ;
galiasskin_t * skin ;
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
if ( ! model | | model - > type ! = mod_alias )
return - 1 ;
inf = Mod_Extradata ( model ) ;
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
skin = ( galiasskin_t * ) ( ( char * ) inf + inf - > ofsskins ) ;
for ( i = 0 ; i < inf - > numskins ; i + + , skin + + )
{
if ( ! strcmp ( skin - > name , name ) )
return i ;
}
return - 1 ;
}
2005-08-10 17:22:49 +00:00
# endif
2004-08-22 22:29:09 +00:00
# ifdef MD3MODELS
//structures from Tenebrae
typedef struct {
int ident ;
int version ;
char name [ MAX_QPATH ] ;
int flags ; //Does anyone know what these are?
int numFrames ;
2005-11-26 03:02:55 +00:00
int numTags ;
2004-08-22 22:29:09 +00:00
int numSurfaces ;
int numSkins ;
int ofsFrames ;
int ofsTags ;
int ofsSurfaces ;
int ofsEnd ;
} md3Header_t ;
//then has header->numFrames of these at header->ofs_Frames
typedef struct md3Frame_s {
vec3_t bounds [ 2 ] ;
vec3_t localOrigin ;
float radius ;
char name [ 16 ] ;
} md3Frame_t ;
//there are header->numSurfaces of these at header->ofsSurfaces, following from ofsEnd
typedef struct {
2005-11-26 03:02:55 +00:00
int ident ; //
2004-08-22 22:29:09 +00:00
char name [ MAX_QPATH ] ; // polyset name
int flags ;
int numFrames ; // all surfaces in a model should have the same
int numShaders ; // all surfaces in a model should have the same
int numVerts ;
int numTriangles ;
int ofsTriangles ;
int ofsShaders ; // offset from start of md3Surface_t
int ofsSt ; // texture coords are common for all frames
int ofsXyzNormals ; // numVerts * numFrames
int ofsEnd ; // next surface follows
} md3Surface_t ;
//at surf+surf->ofsXyzNormals
typedef struct {
short xyz [ 3 ] ;
qbyte latlong [ 2 ] ;
} md3XyzNormal_t ;
//surf->numTriangles at surf+surf->ofsTriangles
typedef struct {
int indexes [ 3 ] ;
} md3Triangle_t ;
//surf->numVerts at surf+surf->ofsSt
typedef struct {
float s ;
float t ;
} md3St_t ;
typedef struct {
char name [ MAX_QPATH ] ;
int shaderIndex ;
} md3Shader_t ;
//End of Tenebrae 'assistance'
2006-03-12 08:01:48 +00:00
qboolean GL_LoadQ3Model ( model_t * mod , void * buffer )
2004-08-22 22:29:09 +00:00
{
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
galiasskin_t * skin ;
galiastexnum_t * texnum ;
float lat , lng ;
md3St_t * inst ;
vec3_t * normals ;
vec2_t * st_array ;
md3Shader_t * inshader ;
# endif
2004-08-22 22:29:09 +00:00
int hunkstart , hunkend , hunktotal ;
// int version;
int s , i , j , d ;
2004-10-19 16:10:14 +00:00
index_t * indexes ;
2004-08-22 22:29:09 +00:00
vec3_t min ;
vec3_t max ;
galiaspose_t * pose ;
2004-10-19 16:10:14 +00:00
galiasinfo_t * parent , * root ;
2004-08-22 22:29:09 +00:00
galiasgroup_t * group ;
vec3_t * verts ;
md3Triangle_t * intris ;
md3XyzNormal_t * invert ;
int size ;
2005-08-03 23:14:59 +00:00
int externalskins ;
2004-08-22 22:29:09 +00:00
md3Header_t * header ;
md3Surface_t * surf ;
loadmodel = mod ;
2005-07-16 00:53:08 +00:00
Mod_DoCRC ( mod , buffer , com_filesize ) ;
2004-08-22 22:29:09 +00:00
hunkstart = Hunk_LowMark ( ) ;
header = buffer ;
// if (header->version != sdfs)
// Sys_Error("GL_LoadQ3Model: Bad version\n");
parent = NULL ;
2004-10-19 16:10:14 +00:00
root = NULL ;
2004-08-22 22:29:09 +00:00
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
externalskins = GL_BuildSkinFileList ( mod - > name ) ;
2005-08-10 17:22:49 +00:00
# else
externalskins = 0 ;
# endif
2005-08-03 23:14:59 +00:00
2004-08-22 22:29:09 +00:00
min [ 0 ] = min [ 1 ] = min [ 2 ] = 0 ;
max [ 0 ] = max [ 1 ] = max [ 2 ] = 0 ;
2005-08-07 02:21:20 +00:00
surf = ( md3Surface_t * ) ( ( qbyte * ) header + LittleLong ( header - > ofsSurfaces ) ) ;
for ( s = 0 ; s < LittleLong ( header - > numSurfaces ) ; s + + )
2004-08-22 22:29:09 +00:00
{
2005-08-07 02:21:20 +00:00
if ( LittleLong ( surf - > ident ) ! = MD3_IDENT )
2006-03-12 08:01:48 +00:00
Con_Printf ( S_WARNING " Warning: md3 sub-surface doesn't match ident \n " ) ;
2005-08-07 02:21:20 +00:00
size = sizeof ( galiasinfo_t ) + sizeof ( galiasgroup_t ) * LittleLong ( header - > numFrames ) ;
2004-08-22 22:29:09 +00:00
galias = Hunk_Alloc ( size ) ;
galias - > groupofs = sizeof ( * galias ) ; //frame groups
2005-08-07 02:21:20 +00:00
galias - > groups = LittleLong ( header - > numFrames ) ;
galias - > numverts = LittleLong ( surf - > numVerts ) ;
galias - > numindexes = LittleLong ( surf - > numTriangles ) * 3 ;
2004-08-22 22:29:09 +00:00
if ( parent )
2004-10-19 16:10:14 +00:00
parent - > nextsurf = ( qbyte * ) galias - ( qbyte * ) parent ;
else
root = galias ;
parent = galias ;
2004-08-22 22:29:09 +00:00
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
st_array = Hunk_Alloc ( sizeof ( vec2_t ) * galias - > numindexes ) ;
galias - > ofs_st_array = ( qbyte * ) st_array - ( qbyte * ) galias ;
2005-08-07 02:21:20 +00:00
inst = ( md3St_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsSt ) ) ;
2004-08-22 22:29:09 +00:00
for ( i = 0 ; i < galias - > numverts ; i + + )
{
2005-08-07 02:21:20 +00:00
st_array [ i ] [ 0 ] = LittleFloat ( inst [ i ] . s ) ;
st_array [ i ] [ 1 ] = LittleFloat ( inst [ i ] . t ) ;
2004-08-22 22:29:09 +00:00
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
indexes = Hunk_Alloc ( sizeof ( * indexes ) * galias - > numindexes ) ;
galias - > ofs_indexes = ( qbyte * ) indexes - ( qbyte * ) galias ;
2005-08-07 02:21:20 +00:00
intris = ( md3Triangle_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsTriangles ) ) ;
for ( i = 0 ; i < LittleLong ( surf - > numTriangles ) ; i + + )
2004-08-22 22:29:09 +00:00
{
2005-08-07 02:21:20 +00:00
indexes [ i * 3 + 0 ] = LittleLong ( intris [ i ] . indexes [ 0 ] ) ;
indexes [ i * 3 + 1 ] = LittleLong ( intris [ i ] . indexes [ 1 ] ) ;
indexes [ i * 3 + 2 ] = LittleLong ( intris [ i ] . indexes [ 2 ] ) ;
2004-08-22 22:29:09 +00:00
}
group = ( galiasgroup_t * ) ( galias + 1 ) ;
2005-08-07 02:21:20 +00:00
invert = ( md3XyzNormal_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsXyzNormals ) ) ;
for ( i = 0 ; i < LittleLong ( surf - > numFrames ) ; i + + )
2004-08-22 22:29:09 +00:00
{
2005-08-07 02:21:20 +00:00
pose = ( galiaspose_t * ) Hunk_Alloc ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * LittleLong ( surf - > numVerts )
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-08-07 02:21:20 +00:00
+ sizeof ( vec3_t ) * LittleLong ( surf - > numVerts )
2005-07-16 00:53:08 +00:00
# endif
) ;
2004-08-22 22:29:09 +00:00
2005-07-16 00:53:08 +00:00
verts = ( vec3_t * ) ( pose + 1 ) ;
2004-08-22 22:29:09 +00:00
pose - > ofsverts = ( qbyte * ) verts - ( qbyte * ) pose ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-08-07 02:21:20 +00:00
normals = verts + LittleLong ( surf - > numVerts ) ;
2005-07-16 00:53:08 +00:00
pose - > ofsnormals = ( qbyte * ) normals - ( qbyte * ) pose ;
# endif
2004-08-22 22:29:09 +00:00
2005-08-07 02:21:20 +00:00
for ( j = 0 ; j < LittleLong ( surf - > numVerts ) ; j + + )
2004-08-22 22:29:09 +00:00
{
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
lat = ( float ) invert [ j ] . latlong [ 0 ] * ( 2 * M_PI ) * ( 1.0 / 255.0 ) ;
lng = ( float ) invert [ j ] . latlong [ 1 ] * ( 2 * M_PI ) * ( 1.0 / 255.0 ) ;
normals [ j ] [ 0 ] = cos ( lng ) * sin ( lat ) ;
normals [ j ] [ 1 ] = sin ( lng ) * sin ( lat ) ;
normals [ j ] [ 2 ] = cos ( lat ) ;
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
for ( d = 0 ; d < 3 ; d + + )
{
2005-08-07 02:21:20 +00:00
verts [ j ] [ d ] = LittleShort ( invert [ j ] . xyz [ d ] ) / 64.0f ;
2004-08-22 22:29:09 +00:00
if ( verts [ j ] [ d ] < min [ d ] )
min [ d ] = verts [ j ] [ d ] ;
if ( verts [ j ] [ d ] > max [ d ] )
max [ d ] = verts [ j ] [ d ] ;
}
}
pose - > scale [ 0 ] = 1 ;
pose - > scale [ 1 ] = 1 ;
pose - > scale [ 2 ] = 1 ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
pose - > scale_origin [ 0 ] = 0 ;
pose - > scale_origin [ 1 ] = 0 ;
pose - > scale_origin [ 2 ] = 0 ;
2006-03-06 01:41:09 +00:00
snprintf ( group - > name , sizeof ( group - > name ) - 1 , " frame%i " , i ) ;
2006-02-27 00:42:25 +00:00
2004-08-22 22:29:09 +00:00
group - > numposes = 1 ;
group - > rate = 1 ;
group - > poseofs = ( qbyte * ) pose - ( qbyte * ) group ;
group + + ;
2005-08-07 02:21:20 +00:00
invert + = LittleLong ( surf - > numVerts ) ;
2004-08-22 22:29:09 +00:00
}
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-12-12 01:58:15 +00:00
if ( externalskins < LittleLong ( surf - > numShaders ) )
externalskins = LittleLong ( surf - > numShaders ) ;
if ( externalskins )
2004-08-22 22:29:09 +00:00
{
2005-11-30 01:20:53 +00:00
# ifndef Q3SHADERS
2004-08-22 22:29:09 +00:00
char name [ 1024 ] ;
2005-11-30 01:20:53 +00:00
extern int gl_bumpmappingpossible ;
2006-03-04 20:43:48 +00:00
# endif
2005-08-03 23:14:59 +00:00
char shadname [ 1024 ] ;
2005-08-07 02:21:20 +00:00
skin = Hunk_Alloc ( ( LittleLong ( surf - > numShaders ) + externalskins ) * ( ( sizeof ( galiasskin_t ) + sizeof ( galiastexnum_t ) ) ) ) ;
2004-08-22 22:29:09 +00:00
galias - > ofsskins = ( qbyte * ) skin - ( qbyte * ) galias ;
2005-08-07 02:21:20 +00:00
texnum = ( galiastexnum_t * ) ( skin + LittleLong ( surf - > numShaders ) + externalskins ) ;
inshader = ( md3Shader_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsShaders ) ) ;
2005-12-12 01:58:15 +00:00
for ( i = 0 ; i < externalskins ; i + + )
2004-08-22 22:29:09 +00:00
{
skin - > texnums = 1 ;
skin - > ofstexnums = ( qbyte * ) texnum - ( qbyte * ) skin ;
skin - > ofstexels = 0 ;
skin - > skinwidth = 0 ;
skin - > skinheight = 0 ;
skin - > skinspeed = 0 ;
2004-12-24 08:45:56 +00:00
2005-12-12 01:58:15 +00:00
shadname [ 0 ] = ' \0 ' ;
GL_ParseQ3SkinFile ( shadname , surf - > name , loadmodel - > name , i , skin - > name ) ;
if ( ! * shadname )
{
if ( i > = LittleLong ( surf - > numShaders ) )
strcpy ( shadname , " missingskin " ) ; //this shouldn't be possible
else
strcpy ( shadname , inshader - > name ) ;
2005-08-03 23:14:59 +00:00
Q_strncpyz ( skin - > name , shadname , sizeof ( skin - > name ) ) ;
2005-12-12 01:58:15 +00:00
}
2005-08-03 23:14:59 +00:00
2004-10-19 16:10:14 +00:00
# ifdef Q3SHADERS
2005-10-04 18:07:32 +00:00
if ( qrenderer )
{
texnum - > shader = R_RegisterSkin ( shadname ) ;
2005-08-03 23:14:59 +00:00
2005-10-04 18:07:32 +00:00
if ( r_shadows . value ) //real-time shadows requires a texture to lighten the model with, even if it has a shader.
2005-08-03 23:14:59 +00:00
//fixme: this should be read from the shader.
2005-10-04 18:07:32 +00:00
texnum - > base = Mod_LoadHiResTexture ( shadname , " models " , true , true , true ) ;
}
2004-10-19 16:10:14 +00:00
# else
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
texnum - > base = Mod_LoadHiResTexture ( shadname , " models " , true , true , true ) ;
2004-08-22 22:29:09 +00:00
if ( ! texnum - > base )
{
strcpy ( name , loadmodel - > name ) ;
2005-08-03 23:14:59 +00:00
strcpy ( COM_SkipPath ( name ) , COM_SkipPath ( shadname ) ) ; //eviile eh?
2005-05-13 10:42:48 +00:00
texnum - > base = Mod_LoadHiResTexture ( name , " models " , true , true , true ) ;
2004-08-22 22:29:09 +00:00
}
texnum - > bump = 0 ;
if ( gl_bumpmappingpossible )
{
2006-03-11 04:39:16 +00:00
COM_StripExtension ( shadname , name , sizeof ( name ) ) ; //go for the normalmap
2004-08-22 22:29:09 +00:00
strcat ( name , " _norm " ) ;
2005-05-13 10:42:48 +00:00
texnum - > bump = Mod_LoadHiResTexture ( name , " models " , true , true , false ) ;
2004-08-22 22:29:09 +00:00
if ( ! texnum - > bump )
{
strcpy ( name , loadmodel - > name ) ;
2006-03-11 04:39:16 +00:00
COM_StripExtension ( COM_SkipPath ( shadname ) , COM_SkipPath ( name ) , sizeof ( name ) ) ;
2004-08-22 22:29:09 +00:00
strcat ( name , " _norm " ) ;
2005-05-13 10:42:48 +00:00
texnum - > bump = Mod_LoadHiResTexture ( name , " models " , true , true , false ) ;
2004-08-22 22:29:09 +00:00
if ( ! texnum - > bump )
{
2006-03-11 04:39:16 +00:00
COM_StripExtension ( shadname , name , sizeof ( name ) ) ; //bother, go for heightmap and convert
2004-08-22 22:29:09 +00:00
strcat ( name , " _bump " ) ;
2005-05-13 10:42:48 +00:00
texnum - > bump = Mod_LoadBumpmapTexture ( name , " models " ) ;
2004-08-22 22:29:09 +00:00
if ( ! texnum - > bump )
{
strcpy ( name , loadmodel - > name ) ;
2005-08-03 23:14:59 +00:00
strcpy ( COM_SkipPath ( name ) , COM_SkipPath ( shadname ) ) ; //eviile eh?
2006-03-11 04:39:16 +00:00
COM_StripExtension ( name , name , sizeof ( name ) ) ;
2004-08-22 22:29:09 +00:00
strcat ( name , " _bump " ) ;
2005-05-13 10:42:48 +00:00
texnum - > bump = Mod_LoadBumpmapTexture ( name , " models " ) ;
2004-08-22 22:29:09 +00:00
}
}
}
}
if ( r_fb_models . value )
{
2006-03-11 04:39:16 +00:00
COM_StripExtension ( shadname , name , sizeof ( name ) ) ; //go for the normalmap
2004-08-22 22:29:09 +00:00
strcat ( name , " _luma " ) ;
2005-05-13 10:42:48 +00:00
texnum - > fullbright = Mod_LoadHiResTexture ( name , " models " , true , true , true ) ;
2004-08-22 22:29:09 +00:00
if ( ! texnum - > base )
{
strcpy ( name , loadmodel - > name ) ;
2005-08-03 23:14:59 +00:00
strcpy ( COM_SkipPath ( name ) , COM_SkipPath ( shadname ) ) ; //eviile eh?
2006-03-11 04:39:16 +00:00
COM_StripExtension ( name , name , sizeof ( name ) ) ;
2004-08-22 22:29:09 +00:00
strcat ( name , " _luma " ) ;
2005-05-13 10:42:48 +00:00
texnum - > fullbright = Mod_LoadBumpmapTexture ( name , " models " ) ;
2004-08-22 22:29:09 +00:00
}
}
2004-10-19 16:10:14 +00:00
# endif
2004-08-22 22:29:09 +00:00
2005-08-03 23:14:59 +00:00
inshader + + ;
2004-08-22 22:29:09 +00:00
skin + + ;
texnum + + ;
}
2005-08-03 23:14:59 +00:00
galias - > numskins = i ;
2004-08-22 22:29:09 +00:00
}
2005-07-16 00:53:08 +00:00
# endif
2004-08-22 22:29:09 +00:00
VectorCopy ( min , loadmodel - > mins ) ;
VectorCopy ( max , loadmodel - > maxs ) ;
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2004-08-22 22:29:09 +00:00
if ( r_shadows . value )
{
int * neighbours ;
2005-08-07 02:21:20 +00:00
neighbours = Hunk_Alloc ( sizeof ( int ) * 3 * LittleLong ( surf - > numTriangles ) ) ;
2004-08-22 22:29:09 +00:00
galias - > ofs_trineighbours = ( qbyte * ) neighbours - ( qbyte * ) galias ;
2005-08-07 02:21:20 +00:00
R_BuildTriangleNeighbours ( neighbours , indexes , LittleLong ( surf - > numTriangles ) ) ;
2004-08-22 22:29:09 +00:00
}
2005-07-16 00:53:08 +00:00
# endif
2005-08-07 02:21:20 +00:00
surf = ( md3Surface_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsEnd ) ) ;
2004-08-22 22:29:09 +00:00
}
2004-12-24 08:45:56 +00:00
if ( ! root )
root = Hunk_Alloc ( sizeof ( galiasinfo_t ) ) ;
2005-08-07 02:21:20 +00:00
root - > numtagframes = LittleLong ( header - > numFrames ) ;
root - > numtags = LittleLong ( header - > numTags ) ;
root - > ofstags = ( char * ) Hunk_Alloc ( LittleLong ( header - > numTags ) * sizeof ( md3tag_t ) * LittleLong ( header - > numFrames ) ) - ( char * ) root ;
{
md3tag_t * src ;
md3tag_t * dst ;
src = ( md3tag_t * ) ( ( ( unsigned int ) header ) + LittleLong ( header - > ofsTags ) ) ;
dst = ( md3tag_t * ) ( ( ( unsigned int ) root ) + root - > ofstags ) ;
for ( i = 0 ; i < LittleLong ( header - > numTags ) * LittleLong ( header - > numFrames ) ; i + + )
{
memcpy ( dst - > name , src - > name , sizeof ( dst - > name ) ) ;
for ( j = 0 ; j < 3 ; j + + )
{
dst - > org [ j ] = LittleFloat ( src - > org [ j ] ) ;
}
for ( j = 0 ; j < 3 ; j + + )
{
for ( s = 0 ; s < 3 ; s + + )
{
dst - > ang [ j ] [ s ] = LittleFloat ( src - > ang [ j ] [ s ] ) ;
}
}
src + + ;
dst + + ;
}
}
2004-11-17 18:13:33 +00:00
2004-08-22 22:29:09 +00:00
//
// move the complete, relocatable alias model to the cache
2004-11-17 18:13:33 +00:00
//
2004-08-22 22:29:09 +00:00
2004-10-19 16:10:14 +00:00
hunkend = Hunk_LowMark ( ) ;
2005-09-09 23:54:54 +00:00
# ifndef SERVERONLY
2005-09-08 02:02:09 +00:00
if ( mod_md3flags . value )
mod - > flags = LittleLong ( header - > flags ) ;
else
2005-09-09 23:54:54 +00:00
# endif
2005-09-08 02:02:09 +00:00
mod - > flags = 0 ;
2005-05-15 18:49:04 +00:00
if ( ! mod - > flags )
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ;
2004-08-22 22:29:09 +00:00
2004-10-19 16:10:14 +00:00
Hunk_Alloc ( 0 ) ;
2004-08-22 22:29:09 +00:00
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2004-08-22 22:29:09 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-12 08:01:48 +00:00
return false ;
2004-08-22 22:29:09 +00:00
}
2004-10-19 16:10:14 +00:00
memcpy ( mod - > cache . data , root , hunktotal ) ;
2004-08-22 22:29:09 +00:00
Hunk_FreeToLowMark ( hunkstart ) ;
2005-07-16 00:53:08 +00:00
mod - > funcs . Trace = GLMod_Trace ;
2006-03-12 08:01:48 +00:00
return true ;
2004-08-22 22:29:09 +00:00
}
# endif
2004-11-23 01:23:45 +00:00
2004-11-29 01:21:00 +00:00
# ifdef ZYMOTICMODELS
2004-11-23 01:23:45 +00:00
typedef struct zymlump_s
{
int start ;
int length ;
} zymlump_t ;
typedef struct zymtype1header_s
{
char id [ 12 ] ; // "ZYMOTICMODEL", length 12, no termination
int type ; // 0 (vertex morph) 1 (skeletal pose) or 2 (skeletal scripted)
int filesize ; // size of entire model file
float mins [ 3 ] , maxs [ 3 ] , radius ; // for clipping uses
int numverts ;
int numtris ;
2005-05-19 02:43:11 +00:00
int numsurfaces ;
2004-11-23 01:23:45 +00:00
int numbones ; // this may be zero in the vertex morph format (undecided)
int numscenes ; // 0 in skeletal scripted models
// skeletal pose header
// lump offsets are relative to the file
zymlump_t lump_scenes ; // zymscene_t scene[numscenes]; // name and other information for each scene (see zymscene struct)
zymlump_t lump_poses ; // float pose[numposes][numbones][6]; // animation data
zymlump_t lump_bones ; // zymbone_t bone[numbones];
zymlump_t lump_vertbonecounts ; // int vertbonecounts[numvertices]; // how many bones influence each vertex (separate mainly to make this compress better)
zymlump_t lump_verts ; // zymvertex_t vert[numvertices]; // see vertex struct
zymlump_t lump_texcoords ; // float texcoords[numvertices][2];
zymlump_t lump_render ; // int renderlist[rendersize]; // sorted by shader with run lengths (int count), shaders are sequentially used, each run can be used with glDrawElements (each triangle is 3 int indices)
2005-05-19 02:43:11 +00:00
zymlump_t lump_surfnames ; // char shadername[numsurfaces][32]; // shaders used on this model
2004-11-23 01:23:45 +00:00
zymlump_t lump_trizone ; // byte trizone[numtris]; // see trizone explanation
} zymtype1header_t ;
typedef struct zymbone_s
{
char name [ 32 ] ;
int flags ;
int parent ; // parent bone number
} zymbone_t ;
typedef struct zymscene_s
{
char name [ 32 ] ;
float mins [ 3 ] , maxs [ 3 ] , radius ; // for clipping
float framerate ; // the scene will animate at this framerate (in frames per second)
int flags ;
int start , length ; // range of poses
} zymscene_t ;
2005-11-14 01:31:14 +00:00
# define ZYMSCENEFLAG_NOLOOP 1
2004-11-23 01:23:45 +00:00
typedef struct zymvertex_s
{
int bonenum ;
float origin [ 3 ] ;
} zymvertex_t ;
//this can generate multiple meshes (one for each shader).
//but only one set of transforms are ever generated.
2006-03-12 08:01:48 +00:00
qboolean GLMod_LoadZymoticModel ( model_t * mod , void * buffer )
2004-11-23 01:23:45 +00:00
{
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
galiasskin_t * skin ;
galiastexnum_t * texnum ;
int skinfiles ;
int j ;
# endif
int i ;
2004-11-23 01:23:45 +00:00
int hunkstart , hunkend , hunktotal ;
zymtype1header_t * header ;
galiasinfo_t * root ;
galisskeletaltransforms_t * transforms ;
zymvertex_t * intrans ;
galiasbone_t * bone ;
zymbone_t * inbone ;
int v ;
float multiplier ;
float * matrix , * inmatrix ;
2004-11-23 16:14:49 +00:00
vec2_t * stcoords ;
vec2_t * inst ;
2004-11-23 01:23:45 +00:00
int * vertbonecounts ;
galiasgroup_t * grp ;
zymscene_t * inscene ;
int * renderlist , count ;
index_t * indexes ;
2005-05-19 02:43:11 +00:00
char * surfname ;
2004-11-23 01:23:45 +00:00
loadmodel = mod ;
2005-07-16 00:53:08 +00:00
Mod_DoCRC ( mod , buffer , com_filesize ) ;
2004-11-23 01:23:45 +00:00
hunkstart = Hunk_LowMark ( ) ;
header = buffer ;
if ( memcmp ( header - > id , " ZYMOTICMODEL " , 12 ) )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( " GLMod_LoadZymoticModel: %s, doesn't appear to BE a zymotic! \n " , mod - > name ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
if ( BigLong ( header - > type ) ! = 1 )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( " GLMod_LoadZymoticModel: %s, only type 1 is supported \n " , mod - > name ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
for ( i = 0 ; i < sizeof ( zymtype1header_t ) / 4 ; i + + )
( ( int * ) header ) [ i ] = BigLong ( ( ( int * ) header ) [ i ] ) ;
if ( ! header - > numverts )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( " GLMod_LoadZymoticModel: %s, no vertexes \n " , mod - > name ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
2005-05-19 02:43:11 +00:00
if ( ! header - > numsurfaces )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( " GLMod_LoadZymoticModel: %s, no surfaces \n " , mod - > name ) ;
return false ;
}
2005-06-18 23:50:18 +00:00
VectorCopy ( header - > mins , mod - > mins ) ;
VectorCopy ( header - > maxs , mod - > maxs ) ;
2005-05-19 02:43:11 +00:00
root = Hunk_AllocName ( sizeof ( galiasinfo_t ) * header - > numsurfaces , loadname ) ;
2004-11-23 01:23:45 +00:00
root - > numtransforms = header - > lump_verts . length / sizeof ( zymvertex_t ) ;
transforms = Hunk_Alloc ( root - > numtransforms * sizeof ( * transforms ) ) ;
root - > ofstransforms = ( char * ) transforms - ( char * ) root ;
vertbonecounts = ( int * ) ( ( char * ) header + header - > lump_vertbonecounts . start ) ;
intrans = ( zymvertex_t * ) ( ( char * ) header + header - > lump_verts . start ) ;
vertbonecounts [ 0 ] = BigLong ( vertbonecounts [ 0 ] ) ;
multiplier = 1.0f / vertbonecounts [ 0 ] ;
for ( i = 0 , v = 0 ; i < root - > numtransforms ; i + + )
{
while ( ! vertbonecounts [ v ] )
{
v + + ;
if ( v = = header - > numverts )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( " GLMod_LoadZymoticModel: %s, too many transformations \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
vertbonecounts [ v ] = BigLong ( vertbonecounts [ v ] ) ;
multiplier = 1.0f / vertbonecounts [ v ] ;
}
transforms [ i ] . vertexindex = v ;
transforms [ i ] . boneindex = BigLong ( intrans [ i ] . bonenum ) ;
transforms [ i ] . org [ 0 ] = multiplier * BigFloat ( intrans [ i ] . origin [ 0 ] ) ;
transforms [ i ] . org [ 1 ] = multiplier * BigFloat ( intrans [ i ] . origin [ 1 ] ) ;
transforms [ i ] . org [ 2 ] = multiplier * BigFloat ( intrans [ i ] . origin [ 2 ] ) ;
transforms [ i ] . org [ 3 ] = multiplier * 1 ;
vertbonecounts [ v ] - - ;
}
if ( intrans ! = ( zymvertex_t * ) ( ( char * ) header + header - > lump_verts . start ) )
2006-03-12 08:01:48 +00:00
{
2006-03-12 09:19:31 +00:00
Con_Printf ( S_ERROR " %s, Vertex transforms list appears corrupt. \n " , mod - > name ) ;
2006-03-12 08:01:48 +00:00
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2004-11-23 14:58:32 +00:00
if ( vertbonecounts ! = ( int * ) ( ( char * ) header + header - > lump_vertbonecounts . start ) )
2006-03-12 08:01:48 +00:00
{
2006-03-12 09:19:31 +00:00
Con_Printf ( S_ERROR " %s, Vertex bone counts list appears corrupt. \n " , mod - > name ) ;
2006-03-12 08:01:48 +00:00
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
root - > numverts = v + 1 ;
root - > numbones = header - > numbones ;
bone = Hunk_Alloc ( root - > numtransforms * sizeof ( * transforms ) ) ;
inbone = ( zymbone_t * ) ( ( char * ) header + header - > lump_bones . start ) ;
for ( i = 0 ; i < root - > numbones ; i + + )
2005-06-14 04:52:10 +00:00
{
Q_strncpyz ( bone [ i ] . name , inbone [ i ] . name , sizeof ( bone [ i ] . name ) ) ;
2004-11-23 01:23:45 +00:00
bone [ i ] . parent = BigLong ( inbone [ i ] . parent ) ;
2005-06-14 04:52:10 +00:00
}
2004-11-23 01:23:45 +00:00
root - > ofsbones = ( char * ) bone - ( char * ) root ;
renderlist = ( int * ) ( ( char * ) header + header - > lump_render . start ) ;
2005-05-19 02:43:11 +00:00
for ( i = 0 ; i < header - > numsurfaces ; i + + )
2004-11-23 01:23:45 +00:00
{
count = BigLong ( * renderlist + + ) ;
count * = 3 ;
indexes = Hunk_Alloc ( count * sizeof ( * indexes ) ) ;
root [ i ] . ofs_indexes = ( char * ) indexes - ( char * ) & root [ i ] ;
root [ i ] . numindexes = count ;
2004-11-23 16:14:49 +00:00
while ( count )
{ //invert
indexes [ count - 1 ] = BigLong ( renderlist [ count - 3 ] ) ;
indexes [ count - 2 ] = BigLong ( renderlist [ count - 2 ] ) ;
indexes [ count - 3 ] = BigLong ( renderlist [ count - 1 ] ) ;
count - = 3 ;
2004-11-23 01:23:45 +00:00
}
renderlist + = root [ i ] . numindexes ;
}
if ( renderlist ! = ( int * ) ( ( char * ) header + header - > lump_render . start + header - > lump_render . length ) )
2006-03-12 08:01:48 +00:00
{
2006-03-12 09:19:31 +00:00
Con_Printf ( S_ERROR " %s, render list appears corrupt. \n " , mod - > name ) ;
2006-03-12 08:01:48 +00:00
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
2005-05-19 02:43:11 +00:00
grp = Hunk_Alloc ( sizeof ( * grp ) * header - > numscenes * header - > numsurfaces ) ;
2004-11-23 01:23:45 +00:00
matrix = Hunk_Alloc ( header - > lump_poses . length ) ;
2004-11-23 14:58:32 +00:00
inmatrix = ( float * ) ( ( char * ) header + header - > lump_poses . start ) ;
2004-11-23 01:23:45 +00:00
for ( i = 0 ; i < header - > lump_poses . length / 4 ; i + + )
matrix [ i ] = BigFloat ( inmatrix [ i ] ) ;
inscene = ( zymscene_t * ) ( ( char * ) header + header - > lump_scenes . start ) ;
2005-05-19 02:43:11 +00:00
surfname = ( ( char * ) header + header - > lump_surfnames . start ) ;
2004-11-23 16:14:49 +00:00
stcoords = Hunk_Alloc ( root [ 0 ] . numverts * sizeof ( vec2_t ) ) ;
inst = ( vec2_t * ) ( ( char * ) header + header - > lump_texcoords . start ) ;
for ( i = 0 ; i < header - > lump_texcoords . length / 8 ; i + + )
{
stcoords [ i ] [ 0 ] = BigFloat ( inst [ i ] [ 0 ] ) ;
stcoords [ i ] [ 1 ] = 1 - BigFloat ( inst [ i ] [ 1 ] ) ; //hmm. upside down skin coords?
}
2005-11-26 03:02:55 +00:00
2005-07-16 00:53:08 +00:00
# ifndef SERVERONLY
2005-05-19 02:43:11 +00:00
skinfiles = GL_BuildSkinFileList ( loadmodel - > name ) ;
if ( skinfiles < 1 )
skinfiles = 1 ;
2005-07-16 00:53:08 +00:00
# endif
2005-05-19 02:43:11 +00:00
for ( i = 0 ; i < header - > numsurfaces ; i + + , surfname + = 32 )
2004-11-23 01:23:45 +00:00
{
2004-11-23 16:14:49 +00:00
root [ i ] . groups = header - > numscenes ;
root [ i ] . groupofs = ( char * ) grp - ( char * ) & root [ i ] ;
2005-07-16 00:53:08 +00:00
# ifdef SERVERONLY
root [ i ] . numskins = 1 ;
# else
root [ i ] . ofs_st_array = ( char * ) stcoords - ( char * ) & root [ i ] ;
root [ i ] . numskins = skinfiles ;
2005-05-19 02:43:11 +00:00
skin = Hunk_Alloc ( ( sizeof ( galiasskin_t ) + sizeof ( galiastexnum_t ) ) * skinfiles ) ;
texnum = ( galiastexnum_t * ) ( skin + skinfiles ) ;
for ( j = 0 ; j < skinfiles ; j + + , texnum + + )
{
skin [ j ] . texnums = 1 ; //non-sequenced skins.
skin [ j ] . ofstexnums = ( char * ) texnum - ( char * ) & skin [ j ] ;
2005-05-15 18:49:04 +00:00
2005-05-19 02:43:11 +00:00
GL_LoadSkinFile ( texnum , surfname , j , NULL , 0 , 0 , NULL ) ;
}
2005-07-16 00:53:08 +00:00
2004-11-23 16:14:49 +00:00
root [ i ] . ofsskins = ( char * ) skin - ( char * ) & root [ i ] ;
2005-07-16 00:53:08 +00:00
# endif
2004-11-23 01:23:45 +00:00
}
2004-11-23 16:14:49 +00:00
2004-11-23 01:23:45 +00:00
for ( i = 0 ; i < header - > numscenes ; i + + , grp + + , inscene + + )
{
2006-02-27 00:42:25 +00:00
Q_strncpyz ( grp - > name , inscene - > name , sizeof ( grp - > name ) ) ;
2005-08-03 23:14:59 +00:00
grp - > isheirachical = 1 ;
2004-11-23 01:23:45 +00:00
grp - > rate = BigFloat ( inscene - > framerate ) ;
2005-11-14 01:31:14 +00:00
grp - > loop = ! ( BigLong ( inscene - > flags ) & ZYMSCENEFLAG_NOLOOP ) ;
2004-11-23 01:23:45 +00:00
grp - > numposes = BigLong ( inscene - > length ) ;
grp - > poseofs = ( char * ) matrix - ( char * ) grp ;
2004-11-23 15:30:34 +00:00
grp - > poseofs + = BigLong ( inscene - > start ) * 12 * sizeof ( float ) * root - > numbones ;
2004-11-23 01:23:45 +00:00
}
if ( inscene ! = ( zymscene_t * ) ( ( char * ) header + header - > lump_scenes . start + header - > lump_scenes . length ) )
2006-03-12 08:01:48 +00:00
{
2006-03-12 09:19:31 +00:00
Con_Printf ( S_ERROR " %s, scene list appears corrupt. \n " , mod - > name ) ;
2006-03-12 08:01:48 +00:00
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2004-11-23 01:23:45 +00:00
2005-05-19 02:43:11 +00:00
for ( i = 0 ; i < header - > numsurfaces - 1 ; i + + )
2004-11-23 01:23:45 +00:00
root [ i ] . nextsurf = sizeof ( galiasinfo_t ) ;
2005-05-19 02:43:11 +00:00
for ( i = 1 ; i < header - > numsurfaces ; i + + )
2004-11-23 01:23:45 +00:00
{
root [ i ] . sharesverts = true ;
root [ i ] . numbones = root [ 0 ] . numbones ;
root [ i ] . numverts = root [ 0 ] . numverts ;
root [ i ] . ofsbones = root [ 0 ] . ofsbones ;
2005-05-15 18:49:04 +00:00
root [ i - 1 ] . nextsurf = sizeof ( * root ) ;
2004-11-23 01:23:45 +00:00
}
//
// move the complete, relocatable alias model to the cache
//
hunkend = Hunk_LowMark ( ) ;
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ; //file replacement - inherit flags from any defunc mdl files.
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2004-11-23 01:23:45 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-12 08:01:48 +00:00
return false ;
2004-11-23 01:23:45 +00:00
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
2005-07-16 00:53:08 +00:00
mod - > funcs . Trace = GLMod_Trace ;
2006-03-12 08:01:48 +00:00
return true ;
2004-11-29 01:21:00 +00:00
}
2005-09-08 02:02:09 +00:00
//////////////////////////////////////////////////////////////
//dpm
// header for the entire file
typedef struct dpmheader_s
{
char id [ 16 ] ; // "DARKPLACESMODEL\0", length 16
unsigned int type ; // 2 (hierarchical skeletal pose)
unsigned int filesize ; // size of entire model file
float mins [ 3 ] , maxs [ 3 ] , yawradius , allradius ; // for clipping uses
// these offsets are relative to the file
unsigned int num_bones ;
unsigned int num_meshs ;
unsigned int num_frames ;
unsigned int ofs_bones ; // dpmbone_t bone[num_bones];
unsigned int ofs_meshs ; // dpmmesh_t mesh[num_meshs];
unsigned int ofs_frames ; // dpmframe_t frame[num_frames];
} dpmheader_t ;
// there may be more than one of these
typedef struct dpmmesh_s
{
// these offsets are relative to the file
char shadername [ 32 ] ; // name of the shader to use
unsigned int num_verts ;
unsigned int num_tris ;
unsigned int ofs_verts ; // dpmvertex_t vert[numvertices]; // see vertex struct
unsigned int ofs_texcoords ; // float texcoords[numvertices][2];
unsigned int ofs_indices ; // unsigned int indices[numtris*3]; // designed for glDrawElements (each triangle is 3 unsigned int indices)
unsigned int ofs_groupids ; // unsigned int groupids[numtris]; // the meaning of these values is entirely up to the gamecode and modeler
} dpmmesh_t ;
// if set on a bone, it must be protected from removal
# define DPMBONEFLAG_ATTACHMENT 1
// one per bone
typedef struct dpmbone_s
{
// name examples: upperleftarm leftfinger1 leftfinger2 hand, etc
char name [ 32 ] ;
// parent bone number
signed int parent ;
// flags for the bone
unsigned int flags ;
} dpmbone_t ;
// a bonepose matrix is intended to be used like this:
// (n = output vertex, v = input vertex, m = matrix, f = influence)
// n[0] = v[0] * m[0][0] + v[1] * m[0][1] + v[2] * m[0][2] + f * m[0][3];
// n[1] = v[0] * m[1][0] + v[1] * m[1][1] + v[2] * m[1][2] + f * m[1][3];
// n[2] = v[0] * m[2][0] + v[1] * m[2][1] + v[2] * m[2][2] + f * m[2][3];
typedef struct dpmbonepose_s
{
float matrix [ 3 ] [ 4 ] ;
} dpmbonepose_t ;
// immediately followed by bone positions for the frame
typedef struct dpmframe_s
{
// name examples: idle_1 idle_2 idle_3 shoot_1 shoot_2 shoot_3, etc
char name [ 32 ] ;
float mins [ 3 ] , maxs [ 3 ] , yawradius , allradius ;
int ofs_bonepositions ; // dpmbonepose_t bonepositions[bones];
} dpmframe_t ;
// one or more of these per vertex
typedef struct dpmbonevert_s
{
float origin [ 3 ] ; // vertex location (these blend)
float influence ; // influence fraction (these must add up to 1)
float normal [ 3 ] ; // surface normal (these blend)
unsigned int bonenum ; // number of the bone
} dpmbonevert_t ;
// variable size, parsed sequentially
2005-11-26 03:02:55 +00:00
typedef struct dpmvertex_s
2005-09-08 02:02:09 +00:00
{
unsigned int numbones ;
// immediately followed by 1 or more dpmbonevert_t structures
} dpmvertex_t ;
2006-03-12 08:01:48 +00:00
qboolean GLMod_LoadDarkPlacesModel ( model_t * mod , void * buffer )
2005-09-08 02:02:09 +00:00
{
# ifndef SERVERONLY
galiasskin_t * skin ;
galiastexnum_t * texnum ;
int skinfiles ;
2006-01-28 02:35:40 +00:00
float * inst ;
float * outst ;
2005-09-08 02:02:09 +00:00
# endif
int i , j , k ;
int hunkstart , hunkend , hunktotal ;
dpmheader_t * header ;
galiasinfo_t * root , * m ;
dpmmesh_t * mesh ;
dpmvertex_t * vert ;
dpmbonevert_t * bonevert ;
galisskeletaltransforms_t * transforms ;
galiasbone_t * outbone ;
dpmbone_t * inbone ;
float * outposedata ;
galiasgroup_t * outgroups ;
float * inposedata ;
dpmframe_t * inframes ;
unsigned int * index ; index_t * outdex ; // groan...
int numtransforms ;
int numverts ;
loadmodel = mod ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
header = buffer ;
if ( memcmp ( header - > id , " DARKPLACESMODEL \0 " , 16 ) )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " GLMod_LoadDarkPlacesModel: %s, doesn't appear to be a darkplaces model! \n " , mod - > name ) ;
return false ;
}
2005-09-08 02:02:09 +00:00
if ( BigLong ( header - > type ) ! = 2 )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " GLMod_LoadDarkPlacesModel: %s, only type 2 is supported \n " , mod - > name ) ;
return false ;
}
2005-09-08 02:02:09 +00:00
for ( i = 0 ; i < sizeof ( dpmheader_t ) / 4 ; i + + )
( ( int * ) header ) [ i ] = BigLong ( ( ( int * ) header ) [ i ] ) ;
if ( ! header - > num_bones )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " GLMod_LoadDarkPlacesModel: %s, no bones \n " , mod - > name ) ;
return false ;
}
2005-09-08 02:02:09 +00:00
if ( ! header - > num_frames )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " GLMod_LoadDarkPlacesModel: %s, no frames \n " , mod - > name ) ;
return false ;
}
2005-09-08 02:02:09 +00:00
if ( ! header - > num_meshs )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " GLMod_LoadDarkPlacesModel: %s, no surfaces \n " , mod - > name ) ;
return false ;
}
2005-09-08 02:02:09 +00:00
VectorCopy ( header - > mins , mod - > mins ) ;
VectorCopy ( header - > maxs , mod - > maxs ) ;
root = Hunk_AllocName ( sizeof ( galiasinfo_t ) * header - > num_meshs , loadname ) ;
mesh = ( dpmmesh_t * ) ( ( char * ) buffer + header - > ofs_meshs ) ;
for ( i = 0 ; i < header - > num_meshs ; i + + , mesh + + )
{
//work out how much memory we need to allocate
mesh - > num_verts = BigLong ( mesh - > num_verts ) ;
mesh - > num_tris = BigLong ( mesh - > num_tris ) ;
mesh - > ofs_verts = BigLong ( mesh - > ofs_verts ) ;
mesh - > ofs_texcoords = BigLong ( mesh - > ofs_texcoords ) ;
mesh - > ofs_indices = BigLong ( mesh - > ofs_indices ) ;
mesh - > ofs_groupids = BigLong ( mesh - > ofs_groupids ) ;
numverts = mesh - > num_verts ;
numtransforms = 0 ;
//count and byteswap the transformations
vert = ( dpmvertex_t * ) ( ( char * ) buffer + mesh - > ofs_verts ) ;
for ( j = 0 ; j < mesh - > num_verts ; j + + )
{
vert - > numbones = BigLong ( vert - > numbones ) ;
numtransforms + = vert - > numbones ;
bonevert = ( dpmbonevert_t * ) ( vert + 1 ) ;
vert = ( dpmvertex_t * ) ( bonevert + vert - > numbones ) ;
}
m = & root [ i ] ;
# ifdef SERVERONLY
transforms = Hunk_AllocName ( numtransforms * sizeof ( galisskeletaltransforms_t ) + mesh - > num_tris * 3 * sizeof ( index_t ) , loadname ) ;
# else
outst = Hunk_AllocName ( numverts * sizeof ( vec2_t ) + numtransforms * sizeof ( galisskeletaltransforms_t ) + mesh - > num_tris * 3 * sizeof ( index_t ) , loadname ) ;
m - > ofs_st_array = ( char * ) outst - ( char * ) m ;
m - > numverts = mesh - > num_verts ;
inst = ( float * ) ( ( char * ) buffer + mesh - > ofs_texcoords ) ;
for ( j = 0 ; j < numverts ; j + + , outst + = 2 , inst + = 2 )
{
outst [ 0 ] = BigFloat ( inst [ 0 ] ) ;
outst [ 1 ] = BigFloat ( inst [ 1 ] ) ;
}
2006-01-28 02:35:40 +00:00
transforms = ( galisskeletaltransforms_t * ) outst ;
2005-09-08 02:02:09 +00:00
# endif
//build the transform list.
m - > ofstransforms = ( char * ) transforms - ( char * ) m ;
m - > numtransforms = numtransforms ;
vert = ( dpmvertex_t * ) ( ( char * ) buffer + mesh - > ofs_verts ) ;
for ( j = 0 ; j < mesh - > num_verts ; j + + )
{
bonevert = ( dpmbonevert_t * ) ( vert + 1 ) ;
for ( k = 0 ; k < vert - > numbones ; k + + , bonevert + + , transforms + + )
{
transforms - > boneindex = BigLong ( bonevert - > bonenum ) ;
transforms - > vertexindex = j ;
transforms - > org [ 0 ] = BigFloat ( bonevert - > origin [ 0 ] ) ;
transforms - > org [ 1 ] = BigFloat ( bonevert - > origin [ 1 ] ) ;
transforms - > org [ 2 ] = BigFloat ( bonevert - > origin [ 2 ] ) ;
transforms - > org [ 3 ] = BigFloat ( bonevert - > influence ) ;
//do nothing with the normals. :(
}
vert = ( dpmvertex_t * ) bonevert ;
}
index = ( index_t * ) ( ( char * ) buffer + mesh - > ofs_indices ) ;
outdex = ( index_t * ) transforms ;
m - > ofs_indexes = ( char * ) outdex - ( char * ) m ;
m - > numindexes = mesh - > num_tris * 3 ;
for ( j = 0 ; j < m - > numindexes ; j + + )
{
* outdex + + = BigLong ( * index + + ) ;
}
}
outbone = Hunk_Alloc ( sizeof ( galiasbone_t ) * header - > num_bones ) ;
inbone = ( dpmbone_t * ) ( ( char * ) buffer + header - > ofs_bones ) ;
for ( i = 0 ; i < header - > num_bones ; i + + )
{
outbone [ i ] . parent = BigLong ( inbone [ i ] . parent ) ;
if ( outbone [ i ] . parent > = i | | outbone [ i ] . parent < - 1 )
2006-03-12 08:01:48 +00:00
{
Con_Printf ( S_ERROR " GLMod_LoadDarkPlacesModel: bad bone index in %s \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2005-09-08 02:02:09 +00:00
Q_strncpyz ( outbone [ i ] . name , inbone [ i ] . name , sizeof ( outbone [ i ] . name ) ) ;
//throw away the flags.
}
outgroups = Hunk_Alloc ( sizeof ( galiasgroup_t ) * header - > num_frames + sizeof ( float ) * header - > num_frames * header - > num_bones * 12 ) ;
outposedata = ( float * ) ( outgroups + header - > num_frames ) ;
inframes = ( dpmframe_t * ) ( ( char * ) buffer + header - > ofs_frames ) ;
for ( i = 0 ; i < header - > num_frames ; i + + )
{
inframes [ i ] . ofs_bonepositions = BigLong ( inframes [ i ] . ofs_bonepositions ) ;
inframes [ i ] . allradius = BigLong ( inframes [ i ] . allradius ) ;
inframes [ i ] . yawradius = BigLong ( inframes [ i ] . yawradius ) ;
inframes [ i ] . mins [ 0 ] = BigLong ( inframes [ i ] . mins [ 0 ] ) ;
inframes [ i ] . mins [ 1 ] = BigLong ( inframes [ i ] . mins [ 1 ] ) ;
inframes [ i ] . mins [ 2 ] = BigLong ( inframes [ i ] . mins [ 2 ] ) ;
inframes [ i ] . maxs [ 0 ] = BigLong ( inframes [ i ] . maxs [ 0 ] ) ;
inframes [ i ] . maxs [ 1 ] = BigLong ( inframes [ i ] . maxs [ 1 ] ) ;
inframes [ i ] . maxs [ 2 ] = BigLong ( inframes [ i ] . maxs [ 2 ] ) ;
2006-02-27 00:42:25 +00:00
Q_strncpyz ( outgroups [ i ] . name , inframes [ i ] . name , sizeof ( outgroups [ i ] . name ) ) ;
2005-09-08 02:02:09 +00:00
outgroups [ i ] . rate = 10 ;
outgroups [ i ] . numposes = 1 ;
outgroups [ i ] . isheirachical = true ;
outgroups [ i ] . poseofs = ( char * ) outposedata - ( char * ) & outgroups [ i ] ;
inposedata = ( float * ) ( ( char * ) buffer + inframes [ i ] . ofs_bonepositions ) ;
for ( j = 0 ; j < header - > num_bones * 12 ; j + + )
* outposedata + + = BigFloat ( * inposedata + + ) ;
}
# ifndef SERVERONLY
skinfiles = GL_BuildSkinFileList ( loadmodel - > name ) ;
if ( skinfiles < 1 )
skinfiles = 1 ;
# endif
mesh = ( dpmmesh_t * ) ( ( char * ) buffer + header - > ofs_meshs ) ;
for ( i = 0 ; i < header - > num_meshs ; i + + , mesh + + )
{
m = & root [ i ] ;
if ( i < header - > num_meshs - 1 )
m - > nextsurf = sizeof ( galiasinfo_t ) ;
m - > sharesbones = true ;
m - > ofsbones = ( char * ) outbone - ( char * ) m ;
m - > numbones = header - > num_bones ;
m - > groups = header - > num_frames ;
m - > groupofs = ( char * ) outgroups - ( char * ) m ;
# ifdef SERVERONLY
m - > numskins = 1 ;
# else
m - > numskins = skinfiles ;
skin = Hunk_Alloc ( ( sizeof ( galiasskin_t ) + sizeof ( galiastexnum_t ) ) * skinfiles ) ;
texnum = ( galiastexnum_t * ) ( skin + skinfiles ) ;
for ( j = 0 ; j < skinfiles ; j + + , texnum + + )
{
skin [ j ] . texnums = 1 ; //non-sequenced skins.
skin [ j ] . ofstexnums = ( char * ) texnum - ( char * ) & skin [ j ] ;
GL_LoadSkinFile ( texnum , mesh - > shadername , j , NULL , 0 , 0 , NULL ) ;
}
m - > ofsskins = ( char * ) skin - ( char * ) m ;
# endif
}
root [ 0 ] . sharesbones = false ;
//
// move the complete, relocatable alias model to the cache
//
hunkend = Hunk_LowMark ( ) ;
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ; //file replacement - inherit flags from any defunc mdl files.
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2005-09-08 02:02:09 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-12 08:01:48 +00:00
return false ;
2005-09-08 02:02:09 +00:00
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = GLMod_Trace ;
2006-03-12 08:01:48 +00:00
return true ;
2005-09-08 02:02:09 +00:00
}
2005-08-03 23:14:59 +00:00
# endif //ZYMOTICMODELS
# ifdef MD5MODELS
static void GenMatrix ( float x , float y , float z , float qx , float qy , float qz , float result [ 12 ] )
{
float qw ;
{ //figure out qw
float term = 1 - ( qx * qx ) - ( qy * qy ) - ( qz * qz ) ;
if ( term < 0 )
qw = 0 ;
else
2005-11-26 03:02:55 +00:00
qw = - ( float ) sqrt ( term ) ;
2005-08-03 23:14:59 +00:00
}
{ //generate the matrix
/*
float xx = qx * qx ;
float xy = qx * qy ;
float xz = qx * qz ;
float xw = qx * qw ;
float yy = qy * qy ;
float yz = qy * qz ;
float yw = qy * qw ;
float zz = qz * qz ;
float zw = qz * qw ;
result [ 0 * 4 + 0 ] = 1 - 2 * ( yy + zz ) ;
result [ 0 * 4 + 1 ] = 2 * ( xy - zw ) ;
result [ 0 * 4 + 2 ] = 2 * ( xz + yw ) ;
result [ 0 * 4 + 3 ] = x ;
result [ 1 * 4 + 0 ] = 2 * ( xy + zw ) ;
result [ 1 * 4 + 1 ] = 1 - 2 * ( xx + zz ) ;
result [ 1 * 4 + 2 ] = 2 * ( yz - xw ) ;
result [ 1 * 4 + 3 ] = y ;
result [ 2 * 4 + 0 ] = 2 * ( xz - yw ) ;
result [ 2 * 4 + 1 ] = 2 * ( yz + xw ) ;
result [ 2 * 4 + 2 ] = 1 - 2 * ( xx + yy ) ;
result [ 2 * 4 + 3 ] = z ;
*/
float xx , xy , xz , xw , yy , yz , yw , zz , zw ;
float x2 , y2 , z2 ;
x2 = qx + qx ;
y2 = qy + qy ;
z2 = qz + qz ;
xx = qx * x2 ; xy = qx * y2 ; xz = qx * z2 ;
yy = qy * y2 ; yz = qy * z2 ; zz = qz * z2 ;
xw = qw * x2 ; yw = qw * y2 ; zw = qw * z2 ;
result [ 0 * 4 + 0 ] = 1.0f - ( yy + zz ) ;
result [ 1 * 4 + 0 ] = xy + zw ;
result [ 2 * 4 + 0 ] = xz - yw ;
result [ 0 * 4 + 1 ] = xy - zw ;
result [ 1 * 4 + 1 ] = 1.0f - ( xx + zz ) ;
result [ 2 * 4 + 1 ] = yz + xw ;
result [ 0 * 4 + 2 ] = xz + yw ;
result [ 1 * 4 + 2 ] = yz - xw ;
result [ 2 * 4 + 2 ] = 1.0f - ( xx + yy ) ;
result [ 0 * 4 + 3 ] = x ;
result [ 1 * 4 + 3 ] = y ;
result [ 2 * 4 + 3 ] = z ;
}
}
galiasinfo_t * GLMod_ParseMD5MeshModel ( char * buffer )
{
2006-03-13 05:54:12 +00:00
# define MD5ERROR0PARAM(x) { Con_Printf(S_ERROR x "\n"); return NULL; }
# define MD5ERROR1PARAM(x, y) { Con_Printf(S_ERROR x "\n", y); return NULL; }
2005-08-03 23:14:59 +00:00
# define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) Sys_Error("MD5MESH: expected %s", x);
int numjoints = 0 ;
int nummeshes = 0 ;
qboolean foundjoints = false ;
int i ;
2005-11-30 01:20:53 +00:00
galiasbone_t * bones = NULL ;
galiasgroup_t * pose = NULL ;
2005-08-03 23:14:59 +00:00
galiasinfo_t * inf , * root , * lastsurf ;
float * posedata ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
galiasskin_t * skin ;
galiastexnum_t * texnum ;
2005-08-10 17:22:49 +00:00
# endif
2005-08-03 23:14:59 +00:00
float x , y , z , qx , qy , qz ;
buffer = COM_Parse ( buffer ) ;
if ( strcmp ( com_token , " MD5Version " ) )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5 model without MD5Version identifier first " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
if ( atoi ( com_token ) ! = 10 )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5 model with unsupported MD5Version " ) ;
2005-08-03 23:14:59 +00:00
root = Hunk_Alloc ( sizeof ( galiasinfo_t ) ) ;
lastsurf = NULL ;
for ( ; ; )
{
buffer = COM_Parse ( buffer ) ;
if ( ! buffer )
break ;
if ( ! strcmp ( com_token , " commandline " ) )
{ //we don't need this
buffer = strchr ( buffer , ' \" ' ) ;
buffer = strchr ( ( char * ) buffer + 1 , ' \" ' ) + 1 ;
// buffer = COM_Parse(buffer);
}
else if ( ! strcmp ( com_token , " numJoints " ) )
{
if ( numjoints )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numMeshes was already declared " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
numjoints = atoi ( com_token ) ;
if ( numjoints < = 0 )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: Needs some joints " ) ;
2005-08-03 23:14:59 +00:00
}
else if ( ! strcmp ( com_token , " numMeshes " ) )
{
if ( nummeshes )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numMeshes was already declared " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
nummeshes = atoi ( com_token ) ;
if ( nummeshes < = 0 )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: Needs some meshes " ) ;
2005-08-03 23:14:59 +00:00
}
else if ( ! strcmp ( com_token , " joints " ) )
{
if ( foundjoints )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: Duplicate joints section " ) ;
2005-08-03 23:14:59 +00:00
foundjoints = true ;
if ( ! numjoints )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: joints section before (or without) numjoints " ) ;
2005-08-03 23:14:59 +00:00
bones = Hunk_Alloc ( sizeof ( * bones ) * numjoints ) ;
pose = Hunk_Alloc ( sizeof ( galiasgroup_t ) ) ;
posedata = Hunk_Alloc ( sizeof ( float ) * 12 * numjoints ) ;
pose - > isheirachical = false ;
pose - > rate = 1 ;
pose - > numposes = 1 ;
pose - > poseofs = ( char * ) posedata - ( char * ) pose ;
2006-02-27 00:42:25 +00:00
Q_strncpyz ( pose - > name , " base " , sizeof ( pose - > name ) ) ;
2005-08-03 23:14:59 +00:00
EXPECT ( " { " ) ;
//"name" parent (x y z) (s t u)
//stu are a normalized quaternion, which we will convert to a 3*4 matrix for no apparent reason
2005-11-26 03:02:55 +00:00
2005-08-03 23:14:59 +00:00
for ( i = 0 ; i < numjoints ; i + + )
{
buffer = COM_Parse ( buffer ) ;
Q_strncpyz ( bones [ i ] . name , com_token , sizeof ( bones [ i ] . name ) ) ;
buffer = COM_Parse ( buffer ) ;
bones [ i ] . parent = atoi ( com_token ) ;
if ( bones [ i ] . parent > = i )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: joints parent's must be lower " ) ;
2005-08-03 23:14:59 +00:00
if ( ( bones [ i ] . parent < 0 & & i ) | | ( ! i & & bones [ i ] . parent ! = - 1 ) )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: Only the root joint may have a negative parent " ) ;
2005-08-03 23:14:59 +00:00
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
x = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
y = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
z = atof ( com_token ) ;
EXPECT ( " ) " ) ;
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
qx = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
qy = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
qz = atof ( com_token ) ;
EXPECT ( " ) " ) ;
GenMatrix ( x , y , z , qx , qy , qz , posedata + i * 12 ) ;
}
EXPECT ( " } " ) ;
}
else if ( ! strcmp ( com_token , " mesh " ) )
{
int numverts = 0 ;
int numweights = 0 ;
int numtris = 0 ;
int num ;
int vnum ;
int numusableweights = 0 ;
int * firstweightlist = NULL ;
int * numweightslist = NULL ;
galisskeletaltransforms_t * trans ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-11-30 01:20:53 +00:00
float * stcoord = NULL ;
2005-08-10 17:22:49 +00:00
# endif
2005-11-30 01:20:53 +00:00
int * indexes = NULL ;
2005-08-03 23:14:59 +00:00
float w ;
vec4_t * rawweight = NULL ;
int * rawweightbone = NULL ;
if ( ! nummeshes )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: mesh section before (or without) nummeshes " ) ;
2005-11-30 01:20:53 +00:00
if ( ! foundjoints | | ! bones | | ! pose )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: mesh must come after joints " ) ;
2005-08-03 23:14:59 +00:00
if ( ! lastsurf )
{
lastsurf = root ;
inf = root ;
}
else
{
inf = Hunk_Alloc ( sizeof ( * inf ) ) ;
lastsurf - > nextsurf = ( char * ) inf - ( char * ) lastsurf ;
lastsurf = inf ;
}
inf - > ofsbones = ( char * ) bones - ( char * ) inf ;
inf - > numbones = numjoints ;
inf - > groups = 1 ;
inf - > groupofs = ( char * ) pose - ( char * ) inf ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
skin = Hunk_Alloc ( sizeof ( * skin ) ) ;
texnum = Hunk_Alloc ( sizeof ( * texnum ) ) ;
2005-08-03 23:14:59 +00:00
inf - > numskins = 1 ;
inf - > ofsskins = ( char * ) skin - ( char * ) inf ;
skin - > texnums = 1 ;
skin - > skinspeed = 1 ;
skin - > ofstexnums = ( char * ) texnum - ( char * ) skin ;
2005-08-10 17:22:49 +00:00
# endif
2005-08-03 23:14:59 +00:00
EXPECT ( " { " ) ;
for ( ; ; )
{
buffer = COM_Parse ( buffer ) ;
if ( ! buffer )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: unexpected eof " ) ;
2005-08-03 23:14:59 +00:00
if ( ! strcmp ( com_token , " shader " ) )
{
buffer = COM_Parse ( buffer ) ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
// texnum->shader = R_RegisterSkin(com_token);
texnum - > base = Mod_LoadHiResTexture ( com_token , " models " , true , true , true ) ;
2005-08-10 17:22:49 +00:00
# endif
2005-08-03 23:14:59 +00:00
}
else if ( ! strcmp ( com_token , " numverts " ) )
{
if ( numverts )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numverts was already specified " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
numverts = atoi ( com_token ) ;
if ( numverts < 0 )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numverts cannot be negative " ) ;
2005-08-03 23:14:59 +00:00
firstweightlist = Z_Malloc ( sizeof ( * firstweightlist ) * numverts ) ;
numweightslist = Z_Malloc ( sizeof ( * numweightslist ) * numverts ) ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
stcoord = Hunk_Alloc ( sizeof ( float ) * 2 * numverts ) ;
inf - > ofs_st_array = ( char * ) stcoord - ( char * ) inf ;
inf - > numverts = numverts ;
2005-08-10 17:22:49 +00:00
# endif
2005-08-03 23:14:59 +00:00
}
else if ( ! strcmp ( com_token , " vert " ) )
{ //vert num ( s t ) firstweight numweights
buffer = COM_Parse ( buffer ) ;
num = atoi ( com_token ) ;
2005-11-30 21:35:43 +00:00
if ( num < 0 | | num > = numverts | | ! indexes )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: vertex out of range " ) ;
2005-08-03 23:14:59 +00:00
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-11-30 21:35:43 +00:00
if ( ! stcoord )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: vertex out of range " ) ;
2005-08-03 23:14:59 +00:00
stcoord [ num * 2 + 0 ] = atof ( com_token ) ;
2005-08-10 17:22:49 +00:00
# endif
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
2005-08-10 17:22:49 +00:00
# ifndef SERVERONLY
2005-08-03 23:14:59 +00:00
stcoord [ num * 2 + 1 ] = atof ( com_token ) ;
2005-08-10 17:22:49 +00:00
# endif
2005-08-03 23:14:59 +00:00
EXPECT ( " ) " ) ;
buffer = COM_Parse ( buffer ) ;
firstweightlist [ num ] = atoi ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
numweightslist [ num ] = atoi ( com_token ) ;
numusableweights + = numweightslist [ num ] ;
}
else if ( ! strcmp ( com_token , " numtris " ) )
{
if ( numtris )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numtris was already specified " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
numtris = atoi ( com_token ) ;
if ( numtris < 0 )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numverts cannot be negative " ) ;
2005-08-03 23:14:59 +00:00
indexes = Hunk_Alloc ( sizeof ( int ) * 3 * numtris ) ;
inf - > ofs_indexes = ( char * ) indexes - ( char * ) inf ;
inf - > numindexes = numtris * 3 ;
}
else if ( ! strcmp ( com_token , " tri " ) )
{
buffer = COM_Parse ( buffer ) ;
num = atoi ( com_token ) ;
if ( num < 0 | | num > = numtris )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: vertex out of range " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
indexes [ num * 3 + 0 ] = atoi ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
indexes [ num * 3 + 1 ] = atoi ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
indexes [ num * 3 + 2 ] = atoi ( com_token ) ;
}
else if ( ! strcmp ( com_token , " numweights " ) )
{
if ( numweights )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: numweights was already specified " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
numweights = atoi ( com_token ) ;
rawweight = Z_Malloc ( sizeof ( * rawweight ) * numweights ) ;
rawweightbone = Z_Malloc ( sizeof ( * rawweightbone ) * numweights ) ;
}
else if ( ! strcmp ( com_token , " weight " ) )
{
//weight num bone scale ( x y z )
buffer = COM_Parse ( buffer ) ;
num = atoi ( com_token ) ;
if ( num < 0 | | num > = numweights )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: weight out of range " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
rawweightbone [ num ] = atoi ( com_token ) ;
if ( rawweightbone [ num ] < 0 | | rawweightbone [ num ] > = numjoints )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: weight specifies bad bone " ) ;
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
w = atof ( com_token ) ;
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
rawweight [ num ] [ 0 ] = w * atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
rawweight [ num ] [ 1 ] = w * atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
rawweight [ num ] [ 2 ] = w * atof ( com_token ) ;
EXPECT ( " ) " ) ;
rawweight [ num ] [ 3 ] = w ;
}
else if ( ! strcmp ( com_token , " } " ) )
break ;
else
2006-03-13 05:54:12 +00:00
MD5ERROR1PARAM ( " MD5MESH: Unrecognised token inside mesh (%s) " , com_token ) ;
2005-08-03 23:14:59 +00:00
}
trans = Hunk_Alloc ( sizeof ( * trans ) * numusableweights ) ;
inf - > ofstransforms = ( char * ) trans - ( char * ) inf ;
for ( num = 0 , vnum = 0 ; num < numverts ; num + + )
{
if ( numweightslist [ num ] < = 0 )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: weights not set on vertex " ) ;
2005-08-03 23:14:59 +00:00
while ( numweightslist [ num ] )
{
trans [ vnum ] . vertexindex = num ;
trans [ vnum ] . boneindex = rawweightbone [ firstweightlist [ num ] ] ;
trans [ vnum ] . org [ 0 ] = rawweight [ firstweightlist [ num ] ] [ 0 ] ;
trans [ vnum ] . org [ 1 ] = rawweight [ firstweightlist [ num ] ] [ 1 ] ;
trans [ vnum ] . org [ 2 ] = rawweight [ firstweightlist [ num ] ] [ 2 ] ;
trans [ vnum ] . org [ 3 ] = rawweight [ firstweightlist [ num ] ] [ 3 ] ;
vnum + + ;
firstweightlist [ num ] + + ;
numweightslist [ num ] - - ;
}
}
inf - > numtransforms = vnum ;
if ( firstweightlist )
Z_Free ( firstweightlist ) ;
if ( numweightslist )
Z_Free ( numweightslist ) ;
if ( rawweight )
Z_Free ( rawweight ) ;
if ( rawweightbone )
Z_Free ( rawweightbone ) ;
}
else
2006-03-13 05:54:12 +00:00
MD5ERROR1PARAM ( " Unrecognised token in MD5 model (%s) " , com_token ) ;
2005-08-03 23:14:59 +00:00
}
if ( ! lastsurf )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5MESH: No meshes " ) ;
2005-08-03 23:14:59 +00:00
return root ;
2006-03-13 05:54:12 +00:00
# undef MD5ERROR0PARAM
# undef MD5ERROR1PARAM
2005-08-03 23:14:59 +00:00
# undef EXPECT
}
2006-03-13 05:54:12 +00:00
qboolean GLMod_LoadMD5MeshModel ( model_t * mod , void * buffer )
2005-08-03 23:14:59 +00:00
{
galiasinfo_t * root ;
int hunkstart , hunkend , hunktotal ;
loadmodel = mod ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
root = GLMod_ParseMD5MeshModel ( buffer ) ;
2006-03-13 05:54:12 +00:00
if ( root = = NULL )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2005-08-03 23:14:59 +00:00
hunkend = Hunk_LowMark ( ) ;
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ; //file replacement - inherit flags from any defunc mdl files.
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2005-08-03 23:14:59 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-13 05:54:12 +00:00
return false ;
2005-08-03 23:14:59 +00:00
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = GLMod_Trace ;
2006-03-13 05:54:12 +00:00
return true ;
2005-08-03 23:14:59 +00:00
}
2006-03-13 05:54:12 +00:00
qboolean GLMod_ParseMD5Anim ( char * buffer , galiasinfo_t * prototype , void * * poseofs , galiasgroup_t * gat )
2005-08-03 23:14:59 +00:00
{
2006-03-13 05:54:12 +00:00
# define MD5ERROR0PARAM(x) { Con_Printf(S_ERROR x "\n"); return false; }
# define MD5ERROR1PARAM(x, y) { Con_Printf(S_ERROR x "\n", y); return false; }
# define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) MD5ERROR1PARAM("MD5ANIM: expected %s", x);
2005-08-03 23:14:59 +00:00
unsigned int i , j ;
galiasgroup_t grp ;
unsigned int parent ;
unsigned int numframes ;
unsigned int numjoints ;
float framespersecond ;
unsigned int numanimatedparts ;
galiasbone_t * bonelist ;
unsigned char * boneflags ;
unsigned int * firstanimatedcomponants ;
float * animatedcomponants ;
float * baseframe ; //6 componants.
float * posedata ;
float tx , ty , tz , qx , qy , qz ;
int fac , flags ;
2005-08-10 17:22:49 +00:00
float f ;
2005-08-03 23:14:59 +00:00
EXPECT ( " MD5Version " ) ;
EXPECT ( " 10 " ) ;
EXPECT ( " commandline " ) ;
buffer = COM_Parse ( buffer ) ;
EXPECT ( " numFrames " ) ;
buffer = COM_Parse ( buffer ) ;
numframes = atoi ( com_token ) ;
EXPECT ( " numJoints " ) ;
buffer = COM_Parse ( buffer ) ;
numjoints = atoi ( com_token ) ;
EXPECT ( " frameRate " ) ;
buffer = COM_Parse ( buffer ) ;
framespersecond = atof ( com_token ) ;
EXPECT ( " numAnimatedComponents " ) ;
buffer = COM_Parse ( buffer ) ;
numanimatedparts = atoi ( com_token ) ;
firstanimatedcomponants = BZ_Malloc ( sizeof ( int ) * numjoints ) ;
animatedcomponants = BZ_Malloc ( sizeof ( float ) * numanimatedparts ) ;
boneflags = BZ_Malloc ( sizeof ( unsigned char ) * numjoints ) ;
baseframe = BZ_Malloc ( sizeof ( float ) * 12 * numjoints ) ;
* poseofs = posedata = Hunk_Alloc ( sizeof ( float ) * 12 * numjoints * numframes ) ;
if ( prototype )
{
if ( prototype - > numbones ! = numjoints )
2006-03-13 05:54:12 +00:00
MD5ERROR0PARAM ( " MD5ANIM: number of bones doesn't match " ) ;
2005-09-08 02:02:09 +00:00
bonelist = ( galiasbone_t * ) ( ( char * ) prototype + prototype - > ofsbones ) ;
2005-08-03 23:14:59 +00:00
}
else
{
bonelist = Hunk_Alloc ( sizeof ( galiasbone_t ) * numjoints ) ;
prototype - > ofsbones = ( char * ) bonelist - ( char * ) prototype ;
prototype - > numbones = numjoints ;
}
EXPECT ( " hierarchy " ) ;
EXPECT ( " { " ) ;
for ( i = 0 ; i < numjoints ; i + + , bonelist + + )
{
buffer = COM_Parse ( buffer ) ;
if ( prototype )
{
if ( strcmp ( bonelist - > name , com_token ) )
2006-03-13 05:54:12 +00:00
MD5ERROR1PARAM ( " MD5ANIM: bone name doesn't match (%s) " , com_token ) ;
2005-08-03 23:14:59 +00:00
}
else
Q_strncpyz ( bonelist - > name , com_token , sizeof ( bonelist - > name ) ) ;
buffer = COM_Parse ( buffer ) ;
parent = atoi ( com_token ) ;
if ( prototype )
{
if ( bonelist - > parent ! = parent )
2006-03-13 05:54:12 +00:00
MD5ERROR1PARAM ( " MD5ANIM: bone name doesn't match (%s) " , com_token ) ;
2005-08-03 23:14:59 +00:00
}
else
bonelist - > parent = parent ;
buffer = COM_Parse ( buffer ) ;
boneflags [ i ] = atoi ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
firstanimatedcomponants [ i ] = atoi ( com_token ) ;
}
EXPECT ( " } " ) ;
EXPECT ( " bounds " ) ;
EXPECT ( " { " ) ;
for ( i = 0 ; i < numframes ; i + + )
{
EXPECT ( " ( " ) ;
2005-08-10 17:22:49 +00:00
buffer = COM_Parse ( buffer ) ; f = atoi ( com_token ) ;
if ( f < loadmodel - > mins [ 0 ] ) loadmodel - > mins [ 0 ] = f ;
buffer = COM_Parse ( buffer ) ; f = atoi ( com_token ) ;
if ( f < loadmodel - > mins [ 1 ] ) loadmodel - > mins [ 1 ] = f ;
buffer = COM_Parse ( buffer ) ; f = atoi ( com_token ) ;
if ( f < loadmodel - > mins [ 2 ] ) loadmodel - > mins [ 2 ] = f ;
2005-08-03 23:14:59 +00:00
EXPECT ( " ) " ) ;
EXPECT ( " ( " ) ;
2005-08-10 17:22:49 +00:00
buffer = COM_Parse ( buffer ) ; f = atoi ( com_token ) ;
if ( f > loadmodel - > maxs [ 0 ] ) loadmodel - > maxs [ 0 ] = f ;
buffer = COM_Parse ( buffer ) ; f = atoi ( com_token ) ;
if ( f > loadmodel - > maxs [ 1 ] ) loadmodel - > maxs [ 1 ] = f ;
buffer = COM_Parse ( buffer ) ; f = atoi ( com_token ) ;
if ( f > loadmodel - > maxs [ 2 ] ) loadmodel - > maxs [ 2 ] = f ;
2005-08-03 23:14:59 +00:00
EXPECT ( " ) " ) ;
}
EXPECT ( " } " ) ;
EXPECT ( " baseframe " ) ;
EXPECT ( " { " ) ;
for ( i = 0 ; i < numjoints ; i + + )
{
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
baseframe [ i * 6 + 0 ] = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
baseframe [ i * 6 + 1 ] = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
baseframe [ i * 6 + 2 ] = atof ( com_token ) ;
EXPECT ( " ) " ) ;
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
baseframe [ i * 6 + 3 ] = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
baseframe [ i * 6 + 4 ] = atof ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
baseframe [ i * 6 + 5 ] = atof ( com_token ) ;
EXPECT ( " ) " ) ;
}
EXPECT ( " } " ) ;
for ( i = 0 ; i < numframes ; i + + )
{
EXPECT ( " frame " ) ;
EXPECT ( va ( " %i " , i ) ) ;
EXPECT ( " { " ) ;
for ( j = 0 ; j < numanimatedparts ; j + + )
{
buffer = COM_Parse ( buffer ) ;
animatedcomponants [ j ] = atof ( com_token ) ;
}
EXPECT ( " } " ) ;
for ( j = 0 ; j < numjoints ; j + + )
{
fac = firstanimatedcomponants [ j ] ;
flags = boneflags [ j ] ;
if ( flags & 1 )
tx = animatedcomponants [ fac + + ] ;
else
tx = baseframe [ j * 6 + 0 ] ;
if ( flags & 2 )
ty = animatedcomponants [ fac + + ] ;
else
ty = baseframe [ j * 6 + 1 ] ;
if ( flags & 4 )
tz = animatedcomponants [ fac + + ] ;
else
tz = baseframe [ j * 6 + 2 ] ;
if ( flags & 8 )
qx = animatedcomponants [ fac + + ] ;
else
qx = baseframe [ j * 6 + 3 ] ;
if ( flags & 16 )
qy = animatedcomponants [ fac + + ] ;
else
qy = baseframe [ j * 6 + 4 ] ;
if ( flags & 32 )
qz = animatedcomponants [ fac + + ] ;
else
qz = baseframe [ j * 6 + 5 ] ;
GenMatrix ( tx , ty , tz , qx , qy , qz , posedata + 12 * ( j + numjoints * i ) ) ;
}
}
BZ_Free ( firstanimatedcomponants ) ;
BZ_Free ( animatedcomponants ) ;
BZ_Free ( boneflags ) ;
BZ_Free ( baseframe ) ;
2006-02-27 00:42:25 +00:00
Q_strncpyz ( grp . name , " " , sizeof ( grp . name ) ) ;
2005-08-03 23:14:59 +00:00
grp . isheirachical = true ;
grp . numposes = numframes ;
grp . rate = framespersecond ;
2005-11-14 01:31:14 +00:00
grp . loop = true ;
2005-08-03 23:14:59 +00:00
2006-03-13 05:54:12 +00:00
* gat = grp ;
return true ;
# undef MD5ERROR0PARAM
# undef MD5ERROR1PARAM
2005-08-03 23:14:59 +00:00
# undef EXPECT
}
/*
EXTERNALANIM
//File what specifies md5 model/anim stuff.
model test / imp . md5mesh
group test / idle1 . md5anim
clampgroup test / idle1 . md5anim
frames test / idle1 . md5anim
*/
2006-03-13 05:54:12 +00:00
qboolean GLMod_LoadCompositeAnim ( model_t * mod , void * buffer )
2005-08-03 23:14:59 +00:00
{
int i ;
char * file ;
galiasinfo_t * root = NULL ;
int numgroups = 0 ;
galiasgroup_t * grouplist = NULL ;
galiasgroup_t * newgroup = NULL ;
void * * poseofs ;
int hunkstart , hunkend , hunktotal ;
loadmodel = mod ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
buffer = COM_Parse ( buffer ) ;
if ( strcmp ( com_token , " EXTERNALANIM " ) )
2006-03-13 05:54:12 +00:00
{
Con_Printf ( S_ERROR " EXTERNALANIM: header is not compleate (%s) \n " , mod - > name ) ;
return false ;
}
2005-08-03 23:14:59 +00:00
buffer = COM_Parse ( buffer ) ;
if ( ! strcmp ( com_token , " model " ) )
{
buffer = COM_Parse ( buffer ) ;
file = COM_LoadTempFile2 ( com_token ) ;
if ( ! file ) //FIXME: make non fatal somehow..
2006-03-13 05:54:12 +00:00
{
Con_Printf ( S_ERROR " Couldn't open %s (from %s) \n " , com_token , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2005-08-03 23:14:59 +00:00
root = GLMod_ParseMD5MeshModel ( file ) ;
2006-03-13 05:54:12 +00:00
if ( root = = NULL )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2005-08-03 23:14:59 +00:00
newgroup = ( galiasgroup_t * ) ( ( char * ) root + root - > groupofs ) ;
grouplist = BZ_Malloc ( sizeof ( galiasgroup_t ) * ( numgroups + root - > groups ) ) ;
memcpy ( grouplist , newgroup , sizeof ( galiasgroup_t ) * ( numgroups + root - > groups ) ) ;
poseofs = BZ_Malloc ( sizeof ( galiasgroup_t ) * ( numgroups + root - > groups ) ) ;
for ( i = 0 ; i < root - > groups ; i + + )
{
grouplist [ numgroups ] = newgroup [ i ] ;
poseofs [ numgroups ] = ( char * ) & newgroup [ i ] + newgroup [ i ] . poseofs ;
numgroups + + ;
}
}
else
{
2006-03-13 05:54:12 +00:00
Con_Printf ( S_ERROR " EXTERNALANIM: model must be defined immediatly after the header \n " ) ;
return false ;
2005-08-03 23:14:59 +00:00
}
2006-03-13 05:54:12 +00:00
2005-08-03 23:14:59 +00:00
for ( ; ; )
{
buffer = COM_Parse ( buffer ) ;
if ( ! buffer )
break ;
if ( ! strcmp ( com_token , " group " ) )
{
grouplist = BZ_Realloc ( grouplist , sizeof ( galiasgroup_t ) * ( numgroups + 1 ) ) ;
poseofs = BZ_Realloc ( poseofs , sizeof ( * poseofs ) * ( numgroups + 1 ) ) ;
buffer = COM_Parse ( buffer ) ;
file = COM_LoadTempFile2 ( com_token ) ;
if ( file ) //FIXME: make non fatal somehow..
{
2006-02-27 00:42:25 +00:00
char namebkup [ MAX_QPATH ] ;
Q_strncpyz ( namebkup , com_token , sizeof ( namebkup ) ) ;
2006-03-13 05:54:12 +00:00
if ( ! GLMod_ParseMD5Anim ( file , root , & poseofs [ numgroups ] , & grouplist [ numgroups ] ) )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
2006-02-27 00:42:25 +00:00
Q_strncpyz ( grouplist [ numgroups ] . name , namebkup , sizeof ( grouplist [ numgroups ] . name ) ) ;
2005-08-03 23:14:59 +00:00
numgroups + + ;
}
}
else if ( ! strcmp ( com_token , " clampgroup " ) )
{
2006-03-13 05:54:12 +00:00
Con_Printf ( S_ERROR " EXTERNALANIM: clampgroup not yet supported (%s) \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
2005-08-03 23:14:59 +00:00
}
else if ( ! strcmp ( com_token , " frames " ) )
{
2006-03-13 05:54:12 +00:00
Con_Printf ( S_ERROR " EXTERNALANIM: frames not yet supported (%s) \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
2005-08-03 23:14:59 +00:00
}
else
{
2006-03-13 05:54:12 +00:00
Con_Printf ( S_ERROR " EXTERNALANIM: unrecognised token (%s) \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
2005-08-03 23:14:59 +00:00
}
}
newgroup = grouplist ;
grouplist = Hunk_Alloc ( sizeof ( galiasgroup_t ) * numgroups ) ;
for ( ; ; )
{
root - > groupofs = ( char * ) grouplist - ( char * ) root ;
root - > groups = numgroups ;
if ( ! root - > nextsurf )
break ;
2005-09-08 02:02:09 +00:00
root = ( galiasinfo_t * ) ( ( char * ) root + root - > nextsurf ) ;
2005-08-03 23:14:59 +00:00
}
for ( i = 0 ; i < numgroups ; i + + )
{
grouplist [ i ] = newgroup [ i ] ;
grouplist [ i ] . poseofs = ( char * ) poseofs [ i ] - ( char * ) & grouplist [ i ] ;
}
hunkend = Hunk_LowMark ( ) ;
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ; //file replacement - inherit flags from any defunc mdl files.
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
2005-11-26 03:02:55 +00:00
2005-08-03 23:14:59 +00:00
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
2006-03-13 05:54:12 +00:00
return false ;
2005-08-03 23:14:59 +00:00
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = GLMod_Trace ;
2006-03-13 05:54:12 +00:00
return true ;
2005-08-03 23:14:59 +00:00
}
# endif //MD5MODELS
# endif // defined(RGLQUAKE) || defined(SERVERONLY)