Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // studiomdl.c: generates a studio .mdl file from a .qc script
  10. // models/<scriptname>.mdl.
  11. //
  12. #pragma warning( disable : 4244 )
  13. #pragma warning( disable : 4237 )
  14. #pragma warning( disable : 4305 )
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <sys/stat.h>
  18. #include <math.h>
  19. #include "cmdlib.h"
  20. #include "scriplib.h"
  21. #include "mathlib/mathlib.h"
  22. #include "studio.h"
  23. #include "studiomdl.h"
  24. //#include "..\..\dlls\activity.h"
  25. bool IsEnd( char const* pLine )
  26. {
  27. if (strncmp( "end", pLine, 3 ) != 0)
  28. return false;
  29. return (pLine[3] == '\0') || (pLine[3] == '\n');
  30. }
  31. int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] )
  32. {
  33. int i;
  34. // collapse duplicate bone weights
  35. for (i = 0; i < iCount-1; i++)
  36. {
  37. int j;
  38. for (j = i + 1; j < iCount; j++)
  39. {
  40. if (bones[i] == bones[j])
  41. {
  42. weights[i] += weights[j];
  43. weights[j] = 0.0;
  44. }
  45. }
  46. }
  47. // do sleazy bubble sort
  48. int bShouldSort;
  49. do {
  50. bShouldSort = false;
  51. for (i = 0; i < iCount-1; i++)
  52. {
  53. if (weights[i+1] > weights[i])
  54. {
  55. int j = bones[i+1]; bones[i+1] = bones[i]; bones[i] = j;
  56. float w = weights[i+1]; weights[i+1] = weights[i]; weights[i] = w;
  57. bShouldSort = true;
  58. }
  59. }
  60. } while (bShouldSort);
  61. // throw away all weights less than 1/20th
  62. while (iCount > 1 && weights[iCount-1] < 0.05)
  63. {
  64. iCount--;
  65. }
  66. // clip to the top iMaxCount bones
  67. if (iCount > iMaxCount)
  68. {
  69. iCount = iMaxCount;
  70. }
  71. float t = 0;
  72. for (i = 0; i < iCount; i++)
  73. {
  74. t += weights[i];
  75. }
  76. if (t <= 0.0)
  77. {
  78. // missing weights?, go ahead and evenly share?
  79. // FIXME: shouldn't this error out?
  80. t = 1.0 / iCount;
  81. for (i = 0; i < iCount; i++)
  82. {
  83. weights[i] = t;
  84. }
  85. }
  86. else
  87. {
  88. // scale to sum to 1.0
  89. t = 1.0 / t;
  90. for (i = 0; i < iCount; i++)
  91. {
  92. weights[i] = weights[i] * t;
  93. }
  94. }
  95. return iCount;
  96. }
  97. void Grab_Vertexlist( s_source_t *psource )
  98. {
  99. while (1)
  100. {
  101. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  102. {
  103. int j;
  104. int bone;
  105. Vector p;
  106. int iCount, bones[4];
  107. float weights[4];
  108. g_iLinecount++;
  109. // check for end
  110. if (IsEnd(g_szLine))
  111. return;
  112. int i = sscanf( g_szLine, "%d %d %f %f %f %d %d %f %d %f %d %f %d %f",
  113. &j,
  114. &bone,
  115. &p[0], &p[1], &p[2],
  116. &iCount,
  117. &bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
  118. if (i == 5)
  119. {
  120. if (bone < 0 || bone >= psource->numbones)
  121. {
  122. MdlWarning( "bogus bone index\n" );
  123. MdlWarning( "%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
  124. MdlError( "Exiting due to errors\n" );
  125. }
  126. VectorCopy( p, g_vertex[j] );
  127. g_bone[j].numbones = 1;
  128. g_bone[j].bone[0] = bone;
  129. g_bone[j].weight[0] = 1.0;
  130. }
  131. else if (i > 5)
  132. {
  133. iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
  134. VectorCopy( p, g_vertex[j] );
  135. g_bone[j].numbones = iCount;
  136. for (i = 0; i < iCount; i++)
  137. {
  138. g_bone[j].bone[i] = bones[i];
  139. g_bone[j].weight[i] = weights[i];
  140. }
  141. }
  142. else
  143. {
  144. MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
  145. }
  146. }
  147. }
  148. }
  149. void Grab_Facelist( s_source_t *psource )
  150. {
  151. while (1)
  152. {
  153. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  154. {
  155. int j;
  156. s_tmpface_t f;
  157. g_iLinecount++;
  158. // check for end
  159. if (IsEnd(g_szLine))
  160. return;
  161. if (sscanf( g_szLine, "%d %d %d %d",
  162. &j,
  163. &f.a, &f.b, &f.c) == 4)
  164. {
  165. g_face[j] = f;
  166. }
  167. else
  168. {
  169. MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
  170. }
  171. }
  172. }
  173. }
  174. void Grab_Materiallist( s_source_t *psource )
  175. {
  176. while (1)
  177. {
  178. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  179. {
  180. // char name[256];
  181. char path[MAX_PATH];
  182. rgb2_t a, d, s;
  183. float g;
  184. int j;
  185. g_iLinecount++;
  186. // check for end
  187. if (IsEnd(g_szLine))
  188. return;
  189. if (sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %f %f %f %f %f \"%[^\"]s",
  190. &j,
  191. &a.r, &a.g, &a.b, &a.a,
  192. &d.r, &d.g, &d.b, &d.a,
  193. &s.r, &s.g, &s.b, &s.a,
  194. &g,
  195. path ) == 15)
  196. {
  197. if (path[0] == '\0')
  198. {
  199. psource->texmap[j] = -1;
  200. }
  201. else if (j < ARRAYSIZE(psource->texmap))
  202. {
  203. psource->texmap[j] = LookupTexture( path );
  204. }
  205. else
  206. {
  207. MdlError( "Too many materials, max %d\n", ARRAYSIZE(psource->texmap) );
  208. }
  209. }
  210. }
  211. }
  212. }
  213. void Grab_Texcoordlist( s_source_t *psource )
  214. {
  215. while (1)
  216. {
  217. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  218. {
  219. int j;
  220. Vector2D t;
  221. g_iLinecount++;
  222. // check for end
  223. if (IsEnd(g_szLine))
  224. return;
  225. if (sscanf( g_szLine, "%d %f %f",
  226. &j,
  227. &t[0], &t[1]) == 3)
  228. {
  229. t[1] = 1.0 - t[1];
  230. g_texcoord[j][0] = t[0];
  231. g_texcoord[j][1] = t[1];
  232. }
  233. else
  234. {
  235. MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
  236. }
  237. }
  238. }
  239. }
  240. void Grab_Normallist( s_source_t *psource )
  241. {
  242. while (1)
  243. {
  244. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  245. {
  246. int j;
  247. int bone;
  248. Vector n;
  249. g_iLinecount++;
  250. // check for end
  251. if (IsEnd(g_szLine))
  252. return;
  253. if (sscanf( g_szLine, "%d %d %f %f %f",
  254. &j,
  255. &bone,
  256. &n[0], &n[1], &n[2]) == 5)
  257. {
  258. if (bone < 0 || bone >= psource->numbones)
  259. {
  260. MdlWarning( "bogus bone index\n" );
  261. MdlWarning( "%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
  262. MdlError( "Exiting due to errors\n" );
  263. }
  264. VectorCopy( n, g_normal[j] );
  265. }
  266. else
  267. {
  268. MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
  269. }
  270. }
  271. }
  272. }
  273. void Grab_Faceattriblist( s_source_t *psource )
  274. {
  275. while (1)
  276. {
  277. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  278. {
  279. int j;
  280. int smooth;
  281. int material;
  282. s_tmpface_t f;
  283. unsigned short s;
  284. g_iLinecount++;
  285. // check for end
  286. if (IsEnd(g_szLine))
  287. return;
  288. if (sscanf( g_szLine, "%d %d %d %d %d %d %d %d %d",
  289. &j,
  290. &material,
  291. &smooth,
  292. &f.ta, &f.tb, &f.tc,
  293. &f.na, &f.nb, &f.nc) == 9)
  294. {
  295. f.a = g_face[j].a;
  296. f.b = g_face[j].b;
  297. f.c = g_face[j].c;
  298. f.material = UseTextureAsMaterial( psource->texmap[material] );
  299. if (f.material < 0)
  300. {
  301. MdlError( "face %d references NULL texture %d\n", j, material );
  302. }
  303. if (1)
  304. {
  305. s = f.b; f.b = f.c; f.c = s;
  306. s = f.tb; f.tb = f.tc; f.tc = s;
  307. s = f.nb; f.nb = f.nc; f.nc = s;
  308. }
  309. g_face[j] = f;
  310. }
  311. else
  312. {
  313. MdlError("%s: error on line %d: %s", g_szFilename, g_iLinecount, g_szLine );
  314. }
  315. }
  316. }
  317. }
  318. int closestNormal( int v, int n )
  319. {
  320. float maxdot = -1.0;
  321. float dot;
  322. int r = n;
  323. v_unify_t *cur = v_list[v];
  324. while (cur)
  325. {
  326. dot = DotProduct( g_normal[cur->n], g_normal[n] );
  327. if (dot > maxdot)
  328. {
  329. r = cur->n;
  330. maxdot = dot;
  331. }
  332. cur = cur->next;
  333. }
  334. return r;
  335. }
  336. int AddToVlist( int v, int m, int n, int t, int firstref )
  337. {
  338. v_unify_t *prev = NULL;
  339. v_unify_t *cur = v_list[v];
  340. while (cur)
  341. {
  342. if (cur->m == m && cur->n == n && cur->t == t)
  343. {
  344. cur->refcount++;
  345. return cur - v_listdata;
  346. }
  347. prev = cur;
  348. cur = cur->next;
  349. }
  350. if (numvlist >= MAXSTUDIOVERTS)
  351. {
  352. MdlError( "Too many unified vertices\n");
  353. }
  354. cur = &v_listdata[numvlist++];
  355. cur->lastref = -1;
  356. cur->refcount = 1;
  357. cur->firstref = firstref;
  358. cur->v = v;
  359. cur->m = m;
  360. cur->n = n;
  361. cur->t = t;
  362. if (prev)
  363. {
  364. prev->next = cur;
  365. }
  366. else
  367. {
  368. v_list[v] = cur;
  369. }
  370. return numvlist - 1;
  371. }
  372. void DecrementReferenceVlist( int uv, int numverts )
  373. {
  374. if (uv < 0 || uv >= MAXSTUDIOVERTS)
  375. MdlError( "decrement outside of range\n");
  376. v_listdata[uv].refcount--;
  377. if (v_listdata[uv].refcount == 0)
  378. {
  379. v_listdata[uv].lastref = numverts;
  380. }
  381. else if (v_listdata[uv].refcount < 0)
  382. {
  383. MdlError("<0 ref\n");
  384. }
  385. }
  386. void UnifyIndices( s_source_t *psource )
  387. {
  388. int i;
  389. static s_tmpface_t tmpface[MAXSTUDIOTRIANGLES]; // mrm processed g_face
  390. static s_face_t uface[MAXSTUDIOTRIANGLES]; // mrm processed unified face
  391. // clear v_list
  392. numvlist = 0;
  393. memset( v_list, 0, sizeof( v_list ) );
  394. memset( v_listdata, 0, sizeof( v_listdata ) );
  395. // create an list of all the
  396. for (i = 0; i < g_numfaces; i++)
  397. {
  398. tmpface[i] = g_face[i];
  399. uface[i].a = AddToVlist( g_face[i].a, g_face[i].material, g_face[i].na, g_face[i].ta, g_numverts );
  400. uface[i].b = AddToVlist( g_face[i].b, g_face[i].material, g_face[i].nb, g_face[i].tb, g_numverts );
  401. uface[i].c = AddToVlist( g_face[i].c, g_face[i].material, g_face[i].nc, g_face[i].tc, g_numverts );
  402. // keep an original copy
  403. g_src_uface[i] = uface[i];
  404. }
  405. // printf("%d : %d %d %d\n", numvlist, g_numverts, g_numnormals, g_numtexcoords );
  406. }
  407. void CalcModelTangentSpaces( s_source_t *pSrc );
  408. //-----------------------------------------------------------------------------
  409. // Builds a list of unique vertices in a source
  410. //-----------------------------------------------------------------------------
  411. static void BuildUniqueVertexList( s_source_t *pSource, const int *pDesiredToVList )
  412. {
  413. // allocate memory
  414. pSource->vertex = (s_vertexinfo_t *)kalloc( pSource->numvertices, sizeof( s_vertexinfo_t ) );
  415. // create arrays of unique vertexes, normals, texcoords.
  416. for (int i = 0; i < pSource->numvertices; i++)
  417. {
  418. int j = pDesiredToVList[i];
  419. s_vertexinfo_t &vertex = pSource->vertex[i];
  420. VectorCopy( g_vertex[ v_listdata[j].v ], vertex.position );
  421. VectorCopy( g_normal[ v_listdata[j].n ], vertex.normal );
  422. Vector2Copy( g_texcoord[ v_listdata[j].t ], vertex.texcoord );
  423. vertex.boneweight.numbones = g_bone[ v_listdata[j].v ].numbones;
  424. int k;
  425. for( k = 0; k < MAXSTUDIOBONEWEIGHTS; k++ )
  426. {
  427. vertex.boneweight.bone[k] = g_bone[ v_listdata[j].v ].bone[k];
  428. vertex.boneweight.weight[k] = g_bone[ v_listdata[j].v ].weight[k];
  429. }
  430. // store a bunch of other info
  431. vertex.material = v_listdata[j].m;
  432. #if 0
  433. pSource->vertexInfo[i].firstref = v_listdata[j].firstref;
  434. pSource->vertexInfo[i].lastref = v_listdata[j].lastref;
  435. #endif
  436. // 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] );
  437. }
  438. }
  439. //-----------------------------------------------------------------------------
  440. // sort new vertices by materials, last used
  441. //-----------------------------------------------------------------------------
  442. static int vlistCompare( const void *elem1, const void *elem2 )
  443. {
  444. v_unify_t *u1 = &v_listdata[*(int *)elem1];
  445. v_unify_t *u2 = &v_listdata[*(int *)elem2];
  446. // sort by material
  447. if (u1->m < u2->m)
  448. return -1;
  449. if (u1->m > u2->m)
  450. return 1;
  451. // sort by last used
  452. if (u1->lastref < u2->lastref)
  453. return -1;
  454. if (u1->lastref > u2->lastref)
  455. return 1;
  456. return 0;
  457. }
  458. static void SortVerticesByMaterial( int *pDesiredToVList, int *pVListToDesired )
  459. {
  460. for ( int i = 0; i < numvlist; i++ )
  461. {
  462. pDesiredToVList[i] = i;
  463. }
  464. qsort( pDesiredToVList, numvlist, sizeof( int ), vlistCompare );
  465. for ( int i = 0; i < numvlist; i++ )
  466. {
  467. pVListToDesired[ pDesiredToVList[i] ] = i;
  468. }
  469. }
  470. //-----------------------------------------------------------------------------
  471. // sort new faces by materials, last used
  472. //-----------------------------------------------------------------------------
  473. static int faceCompare( const void *elem1, const void *elem2 )
  474. {
  475. int i1 = *(int *)elem1;
  476. int i2 = *(int *)elem2;
  477. // sort by material
  478. if (g_face[i1].material < g_face[i2].material)
  479. return -1;
  480. if (g_face[i1].material > g_face[i2].material)
  481. return 1;
  482. // sort by original usage
  483. if (i1 < i2)
  484. return -1;
  485. if (i1 > i2)
  486. return 1;
  487. return 0;
  488. }
  489. static void SortFacesByMaterial( int *pDesiredToSrcFace )
  490. {
  491. // NOTE: Unlike SortVerticesByMaterial, srcFaceToDesired isn't needed, so we're not computing it
  492. for ( int i = 0; i < g_numfaces; i++ )
  493. {
  494. pDesiredToSrcFace[i] = i;
  495. }
  496. qsort( pDesiredToSrcFace, g_numfaces, sizeof( int ), faceCompare );
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Builds mesh structures in the source
  500. //-----------------------------------------------------------------------------
  501. static void PointMeshesToVertexAndFaceData( s_source_t *pSource, int *pDesiredToSrcFace )
  502. {
  503. // First, assign all meshes to be empty
  504. // A mesh is a set of faces + vertices that all use 1 material
  505. for ( int m = 0; m < MAXSTUDIOSKINS; m++ )
  506. {
  507. pSource->mesh[m].numvertices = 0;
  508. pSource->mesh[m].vertexoffset = pSource->numvertices;
  509. pSource->mesh[m].numfaces = 0;
  510. pSource->mesh[m].faceoffset = pSource->numfaces;
  511. }
  512. // find first and count of vertices per material
  513. for ( int i = 0; i < pSource->numvertices; i++ )
  514. {
  515. int m = pSource->vertex[i].material;
  516. pSource->mesh[m].numvertices++;
  517. if (pSource->mesh[m].vertexoffset > i)
  518. {
  519. pSource->mesh[m].vertexoffset = i;
  520. }
  521. }
  522. // find first and count of faces per material
  523. for ( int i = 0; i < pSource->numfaces; i++ )
  524. {
  525. int m = g_face[ pDesiredToSrcFace[i] ].material;
  526. pSource->mesh[m].numfaces++;
  527. if (pSource->mesh[m].faceoffset > i)
  528. {
  529. pSource->mesh[m].faceoffset = i;
  530. }
  531. }
  532. /*
  533. for (k = 0; k < MAXSTUDIOSKINS; k++)
  534. {
  535. printf("%d : %d:%d %d:%d\n", k, psource->mesh[k].numvertices, psource->mesh[k].vertexoffset, psource->mesh[k].numfaces, psource->mesh[k].faceoffset );
  536. }
  537. */
  538. }
  539. //-----------------------------------------------------------------------------
  540. // Builds the face list in the mesh
  541. //-----------------------------------------------------------------------------
  542. static void BuildFaceList( s_source_t *pSource, int *pVListToDesired, int *pDesiredToSrcFace )
  543. {
  544. pSource->face = (s_face_t *)kalloc( pSource->numfaces, sizeof( s_face_t ));
  545. for ( int m = 0; m < MAXSTUDIOSKINS; m++)
  546. {
  547. if ( !pSource->mesh[m].numfaces )
  548. continue;
  549. pSource->meshindex[ pSource->nummeshes++ ] = m;
  550. for ( int i = pSource->mesh[m].faceoffset; i < pSource->mesh[m].numfaces + pSource->mesh[m].faceoffset; i++)
  551. {
  552. int j = pDesiredToSrcFace[i];
  553. // NOTE: per-face vertex indices a,b,c are mesh relative (hence the subtraction),
  554. // while g_src_uface are model relative
  555. pSource->face[i].a = pVListToDesired[ g_src_uface[j].a ] - pSource->mesh[m].vertexoffset;
  556. pSource->face[i].b = pVListToDesired[ g_src_uface[j].b ] - pSource->mesh[m].vertexoffset;
  557. pSource->face[i].c = pVListToDesired[ g_src_uface[j].c ] - pSource->mesh[m].vertexoffset;
  558. Assert( ((pSource->face[i].a & 0xF0000000) == 0) && ((pSource->face[i].b & 0xF0000000) == 0) &&
  559. ((pSource->face[i].c & 0xF0000000) == 0) );
  560. // printf("%3d : %4d %4d %4d\n", i, pSource->face[i].a, pSource->face[i].b, pSource->face[i].c );
  561. }
  562. }
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Remaps the vertex animations based on the new vertex ordering
  566. //-----------------------------------------------------------------------------
  567. static void RemapVertexAnimations( s_source_t *pSource, int *pVListToDesired )
  568. {
  569. int nAnimationCount = pSource->m_Animations.Count();
  570. for ( int i = 0; i < nAnimationCount; ++i )
  571. {
  572. s_sourceanim_t &anim = pSource->m_Animations[i];
  573. if ( !anim.newStyleVertexAnimations )
  574. continue;
  575. for ( int j = 0; j < MAXSTUDIOANIMFRAMES; ++j )
  576. {
  577. int nVAnimCount = anim.numvanims[j];
  578. if ( nVAnimCount == 0 )
  579. continue;
  580. // Copy off the initial vertex data
  581. // Have to do it in 2 loops because it'll overwrite itself if we do it in 1
  582. int *pTemp = (int*)_alloca( nVAnimCount * sizeof(int) );
  583. for ( int k = 0; k < nVAnimCount; ++k )
  584. {
  585. pTemp[k] = anim.vanim[j][k].vertex;
  586. }
  587. for ( int k = 0; k < nVAnimCount; ++k )
  588. {
  589. // NOTE: vertex animations are model relative, not mesh relative
  590. anim.vanim[j][k].vertex = pVListToDesired[ pTemp[k] ];
  591. }
  592. }
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Sorts vertices by material type, re-maps data structures that refer to those vertices
  597. // to use the new indices
  598. //-----------------------------------------------------------------------------
  599. void BuildIndividualMeshes( s_source_t *pSource )
  600. {
  601. static int v_listsort[MAXSTUDIOVERTS]; // map desired order to vlist entry
  602. static int v_ilistsort[MAXSTUDIOVERTS]; // map vlist entry to desired order
  603. static int facesort[MAXSTUDIOTRIANGLES]; // map desired order to src_face entry
  604. SortVerticesByMaterial( v_listsort, v_ilistsort );
  605. SortFacesByMaterial( facesort );
  606. pSource->numvertices = numvlist;
  607. pSource->numfaces = g_numfaces;
  608. BuildUniqueVertexList( pSource, v_listsort );
  609. PointMeshesToVertexAndFaceData( pSource, facesort );
  610. BuildFaceList( pSource, v_ilistsort, facesort );
  611. RemapVertexAnimations( pSource, v_ilistsort );
  612. CalcModelTangentSpaces( pSource );
  613. }
  614. void Grab_MRMFaceupdates( s_source_t *psource )
  615. {
  616. while (1)
  617. {
  618. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  619. {
  620. g_iLinecount++;
  621. // check for end
  622. if (IsEnd(g_szLine))
  623. return;
  624. }
  625. }
  626. }
  627. int Load_VRM ( s_source_t *psource )
  628. {
  629. char cmd[1024];
  630. int option;
  631. if (!OpenGlobalFile( psource->filename ))
  632. {
  633. return 0;
  634. }
  635. if( !g_quiet )
  636. {
  637. printf ("grabbing %s\n", psource->filename);
  638. }
  639. g_iLinecount = 0;
  640. while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  641. {
  642. g_iLinecount++;
  643. sscanf( g_szLine, "%1023s %d", cmd, &option );
  644. if (stricmp( cmd, "version" ) == 0)
  645. {
  646. if (option != 2)
  647. {
  648. MdlError("bad version\n");
  649. }
  650. }
  651. else if (stricmp( cmd, "name" ) == 0)
  652. {
  653. }
  654. else if (stricmp( cmd, "vertices" ) == 0)
  655. {
  656. g_numverts = option;
  657. }
  658. else if (stricmp( cmd, "faces" ) == 0)
  659. {
  660. g_numfaces = option;
  661. }
  662. else if (stricmp( cmd, "materials" ) == 0)
  663. {
  664. // doesn't matter;
  665. }
  666. else if (stricmp( cmd, "texcoords" ) == 0)
  667. {
  668. g_numtexcoords = option;
  669. if (option == 0)
  670. MdlError( "model has no texture coordinates\n");
  671. }
  672. else if (stricmp( cmd, "normals" ) == 0)
  673. {
  674. g_numnormals = option;
  675. }
  676. else if (stricmp( cmd, "tristrips" ) == 0)
  677. {
  678. // should be 0;
  679. }
  680. else if (stricmp( cmd, "vertexlist" ) == 0)
  681. {
  682. Grab_Vertexlist( psource );
  683. }
  684. else if (stricmp( cmd, "facelist" ) == 0)
  685. {
  686. Grab_Facelist( psource );
  687. }
  688. else if (stricmp( cmd, "materiallist" ) == 0)
  689. {
  690. Grab_Materiallist( psource );
  691. }
  692. else if (stricmp( cmd, "texcoordlist" ) == 0)
  693. {
  694. Grab_Texcoordlist( psource );
  695. }
  696. else if (stricmp( cmd, "normallist" ) == 0)
  697. {
  698. Grab_Normallist( psource );
  699. }
  700. else if (stricmp( cmd, "faceattriblist" ) == 0)
  701. {
  702. Grab_Faceattriblist( psource );
  703. }
  704. else if (stricmp( cmd, "MRM" ) == 0)
  705. {
  706. }
  707. else if (stricmp( cmd, "MRMvertices" ) == 0)
  708. {
  709. }
  710. else if (stricmp( cmd, "MRMfaces" ) == 0)
  711. {
  712. }
  713. else if (stricmp( cmd, "MRMfaceupdates" ) == 0)
  714. {
  715. Grab_MRMFaceupdates( psource );
  716. }
  717. else if (stricmp( cmd, "nodes" ) == 0)
  718. {
  719. psource->numbones = Grab_Nodes( psource->localBone );
  720. }
  721. else if (stricmp( cmd, "skeleton" ) == 0)
  722. {
  723. Grab_Animation( psource, "BindPose" );
  724. }
  725. /*
  726. else if (stricmp( cmd, "triangles" ) == 0) {
  727. Grab_Triangles( psource );
  728. }
  729. */
  730. else
  731. {
  732. MdlError("unknown VRM command : %s \n", cmd );
  733. }
  734. }
  735. UnifyIndices( psource );
  736. BuildIndividualMeshes( psource );
  737. fclose( g_fpInput );
  738. return 1;
  739. }