2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 //=================================================================
27 static void OrderSurfaces( void );
28 static void LoadBase( const char *filename );
29 static int LoadModelFile( const char *filename, polyset_t **ppsets, int *pnumpolysets );
31 #define MAX_SURFACE_TRIS (SHADER_MAX_INDEXES / 3)
32 #define MAX_SURFACE_VERTS SHADER_MAX_VERTEXES
34 #define MD3_TYPE_UNKNOWN 0
35 #define MD3_TYPE_BASE3DS 1
36 #define MD3_TYPE_SPRITE 2
37 #define MD3_TYPE_ASE 3
39 #define MAX_ANIM_FRAMES 512
40 #define MAX_ANIM_SURFACES 32
50 polyset_t *surfaces[MAX_ANIM_SURFACES];
52 } ObjectAnimationFrame_t;
66 //================================================================
71 md3Shader_t shaders[MD3_MAX_SHADERS];
72 // all verts (xyz_normal)
73 float *verts[MD3_MAX_FRAMES];
75 baseTriangle_t baseTriangles[MD3_MAX_TRIANGLES];
77 // the triangles will be sorted so that they form long generalized tristrips
78 int orderedTriangles[MD3_MAX_TRIANGLES][3];
79 int lodTriangles[MD3_MAX_TRIANGLES][3];
80 baseVertex_t baseVertexes[MD3_MAX_VERTS];
86 int skinwidth, skinheight;
88 md3SurfaceData_t surfData[MD3_MAX_SURFACES];
90 md3Tag_t tags[MD3_MAX_FRAMES][MD3_MAX_TAGS];
91 md3Frame_t frames[MD3_MAX_FRAMES];
94 float scale_up; // set by $scale
95 vec3_t adjust; // set by $origin
97 int fixedwidth, fixedheight; // set by $skinsize
101 int lowerSkipFrameStart, lowerSkipFrameEnd;
107 int type; // MD3_TYPE_BASE, MD3_TYPE_OLDBASE, MD3_TYPE_ASE, or MD3_TYPE_SPRITE
113 // the command list holds counts, the count * 3 xyz, st, normal indexes
114 // that are valid for every frame
116 char g_modelname[1024];
118 //==============================================================
125 void ClearModel (void)
129 g_data.type = MD3_TYPE_UNKNOWN;
131 for ( i = 0; i < MD3_MAX_SURFACES; i++ )
133 memset( &g_data.surfData[i].header, 0, sizeof( g_data.surfData[i].header ) );
134 memset( &g_data.surfData[i].shaders, 0, sizeof( g_data.surfData[i].shaders ) );
135 memset( &g_data.surfData[i].verts, 0, sizeof( g_data.surfData[i].verts ) );
138 memset( g_data.tags, 0, sizeof( g_data.tags ) );
140 for ( i = 0; i < g_data.model.numSurfaces; i++ )
144 for ( j = 0; j < g_data.surfData[i].header.numShaders; j++ )
146 memset( &g_data.surfData[i].shaders[j], 0, sizeof( g_data.surfData[i].shaders[j] ) );
149 memset (&g_data.model, 0, sizeof(g_data.model));
150 memset (g_cddir, 0, sizeof(g_cddir));
153 g_data.scale_up = 1.0;
154 memset( &g_data.model, 0, sizeof( g_data.model ) );
155 VectorCopy (vec3_origin, g_data.adjust);
156 g_data.fixedwidth = g_data.fixedheight = 0;
157 g_skipmodel = qfalse;
161 ** void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData )
163 ** This routine assumes that the file position has been adjusted
164 ** properly prior to entry to point at the beginning of the surface.
166 ** Since surface header information is completely relative, we can't
167 ** just randomly seek to an arbitrary surface location right now. Is
168 ** this something we should add?
170 void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData )
172 md3Surface_t *pSurf = &pSurfData->header;
173 md3Shader_t *pShader = pSurfData->shaders;
174 baseVertex_t *pBaseVertex = pSurfData->baseVertexes;
175 float **verts = pSurfData->verts;
177 short xyznormals[MD3_MAX_VERTS][4];
179 float base_st[MD3_MAX_VERTS][2];
180 md3Surface_t surftemp;
184 if ( strstr( pSurf->name, "tag_" ) == pSurf->name )
188 // write out the header
191 surftemp.ident = LittleLong( MD3_IDENT );
192 surftemp.flags = LittleLong( pSurf->flags );
193 surftemp.numFrames = LittleLong( pSurf->numFrames );
194 surftemp.numShaders = LittleLong( pSurf->numShaders );
196 surftemp.ofsShaders = LittleLong( pSurf->ofsShaders );
198 surftemp.ofsTriangles = LittleLong( pSurf->ofsTriangles );
199 surftemp.numTriangles = LittleLong( pSurf->numTriangles );
201 surftemp.ofsSt = LittleLong( pSurf->ofsSt );
202 surftemp.ofsXyzNormals = LittleLong( pSurf->ofsXyzNormals );
203 surftemp.ofsEnd = LittleLong( pSurf->ofsEnd );
205 SafeWrite( modelouthandle, &surftemp, sizeof( surftemp ) );
209 printf( "surface '%s'\n", pSurf->name );
210 printf( "...num shaders: %d\n", pSurf->numShaders );
216 for ( i = 0; i < pSurf->numShaders; i++ )
218 md3Shader_t shadertemp;
221 printf( "......'%s'\n", pShader[i].name );
223 shadertemp = pShader[i];
224 shadertemp.shaderIndex = LittleLong( shadertemp.shaderIndex );
225 SafeWrite( modelouthandle, &shadertemp, sizeof( shadertemp ) );
229 // write out the triangles
231 for ( i = 0 ; i < pSurf->numTriangles ; i++ )
233 for (j = 0 ; j < 3 ; j++)
235 int ivalue = LittleLong( pSurfData->orderedTriangles[i][j] );
236 pSurfData->orderedTriangles[i][j] = ivalue;
240 SafeWrite( modelouthandle, pSurfData->orderedTriangles, pSurf->numTriangles * sizeof( g_data.surfData[0].orderedTriangles[0] ) );
244 printf( "\n...num verts: %d\n", pSurf->numVerts );
245 printf( "...TEX COORDINATES\n" );
249 // write out the texture coordinates
251 for ( i = 0; i < pSurf->numVerts ; i++) {
252 base_st[i][0] = LittleFloat( pBaseVertex[i].st[0] );
253 base_st[i][1] = LittleFloat( pBaseVertex[i].st[1] );
255 printf( "......%d: %f,%f\n", i, base_st[i][0], base_st[i][1] );
257 SafeWrite( modelouthandle, base_st, pSurf->numVerts * sizeof(base_st[0]));
260 // write the xyz_normal
263 printf( "...XYZNORMALS\n" );
264 for ( f = 0; f < g_data.model.numFrames; f++ )
266 for (j=0 ; j< pSurf->numVerts; j++)
270 for (k=0 ; k < 3 ; k++)
272 value = ( short ) ( verts[f][j*6+k] / MD3_XYZ_SCALE );
273 xyznormals[j][k] = LittleShort( value );
275 NormalToLatLong( &verts[f][j*6+3], (byte *)&xyznormals[j][3] );
277 SafeWrite( modelouthandle, xyznormals, pSurf->numVerts * sizeof( short ) * 4 );
282 ** void WriteModelFile( FILE *modelouthandle )
285 ** header sizeof( md3Header_t )
286 ** frames sizeof( md3Frame_t ) * numFrames
287 ** tags sizeof( md3Tag_t ) * numFrames * numTags
288 ** surfaces surfaceSum
290 void WriteModelFile( FILE *modelouthandle )
294 md3Header_t modeltemp;
296 int numRealSurfaces = 0;
297 int numFrames = g_data.model.numFrames;
299 // compute offsets for all surfaces, sum their total size
300 for ( i = 0; i < g_data.model.numSurfaces; i++ )
302 if ( strstr( g_data.surfData[i].header.name, "tag_" ) != g_data.surfData[i].header.name )
304 md3Surface_t *psurf = &g_data.surfData[i].header;
306 if ( psurf->numTriangles == 0 || psurf->numVerts == 0 )
310 // the triangle and vertex split threshold is controlled by a parameter
311 // to $base, a la $base blah.3ds 1900, where "1900" determines the number
312 // of triangles to split on
314 else if ( psurf->numVerts > MAX_SURFACE_VERTS )
316 Error( "too many vertices\n" );
319 psurf->numFrames = numFrames;
321 psurf->ofsShaders = sizeof( md3Surface_t );
323 if ( psurf->numTriangles > MAX_SURFACE_TRIS )
325 Error( "too many faces\n" );
328 psurf->ofsTriangles = psurf->ofsShaders + psurf->numShaders * sizeof( md3Shader_t );
330 psurf->ofsSt = psurf->ofsTriangles + psurf->numTriangles * sizeof( md3Triangle_t );
331 psurf->ofsXyzNormals = psurf->ofsSt + psurf->numVerts * sizeof( md3St_t );
332 psurf->ofsEnd = psurf->ofsXyzNormals + psurf->numFrames * psurf->numVerts * ( sizeof( short ) * 4 );
334 surfaceSum += psurf->ofsEnd;
340 g_data.model.ident = MD3_IDENT;
341 g_data.model.version = MD3_VERSION;
343 g_data.model.ofsFrames = sizeof(md3Header_t);
344 g_data.model.ofsTags = g_data.model.ofsFrames + numFrames*sizeof(md3Frame_t);
345 g_data.model.ofsSurfaces = g_data.model.ofsTags + numFrames*g_data.model.numTags*sizeof(md3Tag_t);
346 g_data.model.ofsEnd = g_data.model.ofsSurfaces + surfaceSum;
349 // write out the model header
351 modeltemp = g_data.model;
352 modeltemp.ident = LittleLong( modeltemp.ident );
353 modeltemp.version = LittleLong( modeltemp.version );
354 modeltemp.numFrames = LittleLong( modeltemp.numFrames );
355 modeltemp.numTags = LittleLong( modeltemp.numTags );
356 modeltemp.numSurfaces = LittleLong( numRealSurfaces );
357 modeltemp.ofsFrames = LittleLong( modeltemp.ofsFrames );
358 modeltemp.ofsTags = LittleLong( modeltemp.ofsTags );
359 modeltemp.ofsSurfaces = LittleLong( modeltemp.ofsSurfaces );
360 modeltemp.ofsEnd = LittleLong( modeltemp.ofsEnd );
362 SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
365 // write out the frames
367 for (i=0 ; i < numFrames ; i++)
373 // compute localOrigin and radius
375 g_data.frames[i].localOrigin[0] =
376 g_data.frames[i].localOrigin[1] =
377 g_data.frames[i].localOrigin[2] = 0;
379 for ( j = 0; j < 8; j++ )
381 tmpVec[0] = g_data.frames[i].bounds[(j&1)!=0][0];
382 tmpVec[1] = g_data.frames[i].bounds[(j&2)!=0][1];
383 tmpVec[2] = g_data.frames[i].bounds[(j&4)!=0][2];
385 if ( VectorLength( tmpVec ) > maxRadius )
386 maxRadius = VectorLength( tmpVec );
389 g_data.frames[i].radius = LittleFloat( maxRadius );
392 for (j=0 ; j<3 ; j++) {
393 g_data.frames[i].bounds[0][j] = LittleFloat( g_data.frames[i].bounds[0][j] );
394 g_data.frames[i].bounds[1][j] = LittleFloat( g_data.frames[i].bounds[1][j] );
395 g_data.frames[i].localOrigin[j] = LittleFloat( g_data.frames[i].localOrigin[j] );
398 fseek (modelouthandle, g_data.model.ofsFrames, SEEK_SET);
399 SafeWrite( modelouthandle, g_data.frames, numFrames * sizeof(g_data.frames[0]) );
402 // write out the tags
404 fseek( modelouthandle, g_data.model.ofsTags, SEEK_SET );
405 for (f=0 ; f<g_data.model.numFrames; f++)
409 for ( t = 0; t < g_data.model.numTags; t++ )
411 g_data.tags[f][t].origin[0] = LittleFloat(g_data.tags[f][t].origin[0]);
412 g_data.tags[f][t].origin[1] = LittleFloat(g_data.tags[f][t].origin[1]);
413 g_data.tags[f][t].origin[2] = LittleFloat(g_data.tags[f][t].origin[2]);
415 for (j=0 ; j<3 ; j++)
417 g_data.tags[f][t].axis[0][j] = LittleFloat(g_data.tags[f][t].axis[0][j]);
418 g_data.tags[f][t].axis[1][j] = LittleFloat(g_data.tags[f][t].axis[1][j]);
419 g_data.tags[f][t].axis[2][j] = LittleFloat(g_data.tags[f][t].axis[2][j]);
422 SafeWrite( modelouthandle, g_data.tags[f], g_data.model.numTags * sizeof(md3Tag_t) );
426 // write out the surfaces
428 fseek( modelouthandle, g_data.model.ofsSurfaces, SEEK_SET );
429 for ( i = 0; i < g_data.model.numSurfaces; i++ )
431 WriteModelSurface( modelouthandle, &g_data.surfData[i] );
441 void FinishModel ( int type )
443 FILE *modelouthandle;
444 FILE *defaultSkinHandle;
448 if (!g_data.model.numFrames)
452 // build generalized triangle strips
456 if ( type == TYPE_PLAYER )
458 sprintf( name, "%s%s", writedir, g_modelname );
459 *strrchr( name, '.' ) = 0;
460 strcat( name, "_default.skin" );
462 defaultSkinHandle = fopen( name, "wt" );
463 for ( i = 0; i < g_data.model.numSurfaces; i++ )
465 fprintf( defaultSkinHandle, "%s,%s\n", g_data.surfData[i].header.name, g_data.surfData[i].shaders[0].name );
467 fclose( defaultSkinHandle );
470 sprintf (name, "%s%s", writedir, g_modelname);
473 // copy the model and its shaders to release directory tree
474 // if doing a release build
478 md3SurfaceData_t *pSurf;
480 ReleaseFile( g_modelname );
482 for ( i = 0; i < g_data.model.numSurfaces; i++ ) {
483 pSurf = &g_data.surfData[i];
484 for ( j = 0; j < g_data.model.numSkins; j++ ) {
485 ReleaseShader( pSurf->shaders[j].name );
492 // write the model output file
494 printf ("saving to %s\n", name);
496 modelouthandle = SafeOpenWrite (name);
498 WriteModelFile (modelouthandle);
500 printf ("%4d surfaces\n", g_data.model.numSurfaces);
501 printf ("%4d frames\n", g_data.model.numFrames);
502 printf ("%4d tags\n", g_data.model.numTags);
503 printf ("file size: %d\n", (int)ftell (modelouthandle) );
504 printf ("---------------------\n");
506 fclose (modelouthandle);
512 ** Reorders triangles in all the surfaces.
514 static void OrderSurfaces( void )
517 extern qboolean g_stripify;
519 // go through each surface and find best strip/fans possible
520 for ( s = 0; s < g_data.model.numSurfaces; s++ )
522 int mesh[MD3_MAX_TRIANGLES][3];
525 printf( "stripifying surface %d/%d with %d tris\n", s, g_data.model.numSurfaces, g_data.surfData[s].header.numTriangles );
527 for ( i = 0; i < g_data.surfData[s].header.numTriangles; i++ )
529 mesh[i][0] = g_data.surfData[s].lodTriangles[i][0];
530 mesh[i][1] = g_data.surfData[s].lodTriangles[i][1];
531 mesh[i][2] = g_data.surfData[s].lodTriangles[i][2];
536 OrderMesh( mesh, // input
537 g_data.surfData[s].orderedTriangles, // output
538 g_data.surfData[s].header.numTriangles );
542 memcpy( g_data.surfData[s].orderedTriangles, mesh, sizeof( int ) * 3 * g_data.surfData[s].header.numTriangles );
549 ===============================================================
553 ===============================================================
557 CopyTrianglesToBaseTriangles
561 static void CopyTrianglesToBaseTriangles(triangle_t *ptri, int numtri, baseTriangle_t *bTri )
564 // int width, height, iwidth, iheight, swidth;
565 // float s_scale, t_scale;
567 // vec3_t mins, maxs;
572 // find bounds of all the verts on the base frame
574 ClearBounds (mins, maxs);
576 for (i=0 ; i<numtri ; i++)
577 for (j=0 ; j<3 ; j++)
578 AddPointToBounds (ptri[i].verts[j], mins, maxs);
580 for (i=0 ; i<3 ; i++)
582 mins[i] = floor(mins[i]);
583 maxs[i] = ceil(maxs[i]);
586 width = maxs[0] - mins[0];
587 height = maxs[2] - mins[2];
589 if (!g_data.fixedwidth)
592 if (width*scale >= 150)
593 scale = 150.0 / width;
594 if (height*scale >= 190)
595 scale = 190.0 / height;
597 s_scale = t_scale = scale;
599 iwidth = ceil(width*s_scale);
600 iheight = ceil(height*t_scale);
607 iwidth = g_data.fixedwidth / 2;
608 iheight = g_data.fixedheight;
610 s_scale = (float)(iwidth-4) / width;
611 t_scale = (float)(iheight-4) / height;
614 // make the width a multiple of 4; some hardware requires this, and it ensures
615 // dword alignment for each scan
617 g_data.skinwidth = (swidth + 3) & ~3;
618 g_data.skinheight = iheight;
621 for (i=0; i<numtri ; i++, ptri++, bTri++)
625 for (j=0 ; j<3 ; j++)
627 pbasevert = ptri->verts[j];
629 VectorCopy( ptri->verts[j], bTri->v[j].xyz);
630 VectorCopy( ptri->normals[j], bTri->v[j].normal );
632 bTri->v[j].st[0] = ptri->texcoords[j][0];
633 bTri->v[j].st[1] = ptri->texcoords[j][1];
638 static void BuildBaseFrame( const char *filename, ObjectAnimationFrame_t *pOAF )
640 baseTriangle_t *bTri;
644 // calculate the base triangles
645 for ( i = 0; i < g_data.model.numSurfaces; i++ )
647 CopyTrianglesToBaseTriangles( pOAF->surfaces[i]->triangles,
648 pOAF->surfaces[i]->numtriangles,
649 g_data.surfData[i].baseTriangles );
651 strcpy( g_data.surfData[i].header.name, pOAF->surfaces[i]->name );
653 g_data.surfData[i].header.numTriangles = pOAF->surfaces[i]->numtriangles;
654 g_data.surfData[i].header.numVerts = 0;
657 if ( strstr( filename, gamedir + 1 ) )
659 strcpy( shaderName, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 );
663 strcpy( shaderName, filename );
666 if ( strrchr( shaderName, '/' ) )
667 *( strrchr( shaderName, '/' ) + 1 ) = 0;
670 strcpy( shaderName, pOAF->surfaces[i]->materialname );
672 strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, pOAF->surfaces[i]->materialname );
674 g_data.surfData[i].header.numShaders++;
678 // compute unique vertices for each polyset
680 for ( i = 0; i < g_data.model.numSurfaces; i++ )
684 for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
686 bTri = &g_data.surfData[i].baseTriangles[t];
688 for (j=0 ; j<3 ; j++)
695 for ( k = 0; k < g_data.surfData[i].header.numVerts; k++ )
697 if ( ( g_data.surfData[i].baseVertexes[k].st[0] == bVert->st[0] ) &&
698 ( g_data.surfData[i].baseVertexes[k].st[1] == bVert->st[1] ) &&
699 ( VectorCompare (bVert->xyz, g_data.surfData[i].baseVertexes[k].xyz) ) &&
700 ( VectorCompare (bVert->normal, g_data.surfData[i].baseVertexes[k].normal) ) )
702 break; // this vertex is already in the base vertex list
706 if (k == g_data.surfData[i].header.numVerts) { // new index
707 g_data.surfData[i].baseVertexes[g_data.surfData[i].header.numVerts] = *bVert;
708 g_data.surfData[i].header.numVerts++;
713 g_data.surfData[i].lodTriangles[t][j] = k;
721 for ( i = 0; i < g_data.model.numSurfaces; i++ )
723 if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name )
725 if ( pOAF->surfaces[i]->numtriangles != 1 )
727 Error( "tag polysets must consist of only one triangle" );
729 if ( strstr( filename, "_flash.md3" ) && !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) )
731 printf( "found tag '%s'\n", pOAF->surfaces[i]->name );
732 g_data.model.numTags++;
738 static int LoadModelFile( const char *filename, polyset_t **psets, int *numpolysets )
742 const char *frameFile;
744 printf ("---------------------\n");
745 if ( filename[1] != ':' )
747 frameFile = filename;
748 sprintf( file1, "%s/%s", g_cddir, frameFile );
752 strcpy( file1, filename );
755 time1 = FileTime (file1);
757 Error ("%s doesn't exist", file1);
760 // load the base triangles
762 *psets = Polyset_LoadSets( file1, numpolysets, g_data.maxSurfaceTris );
767 Polyset_SnapSets( *psets, *numpolysets );
769 if ( strstr( file1, ".3ds" ) || strstr( file1, ".3DS" ) )
770 return MD3_TYPE_BASE3DS;
772 Error( "Unknown model file type" );
774 return MD3_TYPE_UNKNOWN;
782 void Cmd_Base( void )
787 sprintf( filename, "%s/%s", g_cddir, token );
788 LoadBase( filename );
791 static void LoadBase( const char *filename )
796 ObjectAnimationFrame_t oaf;
798 // determine polyset splitting threshold
799 if ( TokenAvailable() )
802 g_data.maxSurfaceTris = atoi( token );
806 g_data.maxSurfaceTris = MAX_SURFACE_TRIS - 1;
809 g_data.type = LoadModelFile( filename, &psets, &numpolysets );
811 Polyset_ComputeNormals( psets, numpolysets );
813 g_data.model.numSurfaces = numpolysets;
815 memset( &oaf, 0, sizeof( oaf ) );
817 for ( i = 0; i < numpolysets; i++ )
819 oaf.surfaces[i] = &psets[i];
820 oaf.numSurfaces = numpolysets;
823 BuildBaseFrame( filename, &oaf );
825 free( psets[0].triangles );
833 $spritebase xorg yorg width height
835 Generate a single square for the model
838 void Cmd_SpriteBase (void)
840 float xl, yl, width, height;
842 g_data.type = MD3_TYPE_SPRITE;
851 height = atof(token);
853 // if (g_skipmodel || g_release || g_archive)
856 printf ("---------------------\n");
858 g_data.surfData[0].verts[0] = ( float * ) calloc( 1, sizeof( float ) * 6 * 4 );
860 g_data.surfData[0].header.numVerts = 4;
862 g_data.surfData[0].verts[0][0+0] = 0;
863 g_data.surfData[0].verts[0][0+1] = -xl;
864 g_data.surfData[0].verts[0][0+2] = yl + height;
866 g_data.surfData[0].verts[0][0+3] = -1;
867 g_data.surfData[0].verts[0][0+4] = 0;
868 g_data.surfData[0].verts[0][0+5] = 0;
869 g_data.surfData[0].baseVertexes[0].st[0] = 0;
870 g_data.surfData[0].baseVertexes[0].st[1] = 0;
873 g_data.surfData[0].verts[0][6+0] = 0;
874 g_data.surfData[0].verts[0][6+1] = -xl - width;
875 g_data.surfData[0].verts[0][6+2] = yl + height;
877 g_data.surfData[0].verts[0][6+3] = -1;
878 g_data.surfData[0].verts[0][6+4] = 0;
879 g_data.surfData[0].verts[0][6+5] = 0;
880 g_data.surfData[0].baseVertexes[1].st[0] = 1;
881 g_data.surfData[0].baseVertexes[1].st[1] = 0;
884 g_data.surfData[0].verts[0][12+0] = 0;
885 g_data.surfData[0].verts[0][12+1] = -xl - width;
886 g_data.surfData[0].verts[0][12+2] = yl;
888 g_data.surfData[0].verts[0][12+3] = -1;
889 g_data.surfData[0].verts[0][12+4] = 0;
890 g_data.surfData[0].verts[0][12+5] = 0;
891 g_data.surfData[0].baseVertexes[2].st[0] = 1;
892 g_data.surfData[0].baseVertexes[2].st[1] = 1;
895 g_data.surfData[0].verts[0][18+0] = 0;
896 g_data.surfData[0].verts[0][18+1] = -xl;
897 g_data.surfData[0].verts[0][18+2] = yl;
899 g_data.surfData[0].verts[0][18+3] = -1;
900 g_data.surfData[0].verts[0][18+4] = 0;
901 g_data.surfData[0].verts[0][18+5] = 0;
902 g_data.surfData[0].baseVertexes[3].st[0] = 0;
903 g_data.surfData[0].baseVertexes[3].st[1] = 1;
905 g_data.surfData[0].lodTriangles[0][0] = 0;
906 g_data.surfData[0].lodTriangles[0][1] = 1;
907 g_data.surfData[0].lodTriangles[0][2] = 2;
909 g_data.surfData[0].lodTriangles[1][0] = 2;
910 g_data.surfData[0].lodTriangles[1][1] = 3;
911 g_data.surfData[0].lodTriangles[1][2] = 0;
913 g_data.model.numSurfaces = 1;
915 g_data.surfData[0].header.numTriangles = 2;
916 g_data.surfData[0].header.numVerts = 4;
918 g_data.model.numFrames = 1;
922 ===========================================================================
926 ===========================================================================
934 void GrabFrame (const char *frame)
942 const char *framefile;
944 qboolean parentTagExists = qfalse;
949 // the frame 'run1' will be looked for as either
950 // run.1 or run1.tri, so the new alias sequence save
951 // feature an be used
952 if ( frame[1] != ':' )
954 // framefile = FindFrameFile (frame);
956 sprintf (file1, "%s/%s",g_cddir, framefile);
960 strcpy( file1, frame );
962 printf ("grabbing %s\n", file1);
964 if (g_data.model.numFrames >= MD3_MAX_FRAMES)
965 Error ("model.numFrames >= MD3_MAX_FRAMES");
966 fr = &g_data.frames[g_data.model.numFrames];
968 strcpy (fr->name, frame);
970 psets = Polyset_LoadSets( file1, &numpolysets, g_data.maxSurfaceTris );
975 Polyset_SnapSets( psets, numpolysets );
978 // compute vertex normals
980 Polyset_ComputeNormals( psets, numpolysets );
983 // flip everything to compensate for the alias coordinate system
984 // and perform global scale and adjust
986 for ( i = 0; i < g_data.model.numSurfaces; i++ )
988 triangle_t *ptri = psets[i].triangles;
991 for ( t = 0; t < psets[i].numtriangles; t++ )
994 for ( j = 0; j < 3; j++ )
998 for ( k = 0 ; k < 3 ; k++ ) {
999 ptri[t].verts[j][k] = ptri[t].verts[j][k] * g_data.scale_up +
1002 if ( ptri[t].verts[j][k] > 1023 ||
1003 ptri[t].verts[j][k] < -1023 )
1005 Error( "Model extents too large" );
1013 // find and count tags, locate parent tag
1015 for ( i = 0; i < numpolysets; i++ )
1017 if ( strstr( psets[i].name, "tag_" ) == psets[i].name )
1019 if ( strstr( psets[i].name, "tag_parent" ) == psets[i].name )
1021 if ( strstr( psets[i].name, "tag_parent" ) )
1025 if ( parentTagExists )
1026 Error( "Multiple parent tags not allowed" );
1028 memcpy( tri[0], psets[i].triangles[0].verts[0], sizeof( float ) * 3 );
1029 memcpy( tri[1], psets[i].triangles[0].verts[1], sizeof( float ) * 3 );
1030 memcpy( tri[2], psets[i].triangles[0].verts[2], sizeof( float ) * 3 );
1032 MD3_ComputeTagFromTri( &tagParent, tri );
1033 strcpy( tagParent.name, psets[i].name );
1034 g_data.tags[g_data.model.numFrames][numtags] = tagParent;
1035 parentTagExists = qtrue;
1042 if ( strcmp( psets[i].name, g_data.surfData[i].header.name ) )
1044 Error( "Mismatched surfaces from base('%s') to frame('%s') in model '%s'\n", g_data.surfData[i].header.name, psets[i].name, g_modelname );
1048 if ( numtags != g_data.model.numTags )
1050 Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags );
1053 if ( numpolysets != g_data.model.numSurfaces )
1055 Error( "mismatched number of surfaces in frame(%d) vs. base(%d)", numpolysets-numtags, g_data.model.numSurfaces );
1059 // prepare to accumulate bounds and normals
1061 ClearBounds( fr->bounds[0], fr->bounds[1] );
1064 // store the frame's vertices in the same order as the base. This assumes the
1065 // triangles and vertices in this frame are in exactly the same order as in the
1068 for ( i = 0, tagcount = 0; i < numpolysets; i++ )
1071 triangle_t *pTris = psets[i].triangles;
1073 strcpy( g_data.surfData[i].header.name, psets[i].name );
1076 // parent tag adjust
1078 if ( parentTagExists ) {
1079 for ( t = 0; t < psets[i].numtriangles; t++ )
1081 for ( j = 0; j < 3 ; j++ )
1085 VectorSubtract( pTris[t].verts[j], tagParent.origin, tmp );
1087 pTris[t].verts[j][0] = DotProduct( tmp, tagParent.axis[0] );
1088 pTris[t].verts[j][1] = DotProduct( tmp, tagParent.axis[1] );
1089 pTris[t].verts[j][2] = DotProduct( tmp, tagParent.axis[2] );
1091 VectorCopy( pTris[t].normals[j], tmp );
1092 pTris[t].normals[j][0] = DotProduct( tmp, tagParent.axis[0] );
1093 pTris[t].normals[j][1] = DotProduct( tmp, tagParent.axis[1] );
1094 pTris[t].normals[j][2] = DotProduct( tmp, tagParent.axis[2] );
1102 if ( strstr( psets[i].name, "tag_" ) == psets[i].name )
1104 md3Tag_t *pTag = &g_data.tags[g_data.model.numFrames][tagcount];
1107 strcpy( pTag->name, psets[i].name );
1109 memcpy( tri[0], pTris[0].verts[0], sizeof( float ) * 3 );
1110 memcpy( tri[1], pTris[0].verts[1], sizeof( float ) * 3 );
1111 memcpy( tri[2], pTris[0].verts[2], sizeof( float ) * 3 );
1113 MD3_ComputeTagFromTri( pTag, tri );
1118 if ( g_data.surfData[i].verts[g_data.model.numFrames] )
1119 free( g_data.surfData[i].verts[g_data.model.numFrames] );
1120 frameXyz = g_data.surfData[i].verts[g_data.model.numFrames] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts );
1121 frameNormals = frameXyz + 3;
1123 for ( t = 0; t < psets[i].numtriangles; t++ )
1125 for ( j = 0; j < 3 ; j++ )
1129 index = g_data.surfData[i].baseTriangles[t].v[j].index;
1130 frameXyz[index*6+0] = pTris[t].verts[j][0];
1131 frameXyz[index*6+1] = pTris[t].verts[j][1];
1132 frameXyz[index*6+2] = pTris[t].verts[j][2];
1133 frameNormals[index*6+0] = pTris[t].normals[j][0];
1134 frameNormals[index*6+1] = pTris[t].normals[j][1];
1135 frameNormals[index*6+2] = pTris[t].normals[j][2];
1136 AddPointToBounds (&frameXyz[index*6], fr->bounds[0], fr->bounds[1] );
1142 g_data.model.numFrames++;
1144 // only free the first triangle array, all of the psets in this array share the
1145 // same triangle pool!!!
1146 // free( psets[0].triangles );
1150 //===========================================================================
1159 void Cmd_Frame (void)
1161 while (TokenAvailable())
1166 if (g_release || g_archive)
1168 g_data.model.numFrames = 1; // don't skip the writeout
1183 void SkinFrom3DS( const char *filename )
1190 _3DS_LoadPolysets( filename, &psets, &numPolysets, g_verbose );
1192 for ( i = 0; i < numPolysets; i++ )
1195 if ( strstr( filename, gamedir + 1 ) )
1197 strcpy( name, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 );
1201 strcpy( name, filename );
1204 if ( strrchr( name, '/' ) )
1205 *( strrchr( name, '/' ) + 1 ) = 0;
1207 strcpy( name, psets[i].materialname );
1208 strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, name );
1210 g_data.surfData[i].header.numShaders++;
1213 free( psets[0].triangles );
1217 void Cmd_Skin (void)
1219 char skinfile[1024];
1221 if ( g_data.type == MD3_TYPE_BASE3DS )
1225 sprintf( skinfile, "%s/%s", g_cddir, token );
1227 if ( strstr( token, ".3ds" ) || strstr( token, ".3DS" ) )
1229 SkinFrom3DS( skinfile );
1233 Error( "Unknown file format for $skin '%s'\n", skinfile );
1238 Error( "invalid model type while processing $skin" );
1241 g_data.model.numSkins++;
1249 This routine is also called for $oldskin
1252 void Cmd_SpriteShader()
1255 strcpy( g_data.surfData[0].shaders[g_data.surfData[0].header.numShaders].name, token );
1256 g_data.surfData[0].header.numShaders++;
1257 g_data.model.numSkins++;
1265 void Cmd_Origin (void)
1267 // rotate points into frame of reference so model points down the
1269 // FIXME: use alias native coordinate system
1271 g_data.adjust[1] = -atof (token);
1274 g_data.adjust[0] = atof (token);
1277 g_data.adjust[2] = -atof (token);
1286 void Cmd_ScaleUp (void)
1289 g_data.scale_up = atof (token);
1290 if (g_skipmodel || g_release || g_archive)
1293 printf ("Scale up: %f\n", g_data.scale_up);
1301 Set a skin size other than the default
1305 void Cmd_Skinsize (void)
1308 g_data.fixedwidth = atoi(token);
1310 g_data.fixedheight = atoi(token);
1317 Begin creating a model of the given name
1320 void Cmd_Modelname (void)
1322 FinishModel ( TYPE_UNKNOWN );
1326 strcpy (g_modelname, token);
1327 StripExtension (g_modelname);
1328 strcat (g_modelname, ".md3");
1329 strcpy (g_data.model.name, g_modelname);
1340 Error ("$cd command without a $modelname");
1345 sprintf ( g_cddir, "%s%s", gamedir, token);
1347 // if -only was specified and this cd doesn't match,
1348 // skip the model (you only need to match leading chars,
1349 // so you could regrab all monsters with -only models/monsters)
1352 if (strncmp(token, g_only, strlen(g_only)))
1354 g_skipmodel = qtrue;
1355 printf ("skipping %s\n", token);
1359 void Convert3DStoMD3( const char *file )
1363 SkinFrom3DS( file );
1365 strcpy( g_data.model.name, g_modelname );
1367 FinishModel( TYPE_UNKNOWN );
1374 void Cmd_3DSConvert()
1378 FinishModel( TYPE_UNKNOWN );
1383 sprintf( file, "%s%s", gamedir, token );
1384 strcpy( g_modelname, token );
1385 if ( strrchr( g_modelname, '.' ) )
1386 *strrchr( g_modelname, '.' ) = 0;
1387 strcat( g_modelname, ".md3" );
1389 if ( FileTime( file ) == -1 )
1390 Error( "%s doesn't exist", file );
1392 if ( TokenAvailable() )
1395 g_data.scale_up = atof( token );
1398 Convert3DStoMD3( file );
1401 static void ConvertASE( const char *filename, int type, qboolean grabAnims );
1406 void Cmd_ASEConvert( qboolean grabAnims )
1408 char filename[1024];
1409 int type = TYPE_ITEM;
1411 FinishModel( TYPE_UNKNOWN );
1415 sprintf( filename, "%s%s", gamedir, token );
1417 strcpy (g_modelname, token);
1418 StripExtension (g_modelname);
1419 strcat (g_modelname, ".md3");
1420 strcpy (g_data.model.name, g_modelname);
1422 if ( !strstr( filename, ".ase" ) && !strstr( filename, ".ASE" ) )
1423 strcat( filename, ".ASE" );
1425 g_data.maxSurfaceTris = MAX_SURFACE_TRIS - 1;
1427 while ( TokenAvailable() )
1430 if ( !strcmp( token, "-origin" ) )
1432 if ( !TokenAvailable() )
1433 Error( "missing parameter for -origin" );
1435 g_data.aseAdjust[1] = -atof( token );
1437 if ( !TokenAvailable() )
1438 Error( "missing parameter for -origin" );
1440 g_data.aseAdjust[0] = atof (token);
1442 if ( !TokenAvailable() )
1443 Error( "missing parameter for -origin" );
1445 g_data.aseAdjust[2] = -atof (token);
1447 else if ( !strcmp( token, "-lod" ) )
1449 if ( !TokenAvailable() )
1450 Error( "No parameter for -lod" );
1452 g_data.currentLod = atoi( token );
1453 if ( g_data.currentLod > MD3_MAX_LODS - 1 )
1455 Error( "-lod parameter too large! (%d)\n", g_data.currentLod );
1458 if ( !TokenAvailable() )
1459 Error( "No second parameter for -lod" );
1461 g_data.lodBias = atof( token );
1463 else if ( !strcmp( token, "-maxtris" ) )
1465 if ( !TokenAvailable() )
1466 Error( "No parameter for -maxtris" );
1468 g_data.maxSurfaceTris = atoi( token );
1470 else if ( !strcmp( token, "-playerparms" ) )
1472 if ( !TokenAvailable() )
1473 Error( "missing skip start parameter for -playerparms" );
1475 g_data.lowerSkipFrameStart = atoi( token );
1478 if ( !TokenAvailable() )
1479 Error( "missing skip end parameter for -playerparms" );
1481 g_data.lowerSkipFrameEnd = atoi( token );
1484 if ( !TokenAvailable() )
1485 Error( "missing upper parameter for -playerparms" );
1487 g_data.maxUpperFrames = atoi( token );
1489 g_data.lowerSkipFrameEnd = g_data.maxUpperFrames - 1;
1492 if ( !TokenAvailable() )
1493 Error( "missing head parameter for -playerparms" );
1495 g_data.maxHeadFrames = atoi( token );
1497 g_data.maxHeadFrames = 1;
1499 if ( type != TYPE_ITEM )
1500 Error( "invalid argument" );
1504 else if ( !strcmp( token, "-weapon" ) )
1506 if ( type != TYPE_ITEM )
1507 Error( "invalid argument" );
1513 g_data.type = MD3_TYPE_ASE;
1515 if ( type == TYPE_WEAPON && grabAnims )
1517 Error( "can't grab anims with weapon models" );
1519 if ( type == TYPE_PLAYER && !grabAnims )
1521 Error( "player models must be converted with $aseanimconvert" );
1524 if ( type == TYPE_WEAPON )
1526 ConvertASE( filename, type, qfalse );
1527 ConvertASE( filename, TYPE_HAND, qtrue );
1531 ConvertASE( filename, type, grabAnims );
1535 static int GetSurfaceAnimations( SurfaceAnimation_t sanims[MAX_ANIM_SURFACES],
1543 int numValidSurfaces;
1547 if ( ( numSurfaces = ASE_GetNumSurfaces() ) > MAX_ANIM_SURFACES )
1549 Error( "Too many surfaces in ASE" );
1552 for ( numValidSurfaces = 0, i = 0; i < numSurfaces; i++ )
1554 polyset_t *splitSets;
1556 const char *surfaceName = ASE_GetSurfaceName( i );
1561 // Error( "Missing animation frames in model" );
1564 if ( strstr( surfaceName, "tag_" ) ||
1565 !strcmp( part, "any" ) ||
1566 ( strstr( surfaceName, part ) == surfaceName ) )
1569 // skip this if it's an inappropriate tag
1570 if ( strcmp( part, "any" ) )
1572 // ignore non-"tag_head" tags if this is the head
1573 if ( !strcmp( part, "h_" ) && strstr( surfaceName, "tag_" ) && strcmp( surfaceName, "tag_head" ) )
1575 // ignore "tag_head" if this is the legs
1576 if ( !strcmp( part, "l_" ) && !strcmp( surfaceName, "tag_head" ) )
1578 // ignore "tag_weapon" if this is the legs
1579 if ( !strcmp( part, "l_" ) && !strcmp( surfaceName, "tag_weapon" ) )
1583 if ( ( sanims[numValidSurfaces].frames = ASE_GetSurfaceAnimation( i, &sanims[numValidSurfaces].numFrames, skipFrameStart, skipFrameEnd, maxFrames ) ) != 0 )
1585 splitSets = Polyset_SplitSets( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames, &numNewFrames, g_data.maxSurfaceTris );
1587 if ( numFrames == -1 )
1588 numFrames = sanims[numValidSurfaces].numFrames;
1589 else if ( numFrames != sanims[numValidSurfaces].numFrames )
1590 Error( "Different number of animation frames on surfaces" );
1592 if ( sanims[numValidSurfaces].frames != splitSets )
1596 // free old data if we split the surfaces
1597 for ( j = 0; j < sanims[numValidSurfaces].numFrames; j++ )
1599 free( sanims[numValidSurfaces].frames[j].triangles );
1600 free( sanims[numValidSurfaces].frames );
1603 sanims[numValidSurfaces].frames = splitSets;
1604 sanims[numValidSurfaces].numFrames = numNewFrames;
1606 Polyset_SnapSets( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames );
1607 Polyset_ComputeNormals( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames );
1614 return numValidSurfaces;
1617 static int SurfaceOrderToFrameOrder( SurfaceAnimation_t sanims[], ObjectAnimationFrame_t oanims[], int numSurfaces )
1623 ** we have the data here arranged in surface order, now we need to convert it to
1626 for ( i = 0, s = 0; i < numSurfaces; i++ )
1630 if ( sanims[i].frames )
1632 if ( numFrames == -1 )
1633 numFrames = sanims[i].numFrames;
1634 else if ( numFrames != sanims[i].numFrames )
1635 Error( "numFrames != sanims[i].numFrames (%d != %d)\n", numFrames, sanims[i].numFrames );
1637 for ( j = 0; j < sanims[i].numFrames; j++ )
1639 oanims[j].surfaces[s] = &sanims[i].frames[j];
1640 oanims[j].numSurfaces = numSurfaces;
1649 static void WriteMD3( const char *_filename, ObjectAnimationFrame_t oanims[], int numFrames )
1651 char filename[1024];
1653 strcpy( filename, _filename );
1654 if ( strchr( filename, '.' ) )
1655 *strchr( filename, '.' ) = 0;
1656 strcat( filename, ".md3" );
1659 static void BuildAnimationFromOAFs( const char *filename, ObjectAnimationFrame_t oanims[], int numFrames, int type )
1661 int f, i, j, tagcount;
1663 float *frameNormals;
1665 g_data.model.numSurfaces = oanims[0].numSurfaces;
1666 g_data.model.numFrames = numFrames;
1667 if ( g_data.model.numFrames < 0)
1668 Error ("model.numFrames < 0");
1669 if ( g_data.model.numFrames >= MD3_MAX_FRAMES)
1670 Error ("model.numFrames >= MD3_MAX_FRAMES");
1673 BuildBaseFrame( filename, &oanims[0] );
1675 // build animation frames
1676 for ( f = 0; f < numFrames; f++ )
1678 ObjectAnimationFrame_t *pOAF = &oanims[f];
1679 qboolean parentTagExists = qfalse;
1684 fr = &g_data.frames[f];
1686 strcpy( fr->name, "(from ASE)" );
1688 // scale and adjust frame
1689 for ( i = 0; i < pOAF->numSurfaces; i++ )
1691 triangle_t *pTris = pOAF->surfaces[i]->triangles;
1694 for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
1696 for ( j = 0; j < 3; j++ )
1701 for ( k = 0 ; k < 3 ; k++ ) {
1702 pTris[t].verts[j][k] = pTris[t].verts[j][k] * g_data.scale_up +
1703 g_data.aseAdjust[k];
1705 if ( pTris[t].verts[j][k] > 1023 ||
1706 pTris[t].verts[j][k] < -1023 )
1708 Error( "Model extents too large" );
1716 // find and count tags, locate parent tag
1718 for ( i = 0; i < pOAF->numSurfaces; i++ )
1720 if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name )
1722 // ignore parent tags when grabbing a weapon model and this is the flash portion
1723 if ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) && strstr( filename, "_flash.md3" ) )
1727 else if ( !strstr( filename, "_hand.md3" ) && (
1728 ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) && !strstr( filename, "_flash.md3" ) ) ||
1729 ( !strcmp( pOAF->surfaces[i]->name, "tag_torso" ) && ( strstr( filename, "upper_" ) || strstr( filename, "upper.md3" ) ) ) ||
1730 ( !strcmp( pOAF->surfaces[i]->name, "tag_head" ) && ( strstr( filename, "head.md3" ) || strstr( filename, "head_" ) ) ) ||
1731 ( !strcmp( pOAF->surfaces[i]->name, "tag_flash" ) && strstr( filename, "_flash.md3" ) )||
1732 ( !strcmp( pOAF->surfaces[i]->name, "tag_weapon" ) && type == TYPE_WEAPON ) ) )
1736 if ( parentTagExists )
1737 Error( "Multiple parent tags not allowed" );
1739 memcpy( tri[0], pOAF->surfaces[i]->triangles[0].verts[0], sizeof( float ) * 3 );
1740 memcpy( tri[1], pOAF->surfaces[i]->triangles[0].verts[1], sizeof( float ) * 3 );
1741 memcpy( tri[2], pOAF->surfaces[i]->triangles[0].verts[2], sizeof( float ) * 3 );
1743 MD3_ComputeTagFromTri( &tagParent, tri );
1744 strcpy( tagParent.name, "tag_parent" );
1745 g_data.tags[f][numtags] = tagParent;
1746 parentTagExists = qtrue;
1752 memcpy( tri[0], pOAF->surfaces[i]->triangles[0].verts[0], sizeof( float ) * 3 );
1753 memcpy( tri[1], pOAF->surfaces[i]->triangles[0].verts[1], sizeof( float ) * 3 );
1754 memcpy( tri[2], pOAF->surfaces[i]->triangles[0].verts[2], sizeof( float ) * 3 );
1756 MD3_ComputeTagFromTri( &g_data.tags[f][numtags], tri );
1757 strcpy( g_data.tags[f][numtags].name, pOAF->surfaces[i]->name );
1758 if ( strstr( g_data.tags[f][numtags].name, "tag_flash" ) )
1759 * ( strstr( g_data.tags[f][numtags].name, "tag_flash" ) + strlen( "tag_flash" ) ) = 0;
1765 if ( strcmp( pOAF->surfaces[i]->name, g_data.surfData[i].header.name ) )
1767 Error( "Mismatched surfaces from base('%s') to frame('%s') in model '%s'\n", g_data.surfData[i].header.name, pOAF->surfaces[i]->name, filename );
1771 if ( numtags != g_data.model.numTags )
1773 Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags );
1777 // prepare to accumulate bounds and normals
1779 ClearBounds( fr->bounds[0], fr->bounds[1] );
1782 // store the frame's vertices in the same order as the base. This assumes the
1783 // triangles and vertices in this frame are in exactly the same order as in the
1786 for ( i = 0, tagcount = 0; i < pOAF->numSurfaces; i++ )
1789 triangle_t *pTris = pOAF->surfaces[i]->triangles;
1792 // parent tag adjust
1794 if ( parentTagExists )
1796 for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
1798 for ( j = 0; j < 3 ; j++ )
1802 VectorSubtract( pTris[t].verts[j], tagParent.origin, tmp );
1804 pTris[t].verts[j][0] = DotProduct( tmp, tagParent.axis[0] );
1805 pTris[t].verts[j][1] = DotProduct( tmp, tagParent.axis[1] );
1806 pTris[t].verts[j][2] = DotProduct( tmp, tagParent.axis[2] );
1808 VectorCopy( pTris[t].normals[j], tmp );
1809 pTris[t].normals[j][0] = DotProduct( tmp, tagParent.axis[0] );
1810 pTris[t].normals[j][1] = DotProduct( tmp, tagParent.axis[1] );
1811 pTris[t].normals[j][2] = DotProduct( tmp, tagParent.axis[2] );
1819 if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name )
1821 md3Tag_t *pTag = &g_data.tags[f][tagcount];
1824 strcpy( pTag->name, pOAF->surfaces[i]->name );
1826 memcpy( tri[0], pTris[0].verts[0], sizeof( float ) * 3 );
1827 memcpy( tri[1], pTris[0].verts[1], sizeof( float ) * 3 );
1828 memcpy( tri[2], pTris[0].verts[2], sizeof( float ) * 3 );
1830 MD3_ComputeTagFromTri( pTag, tri );
1835 if ( g_data.surfData[i].verts[f] )
1836 free( g_data.surfData[i].verts[f] );
1837 frameXyz = g_data.surfData[i].verts[f] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts );
1838 frameNormals = frameXyz + 3;
1840 for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
1842 for ( j = 0; j < 3 ; j++ )
1846 index = g_data.surfData[i].baseTriangles[t].v[j].index;
1847 frameXyz[index*6+0] = pTris[t].verts[j][0];
1848 frameXyz[index*6+1] = pTris[t].verts[j][1];
1849 frameXyz[index*6+2] = pTris[t].verts[j][2];
1850 frameNormals[index*6+0] = pTris[t].normals[j][0];
1851 frameNormals[index*6+1] = pTris[t].normals[j][1];
1852 frameNormals[index*6+2] = pTris[t].normals[j][2];
1853 AddPointToBounds (&frameXyz[index*6], fr->bounds[0], fr->bounds[1] );
1860 if ( strstr( filename, gamedir + 1 ) )
1862 strcpy( g_modelname, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 );
1866 strcpy( g_modelname, filename );
1869 FinishModel( type );
1873 static void ConvertASE( const char *filename, int type, qboolean grabAnims )
1878 SurfaceAnimation_t surfaceAnimations[MAX_ANIM_SURFACES];
1879 ObjectAnimationFrame_t objectAnimationFrames[MAX_ANIM_FRAMES];
1880 char outfilename[1024];
1883 ** load ASE into memory
1885 ASE_Load( filename, g_verbose, grabAnims );
1890 if ( type == TYPE_ITEM )
1892 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "any", -1, -1, -1 );
1894 if ( numSurfaces <= 0 )
1895 Error( "numSurfaces <= 0" );
1897 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
1899 if ( numFrames <= 0 )
1900 Error( "numFrames <= 0" );
1902 strcpy( outfilename, filename );
1903 if ( strrchr( outfilename, '.' ) )
1904 *( strrchr( outfilename, '.' ) + 1 ) = 0;
1905 strcat( outfilename, "md3" );
1906 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
1909 for ( i = 0; i < numSurfaces; i++ )
1911 if ( surfaceAnimations[i].frames )
1913 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
1915 free( surfaceAnimations[i].frames[j].triangles );
1917 free( surfaceAnimations[i].frames );
1918 surfaceAnimations[i].frames = 0;
1922 else if ( type == TYPE_PLAYER )
1924 qboolean tagTorso = qfalse;
1925 qboolean tagHead = qfalse;
1926 qboolean tagWeapon = qfalse;
1929 // verify that all necessary tags exist
1931 numSurfaces = ASE_GetNumSurfaces();
1932 for ( i = 0; i < numSurfaces; i++ )
1934 if ( !strcmp( ASE_GetSurfaceName( i ), "tag_head" ) )
1938 if ( !strcmp( ASE_GetSurfaceName( i ), "tag_torso" ) )
1942 if ( !strcmp( ASE_GetSurfaceName( i ), "tag_weapon" ) )
1950 Error( "Missing tag_weapon!" );
1954 Error( "Missing tag_torso!" );
1958 Error( "Missing tag_weapon!" );
1961 // get all upper body surfaces
1962 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "u_", -1, -1, g_data.maxUpperFrames );
1963 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
1964 strcpy( outfilename, filename );
1965 if ( strrchr( outfilename, '/' ) )
1966 *( strrchr( outfilename, '/' ) + 1 ) = 0;
1968 if ( g_data.currentLod == 0 )
1970 strcat( outfilename, "upper.md3" );
1976 sprintf( temp, "upper_%d.md3", g_data.currentLod );
1977 strcat( outfilename, temp );
1980 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
1983 for ( i = 0; i < numSurfaces; i++ )
1985 if ( surfaceAnimations[i].frames )
1987 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
1989 free( surfaceAnimations[i].frames[j].triangles );
1991 free( surfaceAnimations[i].frames );
1992 surfaceAnimations[i].frames = 0;
1996 // get lower body surfaces
1997 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "l_", g_data.lowerSkipFrameStart, g_data.lowerSkipFrameEnd, -1 );
1998 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
1999 strcpy( outfilename, filename );
2000 if ( strrchr( outfilename, '/' ) )
2001 *( strrchr( outfilename, '/' ) + 1 ) = 0;
2003 if ( g_data.currentLod == 0 )
2005 strcat( outfilename, "lower.md3" );
2011 sprintf( temp, "lower_%d.md3", g_data.currentLod );
2012 strcat( outfilename, temp );
2014 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
2017 for ( i = 0; i < numSurfaces; i++ )
2019 if ( surfaceAnimations[i].frames )
2021 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
2023 free( surfaceAnimations[i].frames[j].triangles );
2025 free( surfaceAnimations[i].frames );
2026 surfaceAnimations[i].frames = 0;
2030 // get head surfaces
2031 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "h_", -1, -1, g_data.maxHeadFrames );
2032 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
2033 strcpy( outfilename, filename );
2034 if ( strrchr( outfilename, '/' ) )
2035 *( strrchr( outfilename, '/' ) + 1 ) = 0;
2037 if ( g_data.currentLod == 0 )
2039 strcat( outfilename, "head.md3" );
2045 sprintf( temp, "head_%d.md3", g_data.currentLod );
2046 strcat( outfilename, temp );
2048 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
2051 for ( i = 0; i < numSurfaces; i++ )
2053 if ( surfaceAnimations[i].frames )
2055 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
2057 free( surfaceAnimations[i].frames[j].triangles );
2059 free( surfaceAnimations[i].frames );
2060 surfaceAnimations[i].frames = 0;
2064 else if ( type == TYPE_WEAPON )
2066 // get the weapon surfaces
2067 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "w_", -1, -1, -1 );
2068 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
2070 strcpy( outfilename, filename );
2071 if ( strrchr( outfilename, '.' ) )
2072 *( strrchr( outfilename, '.' ) + 1 ) = 0;
2073 strcat( outfilename, "md3" );
2074 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
2077 for ( i = 0; i < numSurfaces; i++ )
2079 if ( surfaceAnimations[i].frames )
2081 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
2083 free( surfaceAnimations[i].frames[j].triangles );
2085 free( surfaceAnimations[i].frames );
2086 surfaceAnimations[i].frames = 0;
2090 // get the flash surfaces
2091 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "f_", -1, -1, -1 );
2092 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
2094 strcpy( outfilename, filename );
2095 if ( strrchr( outfilename, '.' ) )
2096 *strrchr( outfilename, '.' ) = 0;
2097 strcat( outfilename, "_flash.md3" );
2098 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_ITEM );
2101 for ( i = 0; i < numSurfaces; i++ )
2103 if ( surfaceAnimations[i].frames )
2105 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
2107 free( surfaceAnimations[i].frames[j].triangles );
2109 free( surfaceAnimations[i].frames );
2110 surfaceAnimations[i].frames = 0;
2114 else if ( type == TYPE_HAND )
2116 // get the hand tags
2117 numSurfaces = GetSurfaceAnimations( surfaceAnimations, "tag_", -1, -1, -1 );
2118 numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
2120 strcpy( outfilename, filename );
2121 if ( strrchr( outfilename, '.' ) )
2122 *strrchr( outfilename, '.' ) = 0;
2123 strcat( outfilename, "_hand.md3" );
2124 BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_HAND );
2127 for ( i = 0; i < numSurfaces; i++ )
2129 if ( surfaceAnimations[i].frames )
2131 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
2133 free( surfaceAnimations[i].frames[j].triangles );
2135 free( surfaceAnimations[i].frames );
2136 surfaceAnimations[i].frames = 0;
2142 Error( "Unknown type passed to ConvertASE()" );
2145 g_data.currentLod = 0;
2147 g_data.maxHeadFrames = 0;
2148 g_data.maxUpperFrames = 0;
2149 g_data.lowerSkipFrameStart = 0;
2150 g_data.lowerSkipFrameEnd = 0;
2151 VectorCopy( vec3_origin, g_data.aseAdjust );
2153 // unload ASE from memory