#include #include "cmdlib.h" #include "mathlib.h" #include "qfiles.h" #include "models.h" #include "tikidata.h" #include "calclod.h" //================================================================= void OrderMesh( int input[][3], int output[][3], int numTris ); static void OrderSurfaces( void ); static void LoadBase( const char *filename ); q3data g_data; qboolean g_verbose; qboolean g_optimize; qboolean g_lod = qtrue; qboolean g_clampz; qboolean g_noorigin; qboolean g_zeroz; qboolean g_clearz; qboolean g_clearxy; // the command list holds counts, the count * 3 xyz, st, normal indexes // that are valid for every frame char g_cddir[1024]; char g_modelname[1024]; /* ** TIKI_ComputeTagFromTri */ void TIKI_ComputeTagFromTri( tikiTagData_t *pTag, const float pTri[3][3], const float pbaseTri[3][3] ) { float len[3]; float origlen[3]; vec3_t axes[3], sides[3]; int longestSide, shortestSide, hypotSide; int origin; int j; float d; longestSide = 0; shortestSide = 0; hypotSide = 0; origin = 0; memset( axes, 0, sizeof( axes ) ); memset( sides, 0, sizeof( sides ) ); // // compute sides // for ( j = 0; j < 3; j++ ) { #if 1 sides[j][0] = pbaseTri[(j+1)%3][0] - pbaseTri[j][0]; sides[j][1] = pbaseTri[(j+1)%3][1] - pbaseTri[j][1]; sides[j][2] = pbaseTri[(j+1)%3][2] - pbaseTri[j][2]; #else sides[j][0] = pTri[(j+1)%3][0] - pTri[j][0]; sides[j][1] = pTri[(j+1)%3][1] - pTri[j][1]; sides[j][2] = pTri[(j+1)%3][2] - pTri[j][2]; #endif origlen[ j ] = len[ j ] = ( float ) sqrt( DotProduct( sides[j], sides[j] ) ); } #if 0 if ( len[0] > len[1] && len[0] > len[2] ) { longestSide = 0; shortestSide = 1; origin = 2; } else if ( len[1] > len[0] && len[1] > len[2] ) { longestSide = 1; shortestSide = 2; origin = 0; } else if ( len[2] > len[0] && len[2] > len[1] ) { longestSide = 2; shortestSide = 0; origin = 1; } else { Error( "invalid tag triangle, must be a right triangle with unequal length sides" ); } #endif if ( len[0] > len[1] && len[0] > len[2] ) { hypotSide = 0; origin = 2; } else if ( len[1] > len[0] && len[1] > len[2] ) { hypotSide = 1; origin = 0; } else if ( len[2] > len[0] && len[2] > len[1] ) { hypotSide = 2; origin = 1; } len[hypotSide] = -1; if ( len[0] > len[1] && len[0] > len[2] ) { longestSide = 0; } else if ( len[1] > len[0] && len[1] > len[2] ) { longestSide = 1; } else if ( len[2] > len[0] && len[2] > len[1] ) { longestSide = 2; } len[longestSide] = -1; if ( len[0] > len[1] && len[0] > len[2] ) { shortestSide = 0; } else if ( len[1] > len[0] && len[1] > len[2] ) { shortestSide = 1; } else if ( len[2] > len[0] && len[2] > len[1] ) { shortestSide = 2; } len[shortestSide] = -1; // // compute sides // for ( j = 0; j < 3; j++ ) { sides[j][0] = pTri[(j+1)%3][0] - pTri[j][0]; sides[j][1] = pTri[(j+1)%3][1] - pTri[j][1]; sides[j][2] = pTri[(j+1)%3][2] - pTri[j][2]; } if ( longestSide == 0 && shortestSide == 1 ) { VectorNegate( sides[ longestSide ] ); VectorNegate( sides[ shortestSide ] ); } else if ( longestSide == 0 && shortestSide == 2 ) { } else if ( longestSide == 1 && shortestSide == 0 ) { } else if ( longestSide == 1 && shortestSide == 2 ) { VectorNegate( sides[ longestSide ] ); VectorNegate( sides[ shortestSide ] ); } else if ( longestSide == 2 && shortestSide == 0 ) { VectorNegate( sides[ longestSide ] ); VectorNegate( sides[ shortestSide ] ); } else if ( longestSide == 2 && shortestSide == 1 ) { } VectorNormalize( sides[longestSide], axes[0] ); VectorNormalize( sides[shortestSide], axes[1] ); // project shortest side so that it is exactly 90 degrees to the longer side d = DotProduct( axes[1], axes[0] ); VectorMA( axes[1], -d, axes[0], axes[1] ); VectorNormalize( axes[1], axes[1] ); CrossProduct( sides[longestSide], sides[shortestSide], axes[2] ); VectorNormalize( axes[2], axes[2] ); pTag->origin[0] = pTri[origin][0]; pTag->origin[1] = pTri[origin][1]; pTag->origin[2] = pTri[origin][2]; VectorCopy( axes[0], pTag->axis[0] ); VectorCopy( axes[1], pTag->axis[1] ); VectorCopy( axes[2], pTag->axis[2] ); } //============================================================== /* ** MyNormalToLatLong ** ** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format ** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format ** ** Latitude is encoded in high 8 bits */ static unsigned short MyNormalToLatLong( vec3_t normal ) { unsigned short ll; // check for singularities if ( normal[0] == 0 && normal[1] == 0 ) { if ( normal[2] > 0 ) { ll = 0; // lat = 0, long = 0 } else { ll = 128; // lat = 0, long = 128 } } else { unsigned short a, b; a = RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ); a &= 0xff; b = RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ); b &= 0xff; ll = ( a << 8 ) | b; } return ll; } /* =============== ClearModel =============== */ void ClearModel (void) { int i; g_data.type = 0; for ( i = 0; i < TIKI_MAX_SURFACES * 2; i++ ) { memset( &g_data.surfData[i].header, 0, sizeof( g_data.surfData[i].header ) ); memset( &g_data.surfData[i].shaders, 0, sizeof( g_data.surfData[i].shaders ) ); memset( &g_data.surfData[i].verts, 0, sizeof( g_data.surfData[i].verts ) ); } memset( g_data.tags, 0, sizeof( g_data.tags ) ); memset( g_data.tagdata, 0, sizeof( g_data.tagdata ) ); memset( g_data.origins, 0, sizeof( g_data.origins ) ); for ( i = 0; i < g_data.model.numSurfaces; i++ ) { int j; for ( j = 0; j < g_data.model.numFrames; j++ ) { if ( g_data.surfData[i].verts[j] ) { free( g_data.surfData[i].verts[j] ); g_data.surfData[i].verts[j] = NULL; } } } memset (&g_data.model, 0, sizeof(g_data.model)); memset (g_cddir, 0, sizeof(g_cddir)); g_modelname[0] = 0; g_data.scale_up = 1.0; memset( &g_data.model, 0, sizeof( g_data.model ) ); VectorCopy (vec3_origin, g_data.adjust); g_data.fixedwidth = g_data.fixedheight = 0; g_data.originname[ 0 ] = 0; } /* ** void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData ) ** ** This routine assumes that the file position has been adjusted ** properly prior to entry to point at the beginning of the surface. ** ** Since surface header information is completely relative, we can't ** just randomly seek to an arbitrary surface location right now. Is ** this something we should add? */ void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData ) { tikiSurface_t *pSurf = &pSurfData->header; md3Shader_t *pShader = pSurfData->shaders; baseVertex_t *pBaseVertex = pSurfData->baseVertexes; float **verts = pSurfData->verts; short xyznormals[TIKI_MAX_VERTS][4]; float base_st[TIKI_MAX_VERTS][2]; tikiSurface_t surftemp; int f, i, j, k, index; if ( ( strstr( pSurf->name, "tag_" ) == pSurf->name ) || ( !strcmpi( g_data.originname, pSurf->name ) ) ) return; // // write out the header // surftemp = *pSurf; surftemp.ident = LittleLong( TIKI_ANIM_IDENT ); surftemp.numFrames = LittleLong( pSurf->numFrames ); surftemp.minLod = LittleLong( pSurf->minLod ); surftemp.ofsTriangles = LittleLong( pSurf->ofsTriangles ); surftemp.numTriangles = LittleLong( pSurf->numTriangles ); surftemp.ofsCollapseMap = LittleLong( pSurf->ofsCollapseMap ); surftemp.ofsSt = LittleLong( pSurf->ofsSt ); surftemp.ofsXyzNormals = LittleLong( pSurf->ofsXyzNormals ); surftemp.ofsEnd = LittleLong( pSurf->ofsEnd ); SafeWrite( modelouthandle, &surftemp, sizeof( surftemp ) ); if ( g_verbose ) { printf( "surface '%s'\n", pSurf->name ); } // // write out the triangles // for ( i = 0 ; i < pSurf->numTriangles ; i++ ) { for (j = 0 ; j < 3 ; j++) { if ( g_lod ) { int ivalue = LittleLong( pSurfData->permutationMap[ pSurfData->orderedTriangles[i][j] ] ); pSurfData->orderedTriangles[i][j] = ivalue; } else { int ivalue = LittleLong( pSurfData->orderedTriangles[i][j] ); pSurfData->orderedTriangles[i][j] = ivalue; } } } SafeWrite( modelouthandle, pSurfData->orderedTriangles, pSurf->numTriangles * sizeof( g_data.surfData[0].orderedTriangles[0] ) ); if ( g_verbose ) { printf( "\n...num verts: %d\n", pSurf->numVerts ); printf( "...COLLAPSE MAP\n" ); } // // write out the collapse map // for ( i = 0 ; i < pSurf->numVerts; i++ ) { { if ( g_lod ) { int ivalue = LittleLong( pSurfData->collapseMap[i] ); pSurfData->collapseMap[i] = ivalue; } else { pSurfData->collapseMap[i] = LittleLong( i );; } } } SafeWrite( modelouthandle, pSurfData->collapseMap, pSurf->numVerts * sizeof( g_data.surfData[0].collapseMap[0] ) ); if ( g_verbose ) { printf( "...TEX COORDINATES\n" ); } // // write out the texture coordinates // for ( i = 0; i < pSurf->numVerts ; i++) { if ( g_lod ) { // reorder the verts for lod as we write them out index = pSurfData->permutationMap[ i ]; base_st[index][0] = LittleFloat( pBaseVertex[i].st[0] ); base_st[index][1] = LittleFloat( pBaseVertex[i].st[1] ); if ( g_verbose ) printf( "......%d: %f,%f\n", i, base_st[index][0], base_st[index][1] ); } else { base_st[i][0] = LittleFloat( pBaseVertex[i].st[0] ); base_st[i][1] = LittleFloat( pBaseVertex[i].st[1] ); if ( g_verbose ) printf( "......%d: %f,%f\n", i, base_st[i][0], base_st[i][1] ); } } SafeWrite( modelouthandle, base_st, pSurf->numVerts * sizeof(base_st[0])); // // write the xyz_normal // if ( g_verbose ) printf( "...XYZNORMALS\n" ); for ( f = 0; f < g_data.model.numFrames; f++ ) { for (j=0 ; j< pSurf->numVerts; j++) { float fvalue; short value; if ( g_lod ) { // reorder the verts for lod as we write them out index = pSurfData->permutationMap[ j ]; } else { index = j; } for (k=0 ; k < 3 ; k++) { fvalue = verts[f][j*6+k] - g_data.frames[ f ].offset[ k ]; value = ( short ) ( fvalue / g_data.frames[ f ].scale[ k ] ); xyznormals[index][k] = LittleShort( value ); } value = MyNormalToLatLong( &verts[f][j*6+3] ); xyznormals[index][3] = LittleShort( value ); } SafeWrite( modelouthandle, xyznormals, pSurf->numVerts * sizeof( short ) * 4 ); } } int numRealSurfaces; /* ** void WriteModelFile( FILE *modelouthandle ) ** ** CHUNK SIZE ** header sizeof( md3Header_t ) ** frames sizeof( tikiFrame_t ) * numFrames ** tags sizeof( tikiTag_t ) * numTags + sizeof( tikiTagData_t ) * numFrames * numTags ** surfaces surfaceSum */ void WriteModelFile( FILE *modelouthandle ) { int f, t; int i, j; tikiHeader_t modeltemp; long surfaceSum = 0; int numFrames = g_data.model.numFrames; int ofstemp; vec3_t totaldelta; numRealSurfaces = 0 ; // compute offsets for all surfaces, sum their total size for ( i = 0; i < g_data.model.numSurfaces; i++ ) { if ( ( strstr( g_data.surfData[i].header.name, "tag_" ) != g_data.surfData[i].header.name ) && ( strcmpi( g_data.originname, g_data.surfData[i].header.name ) ) ) { tikiSurface_t *psurf = &g_data.surfData[i].header; if ( psurf->numTriangles == 0 || psurf->numVerts == 0 ) continue; // // the triangle and vertex split threshold is controlled by a parameter // to $base, a la $base blah.3ds 1900, where "1900" determines the number // of triangles to split on // else if ( psurf->numVerts > MAX_SURFACE_VERTS ) { Error( "too many vertices\n" ); } psurf->numFrames = numFrames; if ( psurf->numTriangles > MAX_SURFACE_TRIS ) { Error( "too many faces\n" ); } psurf->ofsTriangles = sizeof( tikiSurface_t ); psurf->ofsCollapseMap = psurf->ofsTriangles + psurf->numTriangles * sizeof( md3Triangle_t ); psurf->ofsSt = psurf->ofsCollapseMap + psurf->numVerts * sizeof( int ); psurf->ofsXyzNormals = psurf->ofsSt + psurf->numVerts * sizeof( md3St_t ); psurf->ofsEnd = psurf->ofsXyzNormals + psurf->numFrames * psurf->numVerts * ( sizeof( short ) * 4 ); surfaceSum += psurf->ofsEnd; numRealSurfaces++; } } g_data.model.ident = TIKI_ANIM_IDENT; g_data.model.version = TIKI_ANIM_VERSION; g_data.model.ofsFrames = sizeof(tikiHeader_t); ofstemp = g_data.model.ofsFrames + numFrames*sizeof(tikiFrame_t); for ( t = 0; t < g_data.model.numTags; t++ ) { g_data.model.ofsTags[ t ] = ofstemp; ofstemp += sizeof(tikiTag_t); ofstemp += numFrames*sizeof(tikiTagData_t); } g_data.model.ofsSurfaces = ofstemp; g_data.model.ofsEnd = g_data.model.ofsSurfaces + surfaceSum; // was it optimized //g_data.model.optimized = g_optimize; // calculate total delta VectorSubtract( g_data.origins[ numFrames - 1 ], g_data.origins[ 0 ], g_data.model.totaldelta ); // calculate total time g_data.model.totaltime = ( float )numFrames / g_data.framerate; // // write out the model header // modeltemp = g_data.model; modeltemp.ident = LittleLong( modeltemp.ident ); modeltemp.version = LittleLong( modeltemp.version ); modeltemp.numFrames = LittleLong( modeltemp.numFrames ); modeltemp.numTags = LittleLong( modeltemp.numTags ); modeltemp.numSurfaces = LittleLong( numRealSurfaces ); modeltemp.ofsFrames = LittleLong( modeltemp.ofsFrames ); for ( t = 0; t < g_data.model.numTags; t++ ) { modeltemp.ofsTags[ t ] = LittleLong( modeltemp.ofsTags[ t ] ); } modeltemp.ofsSurfaces = LittleLong( modeltemp.ofsSurfaces ); modeltemp.ofsEnd = LittleLong( modeltemp.ofsEnd ); modeltemp.totaltime = LittleFloat( modeltemp.totaltime ); for ( i = 0; i < 3; i++ ) { modeltemp.totaldelta[ i ] = LittleFloat( modeltemp.totaldelta[ i ] ); } SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); // clear out totaldelta VectorClear( totaldelta ); // // write out the frames // for (i=0 ; i < numFrames ; i++) { vec3_t tmpVec; float maxRadius = 0; // // compute localOrigin and radius // for ( j = 0; j < 8; j++ ) { tmpVec[0] = g_data.frames[i].bounds[(j&1)!=0][0]; tmpVec[1] = g_data.frames[i].bounds[(j&2)!=0][1]; tmpVec[2] = g_data.frames[i].bounds[(j&4)!=0][2]; if ( VectorLength( tmpVec ) > maxRadius ) maxRadius = VectorLength( tmpVec ); } g_data.frames[i].radius = LittleFloat( maxRadius ); g_data.frames[i].frametime = LittleFloat( g_data.frames[i].frametime ); for (j=0 ; j<3 ; j++) { g_data.frames[i].scale[j] = ( g_data.frames[i].bounds[1][j] - g_data.frames[i].bounds[0][j] ) / 65535.0f; g_data.frames[i].offset[j] = g_data.frames[i].bounds[0][j]; } // calculate deltas if ( i < ( numFrames - 1 ) ) { for (j=0 ; j<3 ; j++) { g_data.frames[i].delta[j] = g_data.origins[ i + 1 ][ j ] - g_data.origins[ i ][ j ]; } VectorAdd( totaldelta, g_data.frames[ i ].delta, totaldelta ); } else { // fudge the last frame if ( numFrames > 1 ) { VectorScale( totaldelta, 1.0f / ( numFrames - 1 ), g_data.frames[i].delta ); } else { VectorClear( totaldelta ); } } // swap for (j=0 ; j<3 ; j++) { g_data.frames[i].scale[j] = LittleFloat( g_data.frames[i].scale[j] ); g_data.frames[i].offset[j] = LittleFloat( g_data.frames[i].offset[j] ); g_data.frames[i].delta[j] = LittleFloat( g_data.frames[i].delta[j] ); g_data.frames[i].bounds[0][j] = LittleFloat( g_data.frames[i].bounds[0][j] ); g_data.frames[i].bounds[1][j] = LittleFloat( g_data.frames[i].bounds[1][j] ); } } fseek (modelouthandle, g_data.model.ofsFrames, SEEK_SET); SafeWrite( modelouthandle, g_data.frames, numFrames * sizeof(g_data.frames[0]) ); // // write out the tags // for ( t = 0; t < g_data.model.numTags; t++ ) { for (f=0 ; fsurfaces[ i ].numtriangles; t++ ) { for( j = 0; j < 3; j++ ) { g_data.surfData[ i ].baseTriangles[ t ].v[ j ].index = base->surfaces[ i ].triangles[ t ].verts[ j ]; g_data.surfData[ i ].lodTriangles[ t ][ j ] = base->surfaces[ i ].triangles[ t ].verts[ j ]; } } strcpy( g_data.surfData[i].header.name, base->surfaces[ i ].name ); g_data.surfData[i].header.numTriangles = base->surfaces[ i ].numtriangles; g_data.surfData[i].header.numVerts = base->surfaces[ i ].numvertices; for( j = 0; j < base->surfaces[ i ].numvertices; j++ ) { g_data.surfData[ i ].baseVertexes[ j ].index = base->surfaces[ i ].triverts[ j ].map; g_data.surfData[ i ].baseVertexes[ j ].st[ 0 ] = base->surfaces[ i ].triverts[ j ].tex[ 0 ]; g_data.surfData[ i ].baseVertexes[ j ].st[ 1 ] = base->surfaces[ i ].triverts[ j ].tex[ 1 ]; VectorCopy( base->surfaces[ i ].triverts[ j ].xyz.xyz, g_data.surfData[ i ].baseVertexes[ j ].xyz ); VectorCopy( base->surfaces[ i ].triverts[ j ].xyz.normal, g_data.surfData[ i ].baseVertexes[ j ].normal ); } CalculateLOD( &g_data.surfData[i] ); } // // find tags // for ( i = 0; i < g_data.model.numSurfaces; i++ ) { if ( ( strcmpi( g_data.originname, g_data.surfData[ i ].header.name ) ) && ( strstr( g_data.surfData[ i ].header.name, "tag_" ) == g_data.surfData[ i ].header.name ) ) { if ( g_data.surfData[ i ].header.numTriangles != 1 ) { Error( "tag polysets must consist of only one triangle, tag %s", g_data.surfData[ i ].header.name ); } if ( g_verbose ) { printf( "found tag '%s'\n", g_data.surfData[ i ].header.name ); } g_data.model.numTags++; } } } static void BuildAnimation ( const char *filename, baseframe_t * base, animframe_t * anim, int numFrames, float framerate ) { int f, i, j, t, tagcount, index; float *frameXyz; float *frameNormals; g_data.model.numSurfaces = base->numSurfaces; g_data.model.numFrames = numFrames; if ( g_data.model.numFrames >= TIKI_MAX_FRAMES) Error ("model.numFrames >= TIKI_MAX_FRAMES"); // build base frame BuildBaseFrame( filename, base ); // build animation frames for ( f = 0; f < numFrames; f++ ) { animframe_t *panim = &anim[f]; qboolean parentTagExists = qfalse; tikiTagData_t tagParent; int numtags = 0; tikiFrame_t *fr; fr = &g_data.frames[f]; // set frame time fr->frametime = 1.0f / framerate; VectorClear( g_data.origins[ f ] ); // // find and count tags, locate parent tag // for ( i = 0; i < g_data.model.numSurfaces; i++ ) { if ( ( !strcmpi( g_data.originname, g_data.surfData[ i ].header.name ) ) || ( strstr( g_data.surfData[ i ].header.name, "tag_" ) == g_data.surfData[ i ].header.name ) ) { // store off origin info if ( !strcmpi( g_data.originname, g_data.surfData[ i ].header.name ) ) { float basetri[3][3]; float tri[3][3]; if ( parentTagExists ) Error( "Multiple parent tags not allowed" ); for( j = 0; j < 3; j++ ) { index = g_data.surfData[ i ].baseVertexes[ g_data.surfData[ i ].baseTriangles[ 0 ].v[ j ].index ].index; VectorCopy( panim->verts[ index ].xyz, tri[ j ] ); } for( j = 0; j < 3; j++ ) { VectorCopy( g_data.surfData[ i ].baseVertexes[ g_data.surfData[ i ].baseTriangles[ 0 ].v[ j ].index ].xyz, basetri[ j ] ); } TIKI_ComputeTagFromTri( &tagParent, tri, basetri ); //strcpy( tagParent.name, "origin" ); //g_data.tags[f][numtags] = tagParent; parentTagExists = qtrue; if ( g_clampz && tagParent.origin[ 2 ] < 0 ) { tagParent.origin[ 2 ] = 0; } if ( g_zeroz ) { tagParent.origin[ 2 ] = 0; } if ( g_noorigin ) { parentTagExists = qfalse; VectorClear( tagParent.origin ); } VectorCopy( tagParent.origin, g_data.origins[ f ] ); if ( g_clearxy ) { // subtract forward and side movement from deltas g_data.origins[ f ][ 0 ] = 0; g_data.origins[ f ][ 1 ] = 0; } if ( g_clearz ) { g_data.origins[ f ][ 2 ] = 0; } } else { float basetri[3][3]; float tri[3][3]; for( j = 0; j < 3; j++ ) { index = g_data.surfData[ i ].baseVertexes[ g_data.surfData[ i ].baseTriangles[ 0 ].v[ j ].index ].index; VectorCopy( panim->verts[ index ].xyz, tri[ j ] ); } for( j = 0; j < 3; j++ ) { VectorCopy( g_data.surfData[ i ].baseVertexes[ g_data.surfData[ i ].baseTriangles[ 0 ].v[ j ].index ].xyz, basetri[ j ] ); } TIKI_ComputeTagFromTri( &g_data.tagdata[numtags][f], tri, basetri ); strcpy( g_data.tags[numtags].name, g_data.surfData[ i ].header.name ); numtags++; } } } if ( numtags != g_data.model.numTags ) { Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags ); } // // prepare to accumulate bounds and normals // ClearBounds( fr->bounds[0], fr->bounds[1] ); // // store the frame's vertices in the same order as the base. This assumes the // triangles and vertices in this frame are in exactly the same order as in the // base // // // parent tag adjust // if ( parentTagExists ) { for ( t = 0; t < panim->numverts; t++ ) { vec3_t tmp; #if 1 VectorSubtract( panim->verts[ t ].xyz, tagParent.origin, tmp ); panim->verts[ t ].xyz[0] = DotProduct( tmp, tagParent.axis[0] ); panim->verts[ t ].xyz[1] = DotProduct( tmp, tagParent.axis[1] ); panim->verts[ t ].xyz[2] = DotProduct( tmp, tagParent.axis[2] ); #else VectorCopy( panim->verts[ t ].xyz, tmp ); panim->verts[ t ].xyz[0] = DotProduct( tmp, tagParent.axis[0] ); panim->verts[ t ].xyz[1] = DotProduct( tmp, tagParent.axis[1] ); panim->verts[ t ].xyz[2] = DotProduct( tmp, tagParent.axis[2] ); VectorSubtract( panim->verts[ t ].xyz, tagParent.origin, panim->verts[ t ].xyz ); #endif VectorCopy( panim->verts[ t ].normal, tmp ); panim->verts[ t ].normal[0] = DotProduct( tmp, tagParent.axis[0] ); panim->verts[ t ].normal[1] = DotProduct( tmp, tagParent.axis[1] ); panim->verts[ t ].normal[2] = DotProduct( tmp, tagParent.axis[2] ); } } for ( i = 0, tagcount = 0; i < g_data.model.numSurfaces; i++ ) { int t; // // compute tag data // if ( ( strcmpi( g_data.originname, g_data.surfData[ i ].header.name ) ) && ( strstr( g_data.surfData[ i ].header.name, "tag_" ) == g_data.surfData[ i ].header.name ) ) { tikiTag_t *pTag = &g_data.tags[tagcount]; tikiTagData_t *pTagData = &g_data.tagdata[tagcount][f]; float tri[3][3]; float basetri[3][3]; strcpy( pTag->name, g_data.surfData[ i ].header.name ); for( j = 0; j < 3; j++ ) { index = g_data.surfData[ i ].baseVertexes[ g_data.surfData[ i ].baseTriangles[ 0 ].v[ j ].index ].index; VectorCopy( panim->verts[ index ].xyz, tri[ j ] ); } for( j = 0; j < 3; j++ ) { VectorCopy( g_data.surfData[ i ].baseVertexes[ g_data.surfData[ i ].baseTriangles[ 0 ].v[ j ].index ].xyz, basetri[ j ] ); } TIKI_ComputeTagFromTri( pTagData, tri, basetri ); tagcount++; } else { if ( g_data.surfData[i].verts[f] ) free( g_data.surfData[i].verts[f] ); frameXyz = g_data.surfData[i].verts[f] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts ); frameNormals = frameXyz + 3; for ( t = 0; t < g_data.surfData[ i ].header.numVerts; t++ ) { int index; index = g_data.surfData[ i ].baseVertexes[ t ].index; frameXyz[t*6+0] = panim->verts[ index ].xyz[0]; frameXyz[t*6+1] = panim->verts[ index ].xyz[1]; frameXyz[t*6+2] = panim->verts[ index ].xyz[2]; frameNormals[t*6+0] = panim->verts[ index ].normal[0]; frameNormals[t*6+1] = panim->verts[ index ].normal[1]; frameNormals[t*6+2] = panim->verts[ index ].normal[2]; AddPointToBounds (&frameXyz[t*6], fr->bounds[0], fr->bounds[1] ); } } } } // set name strcpy (g_modelname, filename); strcpy (g_data.model.name, g_modelname); FinishModel(); ClearModel(); } void ConvertAnim ( const char *filename, int numFrames, float framerate, qboolean optimize, baseframe_t * base, animframe_t * anim, const char *originname, qboolean dolod, qboolean clampz, qboolean zeroz, qboolean clearz, qboolean clearxy, qboolean noorigin, qboolean verbose ) { char outfilename[1024]; ClearModel(); strcpy( g_data.originname, originname ); g_lod = dolod; g_optimize = optimize; g_verbose = verbose; g_clampz = clampz; g_zeroz = zeroz; g_clearz = clearz; g_clearxy = clearxy; g_noorigin = noorigin; g_data.framerate = framerate; strcpy( outfilename, filename ); // create destination filename StripExtension( outfilename ); strcat( outfilename, ".tan" ); BuildAnimation( outfilename, base, anim, numFrames, framerate ); }