You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
882 lines
19 KiB
882 lines
19 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
|
|
// |
|
// studiomdl.c: generates a studio .mdl file from a .qc script |
|
// models/<scriptname>.mdl. |
|
// |
|
|
|
|
|
#pragma warning( disable : 4244 ) |
|
#pragma warning( disable : 4237 ) |
|
#pragma warning( disable : 4305 ) |
|
|
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <sys/stat.h> |
|
#include <math.h> |
|
|
|
#include "cmdlib.h" |
|
#include "scriplib.h" |
|
#include "mathlib/mathlib.h" |
|
#include "studio.h" |
|
#include "studiomdl.h" |
|
//#include "..\..\dlls\activity.h" |
|
|
|
bool IsEnd( char const* pLine ) |
|
{ |
|
if (strncmp( "end", pLine, 3 ) != 0) |
|
return false; |
|
return (pLine[3] == '\0') || (pLine[3] == '\n'); |
|
} |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
void Grab_Vertexlist( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
int j; |
|
int bone; |
|
Vector p; |
|
int iCount, bones[4]; |
|
float weights[4]; |
|
|
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
|
|
|
|
int i = sscanf( g_szLine, "%d %d %f %f %f %d %d %f %d %f %d %f %d %f", |
|
&j, |
|
&bone, |
|
&p[0], &p[1], &p[2], |
|
&iCount, |
|
&bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] ); |
|
|
|
if (i == 5) |
|
{ |
|
if (bone < 0 || bone >= psource->numbones) |
|
{ |
|
MdlWarning( "bogus bone index\n" ); |
|
MdlWarning( "%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine ); |
|
MdlError( "Exiting due to errors\n" ); |
|
} |
|
|
|
VectorCopy( p, g_vertex[j] ); |
|
g_bone[j].numbones = 1; |
|
g_bone[j].bone[0] = bone; |
|
g_bone[j].weight[0] = 1.0; |
|
} |
|
else if (i > 5) |
|
{ |
|
iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights ); |
|
|
|
VectorCopy( p, g_vertex[j] ); |
|
g_bone[j].numbones = iCount; |
|
for (i = 0; i < iCount; i++) |
|
{ |
|
g_bone[j].bone[i] = bones[i]; |
|
g_bone[j].weight[i] = weights[i]; |
|
} |
|
} |
|
else |
|
{ |
|
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
void Grab_Facelist( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
int j; |
|
s_tmpface_t f; |
|
|
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
|
|
if (sscanf( g_szLine, "%d %d %d %d", |
|
&j, |
|
&f.a, &f.b, &f.c) == 4) |
|
{ |
|
g_face[j] = f; |
|
} |
|
else |
|
{ |
|
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
void Grab_Materiallist( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
// char name[256]; |
|
char path[MAX_PATH]; |
|
rgb2_t a, d, s; |
|
float g; |
|
int j; |
|
|
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
|
|
if (sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %f %f %f %f %f \"%[^\"]s", |
|
&j, |
|
&a.r, &a.g, &a.b, &a.a, |
|
&d.r, &d.g, &d.b, &d.a, |
|
&s.r, &s.g, &s.b, &s.a, |
|
&g, |
|
path ) == 15) |
|
{ |
|
if (path[0] == '\0') |
|
{ |
|
psource->texmap[j] = -1; |
|
} |
|
else if (j < ARRAYSIZE(psource->texmap)) |
|
{ |
|
psource->texmap[j] = LookupTexture( path ); |
|
} |
|
else |
|
{ |
|
MdlError( "Too many materials, max %d\n", ARRAYSIZE(psource->texmap) ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
void Grab_Texcoordlist( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
int j; |
|
Vector2D t; |
|
|
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
|
|
if (sscanf( g_szLine, "%d %f %f", |
|
&j, |
|
&t[0], &t[1]) == 3) |
|
{ |
|
t[1] = 1.0 - t[1]; |
|
g_texcoord[j][0] = t[0]; |
|
g_texcoord[j][1] = t[1]; |
|
} |
|
else |
|
{ |
|
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
void Grab_Normallist( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
int j; |
|
int bone; |
|
Vector n; |
|
|
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
|
|
|
|
if (sscanf( g_szLine, "%d %d %f %f %f", |
|
&j, |
|
&bone, |
|
&n[0], &n[1], &n[2]) == 5) |
|
{ |
|
if (bone < 0 || bone >= psource->numbones) |
|
{ |
|
MdlWarning( "bogus bone index\n" ); |
|
MdlWarning( "%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine ); |
|
MdlError( "Exiting due to errors\n" ); |
|
} |
|
|
|
VectorCopy( n, g_normal[j] ); |
|
} |
|
else |
|
{ |
|
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
void Grab_Faceattriblist( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
int j; |
|
int smooth; |
|
int material; |
|
s_tmpface_t f; |
|
unsigned short s; |
|
|
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
|
|
if (sscanf( g_szLine, "%d %d %d %d %d %d %d %d %d", |
|
&j, |
|
&material, |
|
&smooth, |
|
&f.ta, &f.tb, &f.tc, |
|
&f.na, &f.nb, &f.nc) == 9) |
|
{ |
|
f.a = g_face[j].a; |
|
f.b = g_face[j].b; |
|
f.c = g_face[j].c; |
|
|
|
f.material = UseTextureAsMaterial( psource->texmap[material] ); |
|
if (f.material < 0) |
|
{ |
|
MdlError( "face %d references NULL texture %d\n", j, material ); |
|
} |
|
|
|
if (1) |
|
{ |
|
s = f.b; f.b = f.c; f.c = s; |
|
s = f.tb; f.tb = f.tc; f.tc = s; |
|
s = f.nb; f.nb = f.nc; f.nc = s; |
|
} |
|
|
|
g_face[j] = f; |
|
} |
|
else |
|
{ |
|
MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
int closestNormal( int v, int n ) |
|
{ |
|
float maxdot = -1.0; |
|
float dot; |
|
int r = n; |
|
|
|
v_unify_t *cur = v_list[v]; |
|
|
|
while (cur) |
|
{ |
|
dot = DotProduct( g_normal[cur->n], g_normal[n] ); |
|
if (dot > maxdot) |
|
{ |
|
r = cur->n; |
|
maxdot = dot; |
|
} |
|
cur = cur->next; |
|
} |
|
|
|
return r; |
|
} |
|
|
|
|
|
int AddToVlist( int v, int m, int n, int t, int firstref ) |
|
{ |
|
v_unify_t *prev = NULL; |
|
v_unify_t *cur = v_list[v]; |
|
|
|
while (cur) |
|
{ |
|
if (cur->m == m && cur->n == n && cur->t == t) |
|
{ |
|
cur->refcount++; |
|
return cur - v_listdata; |
|
} |
|
prev = cur; |
|
cur = cur->next; |
|
} |
|
|
|
if (numvlist >= MAXSTUDIOVERTS) |
|
{ |
|
MdlError( "Too many unified vertices\n"); |
|
} |
|
|
|
cur = &v_listdata[numvlist++]; |
|
cur->lastref = -1; |
|
cur->refcount = 1; |
|
cur->firstref = firstref; |
|
cur->v = v; |
|
cur->m = m; |
|
cur->n = n; |
|
cur->t = t; |
|
|
|
if (prev) |
|
{ |
|
prev->next = cur; |
|
} |
|
else |
|
{ |
|
v_list[v] = cur; |
|
} |
|
|
|
return numvlist - 1; |
|
} |
|
|
|
void DecrementReferenceVlist( int uv, int numverts ) |
|
{ |
|
if (uv < 0 || uv >= MAXSTUDIOVERTS) |
|
MdlError( "decrement outside of range\n"); |
|
|
|
v_listdata[uv].refcount--; |
|
|
|
if (v_listdata[uv].refcount == 0) |
|
{ |
|
v_listdata[uv].lastref = numverts; |
|
} |
|
else if (v_listdata[uv].refcount < 0) |
|
{ |
|
MdlError("<0 ref\n"); |
|
} |
|
} |
|
|
|
|
|
void UnifyIndices( s_source_t *psource ) |
|
{ |
|
int i; |
|
|
|
static s_tmpface_t tmpface[MAXSTUDIOTRIANGLES]; // mrm processed g_face |
|
static s_face_t uface[MAXSTUDIOTRIANGLES]; // mrm processed unified face |
|
|
|
// clear v_list |
|
numvlist = 0; |
|
memset( v_list, 0, sizeof( v_list ) ); |
|
memset( v_listdata, 0, sizeof( v_listdata ) ); |
|
|
|
// create an list of all the |
|
for (i = 0; i < g_numfaces; i++) |
|
{ |
|
tmpface[i] = g_face[i]; |
|
|
|
uface[i].a = AddToVlist( g_face[i].a, g_face[i].material, g_face[i].na, g_face[i].ta, g_numverts ); |
|
uface[i].b = AddToVlist( g_face[i].b, g_face[i].material, g_face[i].nb, g_face[i].tb, g_numverts ); |
|
uface[i].c = AddToVlist( g_face[i].c, g_face[i].material, g_face[i].nc, g_face[i].tc, g_numverts ); |
|
|
|
// keep an original copy |
|
g_src_uface[i] = uface[i]; |
|
} |
|
|
|
// printf("%d : %d %d %d\n", numvlist, g_numverts, g_numnormals, g_numtexcoords ); |
|
} |
|
|
|
void CalcModelTangentSpaces( s_source_t *pSrc ); |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Builds a list of unique vertices in a source |
|
//----------------------------------------------------------------------------- |
|
static void BuildUniqueVertexList( s_source_t *pSource, const int *pDesiredToVList ) |
|
{ |
|
// allocate memory |
|
pSource->vertex = (s_vertexinfo_t *)kalloc( pSource->numvertices, sizeof( s_vertexinfo_t ) ); |
|
|
|
// create arrays of unique vertexes, normals, texcoords. |
|
for (int i = 0; i < pSource->numvertices; i++) |
|
{ |
|
int j = pDesiredToVList[i]; |
|
|
|
s_vertexinfo_t &vertex = pSource->vertex[i]; |
|
VectorCopy( g_vertex[ v_listdata[j].v ], vertex.position ); |
|
VectorCopy( g_normal[ v_listdata[j].n ], vertex.normal ); |
|
Vector2Copy( g_texcoord[ v_listdata[j].t ], vertex.texcoord ); |
|
|
|
vertex.boneweight.numbones = g_bone[ v_listdata[j].v ].numbones; |
|
int k; |
|
for( k = 0; k < MAXSTUDIOBONEWEIGHTS; k++ ) |
|
{ |
|
vertex.boneweight.bone[k] = g_bone[ v_listdata[j].v ].bone[k]; |
|
vertex.boneweight.weight[k] = g_bone[ v_listdata[j].v ].weight[k]; |
|
} |
|
|
|
// store a bunch of other info |
|
vertex.material = v_listdata[j].m; |
|
|
|
#if 0 |
|
pSource->vertexInfo[i].firstref = v_listdata[j].firstref; |
|
pSource->vertexInfo[i].lastref = v_listdata[j].lastref; |
|
#endif |
|
// printf("%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 new vertices by materials, last used |
|
//----------------------------------------------------------------------------- |
|
static 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; |
|
} |
|
|
|
static void SortVerticesByMaterial( int *pDesiredToVList, int *pVListToDesired ) |
|
{ |
|
for ( int i = 0; i < numvlist; i++ ) |
|
{ |
|
pDesiredToVList[i] = i; |
|
} |
|
qsort( pDesiredToVList, numvlist, sizeof( int ), vlistCompare ); |
|
for ( int i = 0; i < numvlist; i++ ) |
|
{ |
|
pVListToDesired[ pDesiredToVList[i] ] = i; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// sort new faces by materials, last used |
|
//----------------------------------------------------------------------------- |
|
static 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; |
|
} |
|
|
|
static void SortFacesByMaterial( int *pDesiredToSrcFace ) |
|
{ |
|
// NOTE: Unlike SortVerticesByMaterial, srcFaceToDesired isn't needed, so we're not computing it |
|
for ( int i = 0; i < g_numfaces; i++ ) |
|
{ |
|
pDesiredToSrcFace[i] = i; |
|
} |
|
qsort( pDesiredToSrcFace, g_numfaces, sizeof( int ), faceCompare ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Builds mesh structures in the source |
|
//----------------------------------------------------------------------------- |
|
static void PointMeshesToVertexAndFaceData( s_source_t *pSource, int *pDesiredToSrcFace ) |
|
{ |
|
// First, assign all meshes to be empty |
|
// A mesh is a set of faces + vertices that all use 1 material |
|
for ( int m = 0; m < MAXSTUDIOSKINS; m++ ) |
|
{ |
|
pSource->mesh[m].numvertices = 0; |
|
pSource->mesh[m].vertexoffset = pSource->numvertices; |
|
|
|
pSource->mesh[m].numfaces = 0; |
|
pSource->mesh[m].faceoffset = pSource->numfaces; |
|
} |
|
|
|
// find first and count of vertices per material |
|
for ( int i = 0; i < pSource->numvertices; i++ ) |
|
{ |
|
int m = pSource->vertex[i].material; |
|
pSource->mesh[m].numvertices++; |
|
if (pSource->mesh[m].vertexoffset > i) |
|
{ |
|
pSource->mesh[m].vertexoffset = i; |
|
} |
|
} |
|
|
|
// find first and count of faces per material |
|
for ( int i = 0; i < pSource->numfaces; i++ ) |
|
{ |
|
int m = g_face[ pDesiredToSrcFace[i] ].material; |
|
|
|
pSource->mesh[m].numfaces++; |
|
if (pSource->mesh[m].faceoffset > i) |
|
{ |
|
pSource->mesh[m].faceoffset = i; |
|
} |
|
} |
|
|
|
/* |
|
for (k = 0; k < MAXSTUDIOSKINS; k++) |
|
{ |
|
printf("%d : %d:%d %d:%d\n", k, psource->mesh[k].numvertices, psource->mesh[k].vertexoffset, psource->mesh[k].numfaces, psource->mesh[k].faceoffset ); |
|
} |
|
*/ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Builds the face list in the mesh |
|
//----------------------------------------------------------------------------- |
|
static void BuildFaceList( s_source_t *pSource, int *pVListToDesired, int *pDesiredToSrcFace ) |
|
{ |
|
pSource->face = (s_face_t *)kalloc( pSource->numfaces, sizeof( s_face_t )); |
|
for ( int m = 0; m < MAXSTUDIOSKINS; m++) |
|
{ |
|
if ( !pSource->mesh[m].numfaces ) |
|
continue; |
|
|
|
pSource->meshindex[ pSource->nummeshes++ ] = m; |
|
|
|
for ( int i = pSource->mesh[m].faceoffset; i < pSource->mesh[m].numfaces + pSource->mesh[m].faceoffset; i++) |
|
{ |
|
int j = pDesiredToSrcFace[i]; |
|
|
|
// NOTE: per-face vertex indices a,b,c are mesh relative (hence the subtraction), |
|
// while g_src_uface are model relative |
|
pSource->face[i].a = pVListToDesired[ g_src_uface[j].a ] - pSource->mesh[m].vertexoffset; |
|
pSource->face[i].b = pVListToDesired[ g_src_uface[j].b ] - pSource->mesh[m].vertexoffset; |
|
pSource->face[i].c = pVListToDesired[ g_src_uface[j].c ] - pSource->mesh[m].vertexoffset; |
|
Assert( ((pSource->face[i].a & 0xF0000000) == 0) && ((pSource->face[i].b & 0xF0000000) == 0) && |
|
((pSource->face[i].c & 0xF0000000) == 0) ); |
|
// printf("%3d : %4d %4d %4d\n", i, pSource->face[i].a, pSource->face[i].b, pSource->face[i].c ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Remaps the vertex animations based on the new vertex ordering |
|
//----------------------------------------------------------------------------- |
|
static void RemapVertexAnimations( s_source_t *pSource, int *pVListToDesired ) |
|
{ |
|
int nAnimationCount = pSource->m_Animations.Count(); |
|
for ( int i = 0; i < nAnimationCount; ++i ) |
|
{ |
|
s_sourceanim_t &anim = pSource->m_Animations[i]; |
|
if ( !anim.newStyleVertexAnimations ) |
|
continue; |
|
|
|
for ( int j = 0; j < MAXSTUDIOANIMFRAMES; ++j ) |
|
{ |
|
int nVAnimCount = anim.numvanims[j]; |
|
if ( nVAnimCount == 0 ) |
|
continue; |
|
|
|
// Copy off the initial vertex data |
|
// Have to do it in 2 loops because it'll overwrite itself if we do it in 1 |
|
int *pTemp = (int*)_alloca( nVAnimCount * sizeof(int) ); |
|
for ( int k = 0; k < nVAnimCount; ++k ) |
|
{ |
|
pTemp[k] = anim.vanim[j][k].vertex; |
|
} |
|
|
|
for ( int k = 0; k < nVAnimCount; ++k ) |
|
{ |
|
// NOTE: vertex animations are model relative, not mesh relative |
|
anim.vanim[j][k].vertex = pVListToDesired[ pTemp[k] ]; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sorts vertices by material type, re-maps data structures that refer to those vertices |
|
// to use the new indices |
|
//----------------------------------------------------------------------------- |
|
void BuildIndividualMeshes( s_source_t *pSource ) |
|
{ |
|
static int v_listsort[MAXSTUDIOVERTS]; // map desired order to vlist entry |
|
static int v_ilistsort[MAXSTUDIOVERTS]; // map vlist entry to desired order |
|
static int facesort[MAXSTUDIOTRIANGLES]; // map desired order to src_face entry |
|
|
|
SortVerticesByMaterial( v_listsort, v_ilistsort ); |
|
SortFacesByMaterial( facesort ); |
|
|
|
pSource->numvertices = numvlist; |
|
pSource->numfaces = g_numfaces; |
|
|
|
BuildUniqueVertexList( pSource, v_listsort ); |
|
PointMeshesToVertexAndFaceData( pSource, facesort ); |
|
BuildFaceList( pSource, v_ilistsort, facesort ); |
|
RemapVertexAnimations( pSource, v_ilistsort ); |
|
CalcModelTangentSpaces( pSource ); |
|
} |
|
|
|
|
|
void Grab_MRMFaceupdates( s_source_t *psource ) |
|
{ |
|
while (1) |
|
{ |
|
if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
g_iLinecount++; |
|
|
|
// check for end |
|
if (IsEnd(g_szLine)) |
|
return; |
|
} |
|
} |
|
} |
|
|
|
int Load_VRM ( s_source_t *psource ) |
|
{ |
|
char cmd[1024]; |
|
int option; |
|
|
|
if (!OpenGlobalFile( psource->filename )) |
|
{ |
|
return 0; |
|
} |
|
|
|
if( !g_quiet ) |
|
{ |
|
printf ("grabbing %s\n", psource->filename); |
|
} |
|
|
|
g_iLinecount = 0; |
|
|
|
while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL) |
|
{ |
|
g_iLinecount++; |
|
sscanf( g_szLine, "%1023s %d", cmd, &option ); |
|
if (stricmp( cmd, "version" ) == 0) |
|
{ |
|
if (option != 2) |
|
{ |
|
MdlError("bad version\n"); |
|
} |
|
} |
|
else if (stricmp( cmd, "name" ) == 0) |
|
{ |
|
} |
|
else if (stricmp( cmd, "vertices" ) == 0) |
|
{ |
|
g_numverts = option; |
|
} |
|
else if (stricmp( cmd, "faces" ) == 0) |
|
{ |
|
g_numfaces = option; |
|
} |
|
else if (stricmp( cmd, "materials" ) == 0) |
|
{ |
|
// doesn't matter; |
|
} |
|
else if (stricmp( cmd, "texcoords" ) == 0) |
|
{ |
|
g_numtexcoords = option; |
|
if (option == 0) |
|
MdlError( "model has no texture coordinates\n"); |
|
} |
|
else if (stricmp( cmd, "normals" ) == 0) |
|
{ |
|
g_numnormals = option; |
|
} |
|
else if (stricmp( cmd, "tristrips" ) == 0) |
|
{ |
|
// should be 0; |
|
} |
|
|
|
else if (stricmp( cmd, "vertexlist" ) == 0) |
|
{ |
|
Grab_Vertexlist( psource ); |
|
} |
|
else if (stricmp( cmd, "facelist" ) == 0) |
|
{ |
|
Grab_Facelist( psource ); |
|
} |
|
else if (stricmp( cmd, "materiallist" ) == 0) |
|
{ |
|
Grab_Materiallist( psource ); |
|
} |
|
else if (stricmp( cmd, "texcoordlist" ) == 0) |
|
{ |
|
Grab_Texcoordlist( psource ); |
|
} |
|
else if (stricmp( cmd, "normallist" ) == 0) |
|
{ |
|
Grab_Normallist( psource ); |
|
} |
|
else if (stricmp( cmd, "faceattriblist" ) == 0) |
|
{ |
|
Grab_Faceattriblist( psource ); |
|
} |
|
|
|
else if (stricmp( cmd, "MRM" ) == 0) |
|
{ |
|
} |
|
else if (stricmp( cmd, "MRMvertices" ) == 0) |
|
{ |
|
} |
|
else if (stricmp( cmd, "MRMfaces" ) == 0) |
|
{ |
|
} |
|
else if (stricmp( cmd, "MRMfaceupdates" ) == 0) |
|
{ |
|
Grab_MRMFaceupdates( psource ); |
|
} |
|
|
|
else if (stricmp( cmd, "nodes" ) == 0) |
|
{ |
|
psource->numbones = Grab_Nodes( psource->localBone ); |
|
} |
|
else if (stricmp( cmd, "skeleton" ) == 0) |
|
{ |
|
Grab_Animation( psource, "BindPose" ); |
|
} |
|
/* |
|
else if (stricmp( cmd, "triangles" ) == 0) { |
|
Grab_Triangles( psource ); |
|
} |
|
*/ |
|
else |
|
{ |
|
MdlError("unknown VRM command : %s \n", cmd ); |
|
} |
|
} |
|
|
|
UnifyIndices( psource ); |
|
BuildIndividualMeshes( psource ); |
|
|
|
fclose( g_fpInput ); |
|
|
|
return 1; |
|
} |
|
|
|
|