2007-10-05 18:08:47 +00:00
# include "quakedef.h"
# if defined(D3DQUAKE) || defined(RGLQUAKE) || defined(SERVERONLY)
# ifdef D3DQUAKE
2007-10-05 18:50:10 +00:00
# include "d3dquake.h"
2007-10-05 18:08:47 +00:00
# endif
# ifdef RGLQUAKE
# include "glquake.h"
# endif
# include "com_mesh.h"
# ifdef _WIN32
# include <malloc.h>
# else
# include <alloca.h>
# endif
extern cvar_t gl_part_flame , r_fullbrightSkins , r_fb_models ;
extern cvar_t r_noaliasshadows ;
extern cvar_t mod_md3flags ;
extern model_t * loadmodel ;
extern char loadname [ ] ;
2008-02-01 15:21:14 +00:00
typedef struct
{
char * name ;
float furthestallowedextremety ; //this field is the combined max-min square, added together
//note that while this allows you to move models about a little, you cannot resize the visible part
2008-01-19 05:59:00 +00:00
} clampedmodel_t ;
2008-02-01 15:21:14 +00:00
//these should be rounded up slightly.
2008-01-19 05:59:00 +00:00
//really this is only to catch spiked models. This doesn't prevent more visible models, just bigger ones.
2008-02-01 15:21:14 +00:00
clampedmodel_t clampedmodel [ ] = {
{ " maps/b_bh100.bsp " , 3440 } ,
{ " progs/player.mdl " , 22497 } ,
{ " progs/eyes.mdl " , 755 } ,
{ " progs/gib1.mdl " , 374 } ,
{ " progs/gib2.mdl " , 1779 } ,
{ " progs/gib3.mdl " , 2066 } ,
{ " progs/bolt2.mdl " , 1160 } ,
{ " progs/end1.mdl " , 764 } ,
{ " progs/end2.mdl " , 981 } ,
{ " progs/end3.mdl " , 851 } ,
{ " progs/end4.mdl " , 903 } ,
{ " progs/g_shot.mdl " , 3444 } ,
{ " progs/g_nail.mdl " , 2234 } ,
{ " progs/g_nail2.mdl " , 3660 } ,
{ " progs/g_rock.mdl " , 3441 } ,
{ " progs/g_rock2.mdl " , 3660 } ,
{ " progs/g_light.mdl " , 2698 } ,
{ " progs/invisibl.mdl " , 196 } ,
{ " progs/quaddama.mdl " , 2353 } ,
{ " progs/invulner.mdl " , 2746 } ,
{ " progs/suit.mdl " , 3057 } ,
{ " progs/missile.mdl " , 416 } ,
{ " progs/grenade.mdl " , 473 } ,
{ " progs/spike.mdl " , 112 } ,
{ " progs/s_spike.mdl " , 112 } ,
{ " progs/backpack.mdl " , 1117 } ,
{ " progs/armor.mdl " , 2919 } ,
{ " progs/s_bubble.spr " , 100 } ,
{ " progs/s_explod.spr " , 1000 } ,
//and now TF models
# ifndef _MSC_VER
# warning FIXME: these are placeholders
# endif
{ " progs/disp.mdl " , 3000 } ,
{ " progs/tf_flag.mdl " , 3000 } ,
{ " progs/tf_stan.mdl " , 3000 } ,
{ " progs/turrbase.mdl " , 3000 } ,
{ " progs/turrgun.mdl " , 3000 }
2008-01-19 05:59:00 +00:00
} ;
2007-10-05 18:08:47 +00:00
# ifdef SKELETALMODELS
static void R_LerpBones ( float * plerp , float * * pose , int poses , galiasbone_t * bones , int bonecount , float bonepose [ MAX_BONES ] [ 12 ] )
{
int i , k , b ;
float * matrix , m [ 12 ] ;
if ( poses = = 1 )
{
// 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 + + )
{
for ( k = 0 ; k < 12 ; k + + )
m [ k ] = 0 ;
for ( b = 0 ; b < poses ; b + + )
{
matrix = pose [ b ] + i * 12 ;
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 ] ;
}
}
}
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
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 )
{
float bonepose [ MAX_BONES ] [ 12 ] ;
int i , k , l ;
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 ] ;
}
}
}
}
// blend the vertex bone weights
// memset(outhead, 0, mesh->numvertexes * sizeof(mesh->xyz_array[0]));
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 ;
/*
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;
*/
/*
mesh - > xyz_array [ i ] [ 0 ] = 0 ;
mesh - > xyz_array [ i ] [ 1 ] = 0 ;
mesh - > xyz_array [ i ] [ 2 ] = 0 ;
mesh - > xyz_array [ i ] [ 3 ] = 1 ;
*/
}
mesh - > colors_array = NULL ;
memset ( mesh - > xyz_array , 0 , mesh - > numvertexes * sizeof ( vec3_t ) ) ;
R_TransformVerticies ( bonepose , weights , numweights , ( float * ) mesh - > xyz_array ) ;
#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 ( ) ;
// mesh->numindexes = 0; //don't draw this mesh, as that would obscure the bones. :(
}
# endif
}
# endif
# endif
# if defined(D3DQUAKE) || defined(RGLQUAKE)
extern entity_t * currententity ;
int numTempColours ;
byte_vec4_t * tempColours ;
int numTempVertexCoords ;
vec3_t * tempVertexCoords ;
int numTempNormals ;
vec3_t * tempNormals ;
vec3_t shadevector ;
vec3_t ambientlight ;
vec3_t shadelight ;
static void R_LerpFrames ( mesh_t * mesh , galiaspose_t * p1 , galiaspose_t * p2 , float lerp , qbyte alpha , float expand , qboolean nolightdir )
{
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 ;
p1v = ( vec3_t * ) ( ( char * ) p1 + p1 - > ofsverts ) ;
p2v = ( vec3_t * ) ( ( char * ) p2 + p2 - > ofsverts ) ;
p1n = ( vec3_t * ) ( ( char * ) p1 + p1 - > ofsnormals ) ;
p2n = ( vec3_t * ) ( ( char * ) p2 + p2 - > ofsnormals ) ;
if ( p1v = = p2v | | r_nolerp . value )
{
mesh - > normals_array = p1n ;
mesh - > xyz_array = p1v ;
if ( r_nolightdir . value | | nolightdir )
{
mesh - > colors_array = NULL ;
}
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
{
if ( r_nolightdir . value | | nolightdir )
{
mesh - > colors_array = NULL ;
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 )
{
if ( mesh - > xyz_array = = p1v )
{
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 ;
}
}
}
}
qboolean R_GAliasBuildMesh ( mesh_t * mesh , galiasinfo_t * inf , int frame1 , int frame2 , float lerp , float alpha , float fg1time , float fg2time , qboolean nolightdir )
{
galiasgroup_t * g1 , * g2 ;
if ( ! inf - > groups )
{
Con_DPrintf ( " Model with no frames (%s) \n " , currententity - > model - > name ) ;
return false ;
}
if ( frame1 < 0 )
{
Con_DPrintf ( " Negative frame (%s) \n " , currententity - > model - > name ) ;
frame1 = 0 ;
}
if ( frame2 < 0 )
{
Con_DPrintf ( " Negative frame (%s) \n " , currententity - > model - > name ) ;
frame2 = frame1 ;
}
if ( frame1 > = inf - > groups )
{
Con_DPrintf ( " Too high frame %i (%s) \n " , frame1 , currententity - > model - > name ) ;
frame1 % = inf - > groups ;
}
if ( frame2 > = inf - > groups )
{
Con_DPrintf ( " Too high frame %i (%s) \n " , frame2 , currententity - > model - > name ) ;
frame2 = frame1 ;
}
if ( lerp < = 0 )
frame2 = frame1 ;
else if ( lerp > = 1 )
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 ;
}
mesh - > numvertexes = inf - > numverts ;
mesh - > indexes = ( index_t * ) ( ( char * ) inf + inf - > ofs_indexes ) ;
mesh - > numindexes = inf - > numindexes ;
if ( inf - > sharesverts )
return false ; //don't generate the new vertex positions. We still have them all.
# ifndef SERVERONLY
mesh - > st_array = ( vec2_t * ) ( ( char * ) inf + inf - > ofs_st_array ) ;
mesh - > lmst_array = NULL ;
mesh - > colors_array = tempColours ;
mesh - > trneighbors = ( int * ) ( ( char * ) inf + inf - > ofs_trineighbours ) ;
mesh - > normals_array = tempNormals ;
# endif
mesh - > xyz_array = tempVertexCoords ;
g1 = ( galiasgroup_t * ) ( ( char * ) inf + inf - > groupofs + sizeof ( galiasgroup_t ) * frame1 ) ;
g2 = ( galiasgroup_t * ) ( ( char * ) inf + inf - > groupofs + sizeof ( galiasgroup_t ) * frame2 ) ;
//we don't support meshes with one pose skeletal and annother not.
//we don't support meshes with one group skeletal and annother not.
# ifdef SKELETALMODELS
if ( inf - > numbones )
{
int l = 0 ;
float plerp [ 4 ] ;
float * pose [ 4 ] ;
float mlerp ; //minor lerp, poses within a group.
qboolean hirachy ;
if ( g1 - > isheirachical ! = g2 - > isheirachical | | lerp < 0 )
lerp = 0 ;
hirachy = g1 - > isheirachical ;
mlerp = ( fg1time ) * g1 - > rate ;
frame1 = mlerp ;
frame2 = frame1 + 1 ;
mlerp - = frame1 ;
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 ;
}
plerp [ l ] = ( 1 - mlerp ) * ( 1 - lerp ) ;
if ( plerp [ l ] > 0 )
pose [ l + + ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame1 ) ;
plerp [ l ] = ( mlerp ) * ( 1 - lerp ) ;
if ( plerp [ l ] > 0 )
pose [ l + + ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs + sizeof ( float ) * inf - > numbones * 12 * frame2 ) ;
if ( lerp )
{
mlerp = ( fg2time ) * g2 - > rate ;
frame1 = mlerp ;
frame2 = frame1 + 1 ;
mlerp - = frame1 ;
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 ;
}
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 ) ;
}
/*
pose [ 0 ] = ( float * ) ( ( char * ) g1 + g1 - > poseofs ) ;
plerp [ 0 ] = 1 ;
plerp [ 1 ] = 0 ;
plerp [ 3 ] = 0 ;
plerp [ 4 ] = 0 ;
l = 1 ;
*/
R_BuildSkeletalMesh ( mesh , plerp , pose , l , ( galiasbone_t * ) ( ( char * ) inf + inf - > ofsbones ) , inf - > numbones , ( galisskeletaltransforms_t * ) ( ( char * ) inf + inf - > ofstransforms ) , inf - > numtransforms , hirachy ) ;
return false ;
}
# endif
if ( g1 = = g2 ) //lerping within group is only done if not changing group
{
lerp = fg1time * g1 - > rate ;
if ( lerp < 0 ) lerp = 0 ; //hrm
frame1 = lerp ;
frame2 = frame1 + 1 ;
lerp - = frame1 ;
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 ;
}
}
else //don't bother with a four way lerp. Yeah, this will produce jerkyness with models with just framegroups.
{
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 ) ,
1 - lerp , ( qbyte ) ( alpha * 255 ) , currententity - > fatness , nolightdir ) ;
return true ; //to allow the mesh to be dlighted.
}
# endif
//The whole reason why model loading is supported in the server.
qboolean Mod_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 ;
// float temp;
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 ) ;
# ifdef SKELETALMODELS
if ( mod - > numbones & & ! mod - > sharesverts )
{
float bonepose [ MAX_BONES ] [ 12 ] ;
posedata = alloca ( mod - > numverts * sizeof ( vec3_t ) ) ;
frac = 1 ;
if ( group - > isheirachical )
{
if ( ! mod - > sharesbones )
R_LerpBones ( & frac , ( float * * ) posedata , 1 , ( galiasbone_t * ) ( ( char * ) mod + mod - > ofsbones ) , mod - > numbones , bonepose ) ;
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 ) ;
}
# endif
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 ] ) ;
// temp = DotProduct(impactpoint, normal)-planedist;
CrossProduct ( edge1 , normal , edgenormal ) ;
// temp = DotProduct(impactpoint, edgenormal)-DotProduct(p2, edgenormal);
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 ;
return trace - > fraction ! = 1 ;
}
//Common loader function.
static void Mod_DoCRC ( model_t * mod , char * buffer , int buffersize )
{
# ifndef SERVERONLY
//we've got to have this bit
if ( loadmodel - > engineflags & MDLF_DOCRC )
{
unsigned short crc ;
qbyte * p ;
int len ;
char st [ 40 ] ;
QCRC_Init ( & crc ) ;
for ( len = buffersize , p = buffer ; len ; len - - , p + + )
QCRC_ProcessByte ( & crc , * p ) ;
sprintf ( st , " %d " , ( int ) crc ) ;
Info_SetValueForKey ( cls . userinfo ,
( loadmodel - > engineflags & MDLF_PLAYER ) ? pmodel_name : emodel_name ,
st , MAX_INFO_STRING ) ;
if ( cls . state > = ca_connected )
{
CL_SendClientCommand ( true , " setinfo %s %d " ,
( loadmodel - > engineflags & MDLF_PLAYER ) ? pmodel_name : emodel_name ,
( int ) crc ) ;
}
2008-02-01 15:21:14 +00:00
if ( ! ( loadmodel - > engineflags & MDLF_PLAYER ) )
{ //eyes
loadmodel - > tainted = ( crc ! = 6967 ) ;
}
2007-10-05 18:08:47 +00:00
}
# endif
}
static void Mod_ClampModelSize ( model_t * mod )
{
2008-02-01 15:21:14 +00:00
# ifndef SERVERONLY
int i ;
float rad = 0 , axis ;
axis = ( mod - > maxs [ 0 ] - mod - > mins [ 0 ] ) ;
rad + = axis * axis ;
axis = ( mod - > maxs [ 1 ] - mod - > mins [ 1 ] ) ;
rad + = axis * axis ;
axis = ( mod - > maxs [ 2 ] - mod - > mins [ 2 ] ) ;
rad + = axis * axis ;
if ( loadmodel - > engineflags & MDLF_DOCRC )
{
if ( ! strcmp ( mod - > name , " progs/eyes.mdl " ) )
{ //this is checked elsewhere to make sure the crc matches (this is to make sure the crc check was actually called)
if ( mod - > type ! = mod_alias | | mod - > fromgame ! = fg_quake )
mod - > tainted = true ;
}
}
mod - > clampscale = 1 ;
for ( i = 0 ; i < sizeof ( clampedmodel ) / sizeof ( clampedmodel [ 0 ] ) ; i + + )
{
if ( ! strcmp ( mod - > name , clampedmodel [ i ] . name ) )
{
if ( rad > clampedmodel [ i ] . furthestallowedextremety )
{
axis = clampedmodel [ i ] . furthestallowedextremety ;
mod - > clampscale = axis / rad ;
Con_DPrintf ( " \" %s \" will be clamped. \n " , mod - > name ) ;
}
return ;
}
2008-01-19 05:59:00 +00:00
}
2007-10-05 18:08:47 +00:00
2008-01-19 05:59:00 +00:00
Con_DPrintf ( " Don't know what size to clamp \" %s \" to (size:%f). \n " , mod - > name , rad ) ;
2007-10-05 18:08:47 +00:00
# endif
}
# ifdef RGLQUAKE
static int R_FindTriangleWithEdge ( int * indexes , int numtris , int start , int end , int ignore )
{
int i ;
int match , count ;
count = 0 ;
match = - 1 ;
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 Mod_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 ) ;
}
}
# endif
void Mod_CompileTriangleNeighbours ( galiasinfo_t * galias )
{
# ifdef RGLQUAKE
if ( qrenderer ! = QR_OPENGL )
return ;
if ( r_shadows . value )
{
int * neighbours ;
neighbours = Hunk_Alloc ( sizeof ( int ) * galias - > numindexes / 3 * 3 ) ;
galias - > ofs_trineighbours = ( qbyte * ) neighbours - ( qbyte * ) galias ;
Mod_BuildTriangleNeighbours ( neighbours , ( int * ) ( ( char * ) galias + galias - > ofs_indexes ) , galias - > numindexes / 3 ) ;
}
# endif
}
# if defined(D3DQUAKE) || defined(RGLQUAKE)
/*
= = = = = = = = = = = = = = = = =
Mod_FloodFillSkin
Fill background pixels so mipmapping doesn ' t have haloes - Ed
= = = = = = = = = = = = = = = = =
*/
typedef struct
{
short x , y ;
} floodfill_t ;
// must be a power of 2
# define FLOODFILL_FIFO_SIZE 0x1000
# define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
# define FLOODFILL_STEP( off, dx, dy ) \
{ \
if ( pos [ off ] = = fillcolor ) \
{ \
pos [ off ] = 255 ; \
fifo [ inpt ] . x = x + ( dx ) , fifo [ inpt ] . y = y + ( dy ) ; \
inpt = ( inpt + 1 ) & FLOODFILL_FIFO_MASK ; \
} \
else if ( pos [ off ] ! = 255 ) fdc = pos [ off ] ; \
}
void Mod_FloodFillSkin ( qbyte * skin , int skinwidth , int skinheight )
{
qbyte fillcolor = * skin ; // assume this is the pixel to fill
floodfill_t fifo [ FLOODFILL_FIFO_SIZE ] ;
int inpt = 0 , outpt = 0 ;
int filledcolor = - 1 ;
int i ;
if ( filledcolor = = - 1 )
{
filledcolor = 0 ;
// attempt to find opaque black
for ( i = 0 ; i < 256 ; + + i )
if ( d_8to24rgbtable [ i ] = = ( 255 < < 0 ) ) // alpha 1.0
{
filledcolor = i ;
break ;
}
}
// can't fill to filled color or to transparent color (used as visited marker)
if ( ( fillcolor = = filledcolor ) | | ( fillcolor = = 255 ) )
{
//printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
return ;
}
fifo [ inpt ] . x = 0 , fifo [ inpt ] . y = 0 ;
inpt = ( inpt + 1 ) & FLOODFILL_FIFO_MASK ;
while ( outpt ! = inpt )
{
int x = fifo [ outpt ] . x , y = fifo [ outpt ] . y ;
int fdc = filledcolor ;
qbyte * pos = & skin [ x + skinwidth * y ] ;
outpt = ( outpt + 1 ) & FLOODFILL_FIFO_MASK ;
if ( x > 0 ) FLOODFILL_STEP ( - 1 , - 1 , 0 ) ;
if ( x < skinwidth - 1 ) FLOODFILL_STEP ( 1 , 1 , 0 ) ;
if ( y > 0 ) FLOODFILL_STEP ( - skinwidth , 0 , - 1 ) ;
if ( y < skinheight - 1 ) FLOODFILL_STEP ( skinwidth , 0 , 1 ) ;
skin [ x + skinwidth * y ] = fdc ;
}
}
# endif
//additional skin loading
char * * skinfilelist ;
int skinfilecount ;
static qboolean VARGS Mod_TryAddSkin ( char * skinname , . . . )
{
va_list argptr ;
char string [ MAX_QPATH ] ;
//make sure we don't add it twice
int i ;
va_start ( argptr , skinname ) ;
vsnprintf ( string , sizeof ( string ) - 1 , skinname , argptr ) ;
va_end ( argptr ) ;
string [ MAX_QPATH - 1 ] = ' \0 ' ;
for ( i = 0 ; i < skinfilecount ; i + + )
{
if ( ! strcmp ( skinfilelist [ i ] , string ) )
return true ; //already added
}
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 ;
}
int Mod_EnumerateSkins ( char * name , int size , void * param )
{
Mod_TryAddSkin ( name ) ;
return true ;
}
int Mod_BuildSkinFileList ( char * modelname )
{
int i ;
char skinfilename [ MAX_QPATH ] ;
//flush the old list
for ( i = 0 ; i < skinfilecount ; i + + )
{
Z_Free ( skinfilelist [ i ] ) ;
skinfilelist [ i ] = NULL ;
}
skinfilecount = 0 ;
COM_StripExtension ( modelname , skinfilename , sizeof ( skinfilename ) ) ;
//try and add numbered skins, and then try fixed names.
for ( i = 0 ; ; i + + )
{
if ( ! Mod_TryAddSkin ( " %s_%i.skin " , modelname , i ) )
{
if ( i = = 0 )
{
if ( ! Mod_TryAddSkin ( " %s_default.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 1 )
{
if ( ! Mod_TryAddSkin ( " %s_blue.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 2 )
{
if ( ! Mod_TryAddSkin ( " %s_red.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 3 )
{
if ( ! Mod_TryAddSkin ( " %s_green.skin " , skinfilename , i ) )
break ;
}
else if ( i = = 4 )
{
if ( ! Mod_TryAddSkin ( " %s_yellow.skin " , skinfilename , i ) )
break ;
}
else
break ;
}
}
// if (strstr(modelname, "lower") || strstr(modelname, "upper") || strstr(modelname, "head"))
// {
COM_EnumerateFiles ( va ( " %s_*.skin " , modelname ) , Mod_EnumerateSkins , NULL ) ;
COM_EnumerateFiles ( va ( " %s_*.skin " , skinfilename ) , Mod_EnumerateSkins , NULL ) ;
// }
// else
// COM_EnumerateFiles("*.skin", Mod_EnumerateSkins, NULL);
return skinfilecount ;
}
//This is a hack. It uses an assuption about q3 player models.
void Mod_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 ] ) ;
while ( f )
{
f = COM_ParseToken ( f , NULL ) ;
if ( ! f )
return ;
if ( ! strcmp ( com_token , " replace " ) )
{
f = COM_ParseToken ( f , NULL ) ;
len = strlen ( com_token ) ;
//copy surfname -> out, until we meet the part we need to replace
while ( * surfname )
{
if ( ! strncmp ( com_token , surfname , len ) )
//found it
{
surfname + = len ;
f = COM_ParseToken ( f , NULL ) ;
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 ' )
f + + ;
if ( * f = = ' , ' )
{
if ( ! strcmp ( com_token , surfname ) )
{
f + + ;
COM_ParseToken ( f , NULL ) ;
strcpy ( out , com_token ) ;
return ;
}
}
}
p = strchr ( f , ' \n ' ) ;
if ( ! p )
f = f + strlen ( f ) ;
else
f = p + 1 ;
if ( ! * f )
break ;
}
}
# if defined(D3DQUAKE) || defined(RGLQUAKE)
void Mod_LoadSkinFile ( galiastexnum_t * texnum , char * surfacename , int skinnumber , unsigned char * rawdata , int width , int height , unsigned char * palette )
{
char shadername [ MAX_QPATH ] ;
Q_strncpyz ( shadername , surfacename , sizeof ( shadername ) ) ;
Mod_ParseQ3SkinFile ( shadername , surfacename , loadmodel - > name , skinnumber , NULL ) ;
# ifdef Q3SHADERS
texnum - > shader = R_RegisterSkin ( shadername ) ;
# endif
texnum - > base = Mod_LoadHiResTexture ( shadername , " models " , true , true , true ) ;
}
# endif
//Q1 model loading
# if 1
static galiasinfo_t * galias ;
static dmdl_t * pq1inmodel ;
# define NUMVERTEXNORMALS 162
extern float r_avertexnormals [ NUMVERTEXNORMALS ] [ 3 ] ;
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 ( CON_ERROR " Bad frame type for QTest model in %s \n " , loadmodel - > name ) ;
return NULL ;
}
frame + + ;
}
return pframetype ;
}
static void * Q1_LoadFrameGroup ( daliasframetype_t * pframetype , int * seamremaps )
{
galiaspose_t * pose ;
galiasgroup_t * frame ;
dtrivertx_t * pinframe ;
daliasframe_t * frameinfo ;
int i , j , k ;
daliasgroup_t * ingroup ;
daliasinterval_t * intervals ;
float sinter ;
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 = ( daliasframe_t * ) ( ( char * ) ( pframetype + 1 ) ) ;
pinframe = ( dtrivertx_t * ) ( ( char * ) frameinfo + sizeof ( daliasframe_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 + + ;
Q_strncpyz ( frame - > name , frameinfo - > name , sizeof ( frame - > name ) ) ;
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 ;
case ALIAS_GROUP :
case ALIAS_GROUP_SWAPPED : // prerelease
ingroup = ( daliasgroup_t * ) ( pframetype + 1 ) ;
pose = ( galiaspose_t * ) Hunk_Alloc ( LittleLong ( ingroup - > numframes ) * ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * 2 * galias - > numverts ) ) ;
frame - > poseofs = ( char * ) pose - ( char * ) frame ;
frame - > numposes = LittleLong ( ingroup - > numframes ) ;
frame - > loop = true ;
galias - > groups + + ;
verts = ( vec3_t * ) ( pose + frame - > numposes ) ;
normals = & verts [ galias - > numverts ] ;
intervals = ( daliasinterval_t * ) ( ingroup + 1 ) ;
sinter = LittleFloat ( intervals - > interval ) ;
if ( sinter < = 0 )
sinter = 0.1 ;
frame - > rate = 1 / sinter ;
pinframe = ( dtrivertx_t * ) ( intervals + frame - > numposes ) ;
for ( k = 0 ; k < frame - > numposes ; k + + )
{
pose - > ofsverts = ( char * ) verts - ( char * ) pose ;
# ifndef SERVERONLY
pose - > ofsnormals = ( char * ) normals - ( char * ) pose ;
# endif
frameinfo = ( daliasframe_t * ) pinframe ;
pinframe = ( dtrivertx_t * ) ( ( char * ) frameinfo + sizeof ( daliasframe_t ) ) ;
if ( k = = 0 )
Q_strncpyz ( frame - > name , frameinfo - > name , sizeof ( frame - > name ) ) ;
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 ] ] ) ;
}
}
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);
pframetype = ( daliasframetype_t * ) pinframe ;
break ;
default :
Con_Printf ( CON_ERROR " Bad frame type in %s \n " , loadmodel - > name ) ;
return NULL ;
}
frame + + ;
}
return pframetype ;
}
//greatly reduced version of Q1_LoadSkins
//just skips over the data
static void * Q1_LoadSkins_SV ( 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 ;
}
# if defined(RGLQUAKE) || defined(D3DQUAKE)
static void * Q1_LoadSkins_GL ( daliasskintype_t * pskintype , qboolean alpha )
{
extern cvar_t gl_bump ;
galiastexnum_t * texnums ;
char skinname [ MAX_QPATH ] ;
int i ;
int s , t ;
float sinter ;
daliasskingroup_t * count ;
daliasskininterval_t * intervals ;
qbyte * data , * saved ;
galiasskin_t * outskin = ( galiasskin_t * ) ( ( char * ) galias + galias - > ofsskins ) ;
int texture ;
int fbtexture ;
int bumptexture ;
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 ;
//LH's naming scheme ("models" is likly to be ignored)
fbtexture = 0 ;
bumptexture = 0 ;
snprintf ( skinname , sizeof ( skinname ) , " %s_%i. " , loadmodel - > name , i ) ;
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
if ( texture )
{
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_luma. " , loadmodel - > name , i ) ;
fbtexture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
if ( gl_bump . value )
{
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_bump " , loadmodel - > name , i ) ;
bumptexture = Mod_LoadBumpmapTexture ( skinname , " models " ) ;
}
}
else
{
snprintf ( skinname , sizeof ( skinname ) , " %s_%i " , loadname , i ) ;
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
if ( texture & & r_fb_models . value )
{
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_luma " , loadname , i ) ;
fbtexture = Mod_LoadReplacementTexture ( skinname , " models " , true , true , true ) ;
}
if ( texture & & gl_bump . value )
{
snprintf ( skinname , sizeof ( skinname ) , " %s_%i_bump " , loadname , i ) ;
bumptexture = Mod_LoadBumpmapTexture ( skinname , " models " ) ;
}
}
//but only preload it if we have no replacement.
2008-02-08 23:26:25 +00:00
if ( ! texture | | ( loadmodel - > engineflags & MDLF_NOTREPLACEMENTS ) )
2007-10-05 18:08:47 +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 ) ;
Mod_FloodFillSkin ( saved , outskin - > skinwidth , outskin - > skinheight ) ;
2008-02-08 23:26:25 +00:00
//the extra underscore is to stop
if ( ! texture )
2007-10-05 18:08:47 +00:00
{
2008-02-08 23:26:25 +00:00
snprintf ( skinname , sizeof ( skinname ) , " %s__%i " , loadname , i ) ;
texture = R_LoadTexture8 ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , alpha ) ;
if ( r_fb_models . value )
{
snprintf ( skinname , sizeof ( skinname ) , " %s__%i_luma " , loadname , i ) ;
fbtexture = R_LoadTextureFB ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , true ) ;
}
if ( gl_bump . value )
{
snprintf ( skinname , sizeof ( skinname ) , " %s__%i_bump " , loadname , i ) ;
bumptexture = R_LoadTexture8Bump ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , true ) ;
}
2007-10-05 18:08:47 +00:00
}
}
else
texnums = Hunk_Alloc ( sizeof ( * texnums ) ) ;
outskin - > texnums = 1 ;
outskin - > ofstexnums = ( char * ) texnums - ( char * ) outskin ;
# ifdef Q3SHADERS
if ( cls . allow_shaders )
{
sprintf ( skinname , " %s_%i " , loadname , i ) ;
texnums - > shader = R_RegisterCustom ( skinname , NULL ) ;
}
# endif
texnums - > base = texture ;
texnums - > fullbright = fbtexture ;
texnums - > bump = bumptexture ;
pskintype = ( daliasskintype_t * ) ( ( char * ) ( pskintype + 1 ) + s ) ;
break ;
default :
outskin - > skinwidth = pq1inmodel - > skinwidth ;
outskin - > skinheight = pq1inmodel - > skinheight ;
count = ( daliasskingroup_t * ) ( pskintype + 1 ) ;
intervals = ( daliasskininterval_t * ) ( count + 1 ) ;
outskin - > texnums = LittleLong ( count - > numskins ) ;
data = ( qbyte * ) ( intervals + outskin - > texnums ) ;
texnums = Hunk_Alloc ( sizeof ( * texnums ) * outskin - > texnums ) ;
outskin - > ofstexnums = ( char * ) texnums - ( char * ) outskin ;
outskin - > ofstexels = 0 ;
sinter = LittleFloat ( intervals [ 0 ] . interval ) ;
if ( sinter < = 0 )
sinter = 0.1 ;
outskin - > skinspeed = 1 / sinter ;
for ( t = 0 ; t < outskin - > texnums ; t + + , data + = s , texnums + + )
{
texture = 0 ;
fbtexture = 0 ;
//LH naming scheme
if ( ! texture )
{
sprintf ( skinname , " %s_%i_%i. " , loadmodel - > name , i , t ) ;
texture = Mod_LoadReplacementTexture ( skinname , " models " , true , false , true ) ;
}
if ( ! fbtexture & & r_fb_models . value )
{
sprintf ( skinname , " %s_%i_%i_luma. " , loadmodel - > name , i , t ) ;
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 ) )
{
if ( t = = 0 )
{
saved = Hunk_Alloc ( s ) ;
outskin - > ofstexels = ( qbyte * ) ( saved ) - ( qbyte * ) outskin ;
}
else
saved = BZ_Malloc ( s ) ;
memcpy ( saved , data , s ) ;
Mod_FloodFillSkin ( saved , outskin - > skinwidth , outskin - > skinheight ) ;
if ( ! texture )
{
sprintf ( skinname , " %s_%i_%i " , loadname , i , t ) ;
texture = R_LoadTexture8 ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , alpha ) ;
}
if ( ! fbtexture & & r_fb_models . value )
{
sprintf ( skinname , " %s_%i_%i_luma " , loadname , i , t ) ;
fbtexture = R_LoadTextureFB ( skinname , outskin - > skinwidth , outskin - > skinheight , saved , true , true ) ;
}
if ( t ! = 0 ) //only keep the first.
BZ_Free ( saved ) ;
}
# ifdef Q3SHADERS
if ( cls . allow_shaders )
{
sprintf ( skinname , " %s_%i_%i " , loadname , i , t ) ;
texnums - > shader = R_RegisterCustom ( skinname , NULL ) ;
}
# endif
texnums - > base = texture ;
texnums - > fullbright = fbtexture ;
}
pskintype = ( daliasskintype_t * ) data ;
break ;
}
outskin + + ;
}
galias - > numskins = pq1inmodel - > numskins ;
return pskintype ;
}
# endif
qboolean Mod_LoadQ1Model ( model_t * mod , void * buffer )
{
# ifndef SERVERONLY
vec2_t * st_array ;
int j ;
# endif
int hunkstart , hunkend , hunktotal ;
int version ;
int i , onseams ;
dstvert_t * pinstverts ;
dtriangle_t * pintriangles ;
int * seamremap ;
index_t * indexes ;
qboolean qtest = false ;
daliasskintype_t * skinstart ;
int skintranstype ;
int size ;
loadmodel = mod ;
Mod_DoCRC ( loadmodel , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
pq1inmodel = ( dmdl_t * ) buffer ;
loadmodel - > engineflags | = MDLF_NEEDOVERBRIGHT ;
version = LittleLong ( pq1inmodel - > version ) ;
if ( version = = QTESTALIAS_VERSION )
qtest = true ;
else if ( version ! = ALIAS_VERSION )
{
Con_Printf ( CON_ERROR " %s has wrong version number (%i should be %i) \n " ,
mod - > name , version , ALIAS_VERSION ) ;
return false ;
}
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 ] ) ;
if ( pq1inmodel - > numframes < 1 | |
pq1inmodel - > numskins < 1 | |
pq1inmodel - > numtris < 1 | |
pq1inmodel - > numverts < 3 | |
pq1inmodel - > skinheight < 1 | |
pq1inmodel - > skinwidth < 1 )
{
Con_Printf ( CON_ERROR " Model %s has an invalid quantity \n " , mod - > name ) ;
return false ;
}
if ( qtest )
mod - > flags = 0 ; // Qtest has no flags in header
else
mod - > flags = pq1inmodel - > flags ;
size = sizeof ( galiasinfo_t )
# ifndef SERVERONLY
+ pq1inmodel - > numskins * sizeof ( galiasskin_t )
# endif
+ pq1inmodel - > numframes * sizeof ( galiasgroup_t ) ;
galias = Hunk_Alloc ( size ) ;
galias - > groupofs = sizeof ( * galias ) ;
# ifndef SERVERONLY
galias - > ofsskins = sizeof ( * galias ) + pq1inmodel - > numframes * sizeof ( galiasgroup_t ) ;
# endif
galias - > nextsurf = 0 ;
//skins
if ( qtest )
skinstart = ( daliasskintype_t * ) ( ( char * ) buffer + sizeof ( dmdl_t ) - sizeof ( int ) * 2 ) ;
else
skinstart = ( daliasskintype_t * ) ( pq1inmodel + 1 ) ;
if ( mod - > flags & EF_HOLEY )
skintranstype = 3 ;
else if ( mod - > flags & EF_TRANSPARENT )
skintranstype = 2 ;
else if ( mod - > flags & EF_SPECIAL_TRANS )
skintranstype = 4 ;
else
skintranstype = 0 ;
switch ( qrenderer )
{
# if defined(RGLQUAKE) || defined(D3DQUAKE)
case QR_DIRECT3D :
case QR_OPENGL :
pinstverts = ( dstvert_t * ) Q1_LoadSkins_GL ( skinstart , skintranstype ) ;
break ;
# endif
default :
pinstverts = ( dstvert_t * ) Q1_LoadSkins_SV ( skinstart , skintranstype ) ;
break ;
}
//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 ;
//st
# ifndef SERVERONLY
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 + + )
{
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 ;
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 ;
}
# endif
//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
if ( qtest )
{
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 ;
}
}
BZ_Free ( seamremap ) ;
Mod_CompileTriangleNeighbours ( galias ) ;
VectorCopy ( pq1inmodel - > scale_origin , mod - > mins ) ;
VectorMA ( mod - > mins , 255 , pq1inmodel - > scale , mod - > maxs ) ;
Mod_ClampModelSize ( mod ) ;
//
// move the complete, relocatable alias model to the cache
//
hunkend = Hunk_LowMark ( ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , galias , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
# endif
int Mod_ReadFlagsFromMD1 ( char * name , int md3version )
{
dmdl_t * pinmodel ;
char fname [ MAX_QPATH ] ;
COM_StripExtension ( name , fname , sizeof ( fname ) ) ;
COM_DefaultExtension ( fname , " .mdl " , sizeof ( fname ) ) ;
if ( strcmp ( name , fname ) ) //md3 renamed as mdl
{
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)
return 0 ;
}
pinmodel = ( dmdl_t * ) COM_LoadTempFile ( fname ) ;
if ( ! pinmodel ) //not found
return 0 ;
if ( LittleLong ( pinmodel - > ident ) ! = IDPOLYHEADER )
return 0 ;
if ( LittleLong ( pinmodel - > version ) ! = ALIAS_VERSION )
return 0 ;
return LittleLong ( pinmodel - > flags ) ;
}
# ifdef MD2MODELS
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Q2 model loading
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 ;
//static galiasinfo_t *galias;
//static md2_t *pq2inmodel;
# define Q2NUMVERTEXNORMALS 162
extern vec3_t bytedirs [ Q2NUMVERTEXNORMALS ] ;
static void Q2_LoadSkins ( md2_t * pq2inmodel , char * skins )
{
# ifndef SERVERONLY
int i ;
galiastexnum_t * texnums ;
galiasskin_t * outskin = ( galiasskin_t * ) ( ( char * ) galias + galias - > ofsskins ) ;
for ( i = 0 ; i < LittleLong ( pq2inmodel - > num_skins ) ; i + + , outskin + + )
{
texnums = Hunk_Alloc ( sizeof ( * texnums ) ) ;
outskin - > ofstexnums = ( char * ) texnums - ( char * ) outskin ;
outskin - > texnums = 1 ;
COM_CleanUpPath ( skins ) ; //blooming tanks.
texnums - > base = Mod_LoadReplacementTexture ( skins , " models " , true , false , true ) ;
# ifdef Q3SHADERS
texnums - > shader = R_RegisterCustom ( skins , NULL ) ;
if ( ! texnums - > base & & ! texnums - > shader )
Con_Printf ( " Couldn't load %s \n " , skins ) ;
# endif
outskin - > skinwidth = 0 ;
outskin - > skinheight = 0 ;
outskin - > skinspeed = 0 ;
skins + = MD2MAX_SKINNAME ;
}
# endif
galias - > numskins = LittleLong ( pq2inmodel - > num_skins ) ;
# ifndef SERVERONLY
outskin = ( galiasskin_t * ) ( ( char * ) galias + galias - > ofsskins ) ;
outskin + = galias - > numskins - 1 ;
if ( galias - > numskins )
{
texnums = ( galiastexnum_t * ) ( ( char * ) outskin + outskin - > ofstexnums ) ;
if ( texnums - > base )
return ;
# ifdef Q3SHADERS
if ( texnums - > shader )
return ;
# endif
galias - > numskins - - ;
}
# endif
}
# define MD2_MAX_TRIANGLES 4096
qboolean Mod_LoadQ2Model ( model_t * mod , void * buffer )
{
# ifndef SERVERONLY
dmd2stvert_t * pinstverts ;
vec2_t * st_array ;
vec3_t * normals ;
# endif
md2_t * pq2inmodel ;
int hunkstart , hunkend , hunktotal ;
int version ;
int i , j ;
dmd2triangle_t * pintri ;
index_t * indexes ;
int numindexes ;
vec3_t min ;
vec3_t max ;
galiaspose_t * pose ;
galiasgroup_t * poutframe ;
dmd2aliasframe_t * pinframe ;
int framesize ;
vec3_t * verts ;
int indremap [ MD2_MAX_TRIANGLES * 3 ] ;
unsigned short ptempindex [ MD2_MAX_TRIANGLES * 3 ] , ptempstindex [ MD2_MAX_TRIANGLES * 3 ] ;
int numverts ;
int size ;
loadmodel = mod ;
loadmodel - > engineflags | = MDLF_NEEDOVERBRIGHT ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
pq2inmodel = ( md2_t * ) buffer ;
version = LittleLong ( pq2inmodel - > version ) ;
if ( version ! = MD2ALIAS_VERSION )
{
Con_Printf ( CON_ERROR " %s has wrong version number (%i should be %i) \n " ,
mod - > name , version , MD2ALIAS_VERSION ) ;
return false ;
}
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 )
{
Con_Printf ( CON_ERROR " Model %s has an invalid quantity \n " , mod - > name ) ;
return false ;
}
mod - > flags = 0 ;
loadmodel - > numframes = LittleLong ( pq2inmodel - > num_frames ) ;
size = sizeof ( galiasinfo_t )
# ifndef SERVERONLY
+ LittleLong ( pq2inmodel - > num_skins ) * sizeof ( galiasskin_t )
# endif
+ LittleLong ( pq2inmodel - > num_frames ) * sizeof ( galiasgroup_t ) ;
galias = Hunk_Alloc ( size ) ;
galias - > groupofs = sizeof ( * galias ) ;
# ifndef SERVERONLY
galias - > ofsskins = sizeof ( * galias ) + LittleLong ( pq2inmodel - > num_frames ) * sizeof ( galiasgroup_t ) ;
# endif
galias - > nextsurf = 0 ;
//skins
Q2_LoadSkins ( pq2inmodel , ( ( char * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_skins ) ) ) ;
//trianglelists;
pintri = ( dmd2triangle_t * ) ( ( char * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_tris ) ) ;
for ( i = 0 ; i < LittleLong ( pq2inmodel - > num_tris ) ; i + + , pintri + + )
{
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 ] ) ;
}
}
numindexes = galias - > numindexes = LittleLong ( pq2inmodel - > num_tris ) * 3 ;
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 ;
}
Con_DPrintf ( " %s: remapped %i verts to %i \n " , mod - > name , LittleLong ( pq2inmodel - > num_xyz ) , numverts ) ;
galias - > numverts = numverts ;
// remap remaining indexes
for ( i = 0 ; i < numindexes ; i + + )
{
if ( indremap [ i ] ! = i ) {
indexes [ i ] = indexes [ indremap [ i ] ] ;
}
}
// s and t vertices
# ifndef SERVERONLY
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 + + )
{
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 ) ) ;
}
# endif
//frames
ClearBounds ( mod - > mins , mod - > maxs ) ;
poutframe = ( galiasgroup_t * ) ( ( char * ) galias + galias - > groupofs ) ;
framesize = LittleLong ( pq2inmodel - > framesize ) ;
for ( i = 0 ; i < LittleLong ( pq2inmodel - > num_frames ) ; i + + )
{
pose = ( galiaspose_t * ) Hunk_Alloc ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * numverts
# ifndef SERVERONLY
+ sizeof ( vec3_t ) * numverts
# endif
) ;
poutframe - > poseofs = ( char * ) pose - ( char * ) poutframe ;
poutframe - > numposes = 1 ;
galias - > groups + + ;
verts = ( vec3_t * ) ( pose + 1 ) ;
pose - > ofsverts = ( char * ) verts - ( char * ) pose ;
# ifndef SERVERONLY
normals = & verts [ galias - > numverts ] ;
pose - > ofsnormals = ( char * ) normals - ( char * ) pose ;
# endif
pinframe = ( dmd2aliasframe_t * ) ( ( qbyte * ) pq2inmodel + LittleLong ( pq2inmodel - > ofs_frames ) + i * framesize ) ;
Q_strncpyz ( poutframe - > name , pinframe - > name , sizeof ( poutframe - > name ) ) ;
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 ] ;
# ifndef SERVERONLY
VectorCopy ( bytedirs [ pinframe - > verts [ ptempindex [ indremap [ j ] ] ] . lightnormalindex ] , normals [ indexes [ j ] ] ) ;
# endif
}
// 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 + + ;
}
Mod_CompileTriangleNeighbours ( galias ) ;
/*
VectorCopy ( pq2inmodel - > scale_origin , mod - > mins ) ;
VectorMA ( mod - > mins , 255 , pq2inmodel - > scale , mod - > maxs ) ;
*/
Mod_ClampModelSize ( mod ) ;
//
// move the complete, relocatable alias model to the cache
//
hunkend = Hunk_LowMark ( ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , galias , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
# endif
typedef struct {
char name [ MAX_QPATH ] ;
vec3_t org ;
float ang [ 3 ] [ 3 ] ;
} md3tag_t ;
qboolean Mod_GetTag ( model_t * model , int tagnum , int frame1 , int frame2 , float f2ness , float f1time , float f2time , float * result )
{
galiasinfo_t * inf ;
if ( ! model | | model - > type ! = mod_alias )
return false ;
inf = Mod_Extradata ( model ) ;
# 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 ) ;
f1time * = g1 - > rate ;
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 )
{
f2time * = g2 - > rate ;
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 ;
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 ) ;
tagnum = bone [ tagnum ] . parent ;
}
return true ;
}
# endif
if ( inf - > numtags )
{
md3tag_t * t1 , * t2 ;
if ( tagnum < = 0 | | tagnum > inf - > numtags )
return false ;
if ( frame1 < 0 )
return false ;
if ( frame1 > = inf - > numtagframes )
frame1 = inf - > numtagframes - 1 ;
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 ;
t2 = ( md3tag_t * ) ( ( char * ) inf + inf - > ofstags ) ;
t2 + = tagnum ;
t2 + = inf - > numtags * frame2 ;
if ( t1 = = t2 )
{
result [ 0 ] = t1 - > ang [ 0 ] [ 0 ] ;
result [ 1 ] = t1 - > ang [ 0 ] [ 1 ] ;
result [ 2 ] = t1 - > ang [ 0 ] [ 2 ] ;
result [ 3 ] = t1 - > org [ 0 ] ;
result [ 4 ] = t1 - > ang [ 1 ] [ 0 ] ;
result [ 5 ] = t1 - > ang [ 1 ] [ 1 ] ;
result [ 6 ] = t1 - > ang [ 1 ] [ 2 ] ;
result [ 7 ] = t1 - > org [ 1 ] ;
result [ 8 ] = t1 - > ang [ 2 ] [ 0 ] ;
result [ 9 ] = t1 - > ang [ 2 ] [ 1 ] ;
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 ;
result [ 1 ] = t1 - > ang [ 0 ] [ 1 ] * f1ness + t2 - > ang [ 0 ] [ 1 ] * f2ness ;
result [ 2 ] = t1 - > ang [ 0 ] [ 2 ] * f1ness + t2 - > ang [ 0 ] [ 2 ] * f2ness ;
result [ 3 ] = t1 - > org [ 0 ] * f1ness + t2 - > org [ 0 ] * f2ness ;
result [ 4 ] = t1 - > ang [ 1 ] [ 0 ] * f1ness + t2 - > ang [ 1 ] [ 0 ] * f2ness ;
result [ 5 ] = t1 - > ang [ 1 ] [ 1 ] * f1ness + t2 - > ang [ 1 ] [ 1 ] * f2ness ;
result [ 6 ] = t1 - > ang [ 1 ] [ 2 ] * f1ness + t2 - > ang [ 1 ] [ 2 ] * f2ness ;
result [ 7 ] = t1 - > org [ 1 ] * f1ness + t2 - > org [ 1 ] * f2ness ;
result [ 8 ] = t1 - > ang [ 2 ] [ 0 ] * f1ness + t2 - > ang [ 2 ] [ 0 ] * f2ness ;
result [ 9 ] = t1 - > ang [ 2 ] [ 1 ] * f1ness + t2 - > ang [ 2 ] [ 1 ] * f2ness ;
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 ;
}
int Mod_TagNumForName ( model_t * model , char * name )
{
int i ;
galiasinfo_t * inf ;
md3tag_t * t ;
if ( ! model | | model - > type ! = mod_alias )
return 0 ;
inf = Mod_Extradata ( model ) ;
# 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
t = ( md3tag_t * ) ( ( char * ) inf + inf - > ofstags ) ;
for ( i = 0 ; i < inf - > numtags ; i + + )
{
if ( ! strcmp ( t [ i ] . name , name ) )
return i + 1 ;
}
return 0 ;
}
# ifndef SERVERONLY
int Mod_SkinNumForName ( model_t * model , char * name )
{
int i ;
galiasinfo_t * inf ;
galiasskin_t * skin ;
if ( ! model | | model - > type ! = mod_alias )
return - 1 ;
inf = Mod_Extradata ( model ) ;
skin = ( galiasskin_t * ) ( ( char * ) inf + inf - > ofsskins ) ;
for ( i = 0 ; i < inf - > numskins ; i + + , skin + + )
{
if ( ! strcmp ( skin - > name , name ) )
return i ;
}
return - 1 ;
}
# endif
# 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 ;
int numTags ;
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 {
int ident ; //
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'
qboolean Mod_LoadQ3Model ( model_t * mod , void * buffer )
{
# 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
int hunkstart , hunkend , hunktotal ;
// int version;
int s , i , j , d ;
index_t * indexes ;
vec3_t min ;
vec3_t max ;
galiaspose_t * pose ;
galiasinfo_t * parent , * root ;
galiasgroup_t * group ;
vec3_t * verts ;
md3Triangle_t * intris ;
md3XyzNormal_t * invert ;
int size ;
int externalskins ;
md3Header_t * header ;
md3Surface_t * surf ;
loadmodel = mod ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
header = buffer ;
// if (header->version != sdfs)
// Sys_Error("GL_LoadQ3Model: Bad version\n");
parent = NULL ;
root = NULL ;
# ifndef SERVERONLY
externalskins = Mod_BuildSkinFileList ( mod - > name ) ;
# else
externalskins = 0 ;
# endif
min [ 0 ] = min [ 1 ] = min [ 2 ] = 0 ;
max [ 0 ] = max [ 1 ] = max [ 2 ] = 0 ;
surf = ( md3Surface_t * ) ( ( qbyte * ) header + LittleLong ( header - > ofsSurfaces ) ) ;
for ( s = 0 ; s < LittleLong ( header - > numSurfaces ) ; s + + )
{
if ( LittleLong ( surf - > ident ) ! = MD3_IDENT )
Con_Printf ( CON_WARNING " Warning: md3 sub-surface doesn't match ident \n " ) ;
size = sizeof ( galiasinfo_t ) + sizeof ( galiasgroup_t ) * LittleLong ( header - > numFrames ) ;
galias = Hunk_Alloc ( size ) ;
galias - > groupofs = sizeof ( * galias ) ; //frame groups
galias - > groups = LittleLong ( header - > numFrames ) ;
galias - > numverts = LittleLong ( surf - > numVerts ) ;
galias - > numindexes = LittleLong ( surf - > numTriangles ) * 3 ;
if ( parent )
parent - > nextsurf = ( qbyte * ) galias - ( qbyte * ) parent ;
else
root = galias ;
parent = galias ;
# ifndef SERVERONLY
st_array = Hunk_Alloc ( sizeof ( vec2_t ) * galias - > numindexes ) ;
galias - > ofs_st_array = ( qbyte * ) st_array - ( qbyte * ) galias ;
inst = ( md3St_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsSt ) ) ;
for ( i = 0 ; i < galias - > numverts ; i + + )
{
st_array [ i ] [ 0 ] = LittleFloat ( inst [ i ] . s ) ;
st_array [ i ] [ 1 ] = LittleFloat ( inst [ i ] . t ) ;
}
# endif
indexes = Hunk_Alloc ( sizeof ( * indexes ) * galias - > numindexes ) ;
galias - > ofs_indexes = ( qbyte * ) indexes - ( qbyte * ) galias ;
intris = ( md3Triangle_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsTriangles ) ) ;
for ( i = 0 ; i < LittleLong ( surf - > numTriangles ) ; i + + )
{
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 ] ) ;
}
group = ( galiasgroup_t * ) ( galias + 1 ) ;
invert = ( md3XyzNormal_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsXyzNormals ) ) ;
for ( i = 0 ; i < LittleLong ( surf - > numFrames ) ; i + + )
{
pose = ( galiaspose_t * ) Hunk_Alloc ( sizeof ( galiaspose_t ) + sizeof ( vec3_t ) * LittleLong ( surf - > numVerts )
# ifndef SERVERONLY
+ sizeof ( vec3_t ) * LittleLong ( surf - > numVerts )
# endif
) ;
verts = ( vec3_t * ) ( pose + 1 ) ;
pose - > ofsverts = ( qbyte * ) verts - ( qbyte * ) pose ;
# ifndef SERVERONLY
normals = verts + LittleLong ( surf - > numVerts ) ;
pose - > ofsnormals = ( qbyte * ) normals - ( qbyte * ) pose ;
# endif
for ( j = 0 ; j < LittleLong ( surf - > numVerts ) ; j + + )
{
# ifndef SERVERONLY
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 ) ;
# endif
for ( d = 0 ; d < 3 ; d + + )
{
verts [ j ] [ d ] = LittleShort ( invert [ j ] . xyz [ d ] ) / 64.0f ;
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 ;
pose - > scale_origin [ 0 ] = 0 ;
pose - > scale_origin [ 1 ] = 0 ;
pose - > scale_origin [ 2 ] = 0 ;
snprintf ( group - > name , sizeof ( group - > name ) - 1 , " frame%i " , i ) ;
group - > numposes = 1 ;
group - > rate = 1 ;
group - > poseofs = ( qbyte * ) pose - ( qbyte * ) group ;
group + + ;
invert + = LittleLong ( surf - > numVerts ) ;
}
# ifndef SERVERONLY
if ( externalskins < LittleLong ( surf - > numShaders ) )
externalskins = LittleLong ( surf - > numShaders ) ;
if ( externalskins )
{
# ifndef Q3SHADERS
char name [ 1024 ] ;
extern int gl_bumpmappingpossible ;
# endif
char shadname [ 1024 ] ;
skin = Hunk_Alloc ( ( LittleLong ( surf - > numShaders ) + externalskins ) * ( ( sizeof ( galiasskin_t ) + sizeof ( galiastexnum_t ) ) ) ) ;
galias - > ofsskins = ( qbyte * ) skin - ( qbyte * ) galias ;
texnum = ( galiastexnum_t * ) ( skin + LittleLong ( surf - > numShaders ) + externalskins ) ;
inshader = ( md3Shader_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsShaders ) ) ;
for ( i = 0 ; i < externalskins ; i + + )
{
skin - > texnums = 1 ;
skin - > ofstexnums = ( qbyte * ) texnum - ( qbyte * ) skin ;
skin - > ofstexels = 0 ;
skin - > skinwidth = 0 ;
skin - > skinheight = 0 ;
skin - > skinspeed = 0 ;
shadname [ 0 ] = ' \0 ' ;
Mod_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 ) ;
Q_strncpyz ( skin - > name , shadname , sizeof ( skin - > name ) ) ;
}
# ifdef Q3SHADERS
if ( qrenderer )
{
texnum - > shader = R_RegisterSkin ( shadname ) ;
if ( r_shadows . value ) //real-time shadows requires a texture to lighten the model with, even if it has a shader.
//fixme: this should be read from the shader.
texnum - > base = Mod_LoadHiResTexture ( shadname , " models " , true , true , true ) ;
}
# else
texnum - > base = Mod_LoadHiResTexture ( shadname , " models " , true , true , true ) ;
if ( ! texnum - > base )
{
strcpy ( name , loadmodel - > name ) ;
strcpy ( COM_SkipPath ( name ) , COM_SkipPath ( shadname ) ) ; //eviile eh?
texnum - > base = Mod_LoadHiResTexture ( name , " models " , true , true , true ) ;
}
texnum - > bump = 0 ;
if ( gl_bumpmappingpossible )
{
COM_StripExtension ( shadname , name , sizeof ( name ) ) ; //go for the normalmap
strcat ( name , " _norm " ) ;
texnum - > bump = Mod_LoadHiResTexture ( name , " models " , true , true , false ) ;
if ( ! texnum - > bump )
{
strcpy ( name , loadmodel - > name ) ;
COM_StripExtension ( COM_SkipPath ( shadname ) , COM_SkipPath ( name ) , sizeof ( name ) ) ;
strcat ( name , " _norm " ) ;
texnum - > bump = Mod_LoadHiResTexture ( name , " models " , true , true , false ) ;
if ( ! texnum - > bump )
{
COM_StripExtension ( shadname , name , sizeof ( name ) ) ; //bother, go for heightmap and convert
strcat ( name , " _bump " ) ;
texnum - > bump = Mod_LoadBumpmapTexture ( name , " models " ) ;
if ( ! texnum - > bump )
{
strcpy ( name , loadmodel - > name ) ;
strcpy ( COM_SkipPath ( name ) , COM_SkipPath ( shadname ) ) ; //eviile eh?
COM_StripExtension ( name , name , sizeof ( name ) ) ;
strcat ( name , " _bump " ) ;
texnum - > bump = Mod_LoadBumpmapTexture ( name , " models " ) ;
}
}
}
}
if ( r_fb_models . value )
{
COM_StripExtension ( shadname , name , sizeof ( name ) ) ; //go for the normalmap
strcat ( name , " _luma " ) ;
texnum - > fullbright = Mod_LoadHiResTexture ( name , " models " , true , true , true ) ;
if ( ! texnum - > base )
{
strcpy ( name , loadmodel - > name ) ;
strcpy ( COM_SkipPath ( name ) , COM_SkipPath ( shadname ) ) ; //eviile eh?
COM_StripExtension ( name , name , sizeof ( name ) ) ;
strcat ( name , " _luma " ) ;
texnum - > fullbright = Mod_LoadBumpmapTexture ( name , " models " ) ;
}
}
# endif
inshader + + ;
skin + + ;
texnum + + ;
}
galias - > numskins = i ;
}
# endif
VectorCopy ( min , loadmodel - > mins ) ;
VectorCopy ( max , loadmodel - > maxs ) ;
Mod_CompileTriangleNeighbours ( galias ) ;
surf = ( md3Surface_t * ) ( ( qbyte * ) surf + LittleLong ( surf - > ofsEnd ) ) ;
}
if ( ! root )
root = Hunk_Alloc ( sizeof ( galiasinfo_t ) ) ;
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 * ) ( ( char * ) header + LittleLong ( header - > ofsTags ) ) ;
dst = ( md3tag_t * ) ( ( char * ) 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 + + ;
}
}
//
// move the complete, relocatable alias model to the cache
//
hunkend = Hunk_LowMark ( ) ;
# ifndef SERVERONLY
if ( mod_md3flags . value )
mod - > flags = LittleLong ( header - > flags ) ;
else
# endif
mod - > flags = 0 ;
if ( ! mod - > flags )
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ;
Mod_ClampModelSize ( mod ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
# endif
# ifdef ZYMOTICMODELS
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 ;
int numsurfaces ;
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)
zymlump_t lump_surfnames ; // char shadername[numsurfaces][32]; // shaders used on this model
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 ;
# define ZYMSCENEFLAG_NOLOOP 1
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.
qboolean Mod_LoadZymoticModel ( model_t * mod , void * buffer )
{
# ifndef SERVERONLY
galiasskin_t * skin ;
galiastexnum_t * texnum ;
int skinfiles ;
int j ;
# endif
int i ;
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 ;
vec2_t * stcoords ;
vec2_t * inst ;
int * vertbonecounts ;
galiasgroup_t * grp ;
zymscene_t * inscene ;
int * renderlist , count ;
index_t * indexes ;
char * surfname ;
loadmodel = mod ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
header = buffer ;
if ( memcmp ( header - > id , " ZYMOTICMODEL " , 12 ) )
{
Con_Printf ( " Mod_LoadZymoticModel: %s, doesn't appear to BE a zymotic! \n " , mod - > name ) ;
return false ;
}
if ( BigLong ( header - > type ) ! = 1 )
{
Con_Printf ( " Mod_LoadZymoticModel: %s, only type 1 is supported \n " , mod - > name ) ;
return false ;
}
for ( i = 0 ; i < sizeof ( zymtype1header_t ) / 4 ; i + + )
( ( int * ) header ) [ i ] = BigLong ( ( ( int * ) header ) [ i ] ) ;
if ( ! header - > numverts )
{
Con_Printf ( " Mod_LoadZymoticModel: %s, no vertexes \n " , mod - > name ) ;
return false ;
}
if ( ! header - > numsurfaces )
{
Con_Printf ( " Mod_LoadZymoticModel: %s, no surfaces \n " , mod - > name ) ;
return false ;
}
VectorCopy ( header - > mins , mod - > mins ) ;
VectorCopy ( header - > maxs , mod - > maxs ) ;
root = Hunk_AllocName ( sizeof ( galiasinfo_t ) * header - > numsurfaces , loadname ) ;
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 )
{
Con_Printf ( " Mod_LoadZymoticModel: %s, too many transformations \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
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 ) )
{
Con_Printf ( CON_ERROR " %s, Vertex transforms list appears corrupt. \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
if ( vertbonecounts ! = ( int * ) ( ( char * ) header + header - > lump_vertbonecounts . start ) )
{
Con_Printf ( CON_ERROR " %s, Vertex bone counts list appears corrupt. \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
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 + + )
{
Q_strncpyz ( bone [ i ] . name , inbone [ i ] . name , sizeof ( bone [ i ] . name ) ) ;
bone [ i ] . parent = BigLong ( inbone [ i ] . parent ) ;
}
root - > ofsbones = ( char * ) bone - ( char * ) root ;
renderlist = ( int * ) ( ( char * ) header + header - > lump_render . start ) ;
for ( i = 0 ; i < header - > numsurfaces ; i + + )
{
count = BigLong ( * renderlist + + ) ;
count * = 3 ;
indexes = Hunk_Alloc ( count * sizeof ( * indexes ) ) ;
root [ i ] . ofs_indexes = ( char * ) indexes - ( char * ) & root [ i ] ;
root [ i ] . numindexes = count ;
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 ;
}
renderlist + = root [ i ] . numindexes ;
}
if ( renderlist ! = ( int * ) ( ( char * ) header + header - > lump_render . start + header - > lump_render . length ) )
{
Con_Printf ( CON_ERROR " %s, render list appears corrupt. \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
grp = Hunk_Alloc ( sizeof ( * grp ) * header - > numscenes * header - > numsurfaces ) ;
matrix = Hunk_Alloc ( header - > lump_poses . length ) ;
inmatrix = ( float * ) ( ( char * ) header + header - > lump_poses . start ) ;
for ( i = 0 ; i < header - > lump_poses . length / 4 ; i + + )
matrix [ i ] = BigFloat ( inmatrix [ i ] ) ;
inscene = ( zymscene_t * ) ( ( char * ) header + header - > lump_scenes . start ) ;
surfname = ( ( char * ) header + header - > lump_surfnames . start ) ;
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?
}
# ifndef SERVERONLY
skinfiles = Mod_BuildSkinFileList ( loadmodel - > name ) ;
if ( skinfiles < 1 )
skinfiles = 1 ;
# endif
for ( i = 0 ; i < header - > numsurfaces ; i + + , surfname + = 32 )
{
root [ i ] . groups = header - > numscenes ;
root [ i ] . groupofs = ( char * ) grp - ( char * ) & root [ i ] ;
# ifdef SERVERONLY
root [ i ] . numskins = 1 ;
# else
root [ i ] . ofs_st_array = ( char * ) stcoords - ( char * ) & root [ i ] ;
root [ i ] . 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 ] ;
Mod_LoadSkinFile ( texnum , surfname , j , NULL , 0 , 0 , NULL ) ;
}
root [ i ] . ofsskins = ( char * ) skin - ( char * ) & root [ i ] ;
# endif
}
for ( i = 0 ; i < header - > numscenes ; i + + , grp + + , inscene + + )
{
Q_strncpyz ( grp - > name , inscene - > name , sizeof ( grp - > name ) ) ;
grp - > isheirachical = 1 ;
grp - > rate = BigFloat ( inscene - > framerate ) ;
grp - > loop = ! ( BigLong ( inscene - > flags ) & ZYMSCENEFLAG_NOLOOP ) ;
grp - > numposes = BigLong ( inscene - > length ) ;
grp - > poseofs = ( char * ) matrix - ( char * ) grp ;
grp - > poseofs + = BigLong ( inscene - > start ) * 12 * sizeof ( float ) * root - > numbones ;
}
if ( inscene ! = ( zymscene_t * ) ( ( char * ) header + header - > lump_scenes . start + header - > lump_scenes . length ) )
{
Con_Printf ( CON_ERROR " %s, scene list appears corrupt. \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
for ( i = 0 ; i < header - > numsurfaces - 1 ; i + + )
root [ i ] . nextsurf = sizeof ( galiasinfo_t ) ;
for ( i = 1 ; i < header - > numsurfaces ; i + + )
{
root [ i ] . sharesverts = true ;
root [ i ] . numbones = root [ 0 ] . numbones ;
root [ i ] . numverts = root [ 0 ] . numverts ;
root [ i ] . ofsbones = root [ 0 ] . ofsbones ;
root [ i - 1 ] . nextsurf = sizeof ( * root ) ;
}
//
// 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.
Mod_ClampModelSize ( mod ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
//////////////////////////////////////////////////////////////
//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
typedef struct dpmvertex_s
{
unsigned int numbones ;
// immediately followed by 1 or more dpmbonevert_t structures
} dpmvertex_t ;
qboolean Mod_LoadDarkPlacesModel ( model_t * mod , void * buffer )
{
# ifndef SERVERONLY
galiasskin_t * skin ;
galiastexnum_t * texnum ;
int skinfiles ;
float * inst ;
float * outst ;
# 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 ) )
{
Con_Printf ( CON_ERROR " Mod_LoadDarkPlacesModel: %s, doesn't appear to be a darkplaces model! \n " , mod - > name ) ;
return false ;
}
if ( BigLong ( header - > type ) ! = 2 )
{
Con_Printf ( CON_ERROR " Mod_LoadDarkPlacesModel: %s, only type 2 is supported \n " , mod - > name ) ;
return false ;
}
for ( i = 0 ; i < sizeof ( dpmheader_t ) / 4 ; i + + )
( ( int * ) header ) [ i ] = BigLong ( ( ( int * ) header ) [ i ] ) ;
if ( ! header - > num_bones )
{
Con_Printf ( CON_ERROR " Mod_LoadDarkPlacesModel: %s, no bones \n " , mod - > name ) ;
return false ;
}
if ( ! header - > num_frames )
{
Con_Printf ( CON_ERROR " Mod_LoadDarkPlacesModel: %s, no frames \n " , mod - > name ) ;
return false ;
}
if ( ! header - > num_meshs )
{
Con_Printf ( CON_ERROR " Mod_LoadDarkPlacesModel: %s, no surfaces \n " , mod - > name ) ;
return false ;
}
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 ] ) ;
}
transforms = ( galisskeletaltransforms_t * ) outst ;
# 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 = ( unsigned int * ) ( ( 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 )
{
Con_Printf ( CON_ERROR " Mod_LoadDarkPlacesModel: bad bone index in %s \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
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 ] ) ;
Q_strncpyz ( outgroups [ i ] . name , inframes [ i ] . name , sizeof ( outgroups [ i ] . name ) ) ;
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 = Mod_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 ] ;
Mod_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.
Mod_ClampModelSize ( mod ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
# 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
qw = - ( float ) sqrt ( term ) ;
}
{ //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 * Mod_ParseMD5MeshModel ( char * buffer )
{
# define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return NULL; }
# define MD5ERROR1PARAM(x, y) { Con_Printf(CON_ERROR x "\n", y); return NULL; }
# 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 ;
galiasbone_t * bones = NULL ;
galiasgroup_t * pose = NULL ;
galiasinfo_t * inf , * root , * lastsurf ;
float * posedata ;
# ifndef SERVERONLY
galiasskin_t * skin ;
galiastexnum_t * texnum ;
# endif
float x , y , z , qx , qy , qz ;
buffer = COM_Parse ( buffer ) ;
if ( strcmp ( com_token , " MD5Version " ) )
MD5ERROR0PARAM ( " MD5 model without MD5Version identifier first " ) ;
buffer = COM_Parse ( buffer ) ;
if ( atoi ( com_token ) ! = 10 )
MD5ERROR0PARAM ( " MD5 model with unsupported MD5Version " ) ;
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 )
MD5ERROR0PARAM ( " MD5MESH: numMeshes was already declared " ) ;
buffer = COM_Parse ( buffer ) ;
numjoints = atoi ( com_token ) ;
if ( numjoints < = 0 )
MD5ERROR0PARAM ( " MD5MESH: Needs some joints " ) ;
}
else if ( ! strcmp ( com_token , " numMeshes " ) )
{
if ( nummeshes )
MD5ERROR0PARAM ( " MD5MESH: numMeshes was already declared " ) ;
buffer = COM_Parse ( buffer ) ;
nummeshes = atoi ( com_token ) ;
if ( nummeshes < = 0 )
MD5ERROR0PARAM ( " MD5MESH: Needs some meshes " ) ;
}
else if ( ! strcmp ( com_token , " joints " ) )
{
if ( foundjoints )
MD5ERROR0PARAM ( " MD5MESH: Duplicate joints section " ) ;
foundjoints = true ;
if ( ! numjoints )
MD5ERROR0PARAM ( " MD5MESH: joints section before (or without) numjoints " ) ;
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 ;
Q_strncpyz ( pose - > name , " base " , sizeof ( pose - > name ) ) ;
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
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 )
MD5ERROR0PARAM ( " MD5MESH: joints parent's must be lower " ) ;
if ( ( bones [ i ] . parent < 0 & & i ) | | ( ! i & & bones [ i ] . parent ! = - 1 ) )
MD5ERROR0PARAM ( " MD5MESH: Only the root joint may have a negative parent " ) ;
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 ;
# ifndef SERVERONLY
float * stcoord = NULL ;
# endif
int * indexes = NULL ;
float w ;
vec4_t * rawweight = NULL ;
int * rawweightbone = NULL ;
if ( ! nummeshes )
MD5ERROR0PARAM ( " MD5MESH: mesh section before (or without) nummeshes " ) ;
if ( ! foundjoints | | ! bones | | ! pose )
MD5ERROR0PARAM ( " MD5MESH: mesh must come after joints " ) ;
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 ;
# ifndef SERVERONLY
skin = Hunk_Alloc ( sizeof ( * skin ) ) ;
texnum = Hunk_Alloc ( sizeof ( * texnum ) ) ;
inf - > numskins = 1 ;
inf - > ofsskins = ( char * ) skin - ( char * ) inf ;
skin - > texnums = 1 ;
skin - > skinspeed = 1 ;
skin - > ofstexnums = ( char * ) texnum - ( char * ) skin ;
# endif
EXPECT ( " { " ) ;
for ( ; ; )
{
buffer = COM_Parse ( buffer ) ;
if ( ! buffer )
MD5ERROR0PARAM ( " MD5MESH: unexpected eof " ) ;
if ( ! strcmp ( com_token , " shader " ) )
{
buffer = COM_Parse ( buffer ) ;
# ifndef SERVERONLY
// texnum->shader = R_RegisterSkin(com_token);
texnum - > base = Mod_LoadHiResTexture ( com_token , " models " , true , true , true ) ;
# endif
}
else if ( ! strcmp ( com_token , " numverts " ) )
{
if ( numverts )
MD5ERROR0PARAM ( " MD5MESH: numverts was already specified " ) ;
buffer = COM_Parse ( buffer ) ;
numverts = atoi ( com_token ) ;
if ( numverts < 0 )
MD5ERROR0PARAM ( " MD5MESH: numverts cannot be negative " ) ;
firstweightlist = Z_Malloc ( sizeof ( * firstweightlist ) * numverts ) ;
numweightslist = Z_Malloc ( sizeof ( * numweightslist ) * numverts ) ;
# ifndef SERVERONLY
stcoord = Hunk_Alloc ( sizeof ( float ) * 2 * numverts ) ;
inf - > ofs_st_array = ( char * ) stcoord - ( char * ) inf ;
inf - > numverts = numverts ;
# endif
}
else if ( ! strcmp ( com_token , " vert " ) )
{ //vert num ( s t ) firstweight numweights
buffer = COM_Parse ( buffer ) ;
num = atoi ( com_token ) ;
if ( num < 0 | | num > = numverts | | ! indexes )
MD5ERROR0PARAM ( " MD5MESH: vertex out of range " ) ;
EXPECT ( " ( " ) ;
buffer = COM_Parse ( buffer ) ;
# ifndef SERVERONLY
if ( ! stcoord )
MD5ERROR0PARAM ( " MD5MESH: vertex out of range " ) ;
stcoord [ num * 2 + 0 ] = atof ( com_token ) ;
# endif
buffer = COM_Parse ( buffer ) ;
# ifndef SERVERONLY
stcoord [ num * 2 + 1 ] = atof ( com_token ) ;
# endif
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 )
MD5ERROR0PARAM ( " MD5MESH: numtris was already specified " ) ;
buffer = COM_Parse ( buffer ) ;
numtris = atoi ( com_token ) ;
if ( numtris < 0 )
MD5ERROR0PARAM ( " MD5MESH: numverts cannot be negative " ) ;
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 )
MD5ERROR0PARAM ( " MD5MESH: vertex out of range " ) ;
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 )
MD5ERROR0PARAM ( " MD5MESH: numweights was already specified " ) ;
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 )
MD5ERROR0PARAM ( " MD5MESH: weight out of range " ) ;
buffer = COM_Parse ( buffer ) ;
rawweightbone [ num ] = atoi ( com_token ) ;
if ( rawweightbone [ num ] < 0 | | rawweightbone [ num ] > = numjoints )
MD5ERROR0PARAM ( " MD5MESH: weight specifies bad bone " ) ;
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
MD5ERROR1PARAM ( " MD5MESH: Unrecognised token inside mesh (%s) " , com_token ) ;
}
trans = Hunk_Alloc ( sizeof ( * trans ) * numusableweights ) ;
inf - > ofstransforms = ( char * ) trans - ( char * ) inf ;
for ( num = 0 , vnum = 0 ; num < numverts ; num + + )
{
if ( numweightslist [ num ] < = 0 )
MD5ERROR0PARAM ( " MD5MESH: weights not set on vertex " ) ;
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
MD5ERROR1PARAM ( " Unrecognised token in MD5 model (%s) " , com_token ) ;
}
if ( ! lastsurf )
MD5ERROR0PARAM ( " MD5MESH: No meshes " ) ;
return root ;
# undef MD5ERROR0PARAM
# undef MD5ERROR1PARAM
# undef EXPECT
}
qboolean Mod_LoadMD5MeshModel ( model_t * mod , void * buffer )
{
galiasinfo_t * root ;
int hunkstart , hunkend , hunktotal ;
loadmodel = mod ;
Mod_DoCRC ( mod , buffer , com_filesize ) ;
hunkstart = Hunk_LowMark ( ) ;
root = Mod_ParseMD5MeshModel ( buffer ) ;
if ( root = = NULL )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
hunkend = Hunk_LowMark ( ) ;
mod - > flags = Mod_ReadFlagsFromMD1 ( mod - > name , 0 ) ; //file replacement - inherit flags from any defunc mdl files.
Mod_ClampModelSize ( mod ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
qboolean Mod_ParseMD5Anim ( char * buffer , galiasinfo_t * prototype , void * * poseofs , galiasgroup_t * gat )
{
# define MD5ERROR0PARAM(x) { Con_Printf(CON_ERROR x "\n"); return false; }
# define MD5ERROR1PARAM(x, y) { Con_Printf(CON_ERROR x "\n", y); return false; }
# define EXPECT(x) buffer = COM_Parse(buffer); if (strcmp(com_token, x)) MD5ERROR1PARAM("MD5ANIM: expected %s", x);
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 ;
2007-10-29 06:06:20 +00:00
unsigned int * firstanimatedcomponents ;
2007-10-05 18:08:47 +00:00
2007-10-29 06:06:20 +00:00
float * animatedcomponents ;
float * baseframe ; //6 components.
2007-10-05 18:08:47 +00:00
float * posedata ;
float tx , ty , tz , qx , qy , qz ;
int fac , flags ;
float f ;
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 ) ;
2007-10-29 06:06:20 +00:00
firstanimatedcomponents = BZ_Malloc ( sizeof ( int ) * numjoints ) ;
animatedcomponents = BZ_Malloc ( sizeof ( float ) * numanimatedparts ) ;
2007-10-05 18:08:47 +00:00
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 )
MD5ERROR0PARAM ( " MD5ANIM: number of bones doesn't match " ) ;
bonelist = ( galiasbone_t * ) ( ( char * ) prototype + prototype - > ofsbones ) ;
}
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 ) )
MD5ERROR1PARAM ( " MD5ANIM: bone name doesn't match (%s) " , com_token ) ;
}
else
Q_strncpyz ( bonelist - > name , com_token , sizeof ( bonelist - > name ) ) ;
buffer = COM_Parse ( buffer ) ;
parent = atoi ( com_token ) ;
if ( prototype )
{
if ( bonelist - > parent ! = parent )
MD5ERROR1PARAM ( " MD5ANIM: bone name doesn't match (%s) " , com_token ) ;
}
else
bonelist - > parent = parent ;
buffer = COM_Parse ( buffer ) ;
boneflags [ i ] = atoi ( com_token ) ;
buffer = COM_Parse ( buffer ) ;
2007-10-29 06:06:20 +00:00
firstanimatedcomponents [ i ] = atoi ( com_token ) ;
2007-10-05 18:08:47 +00:00
}
EXPECT ( " } " ) ;
EXPECT ( " bounds " ) ;
EXPECT ( " { " ) ;
for ( i = 0 ; i < numframes ; i + + )
{
EXPECT ( " ( " ) ;
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 ;
EXPECT ( " ) " ) ;
EXPECT ( " ( " ) ;
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 ;
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 ) ;
2007-10-29 06:06:20 +00:00
animatedcomponents [ j ] = atof ( com_token ) ;
2007-10-05 18:08:47 +00:00
}
EXPECT ( " } " ) ;
for ( j = 0 ; j < numjoints ; j + + )
{
2007-10-29 06:06:20 +00:00
fac = firstanimatedcomponents [ j ] ;
2007-10-05 18:08:47 +00:00
flags = boneflags [ j ] ;
if ( flags & 1 )
2007-10-29 06:06:20 +00:00
tx = animatedcomponents [ fac + + ] ;
2007-10-05 18:08:47 +00:00
else
tx = baseframe [ j * 6 + 0 ] ;
if ( flags & 2 )
2007-10-29 06:06:20 +00:00
ty = animatedcomponents [ fac + + ] ;
2007-10-05 18:08:47 +00:00
else
ty = baseframe [ j * 6 + 1 ] ;
if ( flags & 4 )
2007-10-29 06:06:20 +00:00
tz = animatedcomponents [ fac + + ] ;
2007-10-05 18:08:47 +00:00
else
tz = baseframe [ j * 6 + 2 ] ;
if ( flags & 8 )
2007-10-29 06:06:20 +00:00
qx = animatedcomponents [ fac + + ] ;
2007-10-05 18:08:47 +00:00
else
qx = baseframe [ j * 6 + 3 ] ;
if ( flags & 16 )
2007-10-29 06:06:20 +00:00
qy = animatedcomponents [ fac + + ] ;
2007-10-05 18:08:47 +00:00
else
qy = baseframe [ j * 6 + 4 ] ;
if ( flags & 32 )
2007-10-29 06:06:20 +00:00
qz = animatedcomponents [ fac + + ] ;
2007-10-05 18:08:47 +00:00
else
qz = baseframe [ j * 6 + 5 ] ;
GenMatrix ( tx , ty , tz , qx , qy , qz , posedata + 12 * ( j + numjoints * i ) ) ;
}
}
2007-10-29 06:06:20 +00:00
BZ_Free ( firstanimatedcomponents ) ;
BZ_Free ( animatedcomponents ) ;
2007-10-05 18:08:47 +00:00
BZ_Free ( boneflags ) ;
BZ_Free ( baseframe ) ;
Q_strncpyz ( grp . name , " " , sizeof ( grp . name ) ) ;
grp . isheirachical = true ;
grp . numposes = numframes ;
grp . rate = framespersecond ;
grp . loop = true ;
* gat = grp ;
return true ;
# undef MD5ERROR0PARAM
# undef MD5ERROR1PARAM
# 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
*/
qboolean Mod_LoadCompositeAnim ( model_t * mod , void * buffer )
{
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 " ) )
{
Con_Printf ( CON_ERROR " EXTERNALANIM: header is not compleate (%s) \n " , mod - > name ) ;
return false ;
}
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..
{
Con_Printf ( CON_ERROR " Couldn't open %s (from %s) \n " , com_token , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
root = Mod_ParseMD5MeshModel ( file ) ;
if ( root = = NULL )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
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
{
Con_Printf ( CON_ERROR " EXTERNALANIM: model must be defined immediatly after the header \n " ) ;
return false ;
}
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..
{
char namebkup [ MAX_QPATH ] ;
Q_strncpyz ( namebkup , com_token , sizeof ( namebkup ) ) ;
if ( ! Mod_ParseMD5Anim ( file , root , & poseofs [ numgroups ] , & grouplist [ numgroups ] ) )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
Q_strncpyz ( grouplist [ numgroups ] . name , namebkup , sizeof ( grouplist [ numgroups ] . name ) ) ;
numgroups + + ;
}
}
else if ( ! strcmp ( com_token , " clampgroup " ) )
{
Con_Printf ( CON_ERROR " EXTERNALANIM: clampgroup not yet supported (%s) \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
else if ( ! strcmp ( com_token , " frames " ) )
{
Con_Printf ( CON_ERROR " EXTERNALANIM: frames not yet supported (%s) \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
else
{
Con_Printf ( CON_ERROR " EXTERNALANIM: unrecognised token (%s) \n " , mod - > name ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
}
newgroup = grouplist ;
grouplist = Hunk_Alloc ( sizeof ( galiasgroup_t ) * numgroups ) ;
for ( ; ; )
{
root - > groupofs = ( char * ) grouplist - ( char * ) root ;
root - > groups = numgroups ;
if ( ! root - > nextsurf )
break ;
root = ( galiasinfo_t * ) ( ( char * ) root + root - > nextsurf ) ;
}
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.
Mod_ClampModelSize ( mod ) ;
Hunk_Alloc ( 0 ) ;
hunktotal = hunkend - hunkstart ;
Cache_Alloc ( & mod - > cache , hunktotal , loadname ) ;
mod - > type = mod_alias ;
if ( ! mod - > cache . data )
{
Hunk_FreeToLowMark ( hunkstart ) ;
return false ;
}
memcpy ( mod - > cache . data , root , hunktotal ) ;
Hunk_FreeToLowMark ( hunkstart ) ;
mod - > funcs . Trace = Mod_Trace ;
return true ;
}
# endif //MD5MODELS
# else
int Mod_TagNumForName ( model_t * model , char * name )
{
return 0 ;
}
qboolean Mod_GetTag ( model_t * model , int tagnum , int frame1 , int frame2 , float f2ness , float f1time , float f2time , float * result )
{
return false ;
}
# endif //#if defined(D3DQUAKE) || defined(RGLQUAKE)