aboutsummaryrefslogtreecommitdiff
path: root/sp/src/utils/motionmapper/motionmapper.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /sp/src/utils/motionmapper/motionmapper.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'sp/src/utils/motionmapper/motionmapper.cpp')
-rw-r--r--sp/src/utils/motionmapper/motionmapper.cpp6544
1 files changed, 3272 insertions, 3272 deletions
diff --git a/sp/src/utils/motionmapper/motionmapper.cpp b/sp/src/utils/motionmapper/motionmapper.cpp
index 6961e8ec..6825ef39 100644
--- a/sp/src/utils/motionmapper/motionmapper.cpp
+++ b/sp/src/utils/motionmapper/motionmapper.cpp
@@ -1,3272 +1,3272 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <math.h>
-#include "filesystem_tools.h"
-#include "cmdlib.h"
-#include "scriplib.h"
-#include "mathlib/mathlib.h"
-#define EXTERN
-#include "studio.h"
-#include "motionmapper.h"
-#include "tier1/strtools.h"
-#include "tier0/icommandline.h"
-#include "utldict.h"
-#include <windows.h>
-#include "UtlBuffer.h"
-#include "utlsymbol.h"
-
-bool g_quiet = false;
-bool g_verbose = false;
-char g_outfile[1024];
-bool uselogfile = false;
-
-char g_szFilename[1024];
-FILE *g_fpInput;
-char g_szLine[4096];
-int g_iLinecount;
-
-bool g_bZBrush = false;
-bool g_bGaveMissingBoneWarning = false;
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : depth -
-// *fmt -
-// ... -
-//-----------------------------------------------------------------------------
-void vprint( int depth, const char *fmt, ... )
-{
- char string[ 8192 ];
- va_list va;
- va_start( va, fmt );
- V_vsprintf_safe( string, fmt, va );
- va_end( va );
-
- FILE *fp = NULL;
-
- if ( uselogfile )
- {
- fp = fopen( "log.txt", "ab" );
- }
-
- while ( depth-- > 0 )
- {
- vprint( 0, " " );
- OutputDebugString( " " );
- if ( fp )
- {
- fprintf( fp, " " );
- }
- }
-
- ::printf( "%s", string );
- OutputDebugString( string );
-
- if ( fp )
- {
- char *p = string;
- while ( *p )
- {
- if ( *p == '\n' )
- {
- fputc( '\r', fp );
- }
- fputc( *p, fp );
- p++;
- }
- fclose( fp );
- }
-}
-
-
-int k_memtotal;
-void *kalloc( int num, int size )
-{
- // vprint( 0, "calloc( %d, %d )\n", num, size );
- // vprint( 0, "%d ", num * size );
- k_memtotal += num * size;
- return calloc( num, size );
-}
-
-void kmemset( void *ptr, int value, int size )
-{
- // vprint( 0, "kmemset( %x, %d, %d )\n", ptr, value, size );
- memset( ptr, value, size );
- return;
-}
-
-static bool g_bFirstWarning = true;
-
-void MdlWarning( const char *fmt, ... )
-{
- va_list args;
- static char output[1024];
-
- if (g_quiet)
- {
- if (g_bFirstWarning)
- {
- vprint( 0, "%s :\n", fullpath );
- g_bFirstWarning = false;
- }
- vprint( 0, "\t");
- }
-
- vprint( 0, "WARNING: ");
- va_start( args, fmt );
- vprint( 0, fmt, args );
-}
-
-
-void MdlError( char const *fmt, ... )
-{
- va_list args;
-
- if (g_quiet)
- {
- if (g_bFirstWarning)
- {
- vprint( 0, "%s :\n", fullpath );
- g_bFirstWarning = false;
- }
- vprint( 0, "\t");
- }
-
- vprint( 0, "ERROR: ");
- va_start( args, fmt );
- vprint( 0, fmt, args );
-
- exit( -1 );
-}
-
-int OpenGlobalFile( char *src )
-{
- int time1;
- char filename[1024];
-
- // local copy of string
- strcpy( filename, ExpandPath( src ) );
-
- // Ummm, path sanity checking
- int pathLength;
- int numBasePaths = CmdLib_GetNumBasePaths();
- // This is kinda gross. . . doing the same work in cmdlib on SafeOpenRead.
- if( CmdLib_HasBasePath( filename, pathLength ) )
- {
- char tmp[1024];
- int i;
- for( i = 0; i < numBasePaths; i++ )
- {
- strcpy( tmp, CmdLib_GetBasePath( i ) );
- strcat( tmp, filename + pathLength );
-
- time1 = FileTime( tmp );
- if( time1 != -1 )
- {
- if ((g_fpInput = fopen(tmp, "r")) == 0)
- {
- MdlWarning( "reader: could not open file '%s'\n", src );
- return 0;
- }
- else
- {
- return 1;
- }
- }
- }
- return 0;
- }
- else
- {
- time1 = FileTime (filename);
- if (time1 == -1)
- return 0;
-
- // Whoohooo, FOPEN!
- if ((g_fpInput = fopen(filename, "r")) == 0)
- {
- MdlWarning( "reader: could not open file '%s'\n", src );
- return 0;
- }
-
- return 1;
- }
-}
-
-bool IsEnd( char const* pLine )
-{
- if (strncmp( "end", pLine, 3 ) != 0)
- return false;
- return (pLine[3] == '\0') || (pLine[3] == '\n');
-}
-
-
-//Wrong name for the use of it.
-void scale_vertex( Vector &org )
-{
- org[0] = org[0] * g_currentscale;
- org[1] = org[1] * g_currentscale;
- org[2] = org[2] * g_currentscale;
-}
-
-
-void clip_rotations( RadianEuler& rot )
-{
- int j;
- // clip everything to : -M_PI <= x < M_PI
-
- for (j = 0; j < 3; j++) {
- while (rot[j] >= M_PI)
- rot[j] -= M_PI*2;
- while (rot[j] < -M_PI)
- rot[j] += M_PI*2;
- }
-}
-
-
-void clip_rotations( Vector& rot )
-{
- int j;
- // clip everything to : -180 <= x < 180
-
- for (j = 0; j < 3; j++) {
- while (rot[j] >= 180)
- rot[j] -= 180*2;
- while (rot[j] < -180)
- rot[j] += 180*2;
- }
-}
-
-
-void Build_Reference( s_source_t *psource)
-{
- int i, parent;
- Vector angle;
-
- for (i = 0; i < psource->numbones; i++)
- {
- matrix3x4_t m;
- AngleMatrix( psource->rawanim[0][i].rot, m );
- m[0][3] = psource->rawanim[0][i].pos[0];
- m[1][3] = psource->rawanim[0][i].pos[1];
- m[2][3] = psource->rawanim[0][i].pos[2];
-
- parent = psource->localBone[i].parent;
- if (parent == -1)
- {
- // scale the done pos.
- // calc rotational matrices
- MatrixCopy( m, psource->boneToPose[i] );
- }
- else
- {
- // calc compound rotational matrices
- // FIXME : Hey, it's orthogical so inv(A) == transpose(A)
- ConcatTransforms( psource->boneToPose[parent], m, psource->boneToPose[i] );
- }
- // vprint( 0, "%3d %f %f %f\n", i, psource->bonefixup[i].worldorg[0], psource->bonefixup[i].worldorg[1], psource->bonefixup[i].worldorg[2] );
- /*
- AngleMatrix( angle, m );
- vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][0], m[1][0], m[2][0] );
- vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][1], m[1][1], m[2][1] );
- vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][2], m[1][2], m[2][2] );
- */
- }
-}
-
-int Grab_Nodes( s_node_t *pnodes )
-{
- //
- // s_node_t structure: index is index!!
- //
- int index;
- char name[1024];
- int parent;
- int numbones = 0;
-
- // Init parent to none
- for (index = 0; index < MAXSTUDIOSRCBONES; index++)
- {
- pnodes[index].parent = -1;
- }
-
- // March through nodes lines
- while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
- {
- g_iLinecount++;
- // get tokens
- if (sscanf( g_szLine, "%d \"%[^\"]\" %d", &index, name, &parent ) == 3)
- {
- // check for duplicated bones
- /*
- if (strlen(pnodes[index].name) != 0)
- {
- MdlError( "bone \"%s\" exists more than once\n", name );
- }
- */
- // copy name to struct array
- V_strcpy_safe( pnodes[index].name, name );
- // set parent into struct array
- pnodes[index].parent = parent;
- // increment numbones
- if (index > numbones)
- {
- numbones = index;
- }
- }
- else
- {
- return numbones + 1;
- }
- }
- MdlError( "Unexpected EOF at line %d\n", g_iLinecount );
- return 0;
-}
-
-void Grab_Vertexanimation( s_source_t *psource )
-{
- char cmd[1024];
- int index;
- Vector pos;
- Vector normal;
- int t = -1;
- int count = 0;
- static s_vertanim_t tmpvanim[MAXSTUDIOVERTS*4];
-
- while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
- {
- g_iLinecount++;
- if (sscanf( g_szLine, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &normal[0], &normal[1], &normal[2] ) == 7)
- {
- if (psource->startframe < 0)
- {
- MdlError( "Missing frame start(%d) : %s", g_iLinecount, g_szLine );
- }
-
- if (t < 0)
- {
- MdlError( "VTA Frame Sync (%d) : %s", g_iLinecount, g_szLine );
- }
-
- tmpvanim[count].vertex = index;
- VectorCopy( pos, tmpvanim[count].pos );
- VectorCopy( normal, tmpvanim[count].normal );
- count++;
-
- if (index >= psource->numvertices)
- psource->numvertices = index + 1;
- }
- else
- {
- // flush data
-
- if (count)
- {
- psource->numvanims[t] = count;
-
- psource->vanim[t] = (s_vertanim_t *)kalloc( count, sizeof( s_vertanim_t ) );
-
- memcpy( psource->vanim[t], tmpvanim, count * sizeof( s_vertanim_t ) );
- }
- else if (t > 0)
- {
- psource->numvanims[t] = 0;
- }
-
- // next command
- if (sscanf( g_szLine, "%1023s %d", cmd, &index ))
- {
- if (strcmp( cmd, "time" ) == 0)
- {
- t = index;
- count = 0;
-
- if (t < psource->startframe)
- {
- MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
- if (t > psource->endframe)
- {
- MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
-
- t -= psource->startframe;
- }
- else if (strcmp( cmd, "end") == 0)
- {
- psource->numframes = psource->endframe - psource->startframe + 1;
- return;
- }
- else
- {
- MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
-
- }
- else
- {
- MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
- }
- }
- MdlError( "unexpected EOF: %s\n", psource->filename );
-}
-
-void Grab_Animation( s_source_t *psource )
-{
- Vector pos;
- RadianEuler rot;
- char cmd[1024];
- int index;
- int t = -99999999;
- int size;
-
- // Init startframe
- psource->startframe = -1;
-
- // size per frame
- size = psource->numbones * sizeof( s_bone_t );
-
- // march through animation
- while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
- {
- // linecount
- g_iLinecount++;
- // split if big enoough
- if (sscanf( g_szLine, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &rot[0], &rot[1], &rot[2] ) == 7)
- {
- // startframe is sanity check for having determined time
- if (psource->startframe < 0)
- {
- MdlError( "Missing frame start(%d) : %s", g_iLinecount, g_szLine );
- }
-
- // scale if pertinent
- scale_vertex( pos );
- VectorCopy( pos, psource->rawanim[t][index].pos );
- VectorCopy( rot, psource->rawanim[t][index].rot );
-
- clip_rotations( rot ); // !!!
- }
- else if (sscanf( g_szLine, "%1023s %d", cmd, &index ))
- {
- // get time
- if (strcmp( cmd, "time" ) == 0)
- {
- // again time IS an index
- t = index;
- if (psource->startframe == -1)
- {
- psource->startframe = t;
- }
- // sanity check time (little funny logic here, see previous IF)
- if (t < psource->startframe)
- {
- MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
- // bump up endframe?
- if (t > psource->endframe)
- {
- psource->endframe = t;
- }
- // make t into pure index
- t -= psource->startframe;
-
- // check for memory allocation
- if (psource->rawanim[t] == NULL)
- {
- // Allocate 1 frame of full bonecount
- psource->rawanim[t] = (s_bone_t *)kalloc( 1, size );
-
- // duplicate previous frames keys?? preventative sanity?
- if (t > 0 && psource->rawanim[t-1])
- {
- for (int j = 0; j < psource->numbones; j++)
- {
- VectorCopy( psource->rawanim[t-1][j].pos, psource->rawanim[t][j].pos );
- VectorCopy( psource->rawanim[t-1][j].rot, psource->rawanim[t][j].rot );
- }
- }
- }
- else
- {
- // MdlError( "%s has duplicated frame %d\n", psource->filename, t );
- }
- }
- else if (strcmp( cmd, "end") == 0)
- {
- psource->numframes = psource->endframe - psource->startframe + 1;
-
- for (t = 0; t < psource->numframes; t++)
- {
- if (psource->rawanim[t] == NULL)
- {
- MdlError( "%s is missing frame %d\n", psource->filename, t + psource->startframe );
- }
- }
-
- Build_Reference( psource );
- return;
- }
- else
- {
- MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
- }
- else
- {
- MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
- }
- }
-
- MdlError( "unexpected EOF: %s\n", psource->filename );
-}
-
-int lookup_index( s_source_t *psource, int material, Vector& vertex, Vector& normal, Vector2D texcoord )
-{
- int i;
-
- for (i = 0; i < numvlist; i++)
- {
- if (v_listdata[i].m == material
- && DotProduct( g_normal[i], normal ) > normal_blend
- && VectorCompare( g_vertex[i], vertex )
- && g_texcoord[i][0] == texcoord[0]
- && g_texcoord[i][1] == texcoord[1])
- {
- v_listdata[i].lastref = numvlist;
- return i;
- }
- }
- if (i >= MAXSTUDIOVERTS) {
- MdlError( "too many indices in source: \"%s\"\n", psource->filename);
- }
-
- VectorCopy( vertex, g_vertex[i] );
- VectorCopy( normal, g_normal[i] );
- Vector2Copy( texcoord, g_texcoord[i] );
-
- v_listdata[i].v = i;
- v_listdata[i].m = material;
- v_listdata[i].n = i;
- v_listdata[i].t = i;
-
- v_listdata[i].firstref = numvlist;
- v_listdata[i].lastref = numvlist;
-
- numvlist = i + 1;
- return i;
-}
-
-
-void ParseFaceData( s_source_t *psource, int material, s_face_t *pFace )
-{
- int index[3];
- int i, j;
- Vector p;
- Vector normal;
- Vector2D t;
- int iCount, bones[MAXSTUDIOSRCBONES];
- float weights[MAXSTUDIOSRCBONES];
- int bone;
-
- for (j = 0; j < 3; j++)
- {
- memset( g_szLine, 0, sizeof( g_szLine ) );
-
- if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) == NULL)
- {
- MdlError("%s: error on g_szLine %d: %s", g_szFilename, g_iLinecount, g_szLine );
- }
-
- iCount = 0;
-
- g_iLinecount++;
- i = sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %d %d %f %d %f %d %f %d %f",
- &bone,
- &p[0], &p[1], &p[2],
- &normal[0], &normal[1], &normal[2],
- &t[0], &t[1],
- &iCount,
- &bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
-
- if (i < 9)
- continue;
-
- if (bone < 0 || bone >= psource->numbones)
- {
- MdlError("bogus bone index\n%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
- }
-
- //Scale face pos
- scale_vertex( p );
-
- // continue parsing more bones.
- // FIXME: don't we have a built in parser that'll do this?
- if (iCount > 4)
- {
- int k;
- int ctr = 0;
- char *token;
- for (k = 0; k < 18; k++)
- {
- while (g_szLine[ctr] == ' ')
- {
- ctr++;
- }
- token = strtok( &g_szLine[ctr], " " );
- ctr += strlen( token ) + 1;
- }
- for (k = 4; k < iCount && k < MAXSTUDIOSRCBONES; k++)
- {
- while (g_szLine[ctr] == ' ')
- {
- ctr++;
- }
- token = strtok( &g_szLine[ctr], " " );
- ctr += strlen( token ) + 1;
-
- bones[k] = atoi(token);
-
- token = strtok( &g_szLine[ctr], " " );
- ctr += strlen( token ) + 1;
-
- weights[k] = atof(token);
- }
- // vprint( 0, "%d ", iCount );
-
- //vprint( 0, "\n");
- //exit(1);
- }
-
- // adjust_vertex( p );
- // scale_vertex( p );
-
- // move vertex position to object space.
- // VectorSubtract( p, psource->bonefixup[bone].worldorg, tmp );
- // VectorTransform(tmp, psource->bonefixup[bone].im, p );
-
- // move normal to object space.
- // VectorCopy( normal, tmp );
- // VectorTransform(tmp, psource->bonefixup[bone].im, normal );
- // VectorNormalize( normal );
-
- // invert v
- t[1] = 1.0 - t[1];
-
- index[j] = lookup_index( psource, material, p, normal, t );
-
- if (i == 9 || iCount == 0)
- {
- g_bone[index[j]].numbones = 1;
- g_bone[index[j]].bone[0] = bone;
- g_bone[index[j]].weight[0] = 1.0;
- }
- else
- {
- iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
-
- g_bone[index[j]].numbones = iCount;
- for (i = 0; i < iCount; i++)
- {
- g_bone[index[j]].bone[i] = bones[i];
- g_bone[index[j]].weight[i] = weights[i];
- }
- }
- }
-
- // pFace->material = material; // BUG
- pFace->a = index[0];
- pFace->b = index[1];
- pFace->c = index[2];
- Assert( ((pFace->a & 0xF0000000) == 0) && ((pFace->b & 0xF0000000) == 0) &&
- ((pFace->c & 0xF0000000) == 0) );
-
- if (flip_triangles)
- {
- j = pFace->b; pFace->b = pFace->c; pFace->c = j;
- }
-}
-
-int use_texture_as_material( int textureindex )
-{
- if (g_texture[textureindex].material == -1)
- {
- // vprint( 0, "%d %d %s\n", textureindex, g_nummaterials, g_texture[textureindex].name );
- g_material[g_nummaterials] = textureindex;
- g_texture[textureindex].material = g_nummaterials++;
- }
-
- return g_texture[textureindex].material;
-}
-
-int material_to_texture( int material )
-{
- int i;
- for (i = 0; i < g_numtextures; i++)
- {
- if (g_texture[i].material == material)
- {
- return i;
- }
- }
- return -1;
-}
-
-int lookup_texture( char *texturename, int maxlen )
-{
- int i;
-
- Q_StripExtension( texturename, texturename, maxlen );
-
- for (i = 0; i < g_numtextures; i++)
- {
- if (stricmp( g_texture[i].name, texturename ) == 0)
- {
- return i;
- }
- }
-
- if (i >= MAXSTUDIOSKINS)
- MdlError("Too many materials used, max %d\n", ( int )MAXSTUDIOSKINS );
-
-// vprint( 0, "texture %d = %s\n", i, texturename );
- V_strcpy_safe( g_texture[i].name, texturename );
-
- g_texture[i].material = -1;
- /*
- if (stristr( texturename, "chrome" ) != NULL) {
- texture[i].flags = STUDIO_NF_FLATSHADE | STUDIO_NF_CHROME;
- }
- else {
- texture[i].flags = 0;
- }
- */
- g_numtextures++;
- return i;
-}
-
-int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] )
-{
- int i;
-
- // collapse duplicate bone weights
- for (i = 0; i < iCount-1; i++)
- {
- int j;
- for (j = i + 1; j < iCount; j++)
- {
- if (bones[i] == bones[j])
- {
- weights[i] += weights[j];
- weights[j] = 0.0;
- }
- }
- }
-
- // do sleazy bubble sort
- int bShouldSort;
- do {
- bShouldSort = false;
- for (i = 0; i < iCount-1; i++)
- {
- if (weights[i+1] > weights[i])
- {
- int j = bones[i+1]; bones[i+1] = bones[i]; bones[i] = j;
- float w = weights[i+1]; weights[i+1] = weights[i]; weights[i] = w;
- bShouldSort = true;
- }
- }
- } while (bShouldSort);
-
- // throw away all weights less than 1/20th
- while (iCount > 1 && weights[iCount-1] < 0.05)
- {
- iCount--;
- }
-
- // clip to the top iMaxCount bones
- if (iCount > iMaxCount)
- {
- iCount = iMaxCount;
- }
-
- float t = 0;
- for (i = 0; i < iCount; i++)
- {
- t += weights[i];
- }
-
- if (t <= 0.0)
- {
- // missing weights?, go ahead and evenly share?
- // FIXME: shouldn't this error out?
- t = 1.0 / iCount;
-
- for (i = 0; i < iCount; i++)
- {
- weights[i] = t;
- }
- }
- else
- {
- // scale to sum to 1.0
- t = 1.0 / t;
-
- for (i = 0; i < iCount; i++)
- {
- weights[i] = weights[i] * t;
- }
- }
-
- return iCount;
-}
-
-int vlistCompare( const void *elem1, const void *elem2 )
-{
- v_unify_t *u1 = &v_listdata[*(int *)elem1];
- v_unify_t *u2 = &v_listdata[*(int *)elem2];
-
- // sort by material
- if (u1->m < u2->m)
- return -1;
- if (u1->m > u2->m)
- return 1;
-
- // sort by last used
- if (u1->lastref < u2->lastref)
- return -1;
- if (u1->lastref > u2->lastref)
- return 1;
-
- return 0;
-}
-
-int faceCompare( const void *elem1, const void *elem2 )
-{
- int i1 = *(int *)elem1;
- int i2 = *(int *)elem2;
-
- // sort by material
- if (g_face[i1].material < g_face[i2].material)
- return -1;
- if (g_face[i1].material > g_face[i2].material)
- return 1;
-
- // sort by original usage
- if (i1 < i2)
- return -1;
- if (i1 > i2)
- return 1;
-
- return 0;
-}
-
-#define SMALL_FLOAT 1e-12
-
-// NOTE: This routine was taken (and modified) from NVidia's BlinnReflection demo
-// Creates basis vectors, based on a vertex and index list.
-// See the NVidia white paper 'GDC2K PerPixel Lighting' for a description
-// of how this computation works
-static void CalcTriangleTangentSpace( s_source_t *pSrc, int v1, int v2, int v3,
- Vector &sVect, Vector &tVect )
-{
-/*
- static bool firstTime = true;
- static FILE *fp = NULL;
- if( firstTime )
- {
- firstTime = false;
- fp = fopen( "crap.out", "w" );
- }
-*/
-
- /* Compute the partial derivatives of X, Y, and Z with respect to S and T. */
- Vector2D t0( pSrc->texcoord[v1][0], pSrc->texcoord[v1][1] );
- Vector2D t1( pSrc->texcoord[v2][0], pSrc->texcoord[v2][1] );
- Vector2D t2( pSrc->texcoord[v3][0], pSrc->texcoord[v3][1] );
- Vector p0( pSrc->vertex[v1][0], pSrc->vertex[v1][1], pSrc->vertex[v1][2] );
- Vector p1( pSrc->vertex[v2][0], pSrc->vertex[v2][1], pSrc->vertex[v2][2] );
- Vector p2( pSrc->vertex[v3][0], pSrc->vertex[v3][1], pSrc->vertex[v3][2] );
-
- sVect.Init( 0.0f, 0.0f, 0.0f );
- tVect.Init( 0.0f, 0.0f, 0.0f );
-
- // x, s, t
- Vector edge01 = Vector( p1.x - p0.x, t1.x - t0.x, t1.y - t0.y );
- Vector edge02 = Vector( p2.x - p0.x, t2.x - t0.x, t2.y - t0.y );
-
- Vector cross;
- CrossProduct( edge01, edge02, cross );
- if( fabs( cross.x ) > SMALL_FLOAT )
- {
- sVect.x += -cross.y / cross.x;
- tVect.x += -cross.z / cross.x;
- }
-
- // y, s, t
- edge01 = Vector( p1.y - p0.y, t1.x - t0.x, t1.y - t0.y );
- edge02 = Vector( p2.y - p0.y, t2.x - t0.x, t2.y - t0.y );
-
- CrossProduct( edge01, edge02, cross );
- if( fabs( cross.x ) > SMALL_FLOAT )
- {
- sVect.y += -cross.y / cross.x;
- tVect.y += -cross.z / cross.x;
- }
-
- // z, s, t
- edge01 = Vector( p1.z - p0.z, t1.x - t0.x, t1.y - t0.y );
- edge02 = Vector( p2.z - p0.z, t2.x - t0.x, t2.y - t0.y );
-
- CrossProduct( edge01, edge02, cross );
- if( fabs( cross.x ) > SMALL_FLOAT )
- {
- sVect.z += -cross.y / cross.x;
- tVect.z += -cross.z / cross.x;
- }
-
- // Normalize sVect and tVect
- VectorNormalize( sVect );
- VectorNormalize( tVect );
-
-/*
- // Calculate flat normal
- Vector flatNormal;
- edge01 = p1 - p0;
- edge02 = p2 - p0;
- CrossProduct( edge02, edge01, flatNormal );
- VectorNormalize( flatNormal );
-
- // Get the average position
- Vector avgPos = ( p0 + p1 + p2 ) / 3.0f;
-
- // Draw the svect
- Vector endS = avgPos + sVect * .2f;
- fvprint( 0, fp, "2\n" );
- fvprint( 0, fp, "%f %f %f 1.0 0.0 0.0\n", endS[0], endS[1], endS[2] );
- fvprint( 0, fp, "%f %f %f 1.0 0.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
-
- // Draw the tvect
- Vector endT = avgPos + tVect * .2f;
- fvprint( 0, fp, "2\n" );
- fvprint( 0, fp, "%f %f %f 0.0 1.0 0.0\n", endT[0], endT[1], endT[2] );
- fvprint( 0, fp, "%f %f %f 0.0 1.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
-
- // Draw the normal
- Vector endN = avgPos + flatNormal * .2f;
- fvprint( 0, fp, "2\n" );
- fvprint( 0, fp, "%f %f %f 0.0 0.0 1.0\n", endN[0], endN[1], endN[2] );
- fvprint( 0, fp, "%f %f %f 0.0 0.0 1.0\n", avgPos[0], avgPos[1], avgPos[2] );
-
- // Draw the wireframe of the triangle in white.
- fvprint( 0, fp, "2\n" );
- fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
- fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
- fvprint( 0, fp, "2\n" );
- fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
- fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
- fvprint( 0, fp, "2\n" );
- fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
- fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
-
- // Draw a slightly shrunken version of the geometry to hide surfaces
- Vector tmp0 = p0 - flatNormal * .1f;
- Vector tmp1 = p1 - flatNormal * .1f;
- Vector tmp2 = p2 - flatNormal * .1f;
- fvprint( 0, fp, "3\n" );
- fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp0[0], tmp0[1], tmp0[2] );
- fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp1[0], tmp1[1], tmp1[2] );
- fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp2[0], tmp2[1], tmp2[2] );
-
- fflush( fp );
-*/
-}
-
-typedef CUtlVector<int> CIntVector;
-
-void CalcModelTangentSpaces( s_source_t *pSrc )
-{
- // Build a map from vertex to a list of triangles that share the vert.
- int meshID;
- for( meshID = 0; meshID < pSrc->nummeshes; meshID++ )
- {
- s_mesh_t *pMesh = &pSrc->mesh[pSrc->meshindex[meshID]];
- CUtlVector<CIntVector> vertToTriMap;
- vertToTriMap.AddMultipleToTail( pMesh->numvertices );
- int triID;
- for( triID = 0; triID < pMesh->numfaces; triID++ )
- {
- s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
- vertToTriMap[pFace->a].AddToTail( triID );
- vertToTriMap[pFace->b].AddToTail( triID );
- vertToTriMap[pFace->c].AddToTail( triID );
- }
-
- // Calculate the tangent space for each triangle.
- CUtlVector<Vector> triSVect;
- CUtlVector<Vector> triTVect;
- triSVect.AddMultipleToTail( pMesh->numfaces );
- triTVect.AddMultipleToTail( pMesh->numfaces );
- for( triID = 0; triID < pMesh->numfaces; triID++ )
- {
- s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
- CalcTriangleTangentSpace( pSrc,
- pMesh->vertexoffset + pFace->a,
- pMesh->vertexoffset + pFace->b,
- pMesh->vertexoffset + pFace->c,
- triSVect[triID], triTVect[triID] );
- }
-
- // calculate an average tangent space for each vertex.
- int vertID;
- for( vertID = 0; vertID < pMesh->numvertices; vertID++ )
- {
- const Vector &normal = pSrc->normal[vertID+pMesh->vertexoffset];
- Vector4D &finalSVect = pSrc->tangentS[vertID+pMesh->vertexoffset];
- Vector sVect, tVect;
-
- sVect.Init( 0.0f, 0.0f, 0.0f );
- tVect.Init( 0.0f, 0.0f, 0.0f );
- for( triID = 0; triID < vertToTriMap[vertID].Size(); triID++ )
- {
- sVect += triSVect[vertToTriMap[vertID][triID]];
- tVect += triTVect[vertToTriMap[vertID][triID]];
- }
-
- // In the case of zbrush, everything needs to be treated as smooth.
- if( g_bZBrush )
- {
- int vertID2;
- Vector vertPos1( pSrc->vertex[vertID][0], pSrc->vertex[vertID][1], pSrc->vertex[vertID][2] );
- for( vertID2 = 0; vertID2 < pMesh->numvertices; vertID2++ )
- {
- if( vertID2 == vertID )
- {
- continue;
- }
- Vector vertPos2( pSrc->vertex[vertID2][0], pSrc->vertex[vertID2][1], pSrc->vertex[vertID2][2] );
- if( vertPos1 == vertPos2 )
- {
- int triID2;
- for( triID2 = 0; triID2 < vertToTriMap[vertID2].Size(); triID2++ )
- {
- sVect += triSVect[vertToTriMap[vertID2][triID2]];
- tVect += triTVect[vertToTriMap[vertID2][triID2]];
- }
- }
- }
- }
-
- // make an orthonormal system.
- // need to check if we are left or right handed.
- Vector tmpVect;
- CrossProduct( sVect, tVect, tmpVect );
- bool leftHanded = DotProduct( tmpVect, normal ) < 0.0f;
- if( !leftHanded )
- {
- CrossProduct( normal, sVect, tVect );
- CrossProduct( tVect, normal, sVect );
- VectorNormalize( sVect );
- VectorNormalize( tVect );
- finalSVect[0] = sVect[0];
- finalSVect[1] = sVect[1];
- finalSVect[2] = sVect[2];
- finalSVect[3] = 1.0f;
- }
- else
- {
- CrossProduct( sVect, normal, tVect );
- CrossProduct( normal, tVect, sVect );
- VectorNormalize( sVect );
- VectorNormalize( tVect );
- finalSVect[0] = sVect[0];
- finalSVect[1] = sVect[1];
- finalSVect[2] = sVect[2];
- finalSVect[3] = -1.0f;
- }
- }
- }
-}
-
-void BuildIndividualMeshes( s_source_t *psource )
-{
- int i, j, k;
-
- // sort new vertices by materials, last used
- static int v_listsort[MAXSTUDIOVERTS]; // map desired order to vlist entry
- static int v_ilistsort[MAXSTUDIOVERTS]; // map vlist entry to desired order
-
- for (i = 0; i < numvlist; i++)
- {
- v_listsort[i] = i;
- }
- qsort( v_listsort, numvlist, sizeof( int ), vlistCompare );
- for (i = 0; i < numvlist; i++)
- {
- v_ilistsort[v_listsort[i]] = i;
- }
-
-
- // allocate memory
- psource->numvertices = numvlist;
- psource->localBoneweight = (s_boneweight_t *)kalloc( psource->numvertices, sizeof( s_boneweight_t ) );
- psource->globalBoneweight = NULL;
- psource->vertexInfo = (s_vertexinfo_t *)kalloc( psource->numvertices, sizeof( s_vertexinfo_t ) );
- psource->vertex = new Vector[psource->numvertices];
- psource->normal = new Vector[psource->numvertices];
- psource->tangentS = new Vector4D[psource->numvertices];
- psource->texcoord = (Vector2D *)kalloc( psource->numvertices, sizeof( Vector2D ) );
-
- // create arrays of unique vertexes, normals, texcoords.
- for (i = 0; i < psource->numvertices; i++)
- {
- j = v_listsort[i];
-
- VectorCopy( g_vertex[v_listdata[j].v], psource->vertex[i] );
- VectorCopy( g_normal[v_listdata[j].n], psource->normal[i] );
- Vector2Copy( g_texcoord[v_listdata[j].t], psource->texcoord[i] );
-
- psource->localBoneweight[i].numbones = g_bone[v_listdata[j].v].numbones;
- int k;
- for( k = 0; k < MAXSTUDIOBONEWEIGHTS; k++ )
- {
- psource->localBoneweight[i].bone[k] = g_bone[v_listdata[j].v].bone[k];
- psource->localBoneweight[i].weight[k] = g_bone[v_listdata[j].v].weight[k];
- }
-
- // store a bunch of other info
- psource->vertexInfo[i].material = v_listdata[j].m;
-
- psource->vertexInfo[i].firstref = v_listdata[j].firstref;
- psource->vertexInfo[i].lastref = v_listdata[j].lastref;
- // vprint( 0, "%4d : %2d : %6.2f %6.2f %6.2f\n", i, psource->boneweight[i].bone[0], psource->vertex[i][0], psource->vertex[i][1], psource->vertex[i][2] );
- }
-
- // sort faces by materials, last used.
- static int facesort[MAXSTUDIOTRIANGLES]; // map desired order to src_face entry
- static int ifacesort[MAXSTUDIOTRIANGLES]; // map src_face entry to desired order
-
- for (i = 0; i < g_numfaces; i++)
- {
- facesort[i] = i;
- }
- qsort( facesort, g_numfaces, sizeof( int ), faceCompare );
- for (i = 0; i < g_numfaces; i++)
- {
- ifacesort[facesort[i]] = i;
- }
-
- psource->numfaces = g_numfaces;
- // find first occurance for each material
- for (k = 0; k < MAXSTUDIOSKINS; k++)
- {
- psource->mesh[k].numvertices = 0;
- psource->mesh[k].vertexoffset = psource->numvertices;
-
- psource->mesh[k].numfaces = 0;
- psource->mesh[k].faceoffset = g_numfaces;
- }
-
- // find first and count of indices per material
- for (i = 0; i < psource->numvertices; i++)
- {
- k = psource->vertexInfo[i].material;
- psource->mesh[k].numvertices++;
- if (psource->mesh[k].vertexoffset > i)
- psource->mesh[k].vertexoffset = i;
- }
-
- // find first and count of faces per material
- for (i = 0; i < psource->numfaces; i++)
- {
- k = g_face[facesort[i]].material;
-
- psource->mesh[k].numfaces++;
- if (psource->mesh[k].faceoffset > i)
- psource->mesh[k].faceoffset = i;
- }
-
- /*
- for (k = 0; k < MAXSTUDIOSKINS; k++)
- {
- vprint( 0, "%d : %d:%d %d:%d\n", k, psource->mesh[k].numvertices, psource->mesh[k].vertexoffset, psource->mesh[k].numfaces, psource->mesh[k].faceoffset );
- }
- */
-
- // create remapped faces
- psource->face = (s_face_t *)kalloc( psource->numfaces, sizeof( s_face_t ));
- for (k = 0; k < MAXSTUDIOSKINS; k++)
- {
- if (psource->mesh[k].numfaces)
- {
- psource->meshindex[psource->nummeshes] = k;
-
- for (i = psource->mesh[k].faceoffset; i < psource->mesh[k].numfaces + psource->mesh[k].faceoffset; i++)
- {
- j = facesort[i];
-
- psource->face[i].a = v_ilistsort[g_src_uface[j].a] - psource->mesh[k].vertexoffset;
- psource->face[i].b = v_ilistsort[g_src_uface[j].b] - psource->mesh[k].vertexoffset;
- psource->face[i].c = v_ilistsort[g_src_uface[j].c] - psource->mesh[k].vertexoffset;
- Assert( ((psource->face[i].a & 0xF0000000) == 0) && ((psource->face[i].b & 0xF0000000) == 0) &&
- ((psource->face[i].c & 0xF0000000) == 0) );
- // vprint( 0, "%3d : %4d %4d %4d\n", i, psource->face[i].a, psource->face[i].b, psource->face[i].c );
- }
-
- psource->nummeshes++;
- }
- }
-
- CalcModelTangentSpaces( psource );
-}
-
-void Grab_Triangles( s_source_t *psource )
-{
- int i;
- Vector vmin, vmax;
-
- vmin[0] = vmin[1] = vmin[2] = 99999;
- vmax[0] = vmax[1] = vmax[2] = -99999;
-
- g_numfaces = 0;
- numvlist = 0;
-
- //
- // load the base triangles
- //
- int texture;
- int material;
- char texturename[64];
-
- while (1)
- {
- if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) == NULL)
- break;
-
- g_iLinecount++;
-
- // check for end
- if (IsEnd( g_szLine ))
- break;
-
- // Look for extra junk that we may want to avoid...
- int nLineLength = strlen( g_szLine );
- if (nLineLength >= 64)
- {
- MdlWarning("Unexpected data at line %d, (need a texture name) ignoring...\n", g_iLinecount );
- continue;
- }
-
- // strip off trailing smag
- V_strcpy_safe( texturename, g_szLine );
- for (i = strlen( texturename ) - 1; i >= 0 && ! isgraph( texturename[i] ); i--)
- {
- }
- texturename[i + 1] = '\0';
-
- // funky texture overrides
- for (i = 0; i < numrep; i++)
- {
- if (sourcetexture[i][0] == '\0')
- {
- strcpy( texturename, defaulttexture[i] );
- break;
- }
- if (stricmp( texturename, sourcetexture[i]) == 0)
- {
- strcpy( texturename, defaulttexture[i] );
- break;
- }
- }
-
- if (texturename[0] == '\0')
- {
- // weird source problem, skip them
- fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
- fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
- fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
- g_iLinecount += 3;
- continue;
- }
-
- if (stricmp( texturename, "null.bmp") == 0 || stricmp( texturename, "null.tga") == 0)
- {
- // skip all faces with the null texture on them.
- fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
- fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
- fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
- g_iLinecount += 3;
- continue;
- }
-
- texture = lookup_texture( texturename, sizeof( texturename ) );
- psource->texmap[texture] = texture; // hack, make it 1:1
- material = use_texture_as_material( texture );
-
- s_face_t f;
- ParseFaceData( psource, material, &f );
-
- g_src_uface[g_numfaces] = f;
- g_face[g_numfaces].material = material;
- g_numfaces++;
- }
-
- BuildIndividualMeshes( psource );
-}
-
-//--------------------------------------------------------------------
-// Load a SMD file
-//--------------------------------------------------------------------
-int Load_SMD ( s_source_t *psource )
-{
- char cmd[1024];
- int option;
-
- // Open file
- if (!OpenGlobalFile( psource->filename ))
- return 0;
-
- // verbose
- if( !g_quiet )
- {
- printf ("SMD MODEL %s\n", psource->filename);
- }
-
- //March through lines
- g_iLinecount = 0;
- while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
- {
- g_iLinecount++;
- int numRead = sscanf( g_szLine, "%s %d", cmd, &option );
-
- // Blank line
- if ((numRead == EOF) || (numRead == 0))
- continue;
-
- if (strcmp( cmd, "version" ) == 0)
- {
- if (option != 1)
- {
- MdlError("bad version\n");
- }
- }
- // Get hierarchy?
- else if (strcmp( cmd, "nodes" ) == 0)
- {
- psource->numbones = Grab_Nodes( psource->localBone );
- }
- // Get animation??
- else if (strcmp( cmd, "skeleton" ) == 0)
- {
- Grab_Animation( psource );
- }
- // Geo?
- else if (strcmp( cmd, "triangles" ) == 0)
- {
- Grab_Triangles( psource );
- }
- // Geo animation
- else if (strcmp( cmd, "vertexanimation" ) == 0)
- {
- Grab_Vertexanimation( psource );
- }
- else
- {
- MdlWarning("unknown studio command\n" );
- }
- }
- fclose( g_fpInput );
-
- is_v1support = true;
-
- return 1;
-}
-
-//-----------------------------------------------------------------------------
-// Checks to see if the model source was already loaded
-//-----------------------------------------------------------------------------
-static s_source_t *FindCachedSource( char const* name, char const* xext )
-{
- int i;
-
- if( xext[0] )
- {
- // we know what extension is necessary. . look for it.
- sprintf (g_szFilename, "%s%s.%s", cddir[numdirs], name, xext );
- for (i = 0; i < g_numsources; i++)
- {
- if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
- return g_source[i];
- }
- }
- else
- {
- // we don't know what extension to use, so look for all of 'em.
- sprintf (g_szFilename, "%s%s.vrm", cddir[numdirs], name );
- for (i = 0; i < g_numsources; i++)
- {
- if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
- return g_source[i];
- }
- sprintf (g_szFilename, "%s%s.smd", cddir[numdirs], name );
- for (i = 0; i < g_numsources; i++)
- {
- if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
- return g_source[i];
- }
- /*
- sprintf (g_szFilename, "%s%s.vta", cddir[numdirs], name );
- for (i = 0; i < g_numsources; i++)
- {
- if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
- return g_source[i];
- }
- */
- }
-
- // Not found
- return 0;
-}
-
-static void FlipFacing( s_source_t *pSrc )
-{
- unsigned short tmp;
-
- int i, j;
- for( i = 0; i < pSrc->nummeshes; i++ )
- {
- s_mesh_t *pMesh = &pSrc->mesh[i];
- for( j = 0; j < pMesh->numfaces; j++ )
- {
- s_face_t &f = pSrc->face[pMesh->faceoffset + j];
- tmp = f.b; f.b = f.c; f.c = tmp;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Loads an animation source
-//-----------------------------------------------------------------------------
-
-s_source_t *Load_Source( char const *name, const char *ext, bool reverse, bool isActiveModel )
-{
- // Sanity check number of source files
- if ( g_numsources >= MAXSTUDIOSEQUENCES )
- MdlError( "Load_Source( %s ) - overflowed g_numsources.", name );
-
- // Sanity check file and init
- Assert(name);
- int namelen = strlen(name) + 1;
- char* pTempName = (char*)_alloca( namelen );
- char xext[32];
- int result = false;
-
- // Local copy of filename
- strcpy( pTempName, name );
-
- // Sanity check file extension?
- Q_ExtractFileExtension( pTempName, xext, sizeof( xext ) );
- if (xext[0] == '\0')
- {
- V_strcpy_safe( xext, ext );
- }
- else
- {
- Q_StripExtension( pTempName, pTempName, namelen );
- }
-
- // Cached source, ie: already loaded model, legacy
- // s_source_t* pSource = FindCachedSource( pTempName, xext );
- // if (pSource)
- // {
- // if (isActiveModel)
- // pSource->isActiveModel = true;
- // return pSource;
- // }
-
- // allocate space and whatnot
- g_source[g_numsources] = (s_source_t *)kalloc( 1, sizeof( s_source_t ) );
- V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
-
- // legacy stuff
- if (isActiveModel)
- {
- g_source[g_numsources]->isActiveModel = true;
- }
-
- // more ext sanity check
- if ( ( !result && xext[0] == '\0' ) || stricmp( xext, "smd" ) == 0)
- {
- Q_snprintf( g_szFilename, sizeof(g_szFilename), "%s%s.smd", cddir[numdirs], pTempName );
- V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
-
- // Import part, load smd file
- result = Load_SMD( g_source[g_numsources] );
- }
-
- /*
- if ( ( !result && xext[0] == '\0' ) || stricmp( xext, "dmx" ) == 0)
- {
- Q_snprintf( g_szFilename, sizeof(g_szFilename), "%s%s.dmx", cddir[numdirs], pTempName );
- V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
-
- // Import part, load smd file
- result = Load_DMX( g_source[g_numsources] );
- }
- */
-
- // Oops
- if ( !result)
- {
- MdlError( "could not load file '%s'\n", g_source[g_numsources]->filename );
- }
-
- // bump up number of sources
- g_numsources++;
- if( reverse )
- {
- FlipFacing( g_source[g_numsources-1] );
- }
- return g_source[g_numsources-1];
-}
-
-void SaveNodes( s_source_t *source, CUtlBuffer& buf )
-{
- if ( source->numbones <= 0 )
- return;
-
- buf.Printf( "nodes\n" );
-
- for ( int i = 0; i < source->numbones; ++i )
- {
- s_node_t *bone = &source->localBone[ i ];
-
- buf.Printf( "%d \"%s\" %d\n", i, bone->name, bone->parent );
- }
-
- buf.Printf( "end\n" );
-}
-
-// FIXME: since we don't us a .qc, we could have problems with scaling, etc.???
-void descale_vertex( Vector &org )
-{
- float invscale = 1.0f / g_currentscale;
-
- org[0] = org[0] * invscale;
- org[1] = org[1] * invscale;
- org[2] = org[2] * invscale;
-}
-
-void SaveAnimation( s_source_t *source, CUtlBuffer& buf )
-{
- if ( source->numbones <= 0 )
- return;
-
- buf.Printf( "skeleton\n" );
-
- for ( int frame = 0; frame < source->numframes; ++frame )
- {
- buf.Printf( "time %i\n", frame + source->startframe );
-
- for ( int i = 0; i < source->numbones; ++i )
- {
- s_bone_t *prev = NULL;
- if ( frame > 0 )
- {
- if ( source->rawanim[ frame - 1 ] )
- {
- prev = &source->rawanim[ frame - 1 ][ i ];
- }
- }
-
- Vector pos = source->rawanim[ frame ][ i ].pos;
- descale_vertex( pos );
- RadianEuler rot = source->rawanim[ frame ][ i ].rot;
-
-// If this is enabled, then we delta this pos vs the prev frame and don't write out a sample if it's the same value...
-#if 0
- if ( prev )
- {
- Vector ppos = source->rawanim[ frame -1 ][ i ].pos;
- descale_vertex( pos );
- RadianEuler prot = source->rawanim[ frame -1 ][ i ].rot;
-
- // Only output it if there's a delta
- if ( ( ppos != pos ) ||
- Q_memcmp( &prot, &rot, sizeof( prot ) ) )
- {
- buf.Printf
- ( "%d %f %f %f %f %f %f\n",
- i, // bone index
- pos[ 0 ],
- pos[ 1 ],
- pos[ 2 ],
- rot[ 0 ],
- rot[ 1 ],
- rot[ 2 ]
- );
- }
- }
- else
-#endif
- {
- buf.Printf
- ( "%d %f %f %f %f %f %f\n",
- i, // bone index
- pos[ 0 ],
- pos[ 1 ],
- pos[ 2 ],
- rot[ 0 ],
- rot[ 1 ],
- rot[ 2 ]
- );
- }
- }
- }
-
- buf.Printf( "end\n" );
-}
-
-void Save_SMD( char const *filename, s_source_t *source )
-{
- // Text buffer
- CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
-
- buf.Printf( "version 1\n" );
-
- SaveNodes( source, buf );
- SaveAnimation( source, buf );
-
- FileHandle_t fh = g_pFileSystem->Open( filename, "wb" );
- if ( FILESYSTEM_INVALID_HANDLE != fh )
- {
- g_pFileSystem->Write( buf.Base(), buf.TellPut(), fh );
- g_pFileSystem->Close( fh );
- }
-}
-
-//--------------------------------------------------------------------
-// mikes right handed row based linear algebra
-//--------------------------------------------------------------------
-struct M_matrix4x4_t
-{
- M_matrix4x4_t() {
-
- m_flMatVal[0][0] = 1.0; m_flMatVal[0][1] = 0.0; m_flMatVal[0][2] = 0.0; m_flMatVal[0][3] = 0.0;
- m_flMatVal[1][0] = 0.0; m_flMatVal[1][1] = 1.0; m_flMatVal[1][2] = 0.0; m_flMatVal[1][3] = 0.0;
- m_flMatVal[2][0] = 0.0; m_flMatVal[2][1] = 0.0; m_flMatVal[2][2] = 1.0; m_flMatVal[2][3] = 0.0;
- m_flMatVal[3][0] = 0.0; m_flMatVal[3][1] = 0.0; m_flMatVal[3][2] = 0.0; m_flMatVal[3][3] = 1.0;
-
- }
- // M_matrix3x4_t(
- // float m00, float m01, float m02,
- // float m10, float m11, float m12,
- // float m20, float m21, float m22,
- // float m30, float m31, float m32)
- // {
- // m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02;
- // m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12;
- // m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22;
- // m_flMatVal[3][0] = m30; m_flMatVal[3][1] = m31; m_flMatVal[3][2] = m32;
-
- // }
-
- float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 4 )); return m_flMatVal[i]; }
- const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 4 )); return m_flMatVal[i]; }
- float *Base() { return &m_flMatVal[0][0]; }
- const float *Base() const { return &m_flMatVal[0][0]; }
-
- float m_flMatVal[4][4];
-};
-
-void M_MatrixAngles( const M_matrix4x4_t& matrix, RadianEuler &angles, Vector &position)
-{
- float cX, sX, cY, sY, cZ, sZ;
-
- sY = -matrix[0][2];
- cY = sqrtf(1.0-(sY*sY));
-
- if (cY != 0.0)
- {
- sX = matrix[1][2];
- cX = matrix[2][2];
- sZ = matrix[0][1];
- cZ = matrix[0][0];
- }
- else
- {
- sX = -matrix[2][1];
- cX = matrix[1][1];
- sZ = 0.0;
- cZ = 1.0;
- }
-
- angles[0] = atan2f( sX, cX );
- angles[2] = atan2f( sZ, cZ );
-
- sX = sinf(angles[0]);
- cX = cosf(angles[0]);
-
- if (sX > cX)
- cY = matrix[1][2] / sX;
- else
- cY = matrix[2][2] / cX;
-
- angles[1] = atan2f( sY, cY );
-
-
- position.x = matrix[3][0];
- position.y = matrix[3][1];
- position.z = matrix[3][2];
-
-}
-
-// void M_MatrixAngles( const M_matrix4x4_t& matrix, RadianEuler &angles, Vector &position)
-// {
-
- // float cX, sX, cY, sY, cZ, sZ;
-
- // sY = matrix[2][0];
- // cY = sqrtf(1.0-(sY*sY));
-
- // if (cY != 0.0)
- // {
- // sX = -matrix[2][1];
- // cX = matrix[2][2];
- // sZ = -matrix[1][0];
- // cZ = matrix[0][0];
- // }
- // else
- // {
- // sX = matrix[0][1];
- // cX = matrix[1][1];
- // sZ = 0.0;
- // cZ = 1.0;
- // }
-
- // angles[0] = atan2f( sX, cX );
- // angles[2] = atan2f( sZ, cZ );
-
- // sX = sinf(angles[0]);
- // cX = cosf(angles[0]);
-
- // if (sX > cX)
- // cY = -matrix[2][1] / sX;
- // else
- // cY = matrix[2][2] / cX;
-
- // angles[1] = atan2f( sY, cY );
-
- // angles[0] = angles[0];
- // angles[1] = angles[1];
- // angles[2] = angles[2];
-
- // position.x = matrix[3][0];
- // position.y = matrix[3][1];
- // position.z = matrix[3][2];
-// }
-
-void M_MatrixCopy( const M_matrix4x4_t& in, M_matrix4x4_t& out )
-{
- // Assert( s_bMathlibInitialized );
- memcpy( out.Base(), in.Base(), sizeof( float ) * 4 * 4 );
-}
-void M_RotateZMatrix(float radian, M_matrix4x4_t &resultMatrix)
-{
-
- resultMatrix[0][0] = cosf(radian);
- resultMatrix[0][1] = sin(radian);
- resultMatrix[0][2] = 0.0;
- resultMatrix[1][0] =-sin(radian);
- resultMatrix[1][1] = cos(radian);
- resultMatrix[1][2] = 0.0;
- resultMatrix[2][0] = 0.0;
- resultMatrix[2][1] = 0.0;
- resultMatrix[2][2] = 1.0;
-}
-
-// !!! THIS SHIT DOESN'T WORK!! WHY? HAS I EVER?
-void M_AngleAboutAxis(Vector &axis, float radianAngle, M_matrix4x4_t &result)
-{
- float c = cosf(radianAngle);
- float s = sinf(radianAngle);
- float t = 1.0 - c;
- // axis.normalize();
-
- result[0][0] = t * axis[0] * axis[0] + c;
- result[0][1] = t * axis[0] * axis[1] - s * axis[2];
- result[0][2] = t * axis[0] * axis[2] + s * axis[1];
- result[1][0] = t * axis[0] * axis[1] + s * axis[2];
- result[1][1] = t * axis[1] * axis[1] + c;
- result[1][2] = t * axis[1] * axis[2] - s * axis[0];
- result[2][0] = t * axis[1] * axis[2] - s;
- result[2][1] = t * axis[1] * axis[2] + s * axis[1];
- result[2][2] = t * axis[2] * axis[2] + c * axis[0];
-
-}
-
-
-void M_MatrixInvert( const M_matrix4x4_t& in, M_matrix4x4_t& out )
-{
- // Assert( s_bMathlibInitialized );
- if ( &in == &out )
- {
- M_matrix4x4_t in2;
- M_MatrixCopy( in, in2 );
- M_MatrixInvert( in2, out );
- return;
- }
- float tmp[3];
-
- // I'm guessing this only works on a 3x4 orthonormal matrix
- out[0][0] = in[0][0];
- out[1][0] = in[0][1];
- out[2][0] = in[0][2];
-
- out[0][1] = in[1][0];
- out[1][1] = in[1][1];
- out[2][1] = in[1][2];
-
- out[0][2] = in[2][0];
- out[1][2] = in[2][1];
- out[2][2] = in[2][2];
-
- tmp[0] = in[3][0];
- tmp[1] = in[3][1];
- tmp[2] = in[3][2];
-
- float v1[3], v2[3], v3[3];
- v1[0] = out[0][0];
- v1[1] = out[1][0];
- v1[2] = out[2][0];
- v2[0] = out[0][1];
- v2[1] = out[1][1];
- v2[2] = out[2][1];
- v3[0] = out[0][2];
- v3[1] = out[1][2];
- v3[2] = out[2][2];
-
- out[3][0] = -DotProduct( tmp, v1 );
- out[3][1] = -DotProduct( tmp, v2 );
- out[3][2] = -DotProduct( tmp, v3 );
-
- // Trivial case
- // if (IS_IDENTITY(matrix))
- // return SbMatrix::identity();
-
- // // Affine case...
- // // SbMatrix affineAnswer;
- // // if ( affine_inverse( SbMatrix(matrix), affineAnswer ) )
- // // return affineAnswer;
-
- // int index[4];
- // float d, invmat[4][4], temp;
- // SbMatrix inverse = *this;
-
- // if(inverse.LUDecomposition(index, d)) {
-
- // invmat[0][0] = 1.0;
- // invmat[0][1] = 0.0;
- // invmat[0][2] = 0.0;
- // invmat[0][3] = 0.0;
- // inverse.LUBackSubstitution(index, invmat[0]);
- // invmat[1][0] = 0.0;
- // invmat[1][1] = 1.0;
- // invmat[1][2] = 0.0;
- // invmat[1][3] = 0.0;
- // inverse.LUBackSubstitution(index, invmat[1]);
- // invmat[2][0] = 0.0;
- // invmat[2][1] = 0.0;
- // invmat[2][2] = 1.0;
- // invmat[2][3] = 0.0;
- // inverse.LUBackSubstitution(index, invmat[2]);
- // invmat[3][0] = 0.0;
- // invmat[3][1] = 0.0;
- // invmat[3][2] = 0.0;
- // invmat[3][3] = 1.0;
- // inverse.LUBackSubstitution(index, invmat[3]);
-
-// #define SWAP(i,j) \
- // temp = invmat[i][j]; \
- // invmat[i][j] = invmat[j][i]; \
- // invmat[j][i] = temp;
-
- // SWAP(1,0);
-
- // SWAP(2,0);
- // SWAP(2,1);
-
- // SWAP(3,0);
- // SWAP(3,1);
- // SWAP(3,2);
-// #undef SWAP
- // }
-}
-
-/*
-================
-M_ConcatTransforms
-================
-*/
-void M_ConcatTransforms (const M_matrix4x4_t &in1, const M_matrix4x4_t &in2, M_matrix4x4_t &out)
-{
-
- // Assert( s_bMathlibInitialized );
- // if ( &in1 == &out )
- // {
- // matrix3x4_t in1b;
- // MatrixCopy( in1, in1b );
- // ConcatTransforms( in1b, in2, out );
- // return;
- // }
- // if ( &in2 == &out )
- // {
- // matrix3x4_t in2b;
- // MatrixCopy( in2, in2b );
- // ConcatTransforms( in1, in2b, out );
- // return;
- // }
-
-#define MULT(i,j) (in1[i][0]*in2[0][j] + \
- in1[i][1]*in2[1][j] + \
- in1[i][2]*in2[2][j] + \
- in1[i][3]*in2[3][j])
-
- out[0][0] = MULT(0,0);
- out[0][1] = MULT(0,1);
- out[0][2] = MULT(0,2);
- out[0][3] = MULT(0,3);
- out[1][0] = MULT(1,0);
- out[1][1] = MULT(1,1);
- out[1][2] = MULT(1,2);
- out[1][3] = MULT(1,3);
- out[2][0] = MULT(2,0);
- out[2][1] = MULT(2,1);
- out[2][2] = MULT(2,2);
- out[2][3] = MULT(2,3);
- out[3][0] = MULT(3,0);
- out[3][1] = MULT(3,1);
- out[3][2] = MULT(3,2);
- out[3][3] = MULT(3,3);
-
-#undef MULT
-
-}
-
-void M_AngleMatrix( RadianEuler const &angles, const Vector &position, M_matrix4x4_t& matrix )
-{
- // Assert( s_bMathlibInitialized );
- float sx, sy, sz, cx, cy, cz;
-
-
- sx = sinf(angles[0]);
- cx = cosf(angles[0]);
- sy = sinf(angles[1]);
- cy = cosf(angles[1]);
- sz = sinf(angles[2]);
- cz = cosf(angles[2]);
-
- // SinCos( angles[0], &sx, &cx ); // 2
- // SinCos( angles[1], &sy, &cy ); // 1
- // SinCos( angles[2], &sz, &cz ); // 0
-
- M_matrix4x4_t mx, my, mz, temp1;
-
- // rotation about x
- mx[1][1] = cx;
- mx[1][2] = sx;
- mx[2][1] = -sx;
- mx[2][2] = cx;
-
- // rotation about y
- my[0][0] = cy;
- my[0][2] = -sy;
- my[2][0] = sy;
- my[2][2] = cy;
-
- // rotation about z
- mz[0][0] = cz;
- mz[0][1] = sz;
- mz[1][0] = -sz;
- mz[1][1] = cz;
-
- // z * y * x
- M_ConcatTransforms(mx, my, temp1);
- M_ConcatTransforms(temp1, mz, matrix);
-
- // put position in
- matrix[3][0] = position.x;
- matrix[3][1] = position.y;
- matrix[3][2] = position.z;
-
-}
-
-
-//-----------------------------------------------------------------------------
-// Motion mapper functions
-//-----------------------------------------------------------------------------
-#define BONEAXIS 0
-#define BONEDIR 0
-#define BONESIDE 1
-#define BONEUP 2
-#define WORLDUP 2
-#define PRINTMAT(m) \
- printf("\n%f %f %f %f\n", m[0][0], m[0][1], m[0][2], m[0][3]); \
- printf("%f %f %f %f\n", m[1][0], m[1][1], m[1][2], m[1][3]); \
- printf("%f %f %f %f\n", m[2][0], m[2][1], m[2][2], m[2][3]); \
- printf("%f %f %f %f\n", m[3][0], m[3][1], m[3][2], m[3][3]);
-
-struct s_planeConstraint_t
-{
- char jointNameString[1024];
- float floor;
- int axis;
-
-};
-
-struct s_iksolve_t
-{
- char jointNameString[1024];
- int reverseSolve;
- float extremityScale;
- Vector limbRootOffsetScale;
- int doRelativeLock;
- char relativeLockNameString[1024];
- float relativeLockScale;
-
-};
-
-struct s_jointScale_t
-{
- char jointNameString[1024];
- float scale;
-};
-
-struct s_template_t
-{
- char rootScaleJoint[1024];
- float rootScaleAmount;
- int numIKSolves;
- s_iksolve_t *ikSolves[128];
- int numJointScales;
- s_jointScale_t *jointScales[128];
- int numPlaneConstraints;
- s_planeConstraint_t *planeConstraints[128];
- float toeFloorZ;
- int doSkeletonScale;
- float skeletonScale;
-
-};
-
-
-//-----------------------------------------------------------------------------
-// Load a template file into structure
-//-----------------------------------------------------------------------------
-s_template_t *New_Template()
-{
- s_template_t *pTemplate = (s_template_t *)kalloc(1, sizeof(s_template_t));
- pTemplate->rootScaleAmount = 1.0;
- pTemplate->numIKSolves = 0;
- pTemplate->numJointScales = 0;
- pTemplate->toeFloorZ = 2.802277;
- pTemplate->numPlaneConstraints = 0;
- pTemplate->doSkeletonScale = 0;
- pTemplate->skeletonScale = 1.0;
- return pTemplate;
-}
-s_iksolve_t *New_IKSolve()
-{
- s_iksolve_t *pIKSolve = (s_iksolve_t *)kalloc(1, sizeof(s_iksolve_t));
- pIKSolve->reverseSolve = 0;
- pIKSolve->extremityScale = 1.0;
- pIKSolve->limbRootOffsetScale[0] = pIKSolve->limbRootOffsetScale[1] = pIKSolve->limbRootOffsetScale[2] = 0.0;
- pIKSolve->doRelativeLock = 0;
- pIKSolve->relativeLockScale = 1.0;
- return pIKSolve;
-}
-
-s_planeConstraint_t *New_planeConstraint(float floor)
-{
- s_planeConstraint_t *pConstraint = (s_planeConstraint_t *)kalloc(1, sizeof(s_planeConstraint_t));
- pConstraint->floor = floor;
- pConstraint->axis = 2;
-
- return pConstraint;
-}
-
-void Set_DefaultTemplate(s_template_t *pTemplate)
-{
- pTemplate->numJointScales = 0;
-
- strcpy(pTemplate->rootScaleJoint, "ValveBiped.Bip01_L_Foot");
- pTemplate->rootScaleAmount = 1.0;
-
- pTemplate->numIKSolves = 4;
- pTemplate->ikSolves[0] = New_IKSolve();
- pTemplate->ikSolves[1] = New_IKSolve();
- pTemplate->ikSolves[2] = New_IKSolve();
- pTemplate->ikSolves[3] = New_IKSolve();
-
-
- pTemplate->numPlaneConstraints = 2;
- pTemplate->planeConstraints[0] = New_planeConstraint(pTemplate->toeFloorZ);
- strcpy(pTemplate->planeConstraints[0]->jointNameString, "ValveBiped.Bip01_L_Toe0");
- pTemplate->planeConstraints[1] = New_planeConstraint(pTemplate->toeFloorZ);
- strcpy(pTemplate->planeConstraints[1]->jointNameString, "ValveBiped.Bip01_R_Toe0");
-
- strcpy(pTemplate->ikSolves[0]->jointNameString, "ValveBiped.Bip01_L_Foot");
- pTemplate->ikSolves[0]->reverseSolve = 0;
- pTemplate->ikSolves[0]->extremityScale = 1.0;
- pTemplate->ikSolves[0]->limbRootOffsetScale[0] = 1.0;
- pTemplate->ikSolves[0]->limbRootOffsetScale[1] = 1.0;
- pTemplate->ikSolves[0]->limbRootOffsetScale[2] = 0.0;
-
- strcpy(pTemplate->ikSolves[1]->jointNameString, "ValveBiped.Bip01_R_Foot");
- pTemplate->ikSolves[1]->reverseSolve = 0;
- pTemplate->ikSolves[1]->extremityScale = 1.0;
- pTemplate->ikSolves[1]->limbRootOffsetScale[0] = 1.0;
- pTemplate->ikSolves[1]->limbRootOffsetScale[1] = 1.0;
- pTemplate->ikSolves[1]->limbRootOffsetScale[2] = 0.0;
-
- strcpy(pTemplate->ikSolves[2]->jointNameString, "ValveBiped.Bip01_R_Hand");
- pTemplate->ikSolves[2]->reverseSolve = 1;
- pTemplate->ikSolves[2]->extremityScale = 1.0;
- pTemplate->ikSolves[2]->limbRootOffsetScale[0] = 0.0;
- pTemplate->ikSolves[2]->limbRootOffsetScale[1] = 0.0;
- pTemplate->ikSolves[2]->limbRootOffsetScale[2] = 1.0;
-
- strcpy(pTemplate->ikSolves[3]->jointNameString, "ValveBiped.Bip01_L_Hand");
- pTemplate->ikSolves[3]->reverseSolve = 1;
- pTemplate->ikSolves[3]->extremityScale = 1.0;
- pTemplate->ikSolves[3]->limbRootOffsetScale[0] = 0.0;
- pTemplate->ikSolves[3]->limbRootOffsetScale[1] = 0.0;
- pTemplate->ikSolves[3]->limbRootOffsetScale[2] = 1.0;
- // pTemplate->ikSolves[3]->doRelativeLock = 1;
- // strcpy(pTemplate->ikSolves[3]->relativeLockNameString, "ValveBiped.Bip01_R_Hand");
- // pTemplate->ikSolves[3]->relativeLockScale = 1.0;
-
-}
-
-void split(char *str, char *sep, char **sp)
-{
- char *r = strtok(str, sep);
- while(r != NULL)
- {
- *sp = r;
- sp++;
- r = strtok(NULL, sep);
- }
- *sp = NULL;
-}
-
-
-int checkCommand(char *str, char *cmd, int numOptions, int numSplit)
-{
- if(strcmp(str, cmd) == 0)
- {
- if(numOptions <= numSplit)
- return 1;
- else
- {
- printf("Error: Number or argument mismatch in template file cmd %s, requires %i, found %i\n", cmd, numOptions, numSplit);
- return 0;
- }
- }
- return 0;
-}
-
-s_template_t *Load_Template(char *name )
-{
-
- // Sanity check file and init
- Assert(name);
-
- s_template_t *pTemplate = New_Template();
-
-
- // Open file
- if (!OpenGlobalFile( name ))
- return 0;
-
-
- //March through lines
- g_iLinecount = 0;
- while(fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
- {
- g_iLinecount++;
- if(g_szLine[0] == '#')
- continue;
-
- char *endP = strrchr(g_szLine, '\n');
- if(endP != NULL)
- *endP = '\0';
-
-
- char *sp[128];
- char **spp = sp;
-
- char sep[] = " ";
- split(g_szLine, sep, sp);
- int numSplit = 0;
-
- while(*spp != NULL)
- {
- spp++;
- numSplit++;
-
- }
- if(numSplit < 1 ||
- *sp[0] == '\n')
- continue;
-
-
- // int numRead = sscanf( g_szLine, "%s %s %s", cmd, &option, &option2 );
-
- // // Blank line
- // if ((numRead == EOF) || (numRead == 0))
- // continue;
-
- // commands
- char *cmd;
- int numOptions = numSplit - 1;
-
- cmd = sp[0];
- if(checkCommand(cmd, "twoJointIKSolve", 1, numOptions))
- {
- printf("\nCreating two joint IK solve %s\n", sp[1]);
- pTemplate->ikSolves[pTemplate->numIKSolves] = New_IKSolve();
- strcpy(pTemplate->ikSolves[pTemplate->numIKSolves]->jointNameString, sp[1]);
- pTemplate->numIKSolves++;
-
- }
- else if(checkCommand(cmd, "oneJointPlaneConstraint", 1, numOptions))
- {
- printf("\nCreating one joint plane constraint %s\n", sp[1]);
- pTemplate->planeConstraints[pTemplate->numPlaneConstraints] = New_planeConstraint(pTemplate->toeFloorZ);
- strcpy(pTemplate->planeConstraints[pTemplate->numPlaneConstraints]->jointNameString, sp[1]);
- pTemplate->numPlaneConstraints++;
-
- }
- else if(checkCommand(cmd, "reverseSolve", 1, numOptions))
- {
- printf("reverseSolve: %s\n", sp[1]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->reverseSolve = atoi(sp[1]);
- }
- else if(checkCommand(cmd, "extremityScale", 1, numOptions))
- {
- printf("extremityScale: %s\n", sp[1]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->extremityScale = atof(sp[1]);
- }
- else if(checkCommand(cmd, "limbRootOffsetScale", 3, numOptions))
- {
- printf("limbRootOffsetScale: %s %s %s\n", sp[1], sp[2], sp[3]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[0] = atof(sp[1]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[1] = atof(sp[2]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[2] = atof(sp[3]);
- }
- else if(checkCommand(cmd, "toeFloorZ", 1, numOptions))
- {
- printf("toeFloorZ: %s\n", sp[1]);
- pTemplate->toeFloorZ = atof(sp[1]);
- }
- else if(checkCommand(cmd, "relativeLock", 2, numOptions))
- {
- printf("relativeLock: %s\n", sp[1]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->doRelativeLock = 1;
- strcpy(pTemplate->ikSolves[pTemplate->numIKSolves - 1]->relativeLockNameString, sp[1]);
- pTemplate->ikSolves[pTemplate->numIKSolves - 1]->relativeLockScale = atof(sp[2]);
-
- }
- else if(checkCommand(cmd, "rootScaleJoint", 1, numOptions))
- {
- printf("\nrootScaleJoint: %s\n", sp[1]);
- strcpy(pTemplate->rootScaleJoint, sp[1]);
- }
- else if(checkCommand(cmd, "rootScaleAmount", 1, numOptions))
- {
- printf("rootScaleAmount: %s\n", sp[1]);
- pTemplate->rootScaleAmount = atof(sp[1]);
- }
- else if(checkCommand(cmd, "jointScale", 2, numOptions))
- {
- printf("\nCreating joint scale %s of %s\n", sp[1], sp[2]);
- pTemplate->jointScales[pTemplate->numJointScales] = (s_jointScale_t *)kalloc(1, sizeof(s_jointScale_t));
- strcpy(pTemplate->jointScales[pTemplate->numJointScales]->jointNameString, sp[1]);
- pTemplate->jointScales[pTemplate->numJointScales]->scale = atof(sp[2]);
- pTemplate->numJointScales++;
- }
- else if(checkCommand(cmd, "skeletonScale", 2, numOptions))
- {
- printf("\nCreating skeleton scale of %s\n", sp[1]);
- pTemplate->doSkeletonScale = 1;
- pTemplate->skeletonScale = atof(sp[1]);
- }
- else
- {
- MdlWarning("unknown studio command\n" );
- }
- }
- fclose( g_fpInput );
- return pTemplate;
-}
-
-//-----------------------------------------------------------------------------
-// get node index from node string name
-//-----------------------------------------------------------------------------
-int GetNodeIndex(s_source_t *psource, char *nodeName)
-{
- for(int i = 0; i < psource->numbones; i++)
- {
- if(strcmp(nodeName, psource->localBone[i].name) == 0)
- {
- return i;
- }
- }
- return -1;
-}
-
-//-----------------------------------------------------------------------------
-// get node index from node string name
-//-----------------------------------------------------------------------------
-void GetNodePath(s_source_t *psource, int startIndex, int endIndex, int *path)
-{
- *path = endIndex;
-
- s_node_t *nodes;
- nodes = psource->localBone;
- while(*path != startIndex)
- {
- int parent = nodes[*path].parent;
- path++;
- *path = parent;
- }
- path++;
- *path = -1;
-}
-
-void SumBonePathTranslations(int *indexPath, s_bone_t *boneArray, Vector &resultVector, int rootOffset = 0)
-{
-
- // walk the path
- int *pathPtr = indexPath;
- // M_matrix4x4_t matrixCum;
-
- // find length of path
- int length = 0;
- while(*pathPtr != -1)
- {
- length++;
- pathPtr++;
- }
-
- int l = length - (1 + rootOffset);
-
- resultVector[0] = 0.0;
- resultVector[1] = 0.0;
- resultVector[2] = 0.0;
-
- for(int i = l; i > -1; i--)
- {
- s_bone_t *thisBone = boneArray + indexPath[i];
- resultVector += thisBone->pos;
- }
-}
-
-void CatBonePath(int *indexPath, s_bone_t *boneArray, M_matrix4x4_t &resultMatrix, int rootOffset = 0)
-{
-
- // walk the path
- int *pathPtr = indexPath;
- // M_matrix4x4_t matrixCum;
-
- // find length of path
- int length = 0;
- while(*pathPtr != -1)
- {
- length++;
- pathPtr++;
- }
-
- int l = length - (1 + rootOffset);
-
- for(int i = l; i > -1; i--)
- {
- s_bone_t *thisBone = boneArray + indexPath[i];
- // printf("bone index: %i %i\n", i, indexPath[i]);
- // printf("pos: %f %f %f, rot: %f %f %f\n", thisBone->pos.x, thisBone->pos.y, thisBone->pos.z, thisBone->rot.x, thisBone->rot.y, thisBone->rot.z);
- M_matrix4x4_t thisMatrix;
- M_AngleMatrix(thisBone->rot, thisBone->pos, thisMatrix);
- // PRINTMAT(thisMatrix)
- M_matrix4x4_t tempCum;
- M_MatrixCopy(resultMatrix, tempCum);
- M_ConcatTransforms(thisMatrix, tempCum, resultMatrix);
- }
- // PRINTMAT(matrixCum);
- // M_MatrixAngles(matrixCum, resultBone.rot, resultBone.pos);
-
- // printf("pos: %f %f %f, rot: %f %f %f\n", resultBone.pos.x,resultBone.pos.y, resultBone.pos.z, RAD2DEG(resultBone.rot.x),RAD2DEG(resultBone.rot.y),RAD2DEG(resultBone.rot.z));
-
-}
-// int ConformSources(s_source_t *pSource, s_source_t *pTarget)
-// {
- // if(pSource->numbones != *pTarget->numbones)
- // {
- // printf("ERROR: The number of bones in the target file must match the source file.");
- // return 1;
- // }
- // if(pSource->numframes != pTarget->numframes)
- // {
- // printf("Note: Source and target frame lengths do not match");
- // for(int t = 0; t < pTarget->numframes; t++)
- // {
- // free(pTarget->rawanim[t]);
- // }
- // pTarget->numframes = pSource->numframes;
- // int size = pTarget->numbones * sizeof( s_bone_t );
- // for(t = 0; t < pTarget->numframes; t++)
- // {
- // pTarget->rawanim[t] = (s_bone_t *) kalloc(1, size);
- // memcpy((void *) pSource->rawanim[t], (void *) pTarget->rawanim[t], size
- // }
- // }
- // pTarget->startframe = pSource->startframe;
- // pTarget->endframe = pSource->endframe;
-
-
-
-
-void ScaleJointsFrame(s_source_t *pSkeleton, s_jointScale_t *jointScale, int t)
-{
- int numBones = pSkeleton->numbones;
-
- for(int i = 0; i < numBones; i++)
- {
- s_node_t pNode = pSkeleton->localBone[i];
- s_bone_t *pSkelBone = &pSkeleton->rawanim[t][i];
- if(strcmp(jointScale->jointNameString, pNode.name) == 0)
- {
- // printf("Scaling joint %s\n", pNode.name);
- pSkelBone->pos = pSkelBone->pos * jointScale->scale;
- }
-
- }
-}
-void ScaleJoints(s_source_t *pSkeleton, s_jointScale_t *jointScale)
-{
- int numFrames = pSkeleton->numframes;
- for(int t = 0; t < numFrames; t++)
- {
- ScaleJointsFrame(pSkeleton, jointScale, t);
- }
-}
-
-void ScaleSkeletonFrame(s_source_t *pSkeleton, float scale, int t)
-{
- int numBones = pSkeleton->numbones;
-
- for(int i = 0; i < numBones; i++)
- {
- s_bone_t *pSkelBone = &pSkeleton->rawanim[t][i];
- pSkelBone->pos = pSkelBone->pos * scale;
-
- }
-}
-void ScaleSkeleton(s_source_t *pSkeleton, float scale)
-{
- int numFrames = pSkeleton->numframes;
- for(int t = 0; t < numFrames; t++)
- {
- ScaleSkeletonFrame(pSkeleton, scale, t);
- }
-}
-
-void CombineSkeletonAnimationFrame(s_source_t *pSkeleton, s_source_t *pAnimation, s_bone_t **ppAnim, int t)
-{
- int numBones = pAnimation->numbones;
- int size = numBones * sizeof( s_bone_t );
- ppAnim[t] = (s_bone_t *) kalloc(1, size);
- for(int i = 0; i < numBones; i++)
- {
- s_node_t pNode = pAnimation->localBone[i];
- s_bone_t pAnimBone = pAnimation->rawanim[t][i];
-
- if(pNode.parent > -1)
- {
- if ( i < pSkeleton->numbones )
- {
- s_bone_t pSkelBone = pSkeleton->rawanim[0][i];
- ppAnim[t][i].pos = pSkelBone.pos;
- }
- else
- {
- if ( !g_bGaveMissingBoneWarning )
- {
- g_bGaveMissingBoneWarning = true;
- Warning( "Warning: Target skeleton has less bones than source animation. Reverting to source data for extra bones.\n" );
- }
-
- ppAnim[t][i].pos = pAnimBone.pos;
- }
- }
- else
- {
- ppAnim[t][i].pos = pAnimBone.pos;
- }
-
- ppAnim[t][i].rot = pAnimBone.rot;
- }
-}
-void CombineSkeletonAnimation(s_source_t *pSkeleton, s_source_t *pAnimation, s_bone_t **ppAnim)
-{
- int numFrames = pAnimation->numframes;
- for(int t = 0; t < numFrames; t++)
- {
- CombineSkeletonAnimationFrame(pSkeleton, pAnimation, ppAnim, t);
- }
-}
-
-
-//--------------------------------------------------------------------
-// MotionMap
-//--------------------------------------------------------------------
-s_source_t *MotionMap( s_source_t *pSource, s_source_t *pTarget, s_template_t *pTemplate )
-{
-
- // scale skeleton
- if(pTemplate->doSkeletonScale)
- {
- ScaleSkeleton(pTarget, pTemplate->skeletonScale);
- }
-
- // scale joints
- for(int j = 0; j < pTemplate->numJointScales; j++)
- {
- s_jointScale_t *pJointScale = pTemplate->jointScales[j];
- ScaleJoints(pTarget, pJointScale);
- }
-
-
- // root stuff
- char rootString[128] = "ValveBiped.Bip01";
-
- // !!! PARAMETER
- int rootIndex = GetNodeIndex(pSource, rootString);
- int rootScaleIndex = GetNodeIndex(pSource, pTemplate->rootScaleJoint);
- int rootScalePath[512];
- if(rootScaleIndex > -1)
- {
- GetNodePath(pSource, rootIndex, rootScaleIndex, rootScalePath);
- }
- else
- {
- printf("Error: Can't find node\n");
- exit(0);
- }
- float rootScaleLengthSrc = pSource->rawanim[0][rootScaleIndex].pos[BONEDIR];
- float rootScaleParentLengthSrc = pSource->rawanim[0][rootScalePath[1]].pos[BONEDIR];
- float rootScaleSrc = rootScaleLengthSrc + rootScaleParentLengthSrc;
- float rootScaleLengthTgt = pTarget->rawanim[0][rootScaleIndex].pos[BONEDIR];
- float rootScaleParentLengthTgt = pTarget->rawanim[0][rootScalePath[1]].pos[BONEDIR];
- float rootScaleTgt = rootScaleLengthTgt + rootScaleParentLengthTgt;
- float rootScaleFactor = rootScaleTgt / rootScaleSrc;
-
- if(g_verbose)
- printf("Root Scale Factor: %f\n", rootScaleFactor);
-
-
- // root scale origin
- float toeFloorZ = pTemplate->toeFloorZ;
- Vector rootScaleOrigin = pSource->rawanim[0][rootIndex].pos;
- rootScaleOrigin[2] = toeFloorZ;
-
-
- // setup workspace
- s_bone_t *combinedRefAnimation[MAXSTUDIOANIMFRAMES];
- s_bone_t *combinedAnimation[MAXSTUDIOANIMFRAMES];
- s_bone_t *sourceAnimation[MAXSTUDIOANIMFRAMES];
- CombineSkeletonAnimation(pTarget, pSource, combinedAnimation);
- CombineSkeletonAnimation(pTarget, pSource, combinedRefAnimation);
-
-
- // do source and target sanity checking
- int sourceNumFrames = pSource->numframes;
-
-
- // iterate through limb solves
- for(int t = 0; t < sourceNumFrames; t++)
- {
- // setup pTarget for skeleton comparison
- pTarget->rawanim[t] = combinedRefAnimation[t];
-
- printf("Note: Processing frame: %i\n", t);
- for(int ii = 0; ii < pTemplate->numIKSolves; ii++)
- {
- s_iksolve_t *thisSolve = pTemplate->ikSolves[ii];
-
- char *thisJointNameString = thisSolve->jointNameString;
- int thisJointIndex = GetNodeIndex(pSource, thisJointNameString);
-
- // init paths to feet
- int thisJointPathInRoot[512];
-
- // get paths to feet
- if(thisJointIndex > -1)
- {
- GetNodePath(pSource, rootIndex, thisJointIndex, thisJointPathInRoot);
- }
- else
- {
- printf("Error: Can't find node: %s\n" , thisJointNameString);
- exit(0);
- }
-
- // leg "root" or thigh pointers
- //int gParentIndex = thisJointPathInRoot[2];
- int *gParentPath = thisJointPathInRoot + 2;
-
- //----------------------------------------------------------------
- // get limb lengths
- //----------------------------------------------------------------
- float thisJointLengthSrc = pSource->rawanim[0][thisJointIndex].pos[BONEDIR];
- float parentJointLengthSrc = pSource->rawanim[0][thisJointPathInRoot[1]].pos[BONEDIR];
-
- float thisLimbLengthSrc = thisJointLengthSrc + parentJointLengthSrc;
-
- float thisJointLengthTgt = pTarget->rawanim[0][thisJointIndex].pos[BONEDIR];
- float parentJointLengthTgt = pTarget->rawanim[0][thisJointPathInRoot[1]].pos[BONEDIR];
-
- float thisLimbLengthTgt = thisJointLengthTgt + parentJointLengthTgt;
-
- // Factor leg length delta
- float thisLimbLength = thisLimbLengthSrc - thisLimbLengthTgt;
- float thisLimbLengthFactor = thisLimbLengthTgt / thisLimbLengthSrc;
-
- if(g_verbose)
- printf("limb length %s: %i: %f, factor %f\n", thisJointNameString, thisJointIndex, thisLimbLength, thisLimbLengthFactor);
-
- // calculate joint grandparent offset
- // Note: because there's no reference pose this doesn't take rotation into account.
- // This only works because of the assumption that joint translations aren't animated.
- M_matrix4x4_t gParentGlobalMatSrc, gParentGlobalMatTgt;
- Vector gParentGlobalSrc, gParentGlobalTgt;
-
- // SumBonePathTranslations(gParentPath, pSource->rawanim[t], gParentGlobalSrc, 1);
- // SumBonePathTranslations(gParentPath, pTarget->rawanim[t], gParentGlobalTgt, 1);
-
- // get root path to source parent
- CatBonePath(gParentPath, pSource->rawanim[t], gParentGlobalMatSrc, 1);
- // check against reference animation
- CatBonePath(gParentPath, pTarget->rawanim[t], gParentGlobalMatTgt, 1);
-
- gParentGlobalSrc[0] = gParentGlobalMatSrc[3][0];
- gParentGlobalSrc[1] = gParentGlobalMatSrc[3][1];
- gParentGlobalSrc[2] = gParentGlobalMatSrc[3][2];
-
- gParentGlobalTgt[0] = gParentGlobalMatTgt[3][0];
- gParentGlobalTgt[1] = gParentGlobalMatTgt[3][1];
- gParentGlobalTgt[2] = gParentGlobalMatTgt[3][2];
-
-
- Vector gParentDelta(gParentGlobalTgt - gParentGlobalSrc);
-
- if(g_verbose)
- printf("Grand parent delta: %f %f %f\n", gParentDelta[0], gParentDelta[1], gParentDelta[2]);
-
- gParentDelta *= thisSolve->limbRootOffsetScale;
-
-
- //----------------------------------------------------------------
- // time takes effect here
- // above waste is unavoidable?
- //----------------------------------------------------------------
- M_matrix4x4_t rootMat;
- M_AngleMatrix(pSource->rawanim[t][rootIndex].rot, pSource->rawanim[t][rootIndex].pos, rootMat);
-
-
- // OK, time to get it together
- // 1) scale foot by legLengthFactor in the non-translated thigh space
- // 2) translate foot by legRootDelta in the space of the root
- // do we leave everything in the space of the root then? PROBABLY!!
-
- M_matrix4x4_t thisJointMat, parentJointMat, thisJointInGParentMat;
- M_AngleMatrix(pSource->rawanim[t][thisJointPathInRoot[0]].rot, pSource->rawanim[t][thisJointPathInRoot[0]].pos, thisJointMat);
- M_AngleMatrix(pSource->rawanim[t][thisJointPathInRoot[1]].rot, pSource->rawanim[t][thisJointPathInRoot[1]].pos, parentJointMat);
- M_ConcatTransforms(thisJointMat, parentJointMat, thisJointInGParentMat);
-
- if(!thisSolve->doRelativeLock)
- {
- // scale around grand parent
- float effectiveScaleFactor = ((thisLimbLengthFactor - 1.0) * thisSolve->extremityScale ) + 1.0;
- thisJointInGParentMat[3][0] *= effectiveScaleFactor;
- thisJointInGParentMat[3][1] *= effectiveScaleFactor;
- thisJointInGParentMat[3][2] *= effectiveScaleFactor;
- }
-
- // adjust into source root space
- M_matrix4x4_t gParentInRootMat, thisJointInRootMat;
- CatBonePath(gParentPath, pSource->rawanim[t], gParentInRootMat, 1);
- M_ConcatTransforms(thisJointInGParentMat, gParentInRootMat, thisJointInRootMat);
-
- if(!thisSolve->doRelativeLock)
- {
- // adjust by difference of local root
- thisJointInRootMat[3][0] += gParentDelta[0];
- thisJointInRootMat[3][1] += gParentDelta[1];
- thisJointInRootMat[3][2] += gParentDelta[2];
- }
- else
- {
- char *relativeJointNameString = thisSolve->relativeLockNameString;
- int relativeJointIndex = GetNodeIndex(pSource, relativeJointNameString);
-
- // init paths to feet
- int relativeJointPathInRoot[512];
-
- // get paths to feet
- if(relativeJointIndex > -1)
- {
- GetNodePath(pSource, rootIndex, relativeJointIndex, relativeJointPathInRoot);
- }
- else
- {
- printf("Error: Can't find node: %s\n" , relativeJointNameString);
- exit(0);
- }
- // get the source relative joint
- M_matrix4x4_t relativeJointInRootMatSrc, relativeJointInRootMatSrcInverse, thisJointInRelativeSrcMat;
- CatBonePath(relativeJointPathInRoot, pSource->rawanim[t], relativeJointInRootMatSrc, 1);
- M_MatrixInvert(relativeJointInRootMatSrc, relativeJointInRootMatSrcInverse);
- M_ConcatTransforms(thisJointInRootMat, relativeJointInRootMatSrcInverse, thisJointInRelativeSrcMat);
- if(thisSolve->relativeLockScale != 1.0)
- {
- thisJointInRelativeSrcMat[3][0] *= thisSolve->relativeLockScale;
- thisJointInRelativeSrcMat[3][1] *= thisSolve->relativeLockScale;
- thisJointInRelativeSrcMat[3][2] *= thisSolve->relativeLockScale;
- }
-
- // swap momentarily to get new destination
- // NOTE: the relative lock must have already been solved
- sourceAnimation[t] = pSource->rawanim[t];
- pSource->rawanim[t] = combinedAnimation[t];
-
- // get new relative location
- M_matrix4x4_t relativeJointInRootMatTgt;
- CatBonePath(relativeJointPathInRoot, pSource->rawanim[t], relativeJointInRootMatTgt, 1);
- M_ConcatTransforms(thisJointInRelativeSrcMat, relativeJointInRootMatTgt, thisJointInRootMat);
-
- // swap back just for cleanliness
- // a little overkill as it's just swapped
- // just leaving it here for clarity
- combinedAnimation[t] = pSource->rawanim[t];
- pSource->rawanim[t] = sourceAnimation[t];
-
- }
-
- //----------------------------------------------------------------
- // swap animation
- //----------------------------------------------------------------
- sourceAnimation[t] = pSource->rawanim[t];
- pSource->rawanim[t] = combinedAnimation[t];
-
- //----------------------------------------------------------------
- // make thigh data global based on new skeleton
- //----------------------------------------------------------------
- // get thigh in global space
- M_matrix4x4_t gParentInTgtRootMat, ggParentInTgtRootMat;
- // int *gParentPath = thisJointPathInRoot + 2;
- CatBonePath(gParentPath, pSource->rawanim[t], gParentInTgtRootMat, 1);
- CatBonePath(gParentPath+1, pSource->rawanim[t], ggParentInTgtRootMat, 1);
-
-
- //----------------------------------------------------------------
- // Calculate IK for legs
- //----------------------------------------------------------------
- float parentJointLength = pSource->rawanim[t][*(thisJointPathInRoot + 1)].pos[BONEDIR];
- float thisJointLength = pSource->rawanim[t][thisJointIndex].pos[BONEDIR];
-
- Vector thisLimbHypot;
- thisLimbHypot[0] = thisJointInRootMat[3][0] - gParentInTgtRootMat[3][0];
- thisLimbHypot[1] = thisJointInRootMat[3][1] - gParentInTgtRootMat[3][1];
- thisLimbHypot[2] = thisJointInRootMat[3][2] - gParentInTgtRootMat[3][2];
-
- float thisLimbHypotLength = thisLimbHypot.Length();
-
- // law of cosines!
- float gParentCos = (thisLimbHypotLength*thisLimbHypotLength + parentJointLength*parentJointLength - thisJointLength*thisJointLength) / (2*parentJointLength*thisLimbHypotLength);
- float parentCos = (parentJointLength*parentJointLength + thisJointLength*thisJointLength - thisLimbHypotLength*thisLimbHypotLength) / (2*parentJointLength*thisJointLength);
-
- VectorNormalize(thisLimbHypot);
-
- Vector thisLimbHypotUnit = thisLimbHypot;
-
- M_matrix4x4_t gParentJointIKMat;
- Vector gParentJointIKRot, gParentJointIKOrth;
-
- gParentJointIKRot[0] = gParentInTgtRootMat[BONEUP][0];
- gParentJointIKRot[1] = gParentInTgtRootMat[BONEUP][1];
- gParentJointIKRot[2] = gParentInTgtRootMat[BONEUP][2];
-
- VectorNormalize(gParentJointIKRot);
- gParentJointIKOrth = gParentJointIKRot.Cross(thisLimbHypotUnit);
- VectorNormalize(gParentJointIKOrth);
- gParentJointIKRot = thisLimbHypotUnit.Cross(gParentJointIKOrth);
- VectorNormalize(gParentJointIKRot);
-
- M_MatrixCopy(gParentInTgtRootMat, gParentJointIKMat);
-
- gParentJointIKMat[0][0] = thisLimbHypotUnit[0];
- gParentJointIKMat[0][1] = thisLimbHypotUnit[1];
- gParentJointIKMat[0][2] = thisLimbHypotUnit[2];
-
- gParentJointIKMat[1][0] = gParentJointIKOrth[0];
- gParentJointIKMat[1][1] = gParentJointIKOrth[1];
- gParentJointIKMat[1][2] = gParentJointIKOrth[2];
-
- gParentJointIKMat[2][0] = gParentJointIKRot[0];
- gParentJointIKMat[2][1] = gParentJointIKRot[1];
- gParentJointIKMat[2][2] = gParentJointIKRot[2];
-
-
- M_matrix4x4_t gParentJointIKRotMat, gParentJointResultMat;
- float gParentDeg;
- if(thisSolve->reverseSolve)
- {
- gParentDeg = acos(gParentCos);
- }
- else
- {
- gParentDeg = -acos(gParentCos);
- }
-
- // sanity check limb length
- if(thisLimbHypotLength < thisLimbLengthTgt)
- {
- M_RotateZMatrix(gParentDeg, gParentJointIKRotMat);
- }
-
- M_ConcatTransforms(gParentJointIKRotMat, gParentJointIKMat, gParentJointResultMat);
-
- M_matrix4x4_t parentJointIKRotMat;
- //!!! shouldn't need the 180 degree addition, something in the law of cosines!!!
- float parentDeg;
- if(thisSolve->reverseSolve)
- {
- parentDeg = acos(parentCos)+M_PI;
- }
- else
- {
- parentDeg = -acos(parentCos)+M_PI;
- }
-
- // sanity check limb length
- if(thisLimbHypotLength < thisLimbLengthTgt)
- {
- M_RotateZMatrix(parentDeg, parentJointIKRotMat);
- }
-
-
- // Thighs
- M_matrix4x4_t ggParentInTgtRootMatInverse, gParentJointLocalMat;
- M_MatrixInvert(ggParentInTgtRootMat, ggParentInTgtRootMatInverse);
- M_ConcatTransforms(gParentJointResultMat, ggParentInTgtRootMatInverse, gParentJointLocalMat);
-
- s_bone_t resultBone;
-
- // temp test stuff
- // M_MatrixAngles(thisJointInRootMat, resultBone.rot, resultBone.pos);
- // pSource->rawanim[t][thisJointIndex].rot = resultBone.rot;
- // pSource->rawanim[t][thisJointIndex].pos = resultBone.pos;
-
- // M_MatrixAngles(gParentInTgtRootMat, resultBone.rot, resultBone.pos);
- // pSource->rawanim[t][gParentIndex].rot = resultBone.rot;
- // pSource->rawanim[t][gParentIndex].pos = resultBone.pos;
-
-
- M_MatrixAngles(gParentJointLocalMat, resultBone.rot, resultBone.pos);
- pSource->rawanim[t][*gParentPath].pos = resultBone.pos;
- pSource->rawanim[t][*gParentPath].rot = resultBone.rot;
-
- M_MatrixAngles(parentJointIKRotMat, resultBone.rot, resultBone.pos);
- pSource->rawanim[t][*(thisJointPathInRoot+1)].rot = resultBone.rot;
-
- M_matrix4x4_t parentJointGlobalMat, parentJointGlobalMatInverse, thisJointLocalMat;
- CatBonePath(thisJointPathInRoot+1, pSource->rawanim[t], parentJointGlobalMat, 1);
-
-
- M_MatrixInvert(parentJointGlobalMat, parentJointGlobalMatInverse);
- M_ConcatTransforms(thisJointInRootMat, parentJointGlobalMatInverse, thisJointLocalMat);
-
- M_MatrixAngles(thisJointLocalMat, resultBone.rot, resultBone.pos);
- pSource->rawanim[t][thisJointIndex].rot = resultBone.rot;
-
-
- // swap animation back for next solve
- combinedAnimation[t] = pSource->rawanim[t];
- pSource->rawanim[t] = sourceAnimation[t];
-
- }
- // swap animation
- sourceAnimation[t] = pSource->rawanim[t];
- pSource->rawanim[t] = combinedAnimation[t];
-
- //----------------------------------------------------------------
- // adjust root
- //----------------------------------------------------------------
- Vector originBonePos = pSource->rawanim[t][rootIndex].pos;
- Vector rootInScaleOrigin = originBonePos - rootScaleOrigin;
- float effectiveRootScale = ((rootScaleFactor - 1.0) * pTemplate->rootScaleAmount) + 1.0;
- Vector scaledRoot = rootInScaleOrigin * effectiveRootScale;
- pSource->rawanim[t][rootIndex].pos = rootScaleOrigin + scaledRoot;
-
- //------------------------------------------------------------
- // plane constraints
- //------------------------------------------------------------
- for(int ii = 0; ii < pTemplate->numPlaneConstraints; ii++)
- {
- s_planeConstraint_t *thisSolve = pTemplate->planeConstraints[ii];
-
- char *thisJointNameString = thisSolve->jointNameString;
- if(g_verbose)
- printf("Executing plane constraint: %s\n", thisJointNameString);
-
- int thisJointIndex = GetNodeIndex(pSource, thisJointNameString);
-
- // init paths to feet
- int thisJointPath[512];
-
- // get paths to feet
- if(thisJointIndex > -1)
- {
- GetNodePath(pSource, -1, thisJointIndex, thisJointPath);
- }
- else
- {
- printf("Error: Can't find node: %s\n" , thisJointNameString);
- exit(0);
- }
- int parentIndex = thisJointPath[1];
- int *parentPath = thisJointPath + 1;
-
- M_matrix4x4_t thisJointGlobalMat, parentJointGlobalMat, gParentJointGlobalMat, gParentJointGlobalMatInverse;
- CatBonePath(thisJointPath, pSource->rawanim[t], thisJointGlobalMat, 0);
- CatBonePath(parentPath, pSource->rawanim[t], parentJointGlobalMat, 0);
- CatBonePath(parentPath+1, pSource->rawanim[t], gParentJointGlobalMat, 0);
- M_MatrixInvert(gParentJointGlobalMat, gParentJointGlobalMatInverse);
-
- if(thisJointGlobalMat[3][thisSolve->axis] < thisSolve->floor)
- {
- // printf("-- broken plane: %f\n", thisJointGlobalMat[3][thisSolve->axis]);
- if(parentJointGlobalMat[3][thisSolve->axis] < thisSolve->floor)
- {
- printf("Error: Constraint parent has broken the plane, this frame's plane constraint unsolvable!\n");
- }
- else
- {
- Vector parentJointAtPlane(parentJointGlobalMat[3][0], parentJointGlobalMat[3][1], parentJointGlobalMat[3][2]);
- Vector parentPos(parentJointGlobalMat[3][0], parentJointGlobalMat[3][1], parentJointGlobalMat[3][2]);
- Vector thisJointAtPlane(thisJointGlobalMat[3][0], thisJointGlobalMat[3][1], thisJointGlobalMat[3][2]);
- Vector thisJointPos(thisJointGlobalMat[3][0], thisJointGlobalMat[3][1], thisJointGlobalMat[3][2]);
-
- thisJointAtPlane[thisSolve->axis] = thisSolve->floor;
- parentJointAtPlane[thisSolve->axis] = thisSolve->floor;
-
- float thisJointLength = pSource->rawanim[t][thisJointIndex].pos[BONEAXIS];
- float parentLengthToPlane = parentPos[thisSolve->axis] - thisSolve->floor;
- float adjacent = sqrtf((thisJointLength * thisJointLength) - (parentLengthToPlane * parentLengthToPlane));
- Vector parentDirection = thisJointAtPlane - parentJointAtPlane;
- VectorNormalize(parentDirection);
-
- Vector newJointPos = parentJointAtPlane + (parentDirection * adjacent);
-
- Vector newParentDir = newJointPos - parentPos;
- Vector parentUp(parentJointGlobalMat[BONEUP][0], parentJointGlobalMat[BONEUP][1], parentJointGlobalMat[BONEUP][2]);
-
- VectorNormalize(newParentDir);
- VectorNormalize(parentUp);
- // Vector parentSide = newParentDir.Cross(parentUp);
- Vector parentSide = parentUp.Cross(newParentDir);
- VectorNormalize(parentSide);
- parentUp = newParentDir.Cross(parentSide);
- // parentUp = parentSide.Cross(newParentDir);
- VectorNormalize(parentUp);
- parentJointGlobalMat[BONEDIR][0] = newParentDir[0];
- parentJointGlobalMat[BONEDIR][1] = newParentDir[1];
- parentJointGlobalMat[BONEDIR][2] = newParentDir[2];
- parentJointGlobalMat[BONEUP][0] = parentUp[0];
- parentJointGlobalMat[BONEUP][1] = parentUp[1];
- parentJointGlobalMat[BONEUP][2] = parentUp[2];
- parentJointGlobalMat[BONESIDE][0] = parentSide[0];
- parentJointGlobalMat[BONESIDE][1] = parentSide[1];
- parentJointGlobalMat[BONESIDE][2] = parentSide[2];
-
-
- M_matrix4x4_t newParentJointMat;
-
- M_ConcatTransforms(parentJointGlobalMat, gParentJointGlobalMatInverse, newParentJointMat);
-
- s_bone_t resultBone;
- M_MatrixAngles(newParentJointMat, resultBone.rot, resultBone.pos);
- pSource->rawanim[t][parentIndex].rot = resultBone.rot;
- }
- }
- }
-
- // swap animation back for next solve
- combinedAnimation[t] = pSource->rawanim[t];
- pSource->rawanim[t] = sourceAnimation[t];
- }
- for(int t = 0; t < sourceNumFrames; t++)
- {
- pTarget->rawanim[t] = combinedAnimation[t];
- }
- pTarget->numframes = sourceNumFrames;
-
-
-
-
-
-#if 0
- // Process motion mapping into out and return that
- s_source_t *out = new s_source_t;
-
- return out;
-#else
- // Just returns the start animation, to test the Save_SMD API.
- return pTarget;
-#endif
-}
-
-char templates[] =
-"\n\
-#\n\
-# default template file is analogus to not specifying a template file at all\n\
-#\n\
-\n\
-rootScaleJoint ValveBiped.Bip01_L_Foot\n\
-rootScaleAmount 1.0\n\
-toeFloorZ 2.7777\n\
-\n\
-twoJointIKSolve ValveBiped.Bip01_L_Foot\n\
-reverseSolve 0\n\
-extremityScale 1.0\n\
-limbRootOffsetScale 1.0 1.0 0.0\n\
-\n\
-twoJointIKSolve ValveBiped.Bip01_R_Foot\n\
-reverseSolve 0\n\
-extremityScale 1.0\n\
-limbRootOffsetScale 1.0 1.0 0.0\n\
-\n\
-oneJointPlaneConstraint ValveBiped.Bip01_L_Toe0\n\
-\n\
-oneJointPlaneConstraint ValveBiped.Bip01_R_Toe0\n\
-\n\
-twoJointIKSolve ValveBiped.Bip01_R_Hand\n\
-reverseSolve 1\n\
-extremityScale 1.0\n\
-limbRootOffsetScale 0.0 0.0 1.0\n\
-\n\
-twoJointIKSolve ValveBiped.Bip01_L_Hand\n\
-reverseSolve 1\n\
-extremityScale 1.0\n\
-limbRootOffsetScale 0.0 0.0 1.0\n\
-\n\
-";
-
-
-void UsageAndExit()
-{
- MdlError( "usage: motionmapper [-quiet] [-verbose] [-templateFile filename] [-printTemplates] sourceanim.smd targetskeleton.smd output.smd\n\
-\tsourceanim: should contain ref pose and animation data\n\
-\ttargetsekeleton: should contain new ref pose, animation data ignored/can be absent\n\
-\toutput: animation from source mapped onto target skeleton (contains new ref pose)\n\
-\t-templateFile filename : specifies a template file for guiding the mapping of motion\n\
-\t-printTemplate: Causes motionmapper to output the contents of an example template file, which can be used in conjunction with the -templateFile argument to create various motion effects.\n\
-\n");
-}
-
-void PrintHeader()
-{
- vprint( 0, "Valve Software - motionmapper.exe ((c) Valve Coroporation %s)\n", __DATE__ );
- vprint( 0, "--- Maps motion from one animation/skeleton onto another skeleton ---\n" );
-}
-
-
-
-/*
-==============
-main
-==============
-*/
-int main (int argc, char **argv)
-{
- int i;
-
- int useTemplate = 0;
- char templateFileName[1024];
-
- // Header
- PrintHeader();
-
- // Init command line stuff
- CommandLine()->CreateCmdLine( argc, argv );
- InstallSpewFunction();
-
- // init math stuff
- MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
- g_currentscale = g_defaultscale = 1.0;
- g_defaultrotation = RadianEuler( 0, 0, M_PI / 2 );
-
- // No args?
- if (argc == 1)
- {
- UsageAndExit();
- }
-
- // Init variable
- g_quiet = false;
-
- // list template hooey
- CUtlVector< CUtlSymbol > filenames;
-
- // Get args
- for (i = 1; i < argc; i++)
- {
- // Switches
- if (argv[i][0] == '-')
- {
- if (!stricmp(argv[i], "-allowdebug"))
- {
- // Ignore, used by interface system to catch debug builds checked into release tree
- continue;
- }
-
- if (!stricmp(argv[i], "-quiet"))
- {
- g_quiet = true;
- g_verbose = false;
- continue;
- }
-
- if (!stricmp(argv[i], "-verbose"))
- {
- g_quiet = false;
- g_verbose = true;
- continue;
- }
- if (!stricmp(argv[i], "-printTemplate"))
- {
- printf("%s\n", templates);
- exit(0);
-
- }
- if (!stricmp(argv[i], "-templateFile"))
- {
- if(i + 1 < argc)
- {
- strcpy( templateFileName, argv[i+1]);
- useTemplate = 1;
- printf("Note: %s passed as template file", templateFileName);
- }
- else
- {
- printf("Error: -templateFile requires an argument, none found!");
- UsageAndExit();
-
- }
- i++;
- continue;
- }
- }
- else
- {
- // more template stuff
- CUtlSymbol sym = argv[ i ];
- filenames.AddToTail( sym );
- }
- }
-
- // Enough file args?
- if ( filenames.Count() != 3 )
- {
- // misformed arguments
- // otherwise generating unintended results
- printf("Error: 3 file arguments required, %i found!", filenames.Count());
- UsageAndExit();
- }
-
- // Filename arg indexes
- int sourceanim = 0;
- int targetskel = 1;
- int outputanim = 2;
-
- // Copy arg string to global variable
- strcpy( g_outfile, filenames[ outputanim ].String() );
-
- // Init filesystem hooey
- CmdLib_InitFileSystem( g_outfile );
- // ??
- Q_FileBase( g_outfile, g_outfile, sizeof( g_outfile ) );
-
- // Verbose stuff
- if (!g_quiet)
- {
- vprint( 0, "%s, %s, %s, path %s\n", qdir, gamedir, g_outfile );
- }
- // ??
- Q_DefaultExtension(g_outfile, ".smd", sizeof( g_outfile ) );
-
- // Verbose stuff
- if (!g_quiet)
- {
- vprint( 0, "Source animation: %s\n", filenames[ sourceanim ].String() );
- vprint( 0, "Target skeleton: %s\n", filenames[ targetskel ].String() );
-
- vprint( 0, "Creating on \"%s\"\n", g_outfile);
- }
- // fullpath = EXTERNAL GLOBAL!!!???
- strcpy( fullpath, g_outfile );
- strcpy( fullpath, ExpandPath( fullpath ) );
- strcpy( fullpath, ExpandArg( fullpath ) );
-
- // Load source and target data
- s_source_t *pSource = Load_Source( filenames[sourceanim].String(), "smd", false, false );
- s_source_t *pTarget = Load_Source( filenames[targetskel].String(), "smd", false, false );
-
-
- //
- s_template_t *pTemplate = NULL;
- if(useTemplate)
- {
- pTemplate = Load_Template(templateFileName);
- }
- else
- {
- printf("Note: No template file specified, using defaults settings.\n");
-
- pTemplate = New_Template();
- Set_DefaultTemplate(pTemplate);
- }
-
-
- // Process skeleton
- s_source_t *pMappedAnimation = MotionMap( pSource, pTarget, pTemplate );
-
-
- // Save output (ref skeleton & animation data);
- Save_SMD( fullpath, pMappedAnimation );
-
- Q_StripExtension( filenames[outputanim].String(), outname, sizeof( outname ) );
-
- // Verbose stuff
- if (!g_quiet)
- {
- vprint( 0, "\nCompleted \"%s\"\n", g_outfile);
- }
-
- return 0;
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <math.h>
+#include "filesystem_tools.h"
+#include "cmdlib.h"
+#include "scriplib.h"
+#include "mathlib/mathlib.h"
+#define EXTERN
+#include "studio.h"
+#include "motionmapper.h"
+#include "tier1/strtools.h"
+#include "tier0/icommandline.h"
+#include "utldict.h"
+#include <windows.h>
+#include "UtlBuffer.h"
+#include "utlsymbol.h"
+
+bool g_quiet = false;
+bool g_verbose = false;
+char g_outfile[1024];
+bool uselogfile = false;
+
+char g_szFilename[1024];
+FILE *g_fpInput;
+char g_szLine[4096];
+int g_iLinecount;
+
+bool g_bZBrush = false;
+bool g_bGaveMissingBoneWarning = false;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : depth -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void vprint( int depth, const char *fmt, ... )
+{
+ char string[ 8192 ];
+ va_list va;
+ va_start( va, fmt );
+ V_vsprintf_safe( string, fmt, va );
+ va_end( va );
+
+ FILE *fp = NULL;
+
+ if ( uselogfile )
+ {
+ fp = fopen( "log.txt", "ab" );
+ }
+
+ while ( depth-- > 0 )
+ {
+ vprint( 0, " " );
+ OutputDebugString( " " );
+ if ( fp )
+ {
+ fprintf( fp, " " );
+ }
+ }
+
+ ::printf( "%s", string );
+ OutputDebugString( string );
+
+ if ( fp )
+ {
+ char *p = string;
+ while ( *p )
+ {
+ if ( *p == '\n' )
+ {
+ fputc( '\r', fp );
+ }
+ fputc( *p, fp );
+ p++;
+ }
+ fclose( fp );
+ }
+}
+
+
+int k_memtotal;
+void *kalloc( int num, int size )
+{
+ // vprint( 0, "calloc( %d, %d )\n", num, size );
+ // vprint( 0, "%d ", num * size );
+ k_memtotal += num * size;
+ return calloc( num, size );
+}
+
+void kmemset( void *ptr, int value, int size )
+{
+ // vprint( 0, "kmemset( %x, %d, %d )\n", ptr, value, size );
+ memset( ptr, value, size );
+ return;
+}
+
+static bool g_bFirstWarning = true;
+
+void MdlWarning( const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ if (g_quiet)
+ {
+ if (g_bFirstWarning)
+ {
+ vprint( 0, "%s :\n", fullpath );
+ g_bFirstWarning = false;
+ }
+ vprint( 0, "\t");
+ }
+
+ vprint( 0, "WARNING: ");
+ va_start( args, fmt );
+ vprint( 0, fmt, args );
+}
+
+
+void MdlError( char const *fmt, ... )
+{
+ va_list args;
+
+ if (g_quiet)
+ {
+ if (g_bFirstWarning)
+ {
+ vprint( 0, "%s :\n", fullpath );
+ g_bFirstWarning = false;
+ }
+ vprint( 0, "\t");
+ }
+
+ vprint( 0, "ERROR: ");
+ va_start( args, fmt );
+ vprint( 0, fmt, args );
+
+ exit( -1 );
+}
+
+int OpenGlobalFile( char *src )
+{
+ int time1;
+ char filename[1024];
+
+ // local copy of string
+ strcpy( filename, ExpandPath( src ) );
+
+ // Ummm, path sanity checking
+ int pathLength;
+ int numBasePaths = CmdLib_GetNumBasePaths();
+ // This is kinda gross. . . doing the same work in cmdlib on SafeOpenRead.
+ if( CmdLib_HasBasePath( filename, pathLength ) )
+ {
+ char tmp[1024];
+ int i;
+ for( i = 0; i < numBasePaths; i++ )
+ {
+ strcpy( tmp, CmdLib_GetBasePath( i ) );
+ strcat( tmp, filename + pathLength );
+
+ time1 = FileTime( tmp );
+ if( time1 != -1 )
+ {
+ if ((g_fpInput = fopen(tmp, "r")) == 0)
+ {
+ MdlWarning( "reader: could not open file '%s'\n", src );
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+ else
+ {
+ time1 = FileTime (filename);
+ if (time1 == -1)
+ return 0;
+
+ // Whoohooo, FOPEN!
+ if ((g_fpInput = fopen(filename, "r")) == 0)
+ {
+ MdlWarning( "reader: could not open file '%s'\n", src );
+ return 0;
+ }
+
+ return 1;
+ }
+}
+
+bool IsEnd( char const* pLine )
+{
+ if (strncmp( "end", pLine, 3 ) != 0)
+ return false;
+ return (pLine[3] == '\0') || (pLine[3] == '\n');
+}
+
+
+//Wrong name for the use of it.
+void scale_vertex( Vector &org )
+{
+ org[0] = org[0] * g_currentscale;
+ org[1] = org[1] * g_currentscale;
+ org[2] = org[2] * g_currentscale;
+}
+
+
+void clip_rotations( RadianEuler& rot )
+{
+ int j;
+ // clip everything to : -M_PI <= x < M_PI
+
+ for (j = 0; j < 3; j++) {
+ while (rot[j] >= M_PI)
+ rot[j] -= M_PI*2;
+ while (rot[j] < -M_PI)
+ rot[j] += M_PI*2;
+ }
+}
+
+
+void clip_rotations( Vector& rot )
+{
+ int j;
+ // clip everything to : -180 <= x < 180
+
+ for (j = 0; j < 3; j++) {
+ while (rot[j] >= 180)
+ rot[j] -= 180*2;
+ while (rot[j] < -180)
+ rot[j] += 180*2;
+ }
+}
+
+
+void Build_Reference( s_source_t *psource)
+{
+ int i, parent;
+ Vector angle;
+
+ for (i = 0; i < psource->numbones; i++)
+ {
+ matrix3x4_t m;
+ AngleMatrix( psource->rawanim[0][i].rot, m );
+ m[0][3] = psource->rawanim[0][i].pos[0];
+ m[1][3] = psource->rawanim[0][i].pos[1];
+ m[2][3] = psource->rawanim[0][i].pos[2];
+
+ parent = psource->localBone[i].parent;
+ if (parent == -1)
+ {
+ // scale the done pos.
+ // calc rotational matrices
+ MatrixCopy( m, psource->boneToPose[i] );
+ }
+ else
+ {
+ // calc compound rotational matrices
+ // FIXME : Hey, it's orthogical so inv(A) == transpose(A)
+ ConcatTransforms( psource->boneToPose[parent], m, psource->boneToPose[i] );
+ }
+ // vprint( 0, "%3d %f %f %f\n", i, psource->bonefixup[i].worldorg[0], psource->bonefixup[i].worldorg[1], psource->bonefixup[i].worldorg[2] );
+ /*
+ AngleMatrix( angle, m );
+ vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][0], m[1][0], m[2][0] );
+ vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][1], m[1][1], m[2][1] );
+ vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][2], m[1][2], m[2][2] );
+ */
+ }
+}
+
+int Grab_Nodes( s_node_t *pnodes )
+{
+ //
+ // s_node_t structure: index is index!!
+ //
+ int index;
+ char name[1024];
+ int parent;
+ int numbones = 0;
+
+ // Init parent to none
+ for (index = 0; index < MAXSTUDIOSRCBONES; index++)
+ {
+ pnodes[index].parent = -1;
+ }
+
+ // March through nodes lines
+ while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
+ {
+ g_iLinecount++;
+ // get tokens
+ if (sscanf( g_szLine, "%d \"%[^\"]\" %d", &index, name, &parent ) == 3)
+ {
+ // check for duplicated bones
+ /*
+ if (strlen(pnodes[index].name) != 0)
+ {
+ MdlError( "bone \"%s\" exists more than once\n", name );
+ }
+ */
+ // copy name to struct array
+ V_strcpy_safe( pnodes[index].name, name );
+ // set parent into struct array
+ pnodes[index].parent = parent;
+ // increment numbones
+ if (index > numbones)
+ {
+ numbones = index;
+ }
+ }
+ else
+ {
+ return numbones + 1;
+ }
+ }
+ MdlError( "Unexpected EOF at line %d\n", g_iLinecount );
+ return 0;
+}
+
+void Grab_Vertexanimation( s_source_t *psource )
+{
+ char cmd[1024];
+ int index;
+ Vector pos;
+ Vector normal;
+ int t = -1;
+ int count = 0;
+ static s_vertanim_t tmpvanim[MAXSTUDIOVERTS*4];
+
+ while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
+ {
+ g_iLinecount++;
+ if (sscanf( g_szLine, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &normal[0], &normal[1], &normal[2] ) == 7)
+ {
+ if (psource->startframe < 0)
+ {
+ MdlError( "Missing frame start(%d) : %s", g_iLinecount, g_szLine );
+ }
+
+ if (t < 0)
+ {
+ MdlError( "VTA Frame Sync (%d) : %s", g_iLinecount, g_szLine );
+ }
+
+ tmpvanim[count].vertex = index;
+ VectorCopy( pos, tmpvanim[count].pos );
+ VectorCopy( normal, tmpvanim[count].normal );
+ count++;
+
+ if (index >= psource->numvertices)
+ psource->numvertices = index + 1;
+ }
+ else
+ {
+ // flush data
+
+ if (count)
+ {
+ psource->numvanims[t] = count;
+
+ psource->vanim[t] = (s_vertanim_t *)kalloc( count, sizeof( s_vertanim_t ) );
+
+ memcpy( psource->vanim[t], tmpvanim, count * sizeof( s_vertanim_t ) );
+ }
+ else if (t > 0)
+ {
+ psource->numvanims[t] = 0;
+ }
+
+ // next command
+ if (sscanf( g_szLine, "%1023s %d", cmd, &index ))
+ {
+ if (strcmp( cmd, "time" ) == 0)
+ {
+ t = index;
+ count = 0;
+
+ if (t < psource->startframe)
+ {
+ MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+ if (t > psource->endframe)
+ {
+ MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+
+ t -= psource->startframe;
+ }
+ else if (strcmp( cmd, "end") == 0)
+ {
+ psource->numframes = psource->endframe - psource->startframe + 1;
+ return;
+ }
+ else
+ {
+ MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+
+ }
+ else
+ {
+ MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+ }
+ }
+ MdlError( "unexpected EOF: %s\n", psource->filename );
+}
+
+void Grab_Animation( s_source_t *psource )
+{
+ Vector pos;
+ RadianEuler rot;
+ char cmd[1024];
+ int index;
+ int t = -99999999;
+ int size;
+
+ // Init startframe
+ psource->startframe = -1;
+
+ // size per frame
+ size = psource->numbones * sizeof( s_bone_t );
+
+ // march through animation
+ while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
+ {
+ // linecount
+ g_iLinecount++;
+ // split if big enoough
+ if (sscanf( g_szLine, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &rot[0], &rot[1], &rot[2] ) == 7)
+ {
+ // startframe is sanity check for having determined time
+ if (psource->startframe < 0)
+ {
+ MdlError( "Missing frame start(%d) : %s", g_iLinecount, g_szLine );
+ }
+
+ // scale if pertinent
+ scale_vertex( pos );
+ VectorCopy( pos, psource->rawanim[t][index].pos );
+ VectorCopy( rot, psource->rawanim[t][index].rot );
+
+ clip_rotations( rot ); // !!!
+ }
+ else if (sscanf( g_szLine, "%1023s %d", cmd, &index ))
+ {
+ // get time
+ if (strcmp( cmd, "time" ) == 0)
+ {
+ // again time IS an index
+ t = index;
+ if (psource->startframe == -1)
+ {
+ psource->startframe = t;
+ }
+ // sanity check time (little funny logic here, see previous IF)
+ if (t < psource->startframe)
+ {
+ MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+ // bump up endframe?
+ if (t > psource->endframe)
+ {
+ psource->endframe = t;
+ }
+ // make t into pure index
+ t -= psource->startframe;
+
+ // check for memory allocation
+ if (psource->rawanim[t] == NULL)
+ {
+ // Allocate 1 frame of full bonecount
+ psource->rawanim[t] = (s_bone_t *)kalloc( 1, size );
+
+ // duplicate previous frames keys?? preventative sanity?
+ if (t > 0 && psource->rawanim[t-1])
+ {
+ for (int j = 0; j < psource->numbones; j++)
+ {
+ VectorCopy( psource->rawanim[t-1][j].pos, psource->rawanim[t][j].pos );
+ VectorCopy( psource->rawanim[t-1][j].rot, psource->rawanim[t][j].rot );
+ }
+ }
+ }
+ else
+ {
+ // MdlError( "%s has duplicated frame %d\n", psource->filename, t );
+ }
+ }
+ else if (strcmp( cmd, "end") == 0)
+ {
+ psource->numframes = psource->endframe - psource->startframe + 1;
+
+ for (t = 0; t < psource->numframes; t++)
+ {
+ if (psource->rawanim[t] == NULL)
+ {
+ MdlError( "%s is missing frame %d\n", psource->filename, t + psource->startframe );
+ }
+ }
+
+ Build_Reference( psource );
+ return;
+ }
+ else
+ {
+ MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+ }
+ else
+ {
+ MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
+ }
+ }
+
+ MdlError( "unexpected EOF: %s\n", psource->filename );
+}
+
+int lookup_index( s_source_t *psource, int material, Vector& vertex, Vector& normal, Vector2D texcoord )
+{
+ int i;
+
+ for (i = 0; i < numvlist; i++)
+ {
+ if (v_listdata[i].m == material
+ && DotProduct( g_normal[i], normal ) > normal_blend
+ && VectorCompare( g_vertex[i], vertex )
+ && g_texcoord[i][0] == texcoord[0]
+ && g_texcoord[i][1] == texcoord[1])
+ {
+ v_listdata[i].lastref = numvlist;
+ return i;
+ }
+ }
+ if (i >= MAXSTUDIOVERTS) {
+ MdlError( "too many indices in source: \"%s\"\n", psource->filename);
+ }
+
+ VectorCopy( vertex, g_vertex[i] );
+ VectorCopy( normal, g_normal[i] );
+ Vector2Copy( texcoord, g_texcoord[i] );
+
+ v_listdata[i].v = i;
+ v_listdata[i].m = material;
+ v_listdata[i].n = i;
+ v_listdata[i].t = i;
+
+ v_listdata[i].firstref = numvlist;
+ v_listdata[i].lastref = numvlist;
+
+ numvlist = i + 1;
+ return i;
+}
+
+
+void ParseFaceData( s_source_t *psource, int material, s_face_t *pFace )
+{
+ int index[3];
+ int i, j;
+ Vector p;
+ Vector normal;
+ Vector2D t;
+ int iCount, bones[MAXSTUDIOSRCBONES];
+ float weights[MAXSTUDIOSRCBONES];
+ int bone;
+
+ for (j = 0; j < 3; j++)
+ {
+ memset( g_szLine, 0, sizeof( g_szLine ) );
+
+ if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) == NULL)
+ {
+ MdlError("%s: error on g_szLine %d: %s", g_szFilename, g_iLinecount, g_szLine );
+ }
+
+ iCount = 0;
+
+ g_iLinecount++;
+ i = sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %d %d %f %d %f %d %f %d %f",
+ &bone,
+ &p[0], &p[1], &p[2],
+ &normal[0], &normal[1], &normal[2],
+ &t[0], &t[1],
+ &iCount,
+ &bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
+
+ if (i < 9)
+ continue;
+
+ if (bone < 0 || bone >= psource->numbones)
+ {
+ MdlError("bogus bone index\n%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
+ }
+
+ //Scale face pos
+ scale_vertex( p );
+
+ // continue parsing more bones.
+ // FIXME: don't we have a built in parser that'll do this?
+ if (iCount > 4)
+ {
+ int k;
+ int ctr = 0;
+ char *token;
+ for (k = 0; k < 18; k++)
+ {
+ while (g_szLine[ctr] == ' ')
+ {
+ ctr++;
+ }
+ token = strtok( &g_szLine[ctr], " " );
+ ctr += strlen( token ) + 1;
+ }
+ for (k = 4; k < iCount && k < MAXSTUDIOSRCBONES; k++)
+ {
+ while (g_szLine[ctr] == ' ')
+ {
+ ctr++;
+ }
+ token = strtok( &g_szLine[ctr], " " );
+ ctr += strlen( token ) + 1;
+
+ bones[k] = atoi(token);
+
+ token = strtok( &g_szLine[ctr], " " );
+ ctr += strlen( token ) + 1;
+
+ weights[k] = atof(token);
+ }
+ // vprint( 0, "%d ", iCount );
+
+ //vprint( 0, "\n");
+ //exit(1);
+ }
+
+ // adjust_vertex( p );
+ // scale_vertex( p );
+
+ // move vertex position to object space.
+ // VectorSubtract( p, psource->bonefixup[bone].worldorg, tmp );
+ // VectorTransform(tmp, psource->bonefixup[bone].im, p );
+
+ // move normal to object space.
+ // VectorCopy( normal, tmp );
+ // VectorTransform(tmp, psource->bonefixup[bone].im, normal );
+ // VectorNormalize( normal );
+
+ // invert v
+ t[1] = 1.0 - t[1];
+
+ index[j] = lookup_index( psource, material, p, normal, t );
+
+ if (i == 9 || iCount == 0)
+ {
+ g_bone[index[j]].numbones = 1;
+ g_bone[index[j]].bone[0] = bone;
+ g_bone[index[j]].weight[0] = 1.0;
+ }
+ else
+ {
+ iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
+
+ g_bone[index[j]].numbones = iCount;
+ for (i = 0; i < iCount; i++)
+ {
+ g_bone[index[j]].bone[i] = bones[i];
+ g_bone[index[j]].weight[i] = weights[i];
+ }
+ }
+ }
+
+ // pFace->material = material; // BUG
+ pFace->a = index[0];
+ pFace->b = index[1];
+ pFace->c = index[2];
+ Assert( ((pFace->a & 0xF0000000) == 0) && ((pFace->b & 0xF0000000) == 0) &&
+ ((pFace->c & 0xF0000000) == 0) );
+
+ if (flip_triangles)
+ {
+ j = pFace->b; pFace->b = pFace->c; pFace->c = j;
+ }
+}
+
+int use_texture_as_material( int textureindex )
+{
+ if (g_texture[textureindex].material == -1)
+ {
+ // vprint( 0, "%d %d %s\n", textureindex, g_nummaterials, g_texture[textureindex].name );
+ g_material[g_nummaterials] = textureindex;
+ g_texture[textureindex].material = g_nummaterials++;
+ }
+
+ return g_texture[textureindex].material;
+}
+
+int material_to_texture( int material )
+{
+ int i;
+ for (i = 0; i < g_numtextures; i++)
+ {
+ if (g_texture[i].material == material)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int lookup_texture( char *texturename, int maxlen )
+{
+ int i;
+
+ Q_StripExtension( texturename, texturename, maxlen );
+
+ for (i = 0; i < g_numtextures; i++)
+ {
+ if (stricmp( g_texture[i].name, texturename ) == 0)
+ {
+ return i;
+ }
+ }
+
+ if (i >= MAXSTUDIOSKINS)
+ MdlError("Too many materials used, max %d\n", ( int )MAXSTUDIOSKINS );
+
+// vprint( 0, "texture %d = %s\n", i, texturename );
+ V_strcpy_safe( g_texture[i].name, texturename );
+
+ g_texture[i].material = -1;
+ /*
+ if (stristr( texturename, "chrome" ) != NULL) {
+ texture[i].flags = STUDIO_NF_FLATSHADE | STUDIO_NF_CHROME;
+ }
+ else {
+ texture[i].flags = 0;
+ }
+ */
+ g_numtextures++;
+ return i;
+}
+
+int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] )
+{
+ int i;
+
+ // collapse duplicate bone weights
+ for (i = 0; i < iCount-1; i++)
+ {
+ int j;
+ for (j = i + 1; j < iCount; j++)
+ {
+ if (bones[i] == bones[j])
+ {
+ weights[i] += weights[j];
+ weights[j] = 0.0;
+ }
+ }
+ }
+
+ // do sleazy bubble sort
+ int bShouldSort;
+ do {
+ bShouldSort = false;
+ for (i = 0; i < iCount-1; i++)
+ {
+ if (weights[i+1] > weights[i])
+ {
+ int j = bones[i+1]; bones[i+1] = bones[i]; bones[i] = j;
+ float w = weights[i+1]; weights[i+1] = weights[i]; weights[i] = w;
+ bShouldSort = true;
+ }
+ }
+ } while (bShouldSort);
+
+ // throw away all weights less than 1/20th
+ while (iCount > 1 && weights[iCount-1] < 0.05)
+ {
+ iCount--;
+ }
+
+ // clip to the top iMaxCount bones
+ if (iCount > iMaxCount)
+ {
+ iCount = iMaxCount;
+ }
+
+ float t = 0;
+ for (i = 0; i < iCount; i++)
+ {
+ t += weights[i];
+ }
+
+ if (t <= 0.0)
+ {
+ // missing weights?, go ahead and evenly share?
+ // FIXME: shouldn't this error out?
+ t = 1.0 / iCount;
+
+ for (i = 0; i < iCount; i++)
+ {
+ weights[i] = t;
+ }
+ }
+ else
+ {
+ // scale to sum to 1.0
+ t = 1.0 / t;
+
+ for (i = 0; i < iCount; i++)
+ {
+ weights[i] = weights[i] * t;
+ }
+ }
+
+ return iCount;
+}
+
+int vlistCompare( const void *elem1, const void *elem2 )
+{
+ v_unify_t *u1 = &v_listdata[*(int *)elem1];
+ v_unify_t *u2 = &v_listdata[*(int *)elem2];
+
+ // sort by material
+ if (u1->m < u2->m)
+ return -1;
+ if (u1->m > u2->m)
+ return 1;
+
+ // sort by last used
+ if (u1->lastref < u2->lastref)
+ return -1;
+ if (u1->lastref > u2->lastref)
+ return 1;
+
+ return 0;
+}
+
+int faceCompare( const void *elem1, const void *elem2 )
+{
+ int i1 = *(int *)elem1;
+ int i2 = *(int *)elem2;
+
+ // sort by material
+ if (g_face[i1].material < g_face[i2].material)
+ return -1;
+ if (g_face[i1].material > g_face[i2].material)
+ return 1;
+
+ // sort by original usage
+ if (i1 < i2)
+ return -1;
+ if (i1 > i2)
+ return 1;
+
+ return 0;
+}
+
+#define SMALL_FLOAT 1e-12
+
+// NOTE: This routine was taken (and modified) from NVidia's BlinnReflection demo
+// Creates basis vectors, based on a vertex and index list.
+// See the NVidia white paper 'GDC2K PerPixel Lighting' for a description
+// of how this computation works
+static void CalcTriangleTangentSpace( s_source_t *pSrc, int v1, int v2, int v3,
+ Vector &sVect, Vector &tVect )
+{
+/*
+ static bool firstTime = true;
+ static FILE *fp = NULL;
+ if( firstTime )
+ {
+ firstTime = false;
+ fp = fopen( "crap.out", "w" );
+ }
+*/
+
+ /* Compute the partial derivatives of X, Y, and Z with respect to S and T. */
+ Vector2D t0( pSrc->texcoord[v1][0], pSrc->texcoord[v1][1] );
+ Vector2D t1( pSrc->texcoord[v2][0], pSrc->texcoord[v2][1] );
+ Vector2D t2( pSrc->texcoord[v3][0], pSrc->texcoord[v3][1] );
+ Vector p0( pSrc->vertex[v1][0], pSrc->vertex[v1][1], pSrc->vertex[v1][2] );
+ Vector p1( pSrc->vertex[v2][0], pSrc->vertex[v2][1], pSrc->vertex[v2][2] );
+ Vector p2( pSrc->vertex[v3][0], pSrc->vertex[v3][1], pSrc->vertex[v3][2] );
+
+ sVect.Init( 0.0f, 0.0f, 0.0f );
+ tVect.Init( 0.0f, 0.0f, 0.0f );
+
+ // x, s, t
+ Vector edge01 = Vector( p1.x - p0.x, t1.x - t0.x, t1.y - t0.y );
+ Vector edge02 = Vector( p2.x - p0.x, t2.x - t0.x, t2.y - t0.y );
+
+ Vector cross;
+ CrossProduct( edge01, edge02, cross );
+ if( fabs( cross.x ) > SMALL_FLOAT )
+ {
+ sVect.x += -cross.y / cross.x;
+ tVect.x += -cross.z / cross.x;
+ }
+
+ // y, s, t
+ edge01 = Vector( p1.y - p0.y, t1.x - t0.x, t1.y - t0.y );
+ edge02 = Vector( p2.y - p0.y, t2.x - t0.x, t2.y - t0.y );
+
+ CrossProduct( edge01, edge02, cross );
+ if( fabs( cross.x ) > SMALL_FLOAT )
+ {
+ sVect.y += -cross.y / cross.x;
+ tVect.y += -cross.z / cross.x;
+ }
+
+ // z, s, t
+ edge01 = Vector( p1.z - p0.z, t1.x - t0.x, t1.y - t0.y );
+ edge02 = Vector( p2.z - p0.z, t2.x - t0.x, t2.y - t0.y );
+
+ CrossProduct( edge01, edge02, cross );
+ if( fabs( cross.x ) > SMALL_FLOAT )
+ {
+ sVect.z += -cross.y / cross.x;
+ tVect.z += -cross.z / cross.x;
+ }
+
+ // Normalize sVect and tVect
+ VectorNormalize( sVect );
+ VectorNormalize( tVect );
+
+/*
+ // Calculate flat normal
+ Vector flatNormal;
+ edge01 = p1 - p0;
+ edge02 = p2 - p0;
+ CrossProduct( edge02, edge01, flatNormal );
+ VectorNormalize( flatNormal );
+
+ // Get the average position
+ Vector avgPos = ( p0 + p1 + p2 ) / 3.0f;
+
+ // Draw the svect
+ Vector endS = avgPos + sVect * .2f;
+ fvprint( 0, fp, "2\n" );
+ fvprint( 0, fp, "%f %f %f 1.0 0.0 0.0\n", endS[0], endS[1], endS[2] );
+ fvprint( 0, fp, "%f %f %f 1.0 0.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
+
+ // Draw the tvect
+ Vector endT = avgPos + tVect * .2f;
+ fvprint( 0, fp, "2\n" );
+ fvprint( 0, fp, "%f %f %f 0.0 1.0 0.0\n", endT[0], endT[1], endT[2] );
+ fvprint( 0, fp, "%f %f %f 0.0 1.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
+
+ // Draw the normal
+ Vector endN = avgPos + flatNormal * .2f;
+ fvprint( 0, fp, "2\n" );
+ fvprint( 0, fp, "%f %f %f 0.0 0.0 1.0\n", endN[0], endN[1], endN[2] );
+ fvprint( 0, fp, "%f %f %f 0.0 0.0 1.0\n", avgPos[0], avgPos[1], avgPos[2] );
+
+ // Draw the wireframe of the triangle in white.
+ fvprint( 0, fp, "2\n" );
+ fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
+ fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
+ fvprint( 0, fp, "2\n" );
+ fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
+ fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
+ fvprint( 0, fp, "2\n" );
+ fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
+ fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
+
+ // Draw a slightly shrunken version of the geometry to hide surfaces
+ Vector tmp0 = p0 - flatNormal * .1f;
+ Vector tmp1 = p1 - flatNormal * .1f;
+ Vector tmp2 = p2 - flatNormal * .1f;
+ fvprint( 0, fp, "3\n" );
+ fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp0[0], tmp0[1], tmp0[2] );
+ fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp1[0], tmp1[1], tmp1[2] );
+ fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp2[0], tmp2[1], tmp2[2] );
+
+ fflush( fp );
+*/
+}
+
+typedef CUtlVector<int> CIntVector;
+
+void CalcModelTangentSpaces( s_source_t *pSrc )
+{
+ // Build a map from vertex to a list of triangles that share the vert.
+ int meshID;
+ for( meshID = 0; meshID < pSrc->nummeshes; meshID++ )
+ {
+ s_mesh_t *pMesh = &pSrc->mesh[pSrc->meshindex[meshID]];
+ CUtlVector<CIntVector> vertToTriMap;
+ vertToTriMap.AddMultipleToTail( pMesh->numvertices );
+ int triID;
+ for( triID = 0; triID < pMesh->numfaces; triID++ )
+ {
+ s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
+ vertToTriMap[pFace->a].AddToTail( triID );
+ vertToTriMap[pFace->b].AddToTail( triID );
+ vertToTriMap[pFace->c].AddToTail( triID );
+ }
+
+ // Calculate the tangent space for each triangle.
+ CUtlVector<Vector> triSVect;
+ CUtlVector<Vector> triTVect;
+ triSVect.AddMultipleToTail( pMesh->numfaces );
+ triTVect.AddMultipleToTail( pMesh->numfaces );
+ for( triID = 0; triID < pMesh->numfaces; triID++ )
+ {
+ s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
+ CalcTriangleTangentSpace( pSrc,
+ pMesh->vertexoffset + pFace->a,
+ pMesh->vertexoffset + pFace->b,
+ pMesh->vertexoffset + pFace->c,
+ triSVect[triID], triTVect[triID] );
+ }
+
+ // calculate an average tangent space for each vertex.
+ int vertID;
+ for( vertID = 0; vertID < pMesh->numvertices; vertID++ )
+ {
+ const Vector &normal = pSrc->normal[vertID+pMesh->vertexoffset];
+ Vector4D &finalSVect = pSrc->tangentS[vertID+pMesh->vertexoffset];
+ Vector sVect, tVect;
+
+ sVect.Init( 0.0f, 0.0f, 0.0f );
+ tVect.Init( 0.0f, 0.0f, 0.0f );
+ for( triID = 0; triID < vertToTriMap[vertID].Size(); triID++ )
+ {
+ sVect += triSVect[vertToTriMap[vertID][triID]];
+ tVect += triTVect[vertToTriMap[vertID][triID]];
+ }
+
+ // In the case of zbrush, everything needs to be treated as smooth.
+ if( g_bZBrush )
+ {
+ int vertID2;
+ Vector vertPos1( pSrc->vertex[vertID][0], pSrc->vertex[vertID][1], pSrc->vertex[vertID][2] );
+ for( vertID2 = 0; vertID2 < pMesh->numvertices; vertID2++ )
+ {
+ if( vertID2 == vertID )
+ {
+ continue;
+ }
+ Vector vertPos2( pSrc->vertex[vertID2][0], pSrc->vertex[vertID2][1], pSrc->vertex[vertID2][2] );
+ if( vertPos1 == vertPos2 )
+ {
+ int triID2;
+ for( triID2 = 0; triID2 < vertToTriMap[vertID2].Size(); triID2++ )
+ {
+ sVect += triSVect[vertToTriMap[vertID2][triID2]];
+ tVect += triTVect[vertToTriMap[vertID2][triID2]];
+ }
+ }
+ }
+ }
+
+ // make an orthonormal system.
+ // need to check if we are left or right handed.
+ Vector tmpVect;
+ CrossProduct( sVect, tVect, tmpVect );
+ bool leftHanded = DotProduct( tmpVect, normal ) < 0.0f;
+ if( !leftHanded )
+ {
+ CrossProduct( normal, sVect, tVect );
+ CrossProduct( tVect, normal, sVect );
+ VectorNormalize( sVect );
+ VectorNormalize( tVect );
+ finalSVect[0] = sVect[0];
+ finalSVect[1] = sVect[1];
+ finalSVect[2] = sVect[2];
+ finalSVect[3] = 1.0f;
+ }
+ else
+ {
+ CrossProduct( sVect, normal, tVect );
+ CrossProduct( normal, tVect, sVect );
+ VectorNormalize( sVect );
+ VectorNormalize( tVect );
+ finalSVect[0] = sVect[0];
+ finalSVect[1] = sVect[1];
+ finalSVect[2] = sVect[2];
+ finalSVect[3] = -1.0f;
+ }
+ }
+ }
+}
+
+void BuildIndividualMeshes( s_source_t *psource )
+{
+ int i, j, k;
+
+ // sort new vertices by materials, last used
+ static int v_listsort[MAXSTUDIOVERTS]; // map desired order to vlist entry
+ static int v_ilistsort[MAXSTUDIOVERTS]; // map vlist entry to desired order
+
+ for (i = 0; i < numvlist; i++)
+ {
+ v_listsort[i] = i;
+ }
+ qsort( v_listsort, numvlist, sizeof( int ), vlistCompare );
+ for (i = 0; i < numvlist; i++)
+ {
+ v_ilistsort[v_listsort[i]] = i;
+ }
+
+
+ // allocate memory
+ psource->numvertices = numvlist;
+ psource->localBoneweight = (s_boneweight_t *)kalloc( psource->numvertices, sizeof( s_boneweight_t ) );
+ psource->globalBoneweight = NULL;
+ psource->vertexInfo = (s_vertexinfo_t *)kalloc( psource->numvertices, sizeof( s_vertexinfo_t ) );
+ psource->vertex = new Vector[psource->numvertices];
+ psource->normal = new Vector[psource->numvertices];
+ psource->tangentS = new Vector4D[psource->numvertices];
+ psource->texcoord = (Vector2D *)kalloc( psource->numvertices, sizeof( Vector2D ) );
+
+ // create arrays of unique vertexes, normals, texcoords.
+ for (i = 0; i < psource->numvertices; i++)
+ {
+ j = v_listsort[i];
+
+ VectorCopy( g_vertex[v_listdata[j].v], psource->vertex[i] );
+ VectorCopy( g_normal[v_listdata[j].n], psource->normal[i] );
+ Vector2Copy( g_texcoord[v_listdata[j].t], psource->texcoord[i] );
+
+ psource->localBoneweight[i].numbones = g_bone[v_listdata[j].v].numbones;
+ int k;
+ for( k = 0; k < MAXSTUDIOBONEWEIGHTS; k++ )
+ {
+ psource->localBoneweight[i].bone[k] = g_bone[v_listdata[j].v].bone[k];
+ psource->localBoneweight[i].weight[k] = g_bone[v_listdata[j].v].weight[k];
+ }
+
+ // store a bunch of other info
+ psource->vertexInfo[i].material = v_listdata[j].m;
+
+ psource->vertexInfo[i].firstref = v_listdata[j].firstref;
+ psource->vertexInfo[i].lastref = v_listdata[j].lastref;
+ // vprint( 0, "%4d : %2d : %6.2f %6.2f %6.2f\n", i, psource->boneweight[i].bone[0], psource->vertex[i][0], psource->vertex[i][1], psource->vertex[i][2] );
+ }
+
+ // sort faces by materials, last used.
+ static int facesort[MAXSTUDIOTRIANGLES]; // map desired order to src_face entry
+ static int ifacesort[MAXSTUDIOTRIANGLES]; // map src_face entry to desired order
+
+ for (i = 0; i < g_numfaces; i++)
+ {
+ facesort[i] = i;
+ }
+ qsort( facesort, g_numfaces, sizeof( int ), faceCompare );
+ for (i = 0; i < g_numfaces; i++)
+ {
+ ifacesort[facesort[i]] = i;
+ }
+
+ psource->numfaces = g_numfaces;
+ // find first occurance for each material
+ for (k = 0; k < MAXSTUDIOSKINS; k++)
+ {
+ psource->mesh[k].numvertices = 0;
+ psource->mesh[k].vertexoffset = psource->numvertices;
+
+ psource->mesh[k].numfaces = 0;
+ psource->mesh[k].faceoffset = g_numfaces;
+ }
+
+ // find first and count of indices per material
+ for (i = 0; i < psource->numvertices; i++)
+ {
+ k = psource->vertexInfo[i].material;
+ psource->mesh[k].numvertices++;
+ if (psource->mesh[k].vertexoffset > i)
+ psource->mesh[k].vertexoffset = i;
+ }
+
+ // find first and count of faces per material
+ for (i = 0; i < psource->numfaces; i++)
+ {
+ k = g_face[facesort[i]].material;
+
+ psource->mesh[k].numfaces++;
+ if (psource->mesh[k].faceoffset > i)
+ psource->mesh[k].faceoffset = i;
+ }
+
+ /*
+ for (k = 0; k < MAXSTUDIOSKINS; k++)
+ {
+ vprint( 0, "%d : %d:%d %d:%d\n", k, psource->mesh[k].numvertices, psource->mesh[k].vertexoffset, psource->mesh[k].numfaces, psource->mesh[k].faceoffset );
+ }
+ */
+
+ // create remapped faces
+ psource->face = (s_face_t *)kalloc( psource->numfaces, sizeof( s_face_t ));
+ for (k = 0; k < MAXSTUDIOSKINS; k++)
+ {
+ if (psource->mesh[k].numfaces)
+ {
+ psource->meshindex[psource->nummeshes] = k;
+
+ for (i = psource->mesh[k].faceoffset; i < psource->mesh[k].numfaces + psource->mesh[k].faceoffset; i++)
+ {
+ j = facesort[i];
+
+ psource->face[i].a = v_ilistsort[g_src_uface[j].a] - psource->mesh[k].vertexoffset;
+ psource->face[i].b = v_ilistsort[g_src_uface[j].b] - psource->mesh[k].vertexoffset;
+ psource->face[i].c = v_ilistsort[g_src_uface[j].c] - psource->mesh[k].vertexoffset;
+ Assert( ((psource->face[i].a & 0xF0000000) == 0) && ((psource->face[i].b & 0xF0000000) == 0) &&
+ ((psource->face[i].c & 0xF0000000) == 0) );
+ // vprint( 0, "%3d : %4d %4d %4d\n", i, psource->face[i].a, psource->face[i].b, psource->face[i].c );
+ }
+
+ psource->nummeshes++;
+ }
+ }
+
+ CalcModelTangentSpaces( psource );
+}
+
+void Grab_Triangles( s_source_t *psource )
+{
+ int i;
+ Vector vmin, vmax;
+
+ vmin[0] = vmin[1] = vmin[2] = 99999;
+ vmax[0] = vmax[1] = vmax[2] = -99999;
+
+ g_numfaces = 0;
+ numvlist = 0;
+
+ //
+ // load the base triangles
+ //
+ int texture;
+ int material;
+ char texturename[64];
+
+ while (1)
+ {
+ if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) == NULL)
+ break;
+
+ g_iLinecount++;
+
+ // check for end
+ if (IsEnd( g_szLine ))
+ break;
+
+ // Look for extra junk that we may want to avoid...
+ int nLineLength = strlen( g_szLine );
+ if (nLineLength >= 64)
+ {
+ MdlWarning("Unexpected data at line %d, (need a texture name) ignoring...\n", g_iLinecount );
+ continue;
+ }
+
+ // strip off trailing smag
+ V_strcpy_safe( texturename, g_szLine );
+ for (i = strlen( texturename ) - 1; i >= 0 && ! isgraph( texturename[i] ); i--)
+ {
+ }
+ texturename[i + 1] = '\0';
+
+ // funky texture overrides
+ for (i = 0; i < numrep; i++)
+ {
+ if (sourcetexture[i][0] == '\0')
+ {
+ strcpy( texturename, defaulttexture[i] );
+ break;
+ }
+ if (stricmp( texturename, sourcetexture[i]) == 0)
+ {
+ strcpy( texturename, defaulttexture[i] );
+ break;
+ }
+ }
+
+ if (texturename[0] == '\0')
+ {
+ // weird source problem, skip them
+ fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
+ fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
+ fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
+ g_iLinecount += 3;
+ continue;
+ }
+
+ if (stricmp( texturename, "null.bmp") == 0 || stricmp( texturename, "null.tga") == 0)
+ {
+ // skip all faces with the null texture on them.
+ fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
+ fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
+ fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
+ g_iLinecount += 3;
+ continue;
+ }
+
+ texture = lookup_texture( texturename, sizeof( texturename ) );
+ psource->texmap[texture] = texture; // hack, make it 1:1
+ material = use_texture_as_material( texture );
+
+ s_face_t f;
+ ParseFaceData( psource, material, &f );
+
+ g_src_uface[g_numfaces] = f;
+ g_face[g_numfaces].material = material;
+ g_numfaces++;
+ }
+
+ BuildIndividualMeshes( psource );
+}
+
+//--------------------------------------------------------------------
+// Load a SMD file
+//--------------------------------------------------------------------
+int Load_SMD ( s_source_t *psource )
+{
+ char cmd[1024];
+ int option;
+
+ // Open file
+ if (!OpenGlobalFile( psource->filename ))
+ return 0;
+
+ // verbose
+ if( !g_quiet )
+ {
+ printf ("SMD MODEL %s\n", psource->filename);
+ }
+
+ //March through lines
+ g_iLinecount = 0;
+ while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
+ {
+ g_iLinecount++;
+ int numRead = sscanf( g_szLine, "%s %d", cmd, &option );
+
+ // Blank line
+ if ((numRead == EOF) || (numRead == 0))
+ continue;
+
+ if (strcmp( cmd, "version" ) == 0)
+ {
+ if (option != 1)
+ {
+ MdlError("bad version\n");
+ }
+ }
+ // Get hierarchy?
+ else if (strcmp( cmd, "nodes" ) == 0)
+ {
+ psource->numbones = Grab_Nodes( psource->localBone );
+ }
+ // Get animation??
+ else if (strcmp( cmd, "skeleton" ) == 0)
+ {
+ Grab_Animation( psource );
+ }
+ // Geo?
+ else if (strcmp( cmd, "triangles" ) == 0)
+ {
+ Grab_Triangles( psource );
+ }
+ // Geo animation
+ else if (strcmp( cmd, "vertexanimation" ) == 0)
+ {
+ Grab_Vertexanimation( psource );
+ }
+ else
+ {
+ MdlWarning("unknown studio command\n" );
+ }
+ }
+ fclose( g_fpInput );
+
+ is_v1support = true;
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Checks to see if the model source was already loaded
+//-----------------------------------------------------------------------------
+static s_source_t *FindCachedSource( char const* name, char const* xext )
+{
+ int i;
+
+ if( xext[0] )
+ {
+ // we know what extension is necessary. . look for it.
+ sprintf (g_szFilename, "%s%s.%s", cddir[numdirs], name, xext );
+ for (i = 0; i < g_numsources; i++)
+ {
+ if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
+ return g_source[i];
+ }
+ }
+ else
+ {
+ // we don't know what extension to use, so look for all of 'em.
+ sprintf (g_szFilename, "%s%s.vrm", cddir[numdirs], name );
+ for (i = 0; i < g_numsources; i++)
+ {
+ if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
+ return g_source[i];
+ }
+ sprintf (g_szFilename, "%s%s.smd", cddir[numdirs], name );
+ for (i = 0; i < g_numsources; i++)
+ {
+ if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
+ return g_source[i];
+ }
+ /*
+ sprintf (g_szFilename, "%s%s.vta", cddir[numdirs], name );
+ for (i = 0; i < g_numsources; i++)
+ {
+ if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
+ return g_source[i];
+ }
+ */
+ }
+
+ // Not found
+ return 0;
+}
+
+static void FlipFacing( s_source_t *pSrc )
+{
+ unsigned short tmp;
+
+ int i, j;
+ for( i = 0; i < pSrc->nummeshes; i++ )
+ {
+ s_mesh_t *pMesh = &pSrc->mesh[i];
+ for( j = 0; j < pMesh->numfaces; j++ )
+ {
+ s_face_t &f = pSrc->face[pMesh->faceoffset + j];
+ tmp = f.b; f.b = f.c; f.c = tmp;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Loads an animation source
+//-----------------------------------------------------------------------------
+
+s_source_t *Load_Source( char const *name, const char *ext, bool reverse, bool isActiveModel )
+{
+ // Sanity check number of source files
+ if ( g_numsources >= MAXSTUDIOSEQUENCES )
+ MdlError( "Load_Source( %s ) - overflowed g_numsources.", name );
+
+ // Sanity check file and init
+ Assert(name);
+ int namelen = strlen(name) + 1;
+ char* pTempName = (char*)_alloca( namelen );
+ char xext[32];
+ int result = false;
+
+ // Local copy of filename
+ strcpy( pTempName, name );
+
+ // Sanity check file extension?
+ Q_ExtractFileExtension( pTempName, xext, sizeof( xext ) );
+ if (xext[0] == '\0')
+ {
+ V_strcpy_safe( xext, ext );
+ }
+ else
+ {
+ Q_StripExtension( pTempName, pTempName, namelen );
+ }
+
+ // Cached source, ie: already loaded model, legacy
+ // s_source_t* pSource = FindCachedSource( pTempName, xext );
+ // if (pSource)
+ // {
+ // if (isActiveModel)
+ // pSource->isActiveModel = true;
+ // return pSource;
+ // }
+
+ // allocate space and whatnot
+ g_source[g_numsources] = (s_source_t *)kalloc( 1, sizeof( s_source_t ) );
+ V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
+
+ // legacy stuff
+ if (isActiveModel)
+ {
+ g_source[g_numsources]->isActiveModel = true;
+ }
+
+ // more ext sanity check
+ if ( ( !result && xext[0] == '\0' ) || stricmp( xext, "smd" ) == 0)
+ {
+ Q_snprintf( g_szFilename, sizeof(g_szFilename), "%s%s.smd", cddir[numdirs], pTempName );
+ V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
+
+ // Import part, load smd file
+ result = Load_SMD( g_source[g_numsources] );
+ }
+
+ /*
+ if ( ( !result && xext[0] == '\0' ) || stricmp( xext, "dmx" ) == 0)
+ {
+ Q_snprintf( g_szFilename, sizeof(g_szFilename), "%s%s.dmx", cddir[numdirs], pTempName );
+ V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
+
+ // Import part, load smd file
+ result = Load_DMX( g_source[g_numsources] );
+ }
+ */
+
+ // Oops
+ if ( !result)
+ {
+ MdlError( "could not load file '%s'\n", g_source[g_numsources]->filename );
+ }
+
+ // bump up number of sources
+ g_numsources++;
+ if( reverse )
+ {
+ FlipFacing( g_source[g_numsources-1] );
+ }
+ return g_source[g_numsources-1];
+}
+
+void SaveNodes( s_source_t *source, CUtlBuffer& buf )
+{
+ if ( source->numbones <= 0 )
+ return;
+
+ buf.Printf( "nodes\n" );
+
+ for ( int i = 0; i < source->numbones; ++i )
+ {
+ s_node_t *bone = &source->localBone[ i ];
+
+ buf.Printf( "%d \"%s\" %d\n", i, bone->name, bone->parent );
+ }
+
+ buf.Printf( "end\n" );
+}
+
+// FIXME: since we don't us a .qc, we could have problems with scaling, etc.???
+void descale_vertex( Vector &org )
+{
+ float invscale = 1.0f / g_currentscale;
+
+ org[0] = org[0] * invscale;
+ org[1] = org[1] * invscale;
+ org[2] = org[2] * invscale;
+}
+
+void SaveAnimation( s_source_t *source, CUtlBuffer& buf )
+{
+ if ( source->numbones <= 0 )
+ return;
+
+ buf.Printf( "skeleton\n" );
+
+ for ( int frame = 0; frame < source->numframes; ++frame )
+ {
+ buf.Printf( "time %i\n", frame + source->startframe );
+
+ for ( int i = 0; i < source->numbones; ++i )
+ {
+ s_bone_t *prev = NULL;
+ if ( frame > 0 )
+ {
+ if ( source->rawanim[ frame - 1 ] )
+ {
+ prev = &source->rawanim[ frame - 1 ][ i ];
+ }
+ }
+
+ Vector pos = source->rawanim[ frame ][ i ].pos;
+ descale_vertex( pos );
+ RadianEuler rot = source->rawanim[ frame ][ i ].rot;
+
+// If this is enabled, then we delta this pos vs the prev frame and don't write out a sample if it's the same value...
+#if 0
+ if ( prev )
+ {
+ Vector ppos = source->rawanim[ frame -1 ][ i ].pos;
+ descale_vertex( pos );
+ RadianEuler prot = source->rawanim[ frame -1 ][ i ].rot;
+
+ // Only output it if there's a delta
+ if ( ( ppos != pos ) ||
+ Q_memcmp( &prot, &rot, sizeof( prot ) ) )
+ {
+ buf.Printf
+ ( "%d %f %f %f %f %f %f\n",
+ i, // bone index
+ pos[ 0 ],
+ pos[ 1 ],
+ pos[ 2 ],
+ rot[ 0 ],
+ rot[ 1 ],
+ rot[ 2 ]
+ );
+ }
+ }
+ else
+#endif
+ {
+ buf.Printf
+ ( "%d %f %f %f %f %f %f\n",
+ i, // bone index
+ pos[ 0 ],
+ pos[ 1 ],
+ pos[ 2 ],
+ rot[ 0 ],
+ rot[ 1 ],
+ rot[ 2 ]
+ );
+ }
+ }
+ }
+
+ buf.Printf( "end\n" );
+}
+
+void Save_SMD( char const *filename, s_source_t *source )
+{
+ // Text buffer
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "version 1\n" );
+
+ SaveNodes( source, buf );
+ SaveAnimation( source, buf );
+
+ FileHandle_t fh = g_pFileSystem->Open( filename, "wb" );
+ if ( FILESYSTEM_INVALID_HANDLE != fh )
+ {
+ g_pFileSystem->Write( buf.Base(), buf.TellPut(), fh );
+ g_pFileSystem->Close( fh );
+ }
+}
+
+//--------------------------------------------------------------------
+// mikes right handed row based linear algebra
+//--------------------------------------------------------------------
+struct M_matrix4x4_t
+{
+ M_matrix4x4_t() {
+
+ m_flMatVal[0][0] = 1.0; m_flMatVal[0][1] = 0.0; m_flMatVal[0][2] = 0.0; m_flMatVal[0][3] = 0.0;
+ m_flMatVal[1][0] = 0.0; m_flMatVal[1][1] = 1.0; m_flMatVal[1][2] = 0.0; m_flMatVal[1][3] = 0.0;
+ m_flMatVal[2][0] = 0.0; m_flMatVal[2][1] = 0.0; m_flMatVal[2][2] = 1.0; m_flMatVal[2][3] = 0.0;
+ m_flMatVal[3][0] = 0.0; m_flMatVal[3][1] = 0.0; m_flMatVal[3][2] = 0.0; m_flMatVal[3][3] = 1.0;
+
+ }
+ // M_matrix3x4_t(
+ // float m00, float m01, float m02,
+ // float m10, float m11, float m12,
+ // float m20, float m21, float m22,
+ // float m30, float m31, float m32)
+ // {
+ // m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02;
+ // m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12;
+ // m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22;
+ // m_flMatVal[3][0] = m30; m_flMatVal[3][1] = m31; m_flMatVal[3][2] = m32;
+
+ // }
+
+ float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 4 )); return m_flMatVal[i]; }
+ const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 4 )); return m_flMatVal[i]; }
+ float *Base() { return &m_flMatVal[0][0]; }
+ const float *Base() const { return &m_flMatVal[0][0]; }
+
+ float m_flMatVal[4][4];
+};
+
+void M_MatrixAngles( const M_matrix4x4_t& matrix, RadianEuler &angles, Vector &position)
+{
+ float cX, sX, cY, sY, cZ, sZ;
+
+ sY = -matrix[0][2];
+ cY = sqrtf(1.0-(sY*sY));
+
+ if (cY != 0.0)
+ {
+ sX = matrix[1][2];
+ cX = matrix[2][2];
+ sZ = matrix[0][1];
+ cZ = matrix[0][0];
+ }
+ else
+ {
+ sX = -matrix[2][1];
+ cX = matrix[1][1];
+ sZ = 0.0;
+ cZ = 1.0;
+ }
+
+ angles[0] = atan2f( sX, cX );
+ angles[2] = atan2f( sZ, cZ );
+
+ sX = sinf(angles[0]);
+ cX = cosf(angles[0]);
+
+ if (sX > cX)
+ cY = matrix[1][2] / sX;
+ else
+ cY = matrix[2][2] / cX;
+
+ angles[1] = atan2f( sY, cY );
+
+
+ position.x = matrix[3][0];
+ position.y = matrix[3][1];
+ position.z = matrix[3][2];
+
+}
+
+// void M_MatrixAngles( const M_matrix4x4_t& matrix, RadianEuler &angles, Vector &position)
+// {
+
+ // float cX, sX, cY, sY, cZ, sZ;
+
+ // sY = matrix[2][0];
+ // cY = sqrtf(1.0-(sY*sY));
+
+ // if (cY != 0.0)
+ // {
+ // sX = -matrix[2][1];
+ // cX = matrix[2][2];
+ // sZ = -matrix[1][0];
+ // cZ = matrix[0][0];
+ // }
+ // else
+ // {
+ // sX = matrix[0][1];
+ // cX = matrix[1][1];
+ // sZ = 0.0;
+ // cZ = 1.0;
+ // }
+
+ // angles[0] = atan2f( sX, cX );
+ // angles[2] = atan2f( sZ, cZ );
+
+ // sX = sinf(angles[0]);
+ // cX = cosf(angles[0]);
+
+ // if (sX > cX)
+ // cY = -matrix[2][1] / sX;
+ // else
+ // cY = matrix[2][2] / cX;
+
+ // angles[1] = atan2f( sY, cY );
+
+ // angles[0] = angles[0];
+ // angles[1] = angles[1];
+ // angles[2] = angles[2];
+
+ // position.x = matrix[3][0];
+ // position.y = matrix[3][1];
+ // position.z = matrix[3][2];
+// }
+
+void M_MatrixCopy( const M_matrix4x4_t& in, M_matrix4x4_t& out )
+{
+ // Assert( s_bMathlibInitialized );
+ memcpy( out.Base(), in.Base(), sizeof( float ) * 4 * 4 );
+}
+void M_RotateZMatrix(float radian, M_matrix4x4_t &resultMatrix)
+{
+
+ resultMatrix[0][0] = cosf(radian);
+ resultMatrix[0][1] = sin(radian);
+ resultMatrix[0][2] = 0.0;
+ resultMatrix[1][0] =-sin(radian);
+ resultMatrix[1][1] = cos(radian);
+ resultMatrix[1][2] = 0.0;
+ resultMatrix[2][0] = 0.0;
+ resultMatrix[2][1] = 0.0;
+ resultMatrix[2][2] = 1.0;
+}
+
+// !!! THIS SHIT DOESN'T WORK!! WHY? HAS I EVER?
+void M_AngleAboutAxis(Vector &axis, float radianAngle, M_matrix4x4_t &result)
+{
+ float c = cosf(radianAngle);
+ float s = sinf(radianAngle);
+ float t = 1.0 - c;
+ // axis.normalize();
+
+ result[0][0] = t * axis[0] * axis[0] + c;
+ result[0][1] = t * axis[0] * axis[1] - s * axis[2];
+ result[0][2] = t * axis[0] * axis[2] + s * axis[1];
+ result[1][0] = t * axis[0] * axis[1] + s * axis[2];
+ result[1][1] = t * axis[1] * axis[1] + c;
+ result[1][2] = t * axis[1] * axis[2] - s * axis[0];
+ result[2][0] = t * axis[1] * axis[2] - s;
+ result[2][1] = t * axis[1] * axis[2] + s * axis[1];
+ result[2][2] = t * axis[2] * axis[2] + c * axis[0];
+
+}
+
+
+void M_MatrixInvert( const M_matrix4x4_t& in, M_matrix4x4_t& out )
+{
+ // Assert( s_bMathlibInitialized );
+ if ( &in == &out )
+ {
+ M_matrix4x4_t in2;
+ M_MatrixCopy( in, in2 );
+ M_MatrixInvert( in2, out );
+ return;
+ }
+ float tmp[3];
+
+ // I'm guessing this only works on a 3x4 orthonormal matrix
+ out[0][0] = in[0][0];
+ out[1][0] = in[0][1];
+ out[2][0] = in[0][2];
+
+ out[0][1] = in[1][0];
+ out[1][1] = in[1][1];
+ out[2][1] = in[1][2];
+
+ out[0][2] = in[2][0];
+ out[1][2] = in[2][1];
+ out[2][2] = in[2][2];
+
+ tmp[0] = in[3][0];
+ tmp[1] = in[3][1];
+ tmp[2] = in[3][2];
+
+ float v1[3], v2[3], v3[3];
+ v1[0] = out[0][0];
+ v1[1] = out[1][0];
+ v1[2] = out[2][0];
+ v2[0] = out[0][1];
+ v2[1] = out[1][1];
+ v2[2] = out[2][1];
+ v3[0] = out[0][2];
+ v3[1] = out[1][2];
+ v3[2] = out[2][2];
+
+ out[3][0] = -DotProduct( tmp, v1 );
+ out[3][1] = -DotProduct( tmp, v2 );
+ out[3][2] = -DotProduct( tmp, v3 );
+
+ // Trivial case
+ // if (IS_IDENTITY(matrix))
+ // return SbMatrix::identity();
+
+ // // Affine case...
+ // // SbMatrix affineAnswer;
+ // // if ( affine_inverse( SbMatrix(matrix), affineAnswer ) )
+ // // return affineAnswer;
+
+ // int index[4];
+ // float d, invmat[4][4], temp;
+ // SbMatrix inverse = *this;
+
+ // if(inverse.LUDecomposition(index, d)) {
+
+ // invmat[0][0] = 1.0;
+ // invmat[0][1] = 0.0;
+ // invmat[0][2] = 0.0;
+ // invmat[0][3] = 0.0;
+ // inverse.LUBackSubstitution(index, invmat[0]);
+ // invmat[1][0] = 0.0;
+ // invmat[1][1] = 1.0;
+ // invmat[1][2] = 0.0;
+ // invmat[1][3] = 0.0;
+ // inverse.LUBackSubstitution(index, invmat[1]);
+ // invmat[2][0] = 0.0;
+ // invmat[2][1] = 0.0;
+ // invmat[2][2] = 1.0;
+ // invmat[2][3] = 0.0;
+ // inverse.LUBackSubstitution(index, invmat[2]);
+ // invmat[3][0] = 0.0;
+ // invmat[3][1] = 0.0;
+ // invmat[3][2] = 0.0;
+ // invmat[3][3] = 1.0;
+ // inverse.LUBackSubstitution(index, invmat[3]);
+
+// #define SWAP(i,j) \
+ // temp = invmat[i][j]; \
+ // invmat[i][j] = invmat[j][i]; \
+ // invmat[j][i] = temp;
+
+ // SWAP(1,0);
+
+ // SWAP(2,0);
+ // SWAP(2,1);
+
+ // SWAP(3,0);
+ // SWAP(3,1);
+ // SWAP(3,2);
+// #undef SWAP
+ // }
+}
+
+/*
+================
+M_ConcatTransforms
+================
+*/
+void M_ConcatTransforms (const M_matrix4x4_t &in1, const M_matrix4x4_t &in2, M_matrix4x4_t &out)
+{
+
+ // Assert( s_bMathlibInitialized );
+ // if ( &in1 == &out )
+ // {
+ // matrix3x4_t in1b;
+ // MatrixCopy( in1, in1b );
+ // ConcatTransforms( in1b, in2, out );
+ // return;
+ // }
+ // if ( &in2 == &out )
+ // {
+ // matrix3x4_t in2b;
+ // MatrixCopy( in2, in2b );
+ // ConcatTransforms( in1, in2b, out );
+ // return;
+ // }
+
+#define MULT(i,j) (in1[i][0]*in2[0][j] + \
+ in1[i][1]*in2[1][j] + \
+ in1[i][2]*in2[2][j] + \
+ in1[i][3]*in2[3][j])
+
+ out[0][0] = MULT(0,0);
+ out[0][1] = MULT(0,1);
+ out[0][2] = MULT(0,2);
+ out[0][3] = MULT(0,3);
+ out[1][0] = MULT(1,0);
+ out[1][1] = MULT(1,1);
+ out[1][2] = MULT(1,2);
+ out[1][3] = MULT(1,3);
+ out[2][0] = MULT(2,0);
+ out[2][1] = MULT(2,1);
+ out[2][2] = MULT(2,2);
+ out[2][3] = MULT(2,3);
+ out[3][0] = MULT(3,0);
+ out[3][1] = MULT(3,1);
+ out[3][2] = MULT(3,2);
+ out[3][3] = MULT(3,3);
+
+#undef MULT
+
+}
+
+void M_AngleMatrix( RadianEuler const &angles, const Vector &position, M_matrix4x4_t& matrix )
+{
+ // Assert( s_bMathlibInitialized );
+ float sx, sy, sz, cx, cy, cz;
+
+
+ sx = sinf(angles[0]);
+ cx = cosf(angles[0]);
+ sy = sinf(angles[1]);
+ cy = cosf(angles[1]);
+ sz = sinf(angles[2]);
+ cz = cosf(angles[2]);
+
+ // SinCos( angles[0], &sx, &cx ); // 2
+ // SinCos( angles[1], &sy, &cy ); // 1
+ // SinCos( angles[2], &sz, &cz ); // 0
+
+ M_matrix4x4_t mx, my, mz, temp1;
+
+ // rotation about x
+ mx[1][1] = cx;
+ mx[1][2] = sx;
+ mx[2][1] = -sx;
+ mx[2][2] = cx;
+
+ // rotation about y
+ my[0][0] = cy;
+ my[0][2] = -sy;
+ my[2][0] = sy;
+ my[2][2] = cy;
+
+ // rotation about z
+ mz[0][0] = cz;
+ mz[0][1] = sz;
+ mz[1][0] = -sz;
+ mz[1][1] = cz;
+
+ // z * y * x
+ M_ConcatTransforms(mx, my, temp1);
+ M_ConcatTransforms(temp1, mz, matrix);
+
+ // put position in
+ matrix[3][0] = position.x;
+ matrix[3][1] = position.y;
+ matrix[3][2] = position.z;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Motion mapper functions
+//-----------------------------------------------------------------------------
+#define BONEAXIS 0
+#define BONEDIR 0
+#define BONESIDE 1
+#define BONEUP 2
+#define WORLDUP 2
+#define PRINTMAT(m) \
+ printf("\n%f %f %f %f\n", m[0][0], m[0][1], m[0][2], m[0][3]); \
+ printf("%f %f %f %f\n", m[1][0], m[1][1], m[1][2], m[1][3]); \
+ printf("%f %f %f %f\n", m[2][0], m[2][1], m[2][2], m[2][3]); \
+ printf("%f %f %f %f\n", m[3][0], m[3][1], m[3][2], m[3][3]);
+
+struct s_planeConstraint_t
+{
+ char jointNameString[1024];
+ float floor;
+ int axis;
+
+};
+
+struct s_iksolve_t
+{
+ char jointNameString[1024];
+ int reverseSolve;
+ float extremityScale;
+ Vector limbRootOffsetScale;
+ int doRelativeLock;
+ char relativeLockNameString[1024];
+ float relativeLockScale;
+
+};
+
+struct s_jointScale_t
+{
+ char jointNameString[1024];
+ float scale;
+};
+
+struct s_template_t
+{
+ char rootScaleJoint[1024];
+ float rootScaleAmount;
+ int numIKSolves;
+ s_iksolve_t *ikSolves[128];
+ int numJointScales;
+ s_jointScale_t *jointScales[128];
+ int numPlaneConstraints;
+ s_planeConstraint_t *planeConstraints[128];
+ float toeFloorZ;
+ int doSkeletonScale;
+ float skeletonScale;
+
+};
+
+
+//-----------------------------------------------------------------------------
+// Load a template file into structure
+//-----------------------------------------------------------------------------
+s_template_t *New_Template()
+{
+ s_template_t *pTemplate = (s_template_t *)kalloc(1, sizeof(s_template_t));
+ pTemplate->rootScaleAmount = 1.0;
+ pTemplate->numIKSolves = 0;
+ pTemplate->numJointScales = 0;
+ pTemplate->toeFloorZ = 2.802277;
+ pTemplate->numPlaneConstraints = 0;
+ pTemplate->doSkeletonScale = 0;
+ pTemplate->skeletonScale = 1.0;
+ return pTemplate;
+}
+s_iksolve_t *New_IKSolve()
+{
+ s_iksolve_t *pIKSolve = (s_iksolve_t *)kalloc(1, sizeof(s_iksolve_t));
+ pIKSolve->reverseSolve = 0;
+ pIKSolve->extremityScale = 1.0;
+ pIKSolve->limbRootOffsetScale[0] = pIKSolve->limbRootOffsetScale[1] = pIKSolve->limbRootOffsetScale[2] = 0.0;
+ pIKSolve->doRelativeLock = 0;
+ pIKSolve->relativeLockScale = 1.0;
+ return pIKSolve;
+}
+
+s_planeConstraint_t *New_planeConstraint(float floor)
+{
+ s_planeConstraint_t *pConstraint = (s_planeConstraint_t *)kalloc(1, sizeof(s_planeConstraint_t));
+ pConstraint->floor = floor;
+ pConstraint->axis = 2;
+
+ return pConstraint;
+}
+
+void Set_DefaultTemplate(s_template_t *pTemplate)
+{
+ pTemplate->numJointScales = 0;
+
+ strcpy(pTemplate->rootScaleJoint, "ValveBiped.Bip01_L_Foot");
+ pTemplate->rootScaleAmount = 1.0;
+
+ pTemplate->numIKSolves = 4;
+ pTemplate->ikSolves[0] = New_IKSolve();
+ pTemplate->ikSolves[1] = New_IKSolve();
+ pTemplate->ikSolves[2] = New_IKSolve();
+ pTemplate->ikSolves[3] = New_IKSolve();
+
+
+ pTemplate->numPlaneConstraints = 2;
+ pTemplate->planeConstraints[0] = New_planeConstraint(pTemplate->toeFloorZ);
+ strcpy(pTemplate->planeConstraints[0]->jointNameString, "ValveBiped.Bip01_L_Toe0");
+ pTemplate->planeConstraints[1] = New_planeConstraint(pTemplate->toeFloorZ);
+ strcpy(pTemplate->planeConstraints[1]->jointNameString, "ValveBiped.Bip01_R_Toe0");
+
+ strcpy(pTemplate->ikSolves[0]->jointNameString, "ValveBiped.Bip01_L_Foot");
+ pTemplate->ikSolves[0]->reverseSolve = 0;
+ pTemplate->ikSolves[0]->extremityScale = 1.0;
+ pTemplate->ikSolves[0]->limbRootOffsetScale[0] = 1.0;
+ pTemplate->ikSolves[0]->limbRootOffsetScale[1] = 1.0;
+ pTemplate->ikSolves[0]->limbRootOffsetScale[2] = 0.0;
+
+ strcpy(pTemplate->ikSolves[1]->jointNameString, "ValveBiped.Bip01_R_Foot");
+ pTemplate->ikSolves[1]->reverseSolve = 0;
+ pTemplate->ikSolves[1]->extremityScale = 1.0;
+ pTemplate->ikSolves[1]->limbRootOffsetScale[0] = 1.0;
+ pTemplate->ikSolves[1]->limbRootOffsetScale[1] = 1.0;
+ pTemplate->ikSolves[1]->limbRootOffsetScale[2] = 0.0;
+
+ strcpy(pTemplate->ikSolves[2]->jointNameString, "ValveBiped.Bip01_R_Hand");
+ pTemplate->ikSolves[2]->reverseSolve = 1;
+ pTemplate->ikSolves[2]->extremityScale = 1.0;
+ pTemplate->ikSolves[2]->limbRootOffsetScale[0] = 0.0;
+ pTemplate->ikSolves[2]->limbRootOffsetScale[1] = 0.0;
+ pTemplate->ikSolves[2]->limbRootOffsetScale[2] = 1.0;
+
+ strcpy(pTemplate->ikSolves[3]->jointNameString, "ValveBiped.Bip01_L_Hand");
+ pTemplate->ikSolves[3]->reverseSolve = 1;
+ pTemplate->ikSolves[3]->extremityScale = 1.0;
+ pTemplate->ikSolves[3]->limbRootOffsetScale[0] = 0.0;
+ pTemplate->ikSolves[3]->limbRootOffsetScale[1] = 0.0;
+ pTemplate->ikSolves[3]->limbRootOffsetScale[2] = 1.0;
+ // pTemplate->ikSolves[3]->doRelativeLock = 1;
+ // strcpy(pTemplate->ikSolves[3]->relativeLockNameString, "ValveBiped.Bip01_R_Hand");
+ // pTemplate->ikSolves[3]->relativeLockScale = 1.0;
+
+}
+
+void split(char *str, char *sep, char **sp)
+{
+ char *r = strtok(str, sep);
+ while(r != NULL)
+ {
+ *sp = r;
+ sp++;
+ r = strtok(NULL, sep);
+ }
+ *sp = NULL;
+}
+
+
+int checkCommand(char *str, char *cmd, int numOptions, int numSplit)
+{
+ if(strcmp(str, cmd) == 0)
+ {
+ if(numOptions <= numSplit)
+ return 1;
+ else
+ {
+ printf("Error: Number or argument mismatch in template file cmd %s, requires %i, found %i\n", cmd, numOptions, numSplit);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+s_template_t *Load_Template(char *name )
+{
+
+ // Sanity check file and init
+ Assert(name);
+
+ s_template_t *pTemplate = New_Template();
+
+
+ // Open file
+ if (!OpenGlobalFile( name ))
+ return 0;
+
+
+ //March through lines
+ g_iLinecount = 0;
+ while(fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
+ {
+ g_iLinecount++;
+ if(g_szLine[0] == '#')
+ continue;
+
+ char *endP = strrchr(g_szLine, '\n');
+ if(endP != NULL)
+ *endP = '\0';
+
+
+ char *sp[128];
+ char **spp = sp;
+
+ char sep[] = " ";
+ split(g_szLine, sep, sp);
+ int numSplit = 0;
+
+ while(*spp != NULL)
+ {
+ spp++;
+ numSplit++;
+
+ }
+ if(numSplit < 1 ||
+ *sp[0] == '\n')
+ continue;
+
+
+ // int numRead = sscanf( g_szLine, "%s %s %s", cmd, &option, &option2 );
+
+ // // Blank line
+ // if ((numRead == EOF) || (numRead == 0))
+ // continue;
+
+ // commands
+ char *cmd;
+ int numOptions = numSplit - 1;
+
+ cmd = sp[0];
+ if(checkCommand(cmd, "twoJointIKSolve", 1, numOptions))
+ {
+ printf("\nCreating two joint IK solve %s\n", sp[1]);
+ pTemplate->ikSolves[pTemplate->numIKSolves] = New_IKSolve();
+ strcpy(pTemplate->ikSolves[pTemplate->numIKSolves]->jointNameString, sp[1]);
+ pTemplate->numIKSolves++;
+
+ }
+ else if(checkCommand(cmd, "oneJointPlaneConstraint", 1, numOptions))
+ {
+ printf("\nCreating one joint plane constraint %s\n", sp[1]);
+ pTemplate->planeConstraints[pTemplate->numPlaneConstraints] = New_planeConstraint(pTemplate->toeFloorZ);
+ strcpy(pTemplate->planeConstraints[pTemplate->numPlaneConstraints]->jointNameString, sp[1]);
+ pTemplate->numPlaneConstraints++;
+
+ }
+ else if(checkCommand(cmd, "reverseSolve", 1, numOptions))
+ {
+ printf("reverseSolve: %s\n", sp[1]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->reverseSolve = atoi(sp[1]);
+ }
+ else if(checkCommand(cmd, "extremityScale", 1, numOptions))
+ {
+ printf("extremityScale: %s\n", sp[1]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->extremityScale = atof(sp[1]);
+ }
+ else if(checkCommand(cmd, "limbRootOffsetScale", 3, numOptions))
+ {
+ printf("limbRootOffsetScale: %s %s %s\n", sp[1], sp[2], sp[3]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[0] = atof(sp[1]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[1] = atof(sp[2]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[2] = atof(sp[3]);
+ }
+ else if(checkCommand(cmd, "toeFloorZ", 1, numOptions))
+ {
+ printf("toeFloorZ: %s\n", sp[1]);
+ pTemplate->toeFloorZ = atof(sp[1]);
+ }
+ else if(checkCommand(cmd, "relativeLock", 2, numOptions))
+ {
+ printf("relativeLock: %s\n", sp[1]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->doRelativeLock = 1;
+ strcpy(pTemplate->ikSolves[pTemplate->numIKSolves - 1]->relativeLockNameString, sp[1]);
+ pTemplate->ikSolves[pTemplate->numIKSolves - 1]->relativeLockScale = atof(sp[2]);
+
+ }
+ else if(checkCommand(cmd, "rootScaleJoint", 1, numOptions))
+ {
+ printf("\nrootScaleJoint: %s\n", sp[1]);
+ strcpy(pTemplate->rootScaleJoint, sp[1]);
+ }
+ else if(checkCommand(cmd, "rootScaleAmount", 1, numOptions))
+ {
+ printf("rootScaleAmount: %s\n", sp[1]);
+ pTemplate->rootScaleAmount = atof(sp[1]);
+ }
+ else if(checkCommand(cmd, "jointScale", 2, numOptions))
+ {
+ printf("\nCreating joint scale %s of %s\n", sp[1], sp[2]);
+ pTemplate->jointScales[pTemplate->numJointScales] = (s_jointScale_t *)kalloc(1, sizeof(s_jointScale_t));
+ strcpy(pTemplate->jointScales[pTemplate->numJointScales]->jointNameString, sp[1]);
+ pTemplate->jointScales[pTemplate->numJointScales]->scale = atof(sp[2]);
+ pTemplate->numJointScales++;
+ }
+ else if(checkCommand(cmd, "skeletonScale", 2, numOptions))
+ {
+ printf("\nCreating skeleton scale of %s\n", sp[1]);
+ pTemplate->doSkeletonScale = 1;
+ pTemplate->skeletonScale = atof(sp[1]);
+ }
+ else
+ {
+ MdlWarning("unknown studio command\n" );
+ }
+ }
+ fclose( g_fpInput );
+ return pTemplate;
+}
+
+//-----------------------------------------------------------------------------
+// get node index from node string name
+//-----------------------------------------------------------------------------
+int GetNodeIndex(s_source_t *psource, char *nodeName)
+{
+ for(int i = 0; i < psource->numbones; i++)
+ {
+ if(strcmp(nodeName, psource->localBone[i].name) == 0)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// get node index from node string name
+//-----------------------------------------------------------------------------
+void GetNodePath(s_source_t *psource, int startIndex, int endIndex, int *path)
+{
+ *path = endIndex;
+
+ s_node_t *nodes;
+ nodes = psource->localBone;
+ while(*path != startIndex)
+ {
+ int parent = nodes[*path].parent;
+ path++;
+ *path = parent;
+ }
+ path++;
+ *path = -1;
+}
+
+void SumBonePathTranslations(int *indexPath, s_bone_t *boneArray, Vector &resultVector, int rootOffset = 0)
+{
+
+ // walk the path
+ int *pathPtr = indexPath;
+ // M_matrix4x4_t matrixCum;
+
+ // find length of path
+ int length = 0;
+ while(*pathPtr != -1)
+ {
+ length++;
+ pathPtr++;
+ }
+
+ int l = length - (1 + rootOffset);
+
+ resultVector[0] = 0.0;
+ resultVector[1] = 0.0;
+ resultVector[2] = 0.0;
+
+ for(int i = l; i > -1; i--)
+ {
+ s_bone_t *thisBone = boneArray + indexPath[i];
+ resultVector += thisBone->pos;
+ }
+}
+
+void CatBonePath(int *indexPath, s_bone_t *boneArray, M_matrix4x4_t &resultMatrix, int rootOffset = 0)
+{
+
+ // walk the path
+ int *pathPtr = indexPath;
+ // M_matrix4x4_t matrixCum;
+
+ // find length of path
+ int length = 0;
+ while(*pathPtr != -1)
+ {
+ length++;
+ pathPtr++;
+ }
+
+ int l = length - (1 + rootOffset);
+
+ for(int i = l; i > -1; i--)
+ {
+ s_bone_t *thisBone = boneArray + indexPath[i];
+ // printf("bone index: %i %i\n", i, indexPath[i]);
+ // printf("pos: %f %f %f, rot: %f %f %f\n", thisBone->pos.x, thisBone->pos.y, thisBone->pos.z, thisBone->rot.x, thisBone->rot.y, thisBone->rot.z);
+ M_matrix4x4_t thisMatrix;
+ M_AngleMatrix(thisBone->rot, thisBone->pos, thisMatrix);
+ // PRINTMAT(thisMatrix)
+ M_matrix4x4_t tempCum;
+ M_MatrixCopy(resultMatrix, tempCum);
+ M_ConcatTransforms(thisMatrix, tempCum, resultMatrix);
+ }
+ // PRINTMAT(matrixCum);
+ // M_MatrixAngles(matrixCum, resultBone.rot, resultBone.pos);
+
+ // printf("pos: %f %f %f, rot: %f %f %f\n", resultBone.pos.x,resultBone.pos.y, resultBone.pos.z, RAD2DEG(resultBone.rot.x),RAD2DEG(resultBone.rot.y),RAD2DEG(resultBone.rot.z));
+
+}
+// int ConformSources(s_source_t *pSource, s_source_t *pTarget)
+// {
+ // if(pSource->numbones != *pTarget->numbones)
+ // {
+ // printf("ERROR: The number of bones in the target file must match the source file.");
+ // return 1;
+ // }
+ // if(pSource->numframes != pTarget->numframes)
+ // {
+ // printf("Note: Source and target frame lengths do not match");
+ // for(int t = 0; t < pTarget->numframes; t++)
+ // {
+ // free(pTarget->rawanim[t]);
+ // }
+ // pTarget->numframes = pSource->numframes;
+ // int size = pTarget->numbones * sizeof( s_bone_t );
+ // for(t = 0; t < pTarget->numframes; t++)
+ // {
+ // pTarget->rawanim[t] = (s_bone_t *) kalloc(1, size);
+ // memcpy((void *) pSource->rawanim[t], (void *) pTarget->rawanim[t], size
+ // }
+ // }
+ // pTarget->startframe = pSource->startframe;
+ // pTarget->endframe = pSource->endframe;
+
+
+
+
+void ScaleJointsFrame(s_source_t *pSkeleton, s_jointScale_t *jointScale, int t)
+{
+ int numBones = pSkeleton->numbones;
+
+ for(int i = 0; i < numBones; i++)
+ {
+ s_node_t pNode = pSkeleton->localBone[i];
+ s_bone_t *pSkelBone = &pSkeleton->rawanim[t][i];
+ if(strcmp(jointScale->jointNameString, pNode.name) == 0)
+ {
+ // printf("Scaling joint %s\n", pNode.name);
+ pSkelBone->pos = pSkelBone->pos * jointScale->scale;
+ }
+
+ }
+}
+void ScaleJoints(s_source_t *pSkeleton, s_jointScale_t *jointScale)
+{
+ int numFrames = pSkeleton->numframes;
+ for(int t = 0; t < numFrames; t++)
+ {
+ ScaleJointsFrame(pSkeleton, jointScale, t);
+ }
+}
+
+void ScaleSkeletonFrame(s_source_t *pSkeleton, float scale, int t)
+{
+ int numBones = pSkeleton->numbones;
+
+ for(int i = 0; i < numBones; i++)
+ {
+ s_bone_t *pSkelBone = &pSkeleton->rawanim[t][i];
+ pSkelBone->pos = pSkelBone->pos * scale;
+
+ }
+}
+void ScaleSkeleton(s_source_t *pSkeleton, float scale)
+{
+ int numFrames = pSkeleton->numframes;
+ for(int t = 0; t < numFrames; t++)
+ {
+ ScaleSkeletonFrame(pSkeleton, scale, t);
+ }
+}
+
+void CombineSkeletonAnimationFrame(s_source_t *pSkeleton, s_source_t *pAnimation, s_bone_t **ppAnim, int t)
+{
+ int numBones = pAnimation->numbones;
+ int size = numBones * sizeof( s_bone_t );
+ ppAnim[t] = (s_bone_t *) kalloc(1, size);
+ for(int i = 0; i < numBones; i++)
+ {
+ s_node_t pNode = pAnimation->localBone[i];
+ s_bone_t pAnimBone = pAnimation->rawanim[t][i];
+
+ if(pNode.parent > -1)
+ {
+ if ( i < pSkeleton->numbones )
+ {
+ s_bone_t pSkelBone = pSkeleton->rawanim[0][i];
+ ppAnim[t][i].pos = pSkelBone.pos;
+ }
+ else
+ {
+ if ( !g_bGaveMissingBoneWarning )
+ {
+ g_bGaveMissingBoneWarning = true;
+ Warning( "Warning: Target skeleton has less bones than source animation. Reverting to source data for extra bones.\n" );
+ }
+
+ ppAnim[t][i].pos = pAnimBone.pos;
+ }
+ }
+ else
+ {
+ ppAnim[t][i].pos = pAnimBone.pos;
+ }
+
+ ppAnim[t][i].rot = pAnimBone.rot;
+ }
+}
+void CombineSkeletonAnimation(s_source_t *pSkeleton, s_source_t *pAnimation, s_bone_t **ppAnim)
+{
+ int numFrames = pAnimation->numframes;
+ for(int t = 0; t < numFrames; t++)
+ {
+ CombineSkeletonAnimationFrame(pSkeleton, pAnimation, ppAnim, t);
+ }
+}
+
+
+//--------------------------------------------------------------------
+// MotionMap
+//--------------------------------------------------------------------
+s_source_t *MotionMap( s_source_t *pSource, s_source_t *pTarget, s_template_t *pTemplate )
+{
+
+ // scale skeleton
+ if(pTemplate->doSkeletonScale)
+ {
+ ScaleSkeleton(pTarget, pTemplate->skeletonScale);
+ }
+
+ // scale joints
+ for(int j = 0; j < pTemplate->numJointScales; j++)
+ {
+ s_jointScale_t *pJointScale = pTemplate->jointScales[j];
+ ScaleJoints(pTarget, pJointScale);
+ }
+
+
+ // root stuff
+ char rootString[128] = "ValveBiped.Bip01";
+
+ // !!! PARAMETER
+ int rootIndex = GetNodeIndex(pSource, rootString);
+ int rootScaleIndex = GetNodeIndex(pSource, pTemplate->rootScaleJoint);
+ int rootScalePath[512];
+ if(rootScaleIndex > -1)
+ {
+ GetNodePath(pSource, rootIndex, rootScaleIndex, rootScalePath);
+ }
+ else
+ {
+ printf("Error: Can't find node\n");
+ exit(0);
+ }
+ float rootScaleLengthSrc = pSource->rawanim[0][rootScaleIndex].pos[BONEDIR];
+ float rootScaleParentLengthSrc = pSource->rawanim[0][rootScalePath[1]].pos[BONEDIR];
+ float rootScaleSrc = rootScaleLengthSrc + rootScaleParentLengthSrc;
+ float rootScaleLengthTgt = pTarget->rawanim[0][rootScaleIndex].pos[BONEDIR];
+ float rootScaleParentLengthTgt = pTarget->rawanim[0][rootScalePath[1]].pos[BONEDIR];
+ float rootScaleTgt = rootScaleLengthTgt + rootScaleParentLengthTgt;
+ float rootScaleFactor = rootScaleTgt / rootScaleSrc;
+
+ if(g_verbose)
+ printf("Root Scale Factor: %f\n", rootScaleFactor);
+
+
+ // root scale origin
+ float toeFloorZ = pTemplate->toeFloorZ;
+ Vector rootScaleOrigin = pSource->rawanim[0][rootIndex].pos;
+ rootScaleOrigin[2] = toeFloorZ;
+
+
+ // setup workspace
+ s_bone_t *combinedRefAnimation[MAXSTUDIOANIMFRAMES];
+ s_bone_t *combinedAnimation[MAXSTUDIOANIMFRAMES];
+ s_bone_t *sourceAnimation[MAXSTUDIOANIMFRAMES];
+ CombineSkeletonAnimation(pTarget, pSource, combinedAnimation);
+ CombineSkeletonAnimation(pTarget, pSource, combinedRefAnimation);
+
+
+ // do source and target sanity checking
+ int sourceNumFrames = pSource->numframes;
+
+
+ // iterate through limb solves
+ for(int t = 0; t < sourceNumFrames; t++)
+ {
+ // setup pTarget for skeleton comparison
+ pTarget->rawanim[t] = combinedRefAnimation[t];
+
+ printf("Note: Processing frame: %i\n", t);
+ for(int ii = 0; ii < pTemplate->numIKSolves; ii++)
+ {
+ s_iksolve_t *thisSolve = pTemplate->ikSolves[ii];
+
+ char *thisJointNameString = thisSolve->jointNameString;
+ int thisJointIndex = GetNodeIndex(pSource, thisJointNameString);
+
+ // init paths to feet
+ int thisJointPathInRoot[512];
+
+ // get paths to feet
+ if(thisJointIndex > -1)
+ {
+ GetNodePath(pSource, rootIndex, thisJointIndex, thisJointPathInRoot);
+ }
+ else
+ {
+ printf("Error: Can't find node: %s\n" , thisJointNameString);
+ exit(0);
+ }
+
+ // leg "root" or thigh pointers
+ //int gParentIndex = thisJointPathInRoot[2];
+ int *gParentPath = thisJointPathInRoot + 2;
+
+ //----------------------------------------------------------------
+ // get limb lengths
+ //----------------------------------------------------------------
+ float thisJointLengthSrc = pSource->rawanim[0][thisJointIndex].pos[BONEDIR];
+ float parentJointLengthSrc = pSource->rawanim[0][thisJointPathInRoot[1]].pos[BONEDIR];
+
+ float thisLimbLengthSrc = thisJointLengthSrc + parentJointLengthSrc;
+
+ float thisJointLengthTgt = pTarget->rawanim[0][thisJointIndex].pos[BONEDIR];
+ float parentJointLengthTgt = pTarget->rawanim[0][thisJointPathInRoot[1]].pos[BONEDIR];
+
+ float thisLimbLengthTgt = thisJointLengthTgt + parentJointLengthTgt;
+
+ // Factor leg length delta
+ float thisLimbLength = thisLimbLengthSrc - thisLimbLengthTgt;
+ float thisLimbLengthFactor = thisLimbLengthTgt / thisLimbLengthSrc;
+
+ if(g_verbose)
+ printf("limb length %s: %i: %f, factor %f\n", thisJointNameString, thisJointIndex, thisLimbLength, thisLimbLengthFactor);
+
+ // calculate joint grandparent offset
+ // Note: because there's no reference pose this doesn't take rotation into account.
+ // This only works because of the assumption that joint translations aren't animated.
+ M_matrix4x4_t gParentGlobalMatSrc, gParentGlobalMatTgt;
+ Vector gParentGlobalSrc, gParentGlobalTgt;
+
+ // SumBonePathTranslations(gParentPath, pSource->rawanim[t], gParentGlobalSrc, 1);
+ // SumBonePathTranslations(gParentPath, pTarget->rawanim[t], gParentGlobalTgt, 1);
+
+ // get root path to source parent
+ CatBonePath(gParentPath, pSource->rawanim[t], gParentGlobalMatSrc, 1);
+ // check against reference animation
+ CatBonePath(gParentPath, pTarget->rawanim[t], gParentGlobalMatTgt, 1);
+
+ gParentGlobalSrc[0] = gParentGlobalMatSrc[3][0];
+ gParentGlobalSrc[1] = gParentGlobalMatSrc[3][1];
+ gParentGlobalSrc[2] = gParentGlobalMatSrc[3][2];
+
+ gParentGlobalTgt[0] = gParentGlobalMatTgt[3][0];
+ gParentGlobalTgt[1] = gParentGlobalMatTgt[3][1];
+ gParentGlobalTgt[2] = gParentGlobalMatTgt[3][2];
+
+
+ Vector gParentDelta(gParentGlobalTgt - gParentGlobalSrc);
+
+ if(g_verbose)
+ printf("Grand parent delta: %f %f %f\n", gParentDelta[0], gParentDelta[1], gParentDelta[2]);
+
+ gParentDelta *= thisSolve->limbRootOffsetScale;
+
+
+ //----------------------------------------------------------------
+ // time takes effect here
+ // above waste is unavoidable?
+ //----------------------------------------------------------------
+ M_matrix4x4_t rootMat;
+ M_AngleMatrix(pSource->rawanim[t][rootIndex].rot, pSource->rawanim[t][rootIndex].pos, rootMat);
+
+
+ // OK, time to get it together
+ // 1) scale foot by legLengthFactor in the non-translated thigh space
+ // 2) translate foot by legRootDelta in the space of the root
+ // do we leave everything in the space of the root then? PROBABLY!!
+
+ M_matrix4x4_t thisJointMat, parentJointMat, thisJointInGParentMat;
+ M_AngleMatrix(pSource->rawanim[t][thisJointPathInRoot[0]].rot, pSource->rawanim[t][thisJointPathInRoot[0]].pos, thisJointMat);
+ M_AngleMatrix(pSource->rawanim[t][thisJointPathInRoot[1]].rot, pSource->rawanim[t][thisJointPathInRoot[1]].pos, parentJointMat);
+ M_ConcatTransforms(thisJointMat, parentJointMat, thisJointInGParentMat);
+
+ if(!thisSolve->doRelativeLock)
+ {
+ // scale around grand parent
+ float effectiveScaleFactor = ((thisLimbLengthFactor - 1.0) * thisSolve->extremityScale ) + 1.0;
+ thisJointInGParentMat[3][0] *= effectiveScaleFactor;
+ thisJointInGParentMat[3][1] *= effectiveScaleFactor;
+ thisJointInGParentMat[3][2] *= effectiveScaleFactor;
+ }
+
+ // adjust into source root space
+ M_matrix4x4_t gParentInRootMat, thisJointInRootMat;
+ CatBonePath(gParentPath, pSource->rawanim[t], gParentInRootMat, 1);
+ M_ConcatTransforms(thisJointInGParentMat, gParentInRootMat, thisJointInRootMat);
+
+ if(!thisSolve->doRelativeLock)
+ {
+ // adjust by difference of local root
+ thisJointInRootMat[3][0] += gParentDelta[0];
+ thisJointInRootMat[3][1] += gParentDelta[1];
+ thisJointInRootMat[3][2] += gParentDelta[2];
+ }
+ else
+ {
+ char *relativeJointNameString = thisSolve->relativeLockNameString;
+ int relativeJointIndex = GetNodeIndex(pSource, relativeJointNameString);
+
+ // init paths to feet
+ int relativeJointPathInRoot[512];
+
+ // get paths to feet
+ if(relativeJointIndex > -1)
+ {
+ GetNodePath(pSource, rootIndex, relativeJointIndex, relativeJointPathInRoot);
+ }
+ else
+ {
+ printf("Error: Can't find node: %s\n" , relativeJointNameString);
+ exit(0);
+ }
+ // get the source relative joint
+ M_matrix4x4_t relativeJointInRootMatSrc, relativeJointInRootMatSrcInverse, thisJointInRelativeSrcMat;
+ CatBonePath(relativeJointPathInRoot, pSource->rawanim[t], relativeJointInRootMatSrc, 1);
+ M_MatrixInvert(relativeJointInRootMatSrc, relativeJointInRootMatSrcInverse);
+ M_ConcatTransforms(thisJointInRootMat, relativeJointInRootMatSrcInverse, thisJointInRelativeSrcMat);
+ if(thisSolve->relativeLockScale != 1.0)
+ {
+ thisJointInRelativeSrcMat[3][0] *= thisSolve->relativeLockScale;
+ thisJointInRelativeSrcMat[3][1] *= thisSolve->relativeLockScale;
+ thisJointInRelativeSrcMat[3][2] *= thisSolve->relativeLockScale;
+ }
+
+ // swap momentarily to get new destination
+ // NOTE: the relative lock must have already been solved
+ sourceAnimation[t] = pSource->rawanim[t];
+ pSource->rawanim[t] = combinedAnimation[t];
+
+ // get new relative location
+ M_matrix4x4_t relativeJointInRootMatTgt;
+ CatBonePath(relativeJointPathInRoot, pSource->rawanim[t], relativeJointInRootMatTgt, 1);
+ M_ConcatTransforms(thisJointInRelativeSrcMat, relativeJointInRootMatTgt, thisJointInRootMat);
+
+ // swap back just for cleanliness
+ // a little overkill as it's just swapped
+ // just leaving it here for clarity
+ combinedAnimation[t] = pSource->rawanim[t];
+ pSource->rawanim[t] = sourceAnimation[t];
+
+ }
+
+ //----------------------------------------------------------------
+ // swap animation
+ //----------------------------------------------------------------
+ sourceAnimation[t] = pSource->rawanim[t];
+ pSource->rawanim[t] = combinedAnimation[t];
+
+ //----------------------------------------------------------------
+ // make thigh data global based on new skeleton
+ //----------------------------------------------------------------
+ // get thigh in global space
+ M_matrix4x4_t gParentInTgtRootMat, ggParentInTgtRootMat;
+ // int *gParentPath = thisJointPathInRoot + 2;
+ CatBonePath(gParentPath, pSource->rawanim[t], gParentInTgtRootMat, 1);
+ CatBonePath(gParentPath+1, pSource->rawanim[t], ggParentInTgtRootMat, 1);
+
+
+ //----------------------------------------------------------------
+ // Calculate IK for legs
+ //----------------------------------------------------------------
+ float parentJointLength = pSource->rawanim[t][*(thisJointPathInRoot + 1)].pos[BONEDIR];
+ float thisJointLength = pSource->rawanim[t][thisJointIndex].pos[BONEDIR];
+
+ Vector thisLimbHypot;
+ thisLimbHypot[0] = thisJointInRootMat[3][0] - gParentInTgtRootMat[3][0];
+ thisLimbHypot[1] = thisJointInRootMat[3][1] - gParentInTgtRootMat[3][1];
+ thisLimbHypot[2] = thisJointInRootMat[3][2] - gParentInTgtRootMat[3][2];
+
+ float thisLimbHypotLength = thisLimbHypot.Length();
+
+ // law of cosines!
+ float gParentCos = (thisLimbHypotLength*thisLimbHypotLength + parentJointLength*parentJointLength - thisJointLength*thisJointLength) / (2*parentJointLength*thisLimbHypotLength);
+ float parentCos = (parentJointLength*parentJointLength + thisJointLength*thisJointLength - thisLimbHypotLength*thisLimbHypotLength) / (2*parentJointLength*thisJointLength);
+
+ VectorNormalize(thisLimbHypot);
+
+ Vector thisLimbHypotUnit = thisLimbHypot;
+
+ M_matrix4x4_t gParentJointIKMat;
+ Vector gParentJointIKRot, gParentJointIKOrth;
+
+ gParentJointIKRot[0] = gParentInTgtRootMat[BONEUP][0];
+ gParentJointIKRot[1] = gParentInTgtRootMat[BONEUP][1];
+ gParentJointIKRot[2] = gParentInTgtRootMat[BONEUP][2];
+
+ VectorNormalize(gParentJointIKRot);
+ gParentJointIKOrth = gParentJointIKRot.Cross(thisLimbHypotUnit);
+ VectorNormalize(gParentJointIKOrth);
+ gParentJointIKRot = thisLimbHypotUnit.Cross(gParentJointIKOrth);
+ VectorNormalize(gParentJointIKRot);
+
+ M_MatrixCopy(gParentInTgtRootMat, gParentJointIKMat);
+
+ gParentJointIKMat[0][0] = thisLimbHypotUnit[0];
+ gParentJointIKMat[0][1] = thisLimbHypotUnit[1];
+ gParentJointIKMat[0][2] = thisLimbHypotUnit[2];
+
+ gParentJointIKMat[1][0] = gParentJointIKOrth[0];
+ gParentJointIKMat[1][1] = gParentJointIKOrth[1];
+ gParentJointIKMat[1][2] = gParentJointIKOrth[2];
+
+ gParentJointIKMat[2][0] = gParentJointIKRot[0];
+ gParentJointIKMat[2][1] = gParentJointIKRot[1];
+ gParentJointIKMat[2][2] = gParentJointIKRot[2];
+
+
+ M_matrix4x4_t gParentJointIKRotMat, gParentJointResultMat;
+ float gParentDeg;
+ if(thisSolve->reverseSolve)
+ {
+ gParentDeg = acos(gParentCos);
+ }
+ else
+ {
+ gParentDeg = -acos(gParentCos);
+ }
+
+ // sanity check limb length
+ if(thisLimbHypotLength < thisLimbLengthTgt)
+ {
+ M_RotateZMatrix(gParentDeg, gParentJointIKRotMat);
+ }
+
+ M_ConcatTransforms(gParentJointIKRotMat, gParentJointIKMat, gParentJointResultMat);
+
+ M_matrix4x4_t parentJointIKRotMat;
+ //!!! shouldn't need the 180 degree addition, something in the law of cosines!!!
+ float parentDeg;
+ if(thisSolve->reverseSolve)
+ {
+ parentDeg = acos(parentCos)+M_PI;
+ }
+ else
+ {
+ parentDeg = -acos(parentCos)+M_PI;
+ }
+
+ // sanity check limb length
+ if(thisLimbHypotLength < thisLimbLengthTgt)
+ {
+ M_RotateZMatrix(parentDeg, parentJointIKRotMat);
+ }
+
+
+ // Thighs
+ M_matrix4x4_t ggParentInTgtRootMatInverse, gParentJointLocalMat;
+ M_MatrixInvert(ggParentInTgtRootMat, ggParentInTgtRootMatInverse);
+ M_ConcatTransforms(gParentJointResultMat, ggParentInTgtRootMatInverse, gParentJointLocalMat);
+
+ s_bone_t resultBone;
+
+ // temp test stuff
+ // M_MatrixAngles(thisJointInRootMat, resultBone.rot, resultBone.pos);
+ // pSource->rawanim[t][thisJointIndex].rot = resultBone.rot;
+ // pSource->rawanim[t][thisJointIndex].pos = resultBone.pos;
+
+ // M_MatrixAngles(gParentInTgtRootMat, resultBone.rot, resultBone.pos);
+ // pSource->rawanim[t][gParentIndex].rot = resultBone.rot;
+ // pSource->rawanim[t][gParentIndex].pos = resultBone.pos;
+
+
+ M_MatrixAngles(gParentJointLocalMat, resultBone.rot, resultBone.pos);
+ pSource->rawanim[t][*gParentPath].pos = resultBone.pos;
+ pSource->rawanim[t][*gParentPath].rot = resultBone.rot;
+
+ M_MatrixAngles(parentJointIKRotMat, resultBone.rot, resultBone.pos);
+ pSource->rawanim[t][*(thisJointPathInRoot+1)].rot = resultBone.rot;
+
+ M_matrix4x4_t parentJointGlobalMat, parentJointGlobalMatInverse, thisJointLocalMat;
+ CatBonePath(thisJointPathInRoot+1, pSource->rawanim[t], parentJointGlobalMat, 1);
+
+
+ M_MatrixInvert(parentJointGlobalMat, parentJointGlobalMatInverse);
+ M_ConcatTransforms(thisJointInRootMat, parentJointGlobalMatInverse, thisJointLocalMat);
+
+ M_MatrixAngles(thisJointLocalMat, resultBone.rot, resultBone.pos);
+ pSource->rawanim[t][thisJointIndex].rot = resultBone.rot;
+
+
+ // swap animation back for next solve
+ combinedAnimation[t] = pSource->rawanim[t];
+ pSource->rawanim[t] = sourceAnimation[t];
+
+ }
+ // swap animation
+ sourceAnimation[t] = pSource->rawanim[t];
+ pSource->rawanim[t] = combinedAnimation[t];
+
+ //----------------------------------------------------------------
+ // adjust root
+ //----------------------------------------------------------------
+ Vector originBonePos = pSource->rawanim[t][rootIndex].pos;
+ Vector rootInScaleOrigin = originBonePos - rootScaleOrigin;
+ float effectiveRootScale = ((rootScaleFactor - 1.0) * pTemplate->rootScaleAmount) + 1.0;
+ Vector scaledRoot = rootInScaleOrigin * effectiveRootScale;
+ pSource->rawanim[t][rootIndex].pos = rootScaleOrigin + scaledRoot;
+
+ //------------------------------------------------------------
+ // plane constraints
+ //------------------------------------------------------------
+ for(int ii = 0; ii < pTemplate->numPlaneConstraints; ii++)
+ {
+ s_planeConstraint_t *thisSolve = pTemplate->planeConstraints[ii];
+
+ char *thisJointNameString = thisSolve->jointNameString;
+ if(g_verbose)
+ printf("Executing plane constraint: %s\n", thisJointNameString);
+
+ int thisJointIndex = GetNodeIndex(pSource, thisJointNameString);
+
+ // init paths to feet
+ int thisJointPath[512];
+
+ // get paths to feet
+ if(thisJointIndex > -1)
+ {
+ GetNodePath(pSource, -1, thisJointIndex, thisJointPath);
+ }
+ else
+ {
+ printf("Error: Can't find node: %s\n" , thisJointNameString);
+ exit(0);
+ }
+ int parentIndex = thisJointPath[1];
+ int *parentPath = thisJointPath + 1;
+
+ M_matrix4x4_t thisJointGlobalMat, parentJointGlobalMat, gParentJointGlobalMat, gParentJointGlobalMatInverse;
+ CatBonePath(thisJointPath, pSource->rawanim[t], thisJointGlobalMat, 0);
+ CatBonePath(parentPath, pSource->rawanim[t], parentJointGlobalMat, 0);
+ CatBonePath(parentPath+1, pSource->rawanim[t], gParentJointGlobalMat, 0);
+ M_MatrixInvert(gParentJointGlobalMat, gParentJointGlobalMatInverse);
+
+ if(thisJointGlobalMat[3][thisSolve->axis] < thisSolve->floor)
+ {
+ // printf("-- broken plane: %f\n", thisJointGlobalMat[3][thisSolve->axis]);
+ if(parentJointGlobalMat[3][thisSolve->axis] < thisSolve->floor)
+ {
+ printf("Error: Constraint parent has broken the plane, this frame's plane constraint unsolvable!\n");
+ }
+ else
+ {
+ Vector parentJointAtPlane(parentJointGlobalMat[3][0], parentJointGlobalMat[3][1], parentJointGlobalMat[3][2]);
+ Vector parentPos(parentJointGlobalMat[3][0], parentJointGlobalMat[3][1], parentJointGlobalMat[3][2]);
+ Vector thisJointAtPlane(thisJointGlobalMat[3][0], thisJointGlobalMat[3][1], thisJointGlobalMat[3][2]);
+ Vector thisJointPos(thisJointGlobalMat[3][0], thisJointGlobalMat[3][1], thisJointGlobalMat[3][2]);
+
+ thisJointAtPlane[thisSolve->axis] = thisSolve->floor;
+ parentJointAtPlane[thisSolve->axis] = thisSolve->floor;
+
+ float thisJointLength = pSource->rawanim[t][thisJointIndex].pos[BONEAXIS];
+ float parentLengthToPlane = parentPos[thisSolve->axis] - thisSolve->floor;
+ float adjacent = sqrtf((thisJointLength * thisJointLength) - (parentLengthToPlane * parentLengthToPlane));
+ Vector parentDirection = thisJointAtPlane - parentJointAtPlane;
+ VectorNormalize(parentDirection);
+
+ Vector newJointPos = parentJointAtPlane + (parentDirection * adjacent);
+
+ Vector newParentDir = newJointPos - parentPos;
+ Vector parentUp(parentJointGlobalMat[BONEUP][0], parentJointGlobalMat[BONEUP][1], parentJointGlobalMat[BONEUP][2]);
+
+ VectorNormalize(newParentDir);
+ VectorNormalize(parentUp);
+ // Vector parentSide = newParentDir.Cross(parentUp);
+ Vector parentSide = parentUp.Cross(newParentDir);
+ VectorNormalize(parentSide);
+ parentUp = newParentDir.Cross(parentSide);
+ // parentUp = parentSide.Cross(newParentDir);
+ VectorNormalize(parentUp);
+ parentJointGlobalMat[BONEDIR][0] = newParentDir[0];
+ parentJointGlobalMat[BONEDIR][1] = newParentDir[1];
+ parentJointGlobalMat[BONEDIR][2] = newParentDir[2];
+ parentJointGlobalMat[BONEUP][0] = parentUp[0];
+ parentJointGlobalMat[BONEUP][1] = parentUp[1];
+ parentJointGlobalMat[BONEUP][2] = parentUp[2];
+ parentJointGlobalMat[BONESIDE][0] = parentSide[0];
+ parentJointGlobalMat[BONESIDE][1] = parentSide[1];
+ parentJointGlobalMat[BONESIDE][2] = parentSide[2];
+
+
+ M_matrix4x4_t newParentJointMat;
+
+ M_ConcatTransforms(parentJointGlobalMat, gParentJointGlobalMatInverse, newParentJointMat);
+
+ s_bone_t resultBone;
+ M_MatrixAngles(newParentJointMat, resultBone.rot, resultBone.pos);
+ pSource->rawanim[t][parentIndex].rot = resultBone.rot;
+ }
+ }
+ }
+
+ // swap animation back for next solve
+ combinedAnimation[t] = pSource->rawanim[t];
+ pSource->rawanim[t] = sourceAnimation[t];
+ }
+ for(int t = 0; t < sourceNumFrames; t++)
+ {
+ pTarget->rawanim[t] = combinedAnimation[t];
+ }
+ pTarget->numframes = sourceNumFrames;
+
+
+
+
+
+#if 0
+ // Process motion mapping into out and return that
+ s_source_t *out = new s_source_t;
+
+ return out;
+#else
+ // Just returns the start animation, to test the Save_SMD API.
+ return pTarget;
+#endif
+}
+
+char templates[] =
+"\n\
+#\n\
+# default template file is analogus to not specifying a template file at all\n\
+#\n\
+\n\
+rootScaleJoint ValveBiped.Bip01_L_Foot\n\
+rootScaleAmount 1.0\n\
+toeFloorZ 2.7777\n\
+\n\
+twoJointIKSolve ValveBiped.Bip01_L_Foot\n\
+reverseSolve 0\n\
+extremityScale 1.0\n\
+limbRootOffsetScale 1.0 1.0 0.0\n\
+\n\
+twoJointIKSolve ValveBiped.Bip01_R_Foot\n\
+reverseSolve 0\n\
+extremityScale 1.0\n\
+limbRootOffsetScale 1.0 1.0 0.0\n\
+\n\
+oneJointPlaneConstraint ValveBiped.Bip01_L_Toe0\n\
+\n\
+oneJointPlaneConstraint ValveBiped.Bip01_R_Toe0\n\
+\n\
+twoJointIKSolve ValveBiped.Bip01_R_Hand\n\
+reverseSolve 1\n\
+extremityScale 1.0\n\
+limbRootOffsetScale 0.0 0.0 1.0\n\
+\n\
+twoJointIKSolve ValveBiped.Bip01_L_Hand\n\
+reverseSolve 1\n\
+extremityScale 1.0\n\
+limbRootOffsetScale 0.0 0.0 1.0\n\
+\n\
+";
+
+
+void UsageAndExit()
+{
+ MdlError( "usage: motionmapper [-quiet] [-verbose] [-templateFile filename] [-printTemplates] sourceanim.smd targetskeleton.smd output.smd\n\
+\tsourceanim: should contain ref pose and animation data\n\
+\ttargetsekeleton: should contain new ref pose, animation data ignored/can be absent\n\
+\toutput: animation from source mapped onto target skeleton (contains new ref pose)\n\
+\t-templateFile filename : specifies a template file for guiding the mapping of motion\n\
+\t-printTemplate: Causes motionmapper to output the contents of an example template file, which can be used in conjunction with the -templateFile argument to create various motion effects.\n\
+\n");
+}
+
+void PrintHeader()
+{
+ vprint( 0, "Valve Software - motionmapper.exe ((c) Valve Coroporation %s)\n", __DATE__ );
+ vprint( 0, "--- Maps motion from one animation/skeleton onto another skeleton ---\n" );
+}
+
+
+
+/*
+==============
+main
+==============
+*/
+int main (int argc, char **argv)
+{
+ int i;
+
+ int useTemplate = 0;
+ char templateFileName[1024];
+
+ // Header
+ PrintHeader();
+
+ // Init command line stuff
+ CommandLine()->CreateCmdLine( argc, argv );
+ InstallSpewFunction();
+
+ // init math stuff
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
+ g_currentscale = g_defaultscale = 1.0;
+ g_defaultrotation = RadianEuler( 0, 0, M_PI / 2 );
+
+ // No args?
+ if (argc == 1)
+ {
+ UsageAndExit();
+ }
+
+ // Init variable
+ g_quiet = false;
+
+ // list template hooey
+ CUtlVector< CUtlSymbol > filenames;
+
+ // Get args
+ for (i = 1; i < argc; i++)
+ {
+ // Switches
+ if (argv[i][0] == '-')
+ {
+ if (!stricmp(argv[i], "-allowdebug"))
+ {
+ // Ignore, used by interface system to catch debug builds checked into release tree
+ continue;
+ }
+
+ if (!stricmp(argv[i], "-quiet"))
+ {
+ g_quiet = true;
+ g_verbose = false;
+ continue;
+ }
+
+ if (!stricmp(argv[i], "-verbose"))
+ {
+ g_quiet = false;
+ g_verbose = true;
+ continue;
+ }
+ if (!stricmp(argv[i], "-printTemplate"))
+ {
+ printf("%s\n", templates);
+ exit(0);
+
+ }
+ if (!stricmp(argv[i], "-templateFile"))
+ {
+ if(i + 1 < argc)
+ {
+ strcpy( templateFileName, argv[i+1]);
+ useTemplate = 1;
+ printf("Note: %s passed as template file", templateFileName);
+ }
+ else
+ {
+ printf("Error: -templateFile requires an argument, none found!");
+ UsageAndExit();
+
+ }
+ i++;
+ continue;
+ }
+ }
+ else
+ {
+ // more template stuff
+ CUtlSymbol sym = argv[ i ];
+ filenames.AddToTail( sym );
+ }
+ }
+
+ // Enough file args?
+ if ( filenames.Count() != 3 )
+ {
+ // misformed arguments
+ // otherwise generating unintended results
+ printf("Error: 3 file arguments required, %i found!", filenames.Count());
+ UsageAndExit();
+ }
+
+ // Filename arg indexes
+ int sourceanim = 0;
+ int targetskel = 1;
+ int outputanim = 2;
+
+ // Copy arg string to global variable
+ strcpy( g_outfile, filenames[ outputanim ].String() );
+
+ // Init filesystem hooey
+ CmdLib_InitFileSystem( g_outfile );
+ // ??
+ Q_FileBase( g_outfile, g_outfile, sizeof( g_outfile ) );
+
+ // Verbose stuff
+ if (!g_quiet)
+ {
+ vprint( 0, "%s, %s, %s, path %s\n", qdir, gamedir, g_outfile );
+ }
+ // ??
+ Q_DefaultExtension(g_outfile, ".smd", sizeof( g_outfile ) );
+
+ // Verbose stuff
+ if (!g_quiet)
+ {
+ vprint( 0, "Source animation: %s\n", filenames[ sourceanim ].String() );
+ vprint( 0, "Target skeleton: %s\n", filenames[ targetskel ].String() );
+
+ vprint( 0, "Creating on \"%s\"\n", g_outfile);
+ }
+ // fullpath = EXTERNAL GLOBAL!!!???
+ strcpy( fullpath, g_outfile );
+ strcpy( fullpath, ExpandPath( fullpath ) );
+ strcpy( fullpath, ExpandArg( fullpath ) );
+
+ // Load source and target data
+ s_source_t *pSource = Load_Source( filenames[sourceanim].String(), "smd", false, false );
+ s_source_t *pTarget = Load_Source( filenames[targetskel].String(), "smd", false, false );
+
+
+ //
+ s_template_t *pTemplate = NULL;
+ if(useTemplate)
+ {
+ pTemplate = Load_Template(templateFileName);
+ }
+ else
+ {
+ printf("Note: No template file specified, using defaults settings.\n");
+
+ pTemplate = New_Template();
+ Set_DefaultTemplate(pTemplate);
+ }
+
+
+ // Process skeleton
+ s_source_t *pMappedAnimation = MotionMap( pSource, pTarget, pTemplate );
+
+
+ // Save output (ref skeleton & animation data);
+ Save_SMD( fullpath, pMappedAnimation );
+
+ Q_StripExtension( filenames[outputanim].String(), outname, sizeof( outname ) );
+
+ // Verbose stuff
+ if (!g_quiet)
+ {
+ vprint( 0, "\nCompleted \"%s\"\n", g_outfile);
+ }
+
+ return 0;
+}
+