//studio.h takes care of all the other includes we need too
#include "studio.h"
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// This code requires the OrangeBox sdk
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ASSERT_INVARIANT( STUDIO_VERSION == 48 );
#define IDSTUDIOHEADER MAKEID( 'I', 'D', 'S', 'T' ) //Studiomodel ident
#define RAD2DEG_INT( x ) (int)((RAD2DEG(x)) + 0.5f) //Rounds to nearest int
//Get a QC file name
//Assumes input is from a studio model header (studiohdr_t->name)
char *QC_GetName( char *in, char *append = ".qc" )
{
static char out[128] = { 0 };
//Strip any directory info and copy it
int tmp = 0; //this will be the postion of the last slash in the string (+1)
for( int i = strlen( in ); i > 0; --i )
{
if( in[i] == '\\' || in[i] == '/' )
{
tmp = ++i;
break;
}
}
memcpy( out, in+tmp, strlen(in)-tmp );
out[strlen(out)-4] = 0; //remove .mdl
strcat( out, append ); //append .qc (default) or whatever the arg specifies
return out;
}
void QC_DumpJigglebones( studiohdr_t *phdr )
{
char *pszQc = QC_GetName( phdr->name, "_jiggles.qci" );
FILE *qcfile = fopen( pszQc, "w" ); //Will open in the current working directory of your command prompt
//Dump it
for( int i = 0; i < phdr->numbones; ++i )
{
mstudiobone_t *pbone = phdr->pBone( i );
if( pbone->proctype == STUDIO_PROC_JIGGLE && pbone->procindex != 0 )
{
printf( "Jigglebone: %s ", pbone->pszName() );
mstudiojigglebone_t *pjiggle = (mstudiojigglebone_t*)pbone->pProcedure();
fprintf( qcfile, "$jigglebone \"%s\" {\n", pbone->pszName() );
if( pjiggle->flags & JIGGLE_IS_FLEXIBLE )
{
printf( "- is_flexible " );
fprintf( qcfile, "\tis_flexible {\n" );
fprintf( qcfile, "\t\tyaw_stiffness %g\n", pjiggle->yawStiffness );
fprintf( qcfile, "\t\tyaw_damping %g\n", pjiggle->yawDamping );
fprintf( qcfile, "\t\tpitch_stiffness %g\n", pjiggle->pitchStiffness );
fprintf( qcfile, "\t\tpitch_damping %g\n", pjiggle->pitchDamping );
fprintf( qcfile, "\t\talong_stiffness %g\n", pjiggle->alongStiffness );
fprintf( qcfile, "\t\talong_damping %g\n", pjiggle->alongDamping );
fprintf( qcfile, "\t\tlength %g\n", pjiggle->length );
fprintf( qcfile, "\t\ttip_mass %g\n", pjiggle->tipMass );
if( pjiggle->flags & JIGGLE_HAS_YAW_CONSTRAINT )
{
fprintf( qcfile, "\t\tyaw_constraint %i %i\n", RAD2DEG_INT( pjiggle->minYaw ), RAD2DEG_INT( pjiggle->maxYaw ) );
fprintf( qcfile, "\t\tyaw_friction %g\n", pjiggle->yawFriction );
}
if( pjiggle->flags & JIGGLE_HAS_ANGLE_CONSTRAINT )
{
fprintf( qcfile, "\t\tangle_constraint %i\n", RAD2DEG_INT( pjiggle->angleLimit ) );
}
if( pjiggle->flags & JIGGLE_HAS_PITCH_CONSTRAINT )
{
fprintf( qcfile, "\t\tpitch_constraint %i %i\n", RAD2DEG_INT( pjiggle->minPitch ), RAD2DEG_INT( pjiggle->maxPitch ) );
fprintf( qcfile, "\t\tpitch_friction %g\n", pjiggle->pitchFriction );
fprintf( qcfile, "\t\tpitch_bounce %g\n", pjiggle->pitchBounce );
}
fprintf( qcfile, "\t}\n" );
}
if( pjiggle->flags & JIGGLE_IS_RIGID )
{
printf( "- is_rigid " );
fprintf( qcfile, "\tis_rigid {\n" );
fprintf( qcfile, "\t\tlength %g\n", pjiggle->length );
fprintf( qcfile, "\t\ttip_mass %g\n", pjiggle->tipMass );
if( pjiggle->flags & JIGGLE_HAS_YAW_CONSTRAINT )
{
fprintf( qcfile, "\t\tyaw_constraint %i %i\n", RAD2DEG_INT( pjiggle->minYaw ), RAD2DEG_INT( pjiggle->maxYaw ) );
fprintf( qcfile, "\t\tyaw_friction %g\n", pjiggle->yawFriction );
}
if( pjiggle->flags & JIGGLE_HAS_ANGLE_CONSTRAINT )
{
fprintf( qcfile, "\t\tangle_constraint %i\n", RAD2DEG_INT( pjiggle->angleLimit ) );
}
if( pjiggle->flags & JIGGLE_HAS_PITCH_CONSTRAINT )
{
fprintf( qcfile, "\t\tpitch_constraint %i %i\n", RAD2DEG_INT( pjiggle->minPitch ), RAD2DEG_INT( pjiggle->maxPitch ) );
fprintf( qcfile, "\t\tpitch_friction %g\n", pjiggle->pitchFriction );
fprintf( qcfile, "\t\tpitch_bounce %g\n", pjiggle->pitchBounce );
}
fprintf( qcfile, "\t}\n" );
}
if( pjiggle->flags & JIGGLE_HAS_BASE_SPRING )
{
printf( "- has_base_spring " );
fprintf( qcfile, "\n\thas_base_spring {\n" );
fprintf( qcfile, "\t\tbase_mass %g\n", pjiggle->baseMass );
fprintf( qcfile, "\t\tstiffness %g\n", pjiggle->baseStiffness );
fprintf( qcfile, "\t\tdamping %g\n", pjiggle->baseDamping );
fprintf( qcfile, "\t\tleft_constraint %g %g\n", pjiggle->baseMinLeft, pjiggle->baseMaxLeft );
fprintf( qcfile, "\t\tleft_friction %g\n", pjiggle->baseLeftFriction );
fprintf( qcfile, "\t\tup_constraint %g %g\n", pjiggle->baseMinUp, pjiggle->baseMaxUp );
fprintf( qcfile, "\t\tup_friction %g\n", pjiggle->baseUpFriction );
fprintf( qcfile, "\t\tforward_constraint %g %g\n", pjiggle->baseMinUp, pjiggle->baseMaxUp );
fprintf( qcfile, "\t\tforward_friction %g\n", pjiggle->baseUpFriction );
fprintf( qcfile, "\t}\n" );
}
printf("\n");
fprintf( qcfile, "}\n\n" );
}
}
fclose( qcfile );
printf( "Wrote %s\n", pszQc );
}
int main( int argc, char *argv[] )
{
if( argc != 2 )
{
printf( "Usage: jiggle_qcgen.exe modelfile.mdl\n" );
return 1;
}
if( !strstr( argv[1], ".mdl" ) )
{
printf( "Specified file is not a model (*.mdl).\n" );
return 2;
}
FILE *fp = fopen( argv[1], "rb" );
fseek( fp, 0, SEEK_END );
int len = ftell( fp );
rewind( fp );
char *buffer = new char[len];
fread( buffer, 1, len, fp );
studiohdr_t *phdr = (studiohdr_t*)buffer;
fclose( fp );
if( phdr->id != IDSTUDIOHEADER )
{
printf( "%s is not a studio model!\n", argv[1] );
delete[] buffer;
return 3;
}
//Make sure it's an Orange box engine model, pre-OB models don't have jiggle bones.
if( phdr->version < 45 )
{
printf( "Version %i models do not have jigglebone data, exiting..\n", phdr->version );
delete[] buffer;
return 4;
}
//Needs to be after the version check for obvious reasons.
Studio_ConvertStudioHdrToNewVersion( phdr );
//iterate over all the bones to make sure at least one is jiggled first,
//so we don't create an empty qcfile.
for( int i = 0; i < phdr->numbones; ++i )
{
mstudiobone_t *pbone = phdr->pBone( i );
if( pbone->proctype == STUDIO_PROC_JIGGLE && pbone->procindex != 0 )
{
#ifdef _DEBUG
printf( "Found at least one jigglebone, ending check loop..\n" );
#endif
break; //Found at least one, build the file
}
if( i < phdr->numbones-1 )
{
#ifdef _DEBUG
printf( "Skip: %3i %3i %s\n", i, phdr->numbones-1, pbone->pszName() );
#endif
continue; //Skip until the last bone
}
#ifdef _DEBUG
printf( "End: %3i %3i %s\n", i, phdr->numbones-1, pbone->pszName() );
#endif
//None were found, get outta here
printf( "No bones contain jiggle info, exiting..\n" );
delete[] buffer;
return 5;
}
//Build the qc file
QC_DumpJigglebones( phdr );
phdr = NULL;
delete[] buffer;
return 0;
}