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.

1757 lines
52 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "movieobjects/dmetestmesh.h"
  7. #include "movieobjects/dmetransform.h"
  8. #include "movieobjects_interfaces.h"
  9. #include "tier0/dbg.h"
  10. #include "datamodel/dmelementfactoryhelper.h"
  11. #include "mathlib/vector.h"
  12. #include "materialsystem/imaterialsystem.h"
  13. #include "materialsystem/imesh.h"
  14. #include "datacache/imdlcache.h"
  15. #include "istudiorender.h"
  16. #include "studio.h"
  17. #include "bone_setup.h"
  18. #include "materialsystem/ivertextexture.h"
  19. #include "morphdata.h"
  20. #include "tier3/tier3.h"
  21. #include <strstream>
  22. #include <fstream>
  23. #include <algorithm>
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include "tier0/memdbgon.h"
  26. //-----------------------------------------------------------------------------
  27. // Expose this class to the scene database
  28. //-----------------------------------------------------------------------------
  29. IMPLEMENT_ELEMENT_FACTORY( DmeTestMesh, CDmeTestMesh );
  30. //-----------------------------------------------------------------------------
  31. // Purpose:
  32. //-----------------------------------------------------------------------------
  33. void CDmeTestMesh::OnConstruction()
  34. {
  35. m_MDLHandle = MDLHANDLE_INVALID;
  36. m_pMaterial = NULL;
  37. m_pMesh = NULL;
  38. m_pMorph = NULL;
  39. m_pControlCage = NULL;
  40. SetValue( "transform", g_pDataModel->IsUnserializing() ? NULL : CreateElement< CDmeTransform >( "transform", GetFileId() ) );
  41. SetValue( "mdlfilename", "models/alyx.mdl" );
  42. SetValue( "morphfilename", "models/alyx.morph" );
  43. SetValue( "skin", 0 );
  44. SetValue( "body", 0 );
  45. SetValue( "sequence", 0 );
  46. SetValue( "lod", 0 );
  47. SetValue( "playbackrate", 1.0f );
  48. SetValue( "time", 0.0f );
  49. SetValue( "subdivlevel", 1 );
  50. }
  51. void CDmeTestMesh::OnDestruction()
  52. {
  53. UnloadMorphData();
  54. UnreferenceMDL();
  55. DestroyControlCage();
  56. DestroyMesh();
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Addref/Release the MDL handle
  60. //-----------------------------------------------------------------------------
  61. void CDmeTestMesh::ReferenceMDL( const char *pMDLName )
  62. {
  63. if ( !g_pMDLCache )
  64. return;
  65. if ( pMDLName && pMDLName[0] )
  66. {
  67. Assert( m_MDLHandle == MDLHANDLE_INVALID );
  68. m_MDLHandle = g_pMDLCache->FindMDL( pMDLName );
  69. }
  70. }
  71. void CDmeTestMesh::UnreferenceMDL()
  72. {
  73. if ( !g_pMDLCache )
  74. return;
  75. if ( m_MDLHandle != MDLHANDLE_INVALID )
  76. {
  77. g_pMDLCache->Release( m_MDLHandle );
  78. m_MDLHandle = MDLHANDLE_INVALID;
  79. }
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Creates the mesh to draw
  83. //-----------------------------------------------------------------------------
  84. void CDmeTestMesh::CreateMesh()
  85. {
  86. DestroyMesh();
  87. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  88. m_pMaterial = g_pMaterialSystem->FindMaterial( "shadertest/vertextexturetest", NULL, false );
  89. m_pMesh = pRenderContext->CreateStaticMesh( m_pMaterial, 0, "dmemesh" );
  90. CMeshBuilder meshBuilder;
  91. meshBuilder.Begin( m_pMesh, MATERIAL_TRIANGLES, 8, 36 );
  92. // Draw a simple cube
  93. static Vector s_pPositions[8] =
  94. {
  95. Vector( -10, -10, -10 ),
  96. Vector( 10, -10, -10 ),
  97. Vector( -10, 10, -10 ),
  98. Vector( 10, 10, -10 ),
  99. Vector( -10, -10, 10 ),
  100. Vector( 10, -10, 10 ),
  101. Vector( -10, 10, 10 ),
  102. Vector( 10, 10, 10 ),
  103. };
  104. static Vector2D s_pTexCoords[8] =
  105. {
  106. Vector2D( 0, 0 ),
  107. Vector2D( 0.5, 0 ),
  108. Vector2D( 0, 0.5 ),
  109. Vector2D( 0.5, 0.5 ),
  110. Vector2D( 0.5, 0.5 ),
  111. Vector2D( 1, 0.5 ),
  112. Vector2D( 0.5, 1 ),
  113. Vector2D( 1, 1 ),
  114. };
  115. static unsigned char s_pColor[8][3] =
  116. {
  117. { 255, 255, 255 },
  118. { 0, 255, 255 },
  119. { 255, 0, 255 },
  120. { 255, 255, 0 },
  121. { 255, 0, 0 },
  122. { 0, 255, 0 },
  123. { 0, 0, 255 },
  124. { 0, 0, 0 },
  125. };
  126. static int s_pIndices[12][3] =
  127. {
  128. { 0, 1, 5 }, { 0, 5, 4 },
  129. { 4, 5, 7 }, { 4, 7, 6 },
  130. { 0, 4, 6 }, { 0, 6, 2 },
  131. { 0, 2, 3 }, { 0, 3, 1 },
  132. { 1, 3, 7 }, { 1, 7, 5 },
  133. { 2, 6, 7 }, { 2, 7, 3 },
  134. };
  135. for ( int i = 0; i < 8; ++i )
  136. {
  137. meshBuilder.Position3fv( s_pPositions[ i ].Base() );
  138. meshBuilder.TexCoord2fv( 0, s_pTexCoords[ i ].Base() );
  139. // meshBuilder.TexCoord2f( 1, i, 0.0f );
  140. meshBuilder.Color3ubv( s_pColor[ i ] );
  141. meshBuilder.AdvanceVertex();
  142. }
  143. for ( int i = 0; i < 12; ++i )
  144. {
  145. meshBuilder.FastIndex( s_pIndices[i][0] );
  146. meshBuilder.FastIndex( s_pIndices[i][1] );
  147. meshBuilder.FastIndex( s_pIndices[i][2] );
  148. }
  149. meshBuilder.End();
  150. }
  151. void CDmeTestMesh::DestroyMesh()
  152. {
  153. if ( m_pMesh )
  154. {
  155. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  156. pRenderContext->DestroyStaticMesh( m_pMesh );
  157. m_pMesh = NULL;
  158. }
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Morph data
  162. //-----------------------------------------------------------------------------
  163. void CDmeTestMesh::LoadMorphData( const char *pMorphFile, int nVertexCount )
  164. {
  165. UnloadMorphData();
  166. IMorphData *pMorphData = CreateMorphData();
  167. m_pMorph = pMorphData->Compile( pMorphFile, m_pMaterial, nVertexCount );
  168. DestroyMorphData( pMorphData );
  169. }
  170. void CDmeTestMesh::UnloadMorphData()
  171. {
  172. if ( m_pMorph )
  173. {
  174. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  175. pRenderContext->DestroyMorph( m_pMorph );
  176. m_pMorph = NULL;
  177. }
  178. }
  179. //-----------------------------------------------------------------------------
  180. // This function gets called whenever an attribute changes
  181. //-----------------------------------------------------------------------------
  182. void CDmeTestMesh::Resolve()
  183. {
  184. CDmAttribute *pMDLFilename = GetAttribute( "mdlfilename" );
  185. if ( pMDLFilename && pMDLFilename->IsFlagSet( FATTRIB_DIRTY ) )
  186. {
  187. UnreferenceMDL();
  188. ReferenceMDL( GetValueString( "mdlfilename" ) );
  189. return;
  190. }
  191. CDmAttribute *pMorphFilename = GetAttribute( "morphfilename" );
  192. if ( pMorphFilename && pMorphFilename->IsFlagSet( FATTRIB_DIRTY ) )
  193. {
  194. CreateMesh();
  195. UnloadMorphData();
  196. LoadMorphData( GetValueString( "morphfilename" ), 8 );
  197. return;
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Loads the model matrix based on the transform
  202. //-----------------------------------------------------------------------------
  203. void CDmeTestMesh::LoadModelMatrix( CDmeTransform *pTransform )
  204. {
  205. // FIXME: Should this go into the DmeTransform node?
  206. matrix3x4_t transform;
  207. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  208. pTransform->GetTransform( transform );
  209. pRenderContext->MatrixMode( MATERIAL_MODEL );
  210. pRenderContext->LoadMatrix( transform );
  211. }
  212. //-----------------------------------------------------------------------------
  213. // A subvision mesh
  214. //-----------------------------------------------------------------------------
  215. //-----------------------------------------------------------------------------
  216. // NOTES:
  217. // The subdivision mesh is fast because it assumes a very particular ordering
  218. // and definition of the data so that it can determine all subdivided data by
  219. // inspection without any searching. Here's the layout:
  220. //
  221. // First, a face stores a list of edge indices which reference the edges
  222. // that make up the face. A face is assumed to traverse its vertices in CCW order.
  223. // We define the "relative edge index" for an edge within a face as the
  224. // order in which that edge is visited while traversing the edges in CCW order,
  225. // so 0 is the first visited edge, and 1 is the next, etc.
  226. //
  227. // First, edges are defined in a specific way. The edge is assumed to be
  228. // *directed*, starting at vertex 0 and leading toward vertex 1. Now imagine the
  229. // two faces that shared this edge and that they both traverse their edges in
  230. // a right-handed, or CCW direction. Face 0 associated with the edge, to maintain
  231. // a CCW ordering, must traverse the edge in a *reverse* direction, heading from
  232. // vertex 1 to vertex 0. Face 1 associated with the edge traverses the edge
  233. // in a forward direction, from vertex 0 to vertex 1.
  234. //
  235. // When subdivision happens, it occurs in a very specific way also. First, when
  236. // creating the new vertices, for uniform subdivision, we create a new vertex
  237. // per face, a new vertex per edge, and adjust all existing vertices. When creating
  238. // these vertices in the subdivided mesh, we first add the face midpoint vertices,
  239. // then the edge midpoint vertices, then the vertices from the un-subdivided mesh, to
  240. // the m_Vertices array of the subdivided mesh.
  241. //
  242. // Edge subdivision always works in a uniform way: For each edge in the unsubdivided
  243. // mesh, 4 edges are created from the edge midpoint, connecting to the two
  244. // face midpoint vertices and the two edge endpoints. In order to maintain the
  245. // specific ordering of the edges described above, we define the edges in the
  246. // following manner:
  247. // * Subdivided edge 0 : Starts at face 0 midpoint, ends at edge midpoint
  248. // * Subdivided edge 1 : Starts at edge midpoint, ends at face 1 midpoint
  249. // * Subdivided edge 2 : Starts at original edge's vertex 0, ends at edge midpoint
  250. // * Subdivided edge 3 : Starts at edge midpoint, ends at original edge's vertex 1
  251. //
  252. // Face subdivision *also* always works in a uniform way: For each face in the
  253. // unsubdivided mesh, N new faces are created, one for each edge in the unsubdivided
  254. // face. The faces are ordered in a very specific way:
  255. // * Subdivided face 0 : Starts at the face midpoint, goes to unsubdivided edge 0's midpoint,
  256. // winds around the edge until it hits unsubdivided edge 1's midpoint,
  257. // then heads back to the face midpoint.
  258. // * Subdivided face 1 : Starts at the face midpoint, goes to unsubdivided edge 1's midpoint,
  259. // winds around the edge until it hits unsubdivided edge 2's midpoint,
  260. // then heads back to the face midpoint.
  261. // etc.
  262. //-----------------------------------------------------------------------------
  263. struct SubdivVertex_t
  264. {
  265. Vector m_vecPosition;
  266. Vector m_vecNormal;
  267. Vector m_vecTexCoord;
  268. int m_nValence;
  269. };
  270. // NOTE: The edge is always defined such that the edge going from vertex[0] to vertex[1]
  271. // is counter-clockwise when seen from face[1] and and clockwise when seen from face[0].
  272. struct Edge_t
  273. {
  274. int m_pFace[2];
  275. int m_pRelativeEdgeIndex[2]; // Goes from 0-N always, specifies the Nth edge of the polygon it's part of for each of the two faces
  276. int m_pVertex[2];
  277. };
  278. struct Face_t
  279. {
  280. int m_nFirstEdgeIndex;
  281. int m_nEdgeCount;
  282. // Stores the index of the first face in the subdivided mesh
  283. // isn't actually a part of the mesh data, but I'm storing it here to reduce number of allocations to make
  284. mutable int m_nFirstSubdividedFace;
  285. };
  286. struct SubdivMesh_t
  287. {
  288. CUtlVector<SubdivVertex_t> m_Vertices;
  289. CUtlVector<Edge_t> m_Edges;
  290. // Positive values mean read from m_Edges[x], use m_pVertex[0] for leading vertex
  291. // Negative values mean read from m_Edges[-1-x], use m_pVertex[1] for leading vertex
  292. CUtlVector<int> m_EdgeIndices;
  293. CUtlVector<Face_t> m_Faces;
  294. int m_nTotalIndexCount;
  295. int m_nTotalLineCount;
  296. };
  297. //-----------------------------------------------------------------------------
  298. // Clears a mesh
  299. //-----------------------------------------------------------------------------
  300. static void ClearMesh( SubdivMesh_t &dest )
  301. {
  302. dest.m_Vertices.RemoveAll();
  303. dest.m_Edges.RemoveAll();
  304. dest.m_EdgeIndices.RemoveAll();
  305. dest.m_Faces.RemoveAll();
  306. dest.m_nTotalIndexCount = 0;
  307. dest.m_nTotalLineCount = 0;
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Gets the leading vertex of an edge
  311. //-----------------------------------------------------------------------------
  312. static inline int GetLeadingEdgeVertexIndex( const SubdivMesh_t &src, int nEdge )
  313. {
  314. if ( nEdge >= 0 )
  315. {
  316. const Edge_t &edge = src.m_Edges[nEdge];
  317. return edge.m_pVertex[0];
  318. }
  319. const Edge_t &edge = src.m_Edges[ -1 - nEdge ];
  320. return edge.m_pVertex[1];
  321. }
  322. static inline const SubdivVertex_t &GetLeadingEdgeVertex( const SubdivMesh_t &src, int nEdge )
  323. {
  324. return src.m_Vertices[ GetLeadingEdgeVertexIndex( src, nEdge ) ];
  325. }
  326. //-----------------------------------------------------------------------------
  327. // Adds face midpoints to a mesh
  328. //-----------------------------------------------------------------------------
  329. static void AddFaceMidpointsToMesh( const SubdivMesh_t &src, SubdivMesh_t &dest )
  330. {
  331. int nCurrSubdividedFace = 0;
  332. int nSrcFaceCount = src.m_Faces.Count();
  333. for ( int i = 0; i < nSrcFaceCount; ++i )
  334. {
  335. int nEdgeCount = src.m_Faces[i].m_nEdgeCount;
  336. int nEdgeIndex = src.m_Faces[i].m_nFirstEdgeIndex;
  337. Assert( nEdgeCount != 0 );
  338. int v = dest.m_Vertices.AddToTail( );
  339. SubdivVertex_t &vert = dest.m_Vertices[v];
  340. vert.m_vecPosition.Init();
  341. vert.m_vecTexCoord.Init();
  342. vert.m_nValence = nEdgeCount;
  343. for ( int j = 0; j < nEdgeCount; ++j, ++nEdgeIndex )
  344. {
  345. // NOTE: Instead of calling GetLeadingEdgeVertex,
  346. // I could add both vertices for each edge + multiply by 0.5
  347. int nEdge = src.m_EdgeIndices[nEdgeIndex];
  348. const SubdivVertex_t &srcVert = GetLeadingEdgeVertex( src, nEdge );
  349. vert.m_vecPosition += srcVert.m_vecPosition;
  350. vert.m_vecTexCoord += srcVert.m_vecTexCoord;
  351. }
  352. vert.m_vecPosition /= nEdgeCount;
  353. vert.m_vecTexCoord /= nEdgeCount;
  354. // Store off the face index in the dest mesh of the first subdivided face for this guy.
  355. src.m_Faces[i].m_nFirstSubdividedFace = nCurrSubdividedFace;
  356. nCurrSubdividedFace += nEdgeCount;
  357. }
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Adds edge midpoints to a mesh
  361. //-----------------------------------------------------------------------------
  362. static void AddEdgeMidpointsToMesh( const SubdivMesh_t &src, SubdivMesh_t &dest )
  363. {
  364. int nSrcEdgeCount = src.m_Edges.Count();
  365. for ( int i = 0; i < nSrcEdgeCount; ++i )
  366. {
  367. const Edge_t &edge = src.m_Edges[i];
  368. int v = dest.m_Vertices.AddToTail( );
  369. SubdivVertex_t &vert = dest.m_Vertices[v];
  370. vert.m_nValence = 4;
  371. const SubdivVertex_t *pSrcVert = &src.m_Vertices[ edge.m_pVertex[0] ];
  372. vert.m_vecPosition = pSrcVert->m_vecPosition;
  373. vert.m_vecTexCoord = pSrcVert->m_vecTexCoord;
  374. pSrcVert = &src.m_Vertices[ edge.m_pVertex[1] ];
  375. vert.m_vecPosition += pSrcVert->m_vecPosition;
  376. vert.m_vecTexCoord += pSrcVert->m_vecTexCoord;
  377. // NOTE: We know that the first n vertices added to dest correspond to the src face midpoints
  378. pSrcVert = &dest.m_Vertices[ edge.m_pFace[0] ];
  379. vert.m_vecPosition += pSrcVert->m_vecPosition;
  380. vert.m_vecTexCoord += pSrcVert->m_vecTexCoord;
  381. pSrcVert = &dest.m_Vertices[ edge.m_pFace[1] ];
  382. vert.m_vecPosition += pSrcVert->m_vecPosition;
  383. vert.m_vecTexCoord += pSrcVert->m_vecTexCoord;
  384. vert.m_vecPosition /= 4.0f;
  385. vert.m_vecTexCoord /= 4.0f;
  386. }
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Adds edge midpoints to a mesh
  390. //-----------------------------------------------------------------------------
  391. static void AddModifiedVerticesToMesh( const SubdivMesh_t &src, SubdivMesh_t &dest )
  392. {
  393. int nSrcVertexCount = src.m_Vertices.Count();
  394. // This computes the equation v(i+1) = ((N-2)/N) * v(i) + (1/N^2) * sum( ei + fi )
  395. int nFirstDestVertex = dest.m_Vertices.Count();
  396. for ( int i = 0; i < nSrcVertexCount; ++i )
  397. {
  398. int v = dest.m_Vertices.AddToTail( );
  399. SubdivVertex_t &vert = dest.m_Vertices[v];
  400. int nValence = src.m_Vertices[i].m_nValence;
  401. vert.m_nValence = nValence;
  402. float flScale = (float)(nValence - 2) / nValence;
  403. VectorScale( src.m_Vertices[i].m_vecPosition, flScale, vert.m_vecPosition );
  404. VectorScale( src.m_Vertices[i].m_vecTexCoord, flScale, vert.m_vecTexCoord );
  405. }
  406. int nSrcEdgeCount = src.m_Edges.Count();
  407. for ( int i = 0; i < nSrcEdgeCount; ++i )
  408. {
  409. const Edge_t &edge = src.m_Edges[i];
  410. for ( int j = 0; j < 2; ++j )
  411. {
  412. int nDestVertIndex = nFirstDestVertex + edge.m_pVertex[j];
  413. SubdivVertex_t &destVertex = dest.m_Vertices[nDestVertIndex];
  414. float ooValenceSq = 1.0f / destVertex.m_nValence;
  415. ooValenceSq *= ooValenceSq;
  416. // This adds in the contribution from the source vertex at the opposite edge
  417. const SubdivVertex_t &srcOtherVert = src.m_Vertices[ edge.m_pVertex[ 1 - j ] ];
  418. VectorMA( destVertex.m_vecPosition, ooValenceSq, srcOtherVert.m_vecPosition, destVertex.m_vecPosition );
  419. VectorMA( destVertex.m_vecTexCoord, ooValenceSq, srcOtherVert.m_vecTexCoord, destVertex.m_vecTexCoord );
  420. // This adds in the contribution from the two faces it's part of
  421. // NOTE: Usage of dest here is correct; this grabs the vertex that
  422. // was created that was in the middle of the source mesh's face
  423. const SubdivVertex_t *pSrcFace = &dest.m_Vertices[ edge.m_pFace[ 0 ] ];
  424. VectorMA( destVertex.m_vecPosition, 0.5f * ooValenceSq, pSrcFace->m_vecPosition, destVertex.m_vecPosition );
  425. VectorMA( destVertex.m_vecTexCoord, 0.5f * ooValenceSq, pSrcFace->m_vecTexCoord, destVertex.m_vecTexCoord );
  426. pSrcFace = &dest.m_Vertices[ edge.m_pFace[ 1 ] ];
  427. VectorMA( destVertex.m_vecPosition, 0.5f * ooValenceSq, pSrcFace->m_vecPosition, destVertex.m_vecPosition );
  428. VectorMA( destVertex.m_vecTexCoord, 0.5f * ooValenceSq, pSrcFace->m_vecTexCoord, destVertex.m_vecTexCoord );
  429. }
  430. }
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Adds unique subdivided edges so they aren't repeated.
  434. //-----------------------------------------------------------------------------
  435. static void AddSubdividedEdges( const SubdivMesh_t &src, SubdivMesh_t &dest )
  436. {
  437. // NOTE: We iterate over each edge in sequence and add edges
  438. // between face 0, then face 1, then vertex 0, then vertex 1.
  439. // The vertex index for the vert at the center of original face N is N.
  440. // The vertex index for the vert at the center of original edge N is nSrcFaceCount + N;
  441. // The vertex index for the vert at original vertex N is nSrcFaceCount + nSrcEdgeCount + N;
  442. int nSrcFaceCount = src.m_Faces.Count();
  443. int nSrcEdgeCount = src.m_Edges.Count();
  444. for ( int i = 0; i < nSrcEdgeCount; ++i )
  445. {
  446. const Edge_t &srcEdge = src.m_Edges[i];
  447. int e = dest.m_Edges.AddMultipleToTail( 4 );
  448. Edge_t *pDstEdge = &dest.m_Edges[e];
  449. // Grab the two source faces
  450. const Face_t *pFaces[2];
  451. pFaces[0] = &src.m_Faces[ srcEdge.m_pFace[0] ];
  452. pFaces[1] = &src.m_Faces[ srcEdge.m_pFace[1] ];
  453. // Get the first subdivided face index + relative edge index
  454. int pSubdividedFaceIndex[2];
  455. pSubdividedFaceIndex[0] = pFaces[0]->m_nFirstSubdividedFace;
  456. pSubdividedFaceIndex[1] = pFaces[1]->m_nFirstSubdividedFace;
  457. // Get the relative edge index
  458. int pRelativeEdgeIndex[2];
  459. pRelativeEdgeIndex[0] = srcEdge.m_pRelativeEdgeIndex[0];
  460. pRelativeEdgeIndex[1] = srcEdge.m_pRelativeEdgeIndex[1];
  461. int pPrevRelativeEdgeIndex[2];
  462. pPrevRelativeEdgeIndex[0] = (srcEdge.m_pRelativeEdgeIndex[0] - 1);
  463. if ( pPrevRelativeEdgeIndex[0] < 0 )
  464. {
  465. pPrevRelativeEdgeIndex[0] = pFaces[0]->m_nEdgeCount - 1;
  466. }
  467. pPrevRelativeEdgeIndex[1] = (srcEdge.m_pRelativeEdgeIndex[1] - 1);
  468. if ( pPrevRelativeEdgeIndex[1] < 0 )
  469. {
  470. pPrevRelativeEdgeIndex[1] = pFaces[1]->m_nEdgeCount - 1;
  471. }
  472. // This ordering maintains clockwise order
  473. pDstEdge[0].m_pVertex[0] = srcEdge.m_pFace[0];
  474. pDstEdge[0].m_pVertex[1] = nSrcFaceCount + i;
  475. pDstEdge[0].m_pFace[0] = pSubdividedFaceIndex[0] + pPrevRelativeEdgeIndex[0];
  476. pDstEdge[0].m_pFace[1] = pSubdividedFaceIndex[0] + pRelativeEdgeIndex[0];
  477. pDstEdge[0].m_pRelativeEdgeIndex[0] = 3;
  478. pDstEdge[0].m_pRelativeEdgeIndex[1] = 0;
  479. pDstEdge[1].m_pVertex[0] = nSrcFaceCount + i;
  480. pDstEdge[1].m_pVertex[1] = srcEdge.m_pFace[1];
  481. pDstEdge[1].m_pFace[0] = pSubdividedFaceIndex[1] + pRelativeEdgeIndex[1];
  482. pDstEdge[1].m_pFace[1] = pSubdividedFaceIndex[1] + pPrevRelativeEdgeIndex[1];
  483. pDstEdge[1].m_pRelativeEdgeIndex[0] = 0;
  484. pDstEdge[1].m_pRelativeEdgeIndex[1] = 3;
  485. pDstEdge[2].m_pVertex[0] = nSrcFaceCount + nSrcEdgeCount + srcEdge.m_pVertex[0];
  486. pDstEdge[2].m_pVertex[1] = nSrcFaceCount + i;
  487. pDstEdge[2].m_pFace[0] = pSubdividedFaceIndex[0] + pRelativeEdgeIndex[0];
  488. pDstEdge[2].m_pFace[1] = pSubdividedFaceIndex[1] + pPrevRelativeEdgeIndex[1];
  489. pDstEdge[2].m_pRelativeEdgeIndex[0] = 1;
  490. pDstEdge[2].m_pRelativeEdgeIndex[1] = 2;
  491. pDstEdge[3].m_pVertex[0] = nSrcFaceCount + i;
  492. pDstEdge[3].m_pVertex[1] = nSrcFaceCount + nSrcEdgeCount + srcEdge.m_pVertex[1];
  493. pDstEdge[3].m_pFace[0] = pSubdividedFaceIndex[0] + pPrevRelativeEdgeIndex[0];
  494. pDstEdge[3].m_pFace[1] = pSubdividedFaceIndex[1] + pRelativeEdgeIndex[1];
  495. pDstEdge[3].m_pRelativeEdgeIndex[0] = 2;
  496. pDstEdge[3].m_pRelativeEdgeIndex[1] = 1;
  497. }
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Adds unique subdivided faces
  501. //-----------------------------------------------------------------------------
  502. static void AddSubdividedFaces( const SubdivMesh_t &src, SubdivMesh_t &dest )
  503. {
  504. dest.m_nTotalIndexCount = 0;
  505. dest.m_nTotalLineCount = 0;
  506. int nSrcFaceCount = src.m_Faces.Count();
  507. for ( int i = 0; i < nSrcFaceCount; ++i )
  508. {
  509. int nEdgeCount = src.m_Faces[i].m_nEdgeCount;
  510. const int *pSrcEdgeIndex = &src.m_EdgeIndices[ src.m_Faces[i].m_nFirstEdgeIndex ];
  511. int ei = dest.m_EdgeIndices.AddMultipleToTail( nEdgeCount * 4 );
  512. int *pDestEdgeIndex = &dest.m_EdgeIndices[ ei ];
  513. int *pPrevDestEdgeIndex = &pDestEdgeIndex[(nEdgeCount - 1) * 4];
  514. for ( int j = 0; j < nEdgeCount; ++j )
  515. {
  516. // Add another quad.
  517. dest.m_nTotalIndexCount += 6;
  518. dest.m_nTotalLineCount += 4;
  519. // Add a face for every edge. Note that subdivided face N
  520. // is the face whose goes through edge N.
  521. int f = dest.m_Faces.AddToTail();
  522. Face_t *pDestFace = &dest.m_Faces[f];
  523. pDestFace->m_nEdgeCount = 4;
  524. pDestFace->m_nFirstEdgeIndex = ei + (j * 4);
  525. // Fill it with bogus data
  526. pDestFace->m_nFirstSubdividedFace = -1;
  527. // Now add in the edge indices to refer to the edges created in AddSubdividedEdges.
  528. // Note that the new edge index == the old edge index * 4, since we always
  529. // create 4 edges for every edge in the source list.
  530. int *pCurrDestEdgeIndex = &pDestEdgeIndex[j*4];
  531. int nSrcEdgeIndex = pSrcEdgeIndex[j];
  532. if ( nSrcEdgeIndex >= 0 )
  533. {
  534. // This means this polygon is the '1' index in the edge; it's following this edge CCW.
  535. int nDestEdgeIndex = nSrcEdgeIndex * 4;
  536. pCurrDestEdgeIndex[0] = -1 - (nDestEdgeIndex + 1); // We're following this edge backwards
  537. pCurrDestEdgeIndex[1] = nDestEdgeIndex + 3;
  538. pPrevDestEdgeIndex[2] = nDestEdgeIndex + 2;
  539. pPrevDestEdgeIndex[3] = nDestEdgeIndex + 1;
  540. }
  541. else
  542. {
  543. // This means this polygon is the '0' index in the edge; it's following this edge CW.
  544. int nDestEdgeIndex = (-1 - nSrcEdgeIndex) * 4;
  545. pCurrDestEdgeIndex[0] = nDestEdgeIndex;
  546. pCurrDestEdgeIndex[1] = -1 - (nDestEdgeIndex + 2); // We're following this edge backwards
  547. pPrevDestEdgeIndex[2] = -1 - (nDestEdgeIndex + 3); // We're following this edge backwards
  548. pPrevDestEdgeIndex[3] = -1 - (nDestEdgeIndex); // We're following this edge backwards
  549. }
  550. pPrevDestEdgeIndex = pCurrDestEdgeIndex;
  551. }
  552. }
  553. }
  554. //-----------------------------------------------------------------------------
  555. // Subdivides a mesh
  556. //-----------------------------------------------------------------------------
  557. static void SubdivideMesh( const SubdivMesh_t &src, SubdivMesh_t &dest )
  558. {
  559. // Preallocate space for dest data
  560. int nSrcFaceCount = src.m_Faces.Count();
  561. int nSrcEdgeCount = src.m_Edges.Count();
  562. dest.m_Vertices.EnsureCapacity( nSrcFaceCount + nSrcEdgeCount + src.m_Vertices.Count() );
  563. dest.m_Edges.EnsureCapacity( nSrcEdgeCount * 4 );
  564. dest.m_EdgeIndices.EnsureCapacity( nSrcFaceCount * 16 );
  565. dest.m_Faces.EnsureCapacity( nSrcFaceCount * 4 ); // This is only true if we have valence 4 everywhere.
  566. // First, compute midpoints of each face, add them to the mesh
  567. AddFaceMidpointsToMesh( src, dest );
  568. // Next, for each edge, compute a new point which is the average of the edge points and the face midpoints
  569. AddEdgeMidpointsToMesh( src, dest );
  570. // Add modified versions of the vertices in the src mesh based on the new computed points and add them to the dest mesh
  571. AddModifiedVerticesToMesh( src, dest );
  572. // Add subdivided edges based on the previous edges
  573. AddSubdividedEdges( src, dest );
  574. // Add subdivided faces referencing the subdivided edges
  575. AddSubdividedFaces( src, dest );
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Creates/destroys the subdiv control cage
  579. //-----------------------------------------------------------------------------
  580. void CDmeTestMesh::CreateControlCage( )
  581. {
  582. DestroyControlCage();
  583. m_pControlCage = new SubdivMesh_t;
  584. // Draw a simple cube
  585. static Vector s_pPositions[8] =
  586. {
  587. Vector( -30, -30, -30 ),
  588. Vector( 30, -30, -30 ),
  589. Vector( -30, 30, -30 ),
  590. Vector( 30, 30, -30 ),
  591. Vector( -30, -30, 30 ),
  592. Vector( 30, -30, 30 ),
  593. Vector( -30, 30, 30 ),
  594. Vector( 30, 30, 30 ),
  595. };
  596. static Vector2D s_pTexCoords[8] =
  597. {
  598. Vector2D( 0, 0 ),
  599. Vector2D( 0.5, 0 ),
  600. Vector2D( 0, 0.5 ),
  601. Vector2D( 0.5, 0.5 ),
  602. Vector2D( 0.5, 0.5 ),
  603. Vector2D( 1, 0.5 ),
  604. Vector2D( 0.5, 1 ),
  605. Vector2D( 1, 1 ),
  606. };
  607. // Indices into the vertex array
  608. static int s_pEdges[12][2] =
  609. {
  610. { 0, 4 }, { 4, 6 }, { 6, 2 }, { 2, 0 }, // 0 -> -x
  611. { 1, 3 }, { 3, 7 }, { 7, 5 }, { 5, 1 }, // 1 -> +x
  612. { 0, 1 }, { 5, 4 }, // 2 -> -y
  613. { 6, 7 }, { 3, 2 }, // 3 -> +y
  614. // 4 -> -z
  615. // 5 -> +z
  616. };
  617. // Indices into the face array associated w/ the edges above
  618. static int s_pEdgeFaces[12][2] =
  619. {
  620. { 2, 0 }, { 5, 0 }, { 3, 0 }, { 4, 0 }, // 0 -> -x
  621. { 4, 1 }, { 3, 1 }, { 5, 1 }, { 2, 1 }, // 1 -> +x
  622. { 4, 2 }, { 5, 2 }, // 2 -> -y
  623. { 5, 3 }, { 4, 3 }, // 3 -> +y
  624. // 4 -> -z
  625. // 5 -> +z
  626. };
  627. // In what order does edge s_pEdges[i] appear on faces s_pEdgeFaces[i][0] and s_pEdgeFaces[i][1]
  628. // in the list s_pIndices[s_pEdgeFaces[i][j]] below? Note the #s 0, 1, 2, and 3 should appear 6 times each in this array
  629. // representing the fact that each face has a 0th,1st,2nd, and 3rd edge.
  630. static int s_pRelativeEdgeIndex[12][2] =
  631. {
  632. { 3, 0 }, { 3, 1 }, { 0, 2 }, { 0, 3 }, // 0 -> -x
  633. { 2, 0 }, { 2, 1 }, { 1, 2 }, { 1, 3 }, // 1 -> +x
  634. { 3, 0 }, { 0, 2 }, // 2 -> -y
  635. { 2, 1 }, { 1, 3 }, // 3 -> +y
  636. // 4 -> -z
  637. // 5 -> +z
  638. };
  639. static int s_pIndices[6][5] =
  640. {
  641. { 0, 4, 6, 2, 0 }, // 0 -> -x
  642. { 1, 3, 7, 5, 1 }, // 1 -> +x
  643. { 0, 1, 5, 4, 0 }, // 2 -> -y
  644. { 2, 6, 7, 3, 2 }, // 3 -> +y
  645. { 0, 2, 3, 1, 0 }, // 4 -> -z
  646. { 4, 5, 7, 6, 4 }, // 5 -> +z
  647. };
  648. // Add vertices
  649. int i;
  650. for ( i = 0; i < 8; ++i )
  651. {
  652. int v = m_pControlCage->m_Vertices.AddToTail();
  653. SubdivVertex_t &vert = m_pControlCage->m_Vertices[v];
  654. vert.m_vecPosition = s_pPositions[i];
  655. vert.m_vecNormal = vec3_origin;
  656. vert.m_vecTexCoord.AsVector2D() = s_pTexCoords[i];
  657. vert.m_nValence = 3;
  658. }
  659. // Add unique edges
  660. for ( i = 0; i < 12; ++i )
  661. {
  662. int e = m_pControlCage->m_Edges.AddToTail();
  663. Edge_t &edge = m_pControlCage->m_Edges[e];
  664. edge.m_pVertex[0] = s_pEdges[i][0];
  665. edge.m_pVertex[1] = s_pEdges[i][1];
  666. edge.m_pFace[0] = s_pEdgeFaces[i][0];
  667. edge.m_pFace[1] = s_pEdgeFaces[i][1];
  668. edge.m_pRelativeEdgeIndex[0] = s_pRelativeEdgeIndex[i][0];
  669. edge.m_pRelativeEdgeIndex[1] = s_pRelativeEdgeIndex[i][1];
  670. }
  671. m_pControlCage->m_nTotalIndexCount = 0;
  672. m_pControlCage->m_nTotalLineCount = 0;
  673. for ( i = 0; i < 6; ++i )
  674. {
  675. int f = m_pControlCage->m_Faces.AddToTail();
  676. Face_t &face = m_pControlCage->m_Faces[f];
  677. face.m_nFirstEdgeIndex = m_pControlCage->m_EdgeIndices.Count();
  678. face.m_nEdgeCount = 4;
  679. // Place an invalid value here
  680. face.m_nFirstSubdividedFace = -1;
  681. // Two triangles per quad
  682. m_pControlCage->m_nTotalIndexCount += 6;
  683. m_pControlCage->m_nTotalLineCount += 4;
  684. for ( int j = 0; j < 4; ++j )
  685. {
  686. int k;
  687. for ( k = 0; k < 12; ++k )
  688. {
  689. if ( (s_pIndices[i][j] == s_pEdges[k][0]) && (s_pIndices[i][j+1] == s_pEdges[k][1]) )
  690. {
  691. m_pControlCage->m_EdgeIndices.AddToTail( k );
  692. break;
  693. }
  694. if ( (s_pIndices[i][j] == s_pEdges[k][1]) && (s_pIndices[i][j+1] == s_pEdges[k][0]) )
  695. {
  696. m_pControlCage->m_EdgeIndices.AddToTail( -1-k );
  697. break;
  698. }
  699. }
  700. Assert( k != 12 );
  701. }
  702. }
  703. }
  704. void CDmeTestMesh::DestroyControlCage( )
  705. {
  706. if ( m_pControlCage )
  707. {
  708. delete m_pControlCage;
  709. m_pControlCage = NULL;
  710. }
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Draws a subdiv mesh
  714. //-----------------------------------------------------------------------------
  715. void CDmeTestMesh::DrawSubdivMesh( const SubdivMesh_t &mesh )
  716. {
  717. if ( !g_pMaterialSystem )
  718. return;
  719. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  720. IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( "debug/debugwireframe", NULL, false );
  721. pRenderContext->Bind( pMaterial );
  722. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  723. CMeshBuilder meshBuilder;
  724. int nVertexCount = mesh.m_Vertices.Count();
  725. // meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertexCount, mesh.m_nTotalIndexCount );
  726. meshBuilder.Begin( pMesh, MATERIAL_LINES, nVertexCount, mesh.m_nTotalLineCount * 2 );
  727. for ( int i = 0; i < nVertexCount; ++i )
  728. {
  729. meshBuilder.Position3fv( mesh.m_Vertices[ i ].m_vecPosition.Base() );
  730. meshBuilder.TexCoord2fv( 0, mesh.m_Vertices[ i ].m_vecTexCoord.Base() );
  731. meshBuilder.TexCoord2f( 1, i, 0.0f );
  732. meshBuilder.Color3ub( 255, 255, 255 );
  733. meshBuilder.AdvanceVertex();
  734. }
  735. int nFaceCount = mesh.m_Faces.Count();
  736. for ( int i = 0; i < nFaceCount; ++i )
  737. {
  738. int nEdgeCount = mesh.m_Faces[i].m_nEdgeCount;
  739. const int *pEdgeIndex = &mesh.m_EdgeIndices[ mesh.m_Faces[i].m_nFirstEdgeIndex ];
  740. int nPrevIndex = GetLeadingEdgeVertexIndex( mesh, pEdgeIndex[nEdgeCount-1] );
  741. for ( int j = 0; j < nEdgeCount; ++j )
  742. {
  743. int nCurrIndex = GetLeadingEdgeVertexIndex( mesh, pEdgeIndex[j] );
  744. meshBuilder.FastIndex( nPrevIndex );
  745. meshBuilder.FastIndex( nCurrIndex );
  746. nPrevIndex = nCurrIndex;
  747. }
  748. }
  749. /*
  750. int nFaceCount = mesh.m_Faces.Count();
  751. for ( int i = 0; i < nFaceCount; ++i )
  752. {
  753. int nEdgeCount = mesh.m_Faces[i].m_nEdgeCount;
  754. const int *pEdgeIndex = &mesh.m_EdgeIndices[ mesh.m_Faces[i].m_nFirstEdgeIndex ];
  755. int nRootIndex = GetLeadingEdgeVertexIndex( mesh, pEdgeIndex[0] );
  756. int nPrevIndex = GetLeadingEdgeVertexIndex( mesh, pEdgeIndex[1] );
  757. for ( int j = 0; j < nEdgeCount - 2; ++j )
  758. {
  759. int nCurrIndex = GetLeadingEdgeVertexIndex( mesh, pEdgeIndex[j+2] );
  760. meshBuilder.FastIndex( nRootIndex );
  761. meshBuilder.FastIndex( nPrevIndex );
  762. meshBuilder.FastIndex( nCurrIndex );
  763. nPrevIndex = nCurrIndex;
  764. }
  765. }
  766. */
  767. meshBuilder.End();
  768. pMesh->Draw();
  769. }
  770. //-----------------------------------------------------------------------------
  771. // Draws a subdivided box
  772. //-----------------------------------------------------------------------------
  773. void CDmeTestMesh::DrawSubdividedBox()
  774. {
  775. if ( !g_pMaterialSystem )
  776. return;
  777. if ( !m_pControlCage )
  778. {
  779. CreateControlCage( );
  780. }
  781. int nSubdivLevel = GetValue<int>( "subdivlevel" );
  782. if ( nSubdivLevel == 0 )
  783. {
  784. DrawSubdivMesh( *m_pControlCage );
  785. return;
  786. }
  787. // Construct the initial mesh
  788. SubdivMesh_t subdivMesh[2];
  789. SubdivideMesh( *m_pControlCage, subdivMesh[0] );
  790. // Compute the subdivided vertices
  791. int nCurrMesh = 0;
  792. while ( --nSubdivLevel > 0 )
  793. {
  794. ClearMesh( subdivMesh[1 - nCurrMesh] );
  795. SubdivideMesh( subdivMesh[nCurrMesh], subdivMesh[1 - nCurrMesh] );
  796. if (( subdivMesh[1 - nCurrMesh].m_nTotalLineCount * 2 >= 32768 ) || ( subdivMesh[1 - nCurrMesh].m_Vertices.Count() >= 32768 ))
  797. break;
  798. nCurrMesh = 1 - nCurrMesh;
  799. }
  800. // Draw the subdivided mesh
  801. DrawSubdivMesh( subdivMesh[nCurrMesh] );
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Draws the mesh
  805. //-----------------------------------------------------------------------------
  806. void CDmeTestMesh::DrawBox( CDmeTransform *pTransform )
  807. {
  808. if ( !g_pMaterialSystem )
  809. return;
  810. // FIXME: Hack!
  811. if ( !m_pMorph || !m_pMesh )
  812. return;
  813. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  814. // Set up morph factors
  815. float pMorphFactors[32];
  816. for ( int i = 0; i < 32; ++i )
  817. {
  818. pMorphFactors[i] = 0.5f + 0.5f * sin( 2 * 3.14 * ( Plat_FloatTime() / 5.0f + (float)i / 32.0f ) );
  819. }
  820. pMorphFactors[1] = 1.0f - pMorphFactors[0];
  821. pRenderContext->SetMorphTargetFactors( 0, pMorphFactors, 32 );
  822. // FIXME: Should this call be made from the application rendering the mesh?
  823. LoadModelMatrix( pTransform );
  824. pRenderContext->BindMorph( m_pMorph );
  825. pRenderContext->Bind( m_pMaterial );
  826. m_pMesh->Draw();
  827. pRenderContext->BindMorph( NULL );
  828. }
  829. //-----------------------------------------------------------------------------
  830. // Draws the mesh
  831. //-----------------------------------------------------------------------------
  832. void CDmeTestMesh::Draw( const matrix3x4_t& shapeToWorld, CDmeDrawSettings *pDrawSettings )
  833. {
  834. if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
  835. return;
  836. #if 0
  837. // DrawSubdividedBox( pTransform );
  838. DrawBox( pTransform );
  839. return;
  840. #elif 0
  841. if ( m_MDLHandle == MDLHANDLE_INVALID )
  842. return;
  843. // Color + alpha modulation
  844. Vector white(1.0f, 1.0f, 1.0f);
  845. g_pStudioRender->SetColorModulation( white.Base() );
  846. g_pStudioRender->SetAlphaModulation( 1.0f );
  847. DrawModelInfo_t info;
  848. info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  849. info.m_pHardwareData = g_pMDLCache->GetHardwareData( m_MDLHandle );
  850. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  851. info.m_Skin = GetAttributeValueInt( "skin" );
  852. info.m_Body = GetAttributeValueInt( "body" );
  853. info.m_HitboxSet = 0;
  854. info.m_pClientEntity = NULL;
  855. info.m_ppColorMeshes = NULL;
  856. info.m_bStaticLighting = false;
  857. info.m_Lod = GetAttributeValueInt( "lod" );
  858. // FIXME: Deal with lighting
  859. for ( int i = 0; i < 6; ++ i )
  860. {
  861. info.m_vecAmbientCube[i].Init( 1, 1, 1 );
  862. }
  863. info.m_nLocalLightCount = 0;
  864. // info.m_LocalLightDescs;
  865. matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( info.m_pStudioHdr->numbones );
  866. SetUpBones( pTransform, info.m_pStudioHdr->numbones, pBoneToWorld );
  867. g_pStudioRender->UnlockBoneMatrices();
  868. // Root transform
  869. matrix3x4_t rootToWorld;
  870. pTransform->GetTransform( rootToWorld );
  871. Vector vecModelOrigin;
  872. MatrixGetColumn( rootToWorld, 3, vecModelOrigin );
  873. g_pStudioRender->DrawModel( NULL, info, pBoneToWorld, vecModelOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL );
  874. #else
  875. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  876. #if 1
  877. matrix3x4_t mat;
  878. if ( m_bones.size() == 1 )
  879. {
  880. pRenderContext->MatrixMode( MATERIAL_MODEL );
  881. m_bones[0]->GetTransform( mat );
  882. pRenderContext->LoadMatrix( mat );
  883. // pRenderContext->LoadMatrix( m_bones[0] ); // m_PoseToWorld[0]
  884. }
  885. pRenderContext->SetNumBoneWeights( 2 ); // pStrip->numBones
  886. uint bn = m_bones.size();
  887. for ( uint bi = 0; bi < bn; ++bi )
  888. {
  889. m_bones[bi]->GetTransform( mat );
  890. #if 0 // hack to see whether bones are actually affecting the model
  891. float f = 100.0f;
  892. Vector translation;
  893. MatrixGetColumn( mat, 3, &translation );
  894. translation.x += (bi&1) ? f : -f;
  895. translation.y += (bi&2) ? f : -f;
  896. translation.z += (bi&4) ? f : -f;
  897. MatrixSetColumn( translation, 3, mat );
  898. #endif
  899. pRenderContext->LoadBoneMatrix( bi, mat );
  900. }
  901. #else
  902. pRenderContext->MatrixMode( MATERIAL_MODEL );
  903. matrix3x4_t mat;
  904. Assert( !m_bones.empty() );
  905. m_bones[0]->GetTransform( mat );
  906. pRenderContext->LoadMatrix( mat );
  907. #endif
  908. IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( "Models/shadertest/unlitgenericmodel", NULL, false );
  909. // IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( "debug/debugwireframevertexcolor", NULL, false );
  910. // IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( "debug/debugwireframe", NULL, false );
  911. pRenderContext->Bind( pMaterial );
  912. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  913. int mn = m_submeshes.size();
  914. for ( int mi = 0; mi < mn; ++mi )
  915. {
  916. CMeshBuilder meshBuilder;
  917. std::vector< int > &indices = m_submeshes[mi]->indices;
  918. std::vector< vertex_t > &vertices = m_submeshes[mi]->vertices;
  919. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertices.size(), indices.size() );
  920. int vn = vertices.size();
  921. for ( int vi = 0; vi < vn; ++vi )
  922. {
  923. vertex_t &vertex = vertices[vi];
  924. meshBuilder.Position3fv( vertex.coord.Base() );
  925. meshBuilder.Normal3fv ( vertex.normal.Base() );
  926. meshBuilder.TexCoord2fv( 0, vertex.texcoord.Base() );
  927. switch ( vertex.skinning[0].index )
  928. {
  929. case 0: meshBuilder.Color3f(1,0,0); break;
  930. case 1: meshBuilder.Color3f(0,1,0); break;
  931. case 2: meshBuilder.Color3f(0,0,1); break;
  932. case 3: meshBuilder.Color3f(1,1,0); break;
  933. case 4: meshBuilder.Color3f(0,1,1); break;
  934. case 5: meshBuilder.Color3f(1,0,1); break;
  935. case 6: meshBuilder.Color3f(0,0,0); break;
  936. case 7: meshBuilder.Color3f(1,1,1); break;
  937. default: meshBuilder.Color3f(0.5f,0.5f,0.5f); break;
  938. }
  939. int bn = vertex.skinning.size();
  940. for ( int bi = 0; bi < bn; ++bi )
  941. {
  942. meshBuilder.BoneMatrix( bi, vertex.skinning[bi].index );
  943. meshBuilder.BoneWeight( bi, vertex.skinning[bi].weight );
  944. }
  945. meshBuilder.AdvanceVertex();
  946. }
  947. int in = indices.size();
  948. for ( int ii = 0; ii < in; ++ii )
  949. {
  950. meshBuilder.FastIndex( indices[ii] );
  951. }
  952. meshBuilder.End();
  953. pMesh->Draw();
  954. }
  955. #endif
  956. }
  957. //-----------------------------------------------------------------------------
  958. // Returns a mask indicating which bones to set up
  959. //-----------------------------------------------------------------------------
  960. int CDmeTestMesh::BoneMask( void )
  961. {
  962. int nLod = GetValue<int>( "lod" );
  963. return BONE_USED_BY_VERTEX_AT_LOD( nLod );
  964. }
  965. void CDmeTestMesh::SetUpBones( CDmeTransform *pTransform, int nMaxBoneCount, matrix3x4_t *pBoneToWorld )
  966. {
  967. // Default to middle of the pose parameter range
  968. float pPoseParameter[MAXSTUDIOPOSEPARAM];
  969. for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
  970. {
  971. pPoseParameter[i] = 0.5f;
  972. }
  973. CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_MDLHandle ), g_pMDLCache );
  974. int nSequence = GetValue<int>( "sequence" );
  975. float flPlaybackRate = GetValue<float>( "playbackrate" );
  976. float flTime = GetValue<float>( "time" );
  977. int nFrameCount = Studio_MaxFrame( &studioHdr, nSequence, pPoseParameter );
  978. if ( nFrameCount == 0 )
  979. {
  980. nFrameCount = 1;
  981. }
  982. float flCycle = ( flTime * flPlaybackRate ) / nFrameCount;
  983. // FIXME: We're always wrapping; may want to determing if we should clamp
  984. flCycle -= (int)(flCycle);
  985. Vector pos[MAXSTUDIOBONES];
  986. Quaternion q[MAXSTUDIOBONES];
  987. IBoneSetup boneSetup( &studioHdr, BoneMask(), pPoseParameter );
  988. boneSetup.InitPose( pos, q );
  989. boneSetup.AccumulatePose( pos, q, nSequence, flCycle, 1.0f, flTime, NULL );
  990. // FIXME: Try enabling this?
  991. // CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BoneMask( ), flTime );
  992. // Root transform
  993. matrix3x4_t rootToWorld;
  994. pTransform->GetTransform( rootToWorld );
  995. if ( studioHdr.numBones() < nMaxBoneCount )
  996. {
  997. nMaxBoneCount = studioHdr.numBones();
  998. }
  999. for ( int i = 0; i < nMaxBoneCount; i++ )
  1000. {
  1001. // If it's not being used, fill with NAN for errors
  1002. #ifdef _DEBUG
  1003. if ( !(studioHdr.pBone( i )->flags & BoneMask()))
  1004. {
  1005. int j, k;
  1006. for (j = 0; j < 3; j++)
  1007. {
  1008. for (k = 0; k < 4; k++)
  1009. {
  1010. pBoneToWorld[i][j][k] = VEC_T_NAN;
  1011. }
  1012. }
  1013. continue;
  1014. }
  1015. #endif
  1016. matrix3x4_t boneMatrix;
  1017. QuaternionMatrix( q[i], boneMatrix );
  1018. MatrixSetColumn( pos[i], 3, boneMatrix );
  1019. if (studioHdr.pBone(i)->parent == -1)
  1020. {
  1021. ConcatTransforms (rootToWorld, boneMatrix, pBoneToWorld[ i ]);
  1022. }
  1023. else
  1024. {
  1025. ConcatTransforms ( pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[ i ] );
  1026. }
  1027. }
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // FIXME: This trashy glue code is really not acceptable. Figure out a way of making it unnecessary.
  1031. //-----------------------------------------------------------------------------
  1032. const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName ) const
  1033. {
  1034. MDLHandle_t handle = g_pMDLCache->FindMDL( pModelName );
  1035. *cache = (void*)handle;
  1036. return g_pMDLCache->GetStudioHdr( handle );
  1037. }
  1038. virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const
  1039. {
  1040. return g_pMDLCache->GetVirtualModel( (MDLHandle_t)virtualModel );
  1041. }
  1042. byte *studiohdr_t::GetAnimBlock( int i ) const
  1043. {
  1044. return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i );
  1045. }
  1046. int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const
  1047. {
  1048. return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut );
  1049. }
  1050. const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const
  1051. {
  1052. return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache );
  1053. }
  1054. //-----------------------------------------------------------------------------
  1055. // First attempt at making a hacky SMD loader - clean this up later
  1056. //-----------------------------------------------------------------------------
  1057. //-----------------------------------------------------------------------------
  1058. // SMD format:
  1059. //
  1060. // format key:
  1061. // #n = integer
  1062. // .x = float
  1063. // 'a' = literal string
  1064. // $s = string
  1065. // " = the literal quote character
  1066. // // = comment - not in file!!!
  1067. //
  1068. // 'version' #version // right now, #version = 1
  1069. //
  1070. // 'nodes' // bone naming and hierarchy
  1071. // #bone "$bonename" #parent // one of these per bone - can be in any order, but generally sequential
  1072. // 'end'
  1073. //
  1074. // 'skeleton' // joint animation (and begin pose)
  1075. // 'time' #time // repeat time + joints block once per frame
  1076. // #bone .x .y .z .rx .ry .rz // bone/translation/rotation - can traverse bones in any order, and even skip them
  1077. // 'end'
  1078. //
  1079. // 'triangles' // actual vertex data - as non-indexed triangle lists
  1080. // $texturefilename // repeat texture + 3 vertex lines for each triangle
  1081. // #bone .x .y .z .nx .ny .nz .tu .tv #count #bone0 .weight0 // boneN & weightN may or may not exist for N={0..511}
  1082. // #bone .x .y .z .nx .ny .nz .tu .tv #count #bone0 .weight0 // boneN & weightN may or may not exist for N={0..511}
  1083. // #bone .x .y .z .nx .ny .nz .tu .tv #count #bone0 .weight0 // boneN & weightN may or may not exist for N={0..511}
  1084. // 'end'
  1085. //
  1086. // 'vertexanimation' // morph targets
  1087. // 'time' #time // repeat time + vertices block once per vertex
  1088. // #vertex .x .y .z .nx .ny .nz // vertex/position/normal
  1089. // 'end'
  1090. //
  1091. //-----------------------------------------------------------------------------
  1092. // TODO - check out lookup_index for whether it's looking for exact vertex matches, or within a float tolerance
  1093. // DONE - lookup_index checks materiaks, coords and texcoords for exact match, and normals for within 2 degrees
  1094. const int MAXNAME = 128;
  1095. const int MAXLINE = 4096;
  1096. const int MAXCMD = 1024;
  1097. const int MAXBONEWEIGHTS = 3;
  1098. const int MAXTEXNAME = 64;
  1099. void ReadBonesFromSMD( std::vector< CDmeTransform* > &bones, std::istream &is, DmFileId_t fileid )
  1100. {
  1101. uint index;
  1102. int parent;
  1103. char name[ MAXNAME ];
  1104. char line[ MAXLINE ];
  1105. while ( is.getline( line, MAXLINE ) )
  1106. {
  1107. if ( sscanf( line, "%d \"%[^\"]\" %d", &index, name, &parent ) == 3 )
  1108. {
  1109. if ( index != bones.size() )
  1110. {
  1111. Warning( "ReadBonesFromSMD: reading node %d out of order\n", index );
  1112. }
  1113. if ( index >= bones.size() )
  1114. {
  1115. bones.resize( index + 1 );
  1116. }
  1117. bones[index] = CreateElement< CDmeTransform >( name, fileid );
  1118. if ( parent > 0 )
  1119. {
  1120. if ( ( uint( parent ) >= bones.size() ) || ( bones[ parent ] == NULL ) )
  1121. {
  1122. Warning( "ReadBonesFromSMD: reading node %d before parent\n", index, parent );
  1123. }
  1124. else
  1125. {
  1126. Assert( 0 ); // this code is so badly bit-rotten...
  1127. // bones[parent]->AddChild( bones[index]->GetHandle() );
  1128. }
  1129. }
  1130. }
  1131. else
  1132. {
  1133. if ( strncmp( line, "end", 3 ) != 0 )
  1134. {
  1135. Warning( "ReadBonesFromSMD: expected 'end' or bone, found %s\n", line );
  1136. }
  1137. return;
  1138. }
  1139. }
  1140. }
  1141. void clip_rotations( RadianEuler& rot )
  1142. {
  1143. // remap rotations to [ -M_PI .. M_PI )
  1144. for ( int j = 0; j < 3; j++ ) {
  1145. if ( rot[j] != -M_PI ) // keep -M_PI as is
  1146. {
  1147. rot[j] = fmod( (double)rot[j], M_PI );
  1148. }
  1149. }
  1150. }
  1151. void ReadSkeletalAnimationFromSMD( std::vector< CDmeTransform* > &bones, std::istream &is )
  1152. {
  1153. char line[ MAXLINE ];
  1154. char cmd[ MAXCMD ];
  1155. int time = INT_MIN;
  1156. int startframe = -1;
  1157. int endframe = -1;
  1158. #if 1
  1159. // Root transform
  1160. matrix3x4_t rootToWorld;
  1161. SetIdentityMatrix( rootToWorld );
  1162. // GetTransform()->GetTransform( rootToWorld );
  1163. #endif
  1164. while ( is.getline( line, MAXLINE ) )
  1165. {
  1166. int index;
  1167. Vector pos;
  1168. RadianEuler rot;
  1169. if ( sscanf( line, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &rot[0], &rot[1], &rot[2] ) == 7 )
  1170. {
  1171. if ( startframe < 0 )
  1172. {
  1173. Warning( "ReadSkeletalAnimationFromSMD: missing frame start\n" );
  1174. }
  1175. // clip_rotations( rot );
  1176. Quaternion quat;
  1177. AngleQuaternion( rot, quat );
  1178. #if 0
  1179. matrix3x4_t boneMatrix;
  1180. QuaternionMatrix( quat, boneMatrix );
  1181. MatrixSetColumn( pos, 3, boneMatrix );
  1182. if ( bones[index]->NumParents() > 0 )
  1183. {
  1184. DmElementHandle_t hParent = bones[index]->GetParent( 0 );
  1185. CDmeTransform *parentXform = GetElement< CDmeTransform >( hParent );
  1186. matrix3x4_t parentMatrix, newMatrix;
  1187. parentXform->GetTransform( parentMatrix );
  1188. // ConcatTransforms( parentMatrix, boneMatrix, newMatrix );
  1189. SetIdentityMatrix( newMatrix );
  1190. MatrixAngles( newMatrix, quat, pos );
  1191. }
  1192. else
  1193. {
  1194. matrix3x4_t parentMatrix, newMatrix;
  1195. // ConcatTransforms( rootToWorld, boneMatrix, newMatrix );
  1196. SetIdentityMatrix( newMatrix );
  1197. MatrixAngles( newMatrix, quat, pos );
  1198. }
  1199. #endif
  1200. bones[index]->SetValue( "orientation", quat );
  1201. bones[index]->SetValue( "position", pos );
  1202. // TODO - save animation data - currently just overwriting w/ last frame
  1203. }
  1204. else if ( sscanf( line, "%1023s %d", cmd, &index ) )
  1205. {
  1206. if ( strcmp( cmd, "time" ) == 0 )
  1207. {
  1208. time = index;
  1209. if ( startframe == -1 )
  1210. {
  1211. startframe = index;
  1212. }
  1213. if ( time < startframe )
  1214. {
  1215. Error( "ReadSkeletalAnimationFromSMD: time %d found after time %d\n", time, startframe );
  1216. }
  1217. if ( time > endframe )
  1218. {
  1219. endframe = time;
  1220. }
  1221. time -= startframe;
  1222. /*
  1223. if ( time != anim.size() )
  1224. {
  1225. Warning( "ReadSkeletalAnimationFromSMD: reading keyframe %d out of order\n", time );
  1226. }
  1227. if ( time >= anim.size() )
  1228. {
  1229. anim.resize( time + 1 );
  1230. anim[time] = new bone_t[nodes.size()];
  1231. }
  1232. if ( time > 0 )
  1233. {
  1234. if ( anim[time-1] )
  1235. {
  1236. std::copy( anim[time-1], anim[time-1] + nodes.size(), anim[time] );
  1237. }
  1238. else
  1239. {
  1240. Warning( "ReadSkeletalAnimationFromSMD: missing skeletal keyframe %d\n", time-1 );
  1241. }
  1242. }
  1243. */
  1244. }
  1245. else if ( strcmp( cmd, "end" ) == 0 )
  1246. {
  1247. // Build_Reference( nodes, anim, matrices ); // skip - leave this for dmemesh generation
  1248. return;
  1249. }
  1250. else
  1251. {
  1252. Warning( "ReadSkeletalAnimationFromSMD: expected bone, time or end, found %s\n", line );
  1253. }
  1254. }
  1255. else
  1256. {
  1257. Warning( "ReadSkeletalAnimationFromSMD: expected bone, time or end, found %s\n", line );
  1258. }
  1259. }
  1260. Error( "ReadSkeletalAnimationFromSMD: unexpected EOF\n" );
  1261. }
  1262. float vertex_t::normal_tolerance = cos( DEG2RAD( 2.0f ));
  1263. void SortAndBalanceBones( std::vector< skinning_info_t > &skinning )
  1264. {
  1265. // TODO - studiomdl collapses (sums) duplicate bone weights - is this necessary?!?!
  1266. std::sort( skinning.begin(), skinning.end() );
  1267. // throw away bone weights < 0.05f
  1268. while ( skinning.size() > 1 && skinning.back().weight >= 0.05f )
  1269. {
  1270. skinning.pop_back();
  1271. }
  1272. Assert( !skinning.empty() );
  1273. if ( skinning.size() > MAXBONEWEIGHTS )
  1274. {
  1275. skinning.resize( MAXBONEWEIGHTS );
  1276. }
  1277. float weightSum = 0.0f;
  1278. for ( uint i = 0; i < skinning.size(); ++i )
  1279. {
  1280. weightSum += skinning[i].weight;
  1281. }
  1282. if ( weightSum <= 0.0f )
  1283. {
  1284. for ( uint i = 0; i < skinning.size(); ++i )
  1285. {
  1286. skinning[i].weight = weightSum;
  1287. }
  1288. }
  1289. else
  1290. {
  1291. float weightScale = 1.0f / weightSum;
  1292. for ( uint i = 0; i < skinning.size(); ++i )
  1293. {
  1294. skinning[i].weight *= weightScale;
  1295. }
  1296. }
  1297. }
  1298. int ReadVertexFromSMD( std::vector< vertex_t > &vertices, int numbones, std::istream &is )
  1299. {
  1300. int boneIndex;
  1301. is >> boneIndex;
  1302. if ( boneIndex < 0 || boneIndex >= numbones )
  1303. {
  1304. Error( "ReadVertexFromSMD: invalid bone index: %d\n", boneIndex );
  1305. }
  1306. vertex_t vert;
  1307. is >> vert.coord.x >> vert.coord.y >> vert.coord.z;
  1308. is >> vert.normal.x >> vert.normal.y >> vert.normal.z;
  1309. is >> vert.texcoord.x >> vert.texcoord.y;
  1310. // invert v
  1311. vert.texcoord.y = 1.0f - vert.texcoord.y;
  1312. char line[MAXLINE];
  1313. is.getline( line, MAXLINE );
  1314. std::istrstream istr( line );
  1315. int nBones = 0;
  1316. istr >> nBones;
  1317. Assert( istr.good() || nBones == 0 );
  1318. if ( nBones == 0 )
  1319. {
  1320. vert.skinning.push_back( skinning_info_t( boneIndex, 1.0f ) );
  1321. }
  1322. else
  1323. {
  1324. vert.skinning.reserve( nBones );
  1325. for ( int i = 0; i < nBones; ++i )
  1326. {
  1327. skinning_info_t info;
  1328. istr >> info.index >> info.weight;
  1329. vert.skinning.push_back( info );
  1330. if ( info.index < 0 || info.index >= numbones )
  1331. {
  1332. Error( "ReadVertexFromSMD: invalid bone index: %d\n", info.index );
  1333. }
  1334. }
  1335. }
  1336. std::vector< vertex_t >::iterator vi = std::find( vertices.begin(), vertices.end(), vert );
  1337. if ( vi != vertices.end() )
  1338. return vi - vertices.begin();
  1339. SortAndBalanceBones( vert.skinning );
  1340. vertices.push_back( vert );
  1341. return vertices.size() - 1;
  1342. }
  1343. bool IsEnd( char const* pLine )
  1344. {
  1345. if ( strncmp( "end", pLine, 3 ) != 0 )
  1346. return false;
  1347. return ( pLine[3] == '\0' ) || ( pLine[3] == '\n' );
  1348. }
  1349. void ReadTrianglesFromSMD( std::vector< submesh_t* > &meshes, int numbones, std::istream &is )
  1350. {
  1351. Vector vmin( FLT_MAX, FLT_MAX, FLT_MAX );
  1352. Vector vmax( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  1353. char line[ MAXLINE ];
  1354. char texname[ MAXTEXNAME ];
  1355. while ( is.getline( line, MAXLINE ) )
  1356. {
  1357. if ( IsEnd( line ) )
  1358. break;
  1359. int lineLen = is.gcount();
  1360. if ( lineLen >= MAXTEXNAME )
  1361. {
  1362. Warning( "ReadTrianglesFromSMD: expected a texture name, found %s\n", line );
  1363. continue;
  1364. }
  1365. // the studiomdl comment here is "strip off trailing smag" whatever smag is...
  1366. strncpy( texname, line, MAXTEXNAME );
  1367. int i;
  1368. for ( i = strlen( texname ) - 1; i >= 0 && ! isgraph( texname[i] ); i-- )
  1369. {
  1370. }
  1371. texname[i + 1] = '\0';
  1372. // Skip empty names (studiomdl comment: "weird source problem, skip them")
  1373. // Skip null texture references
  1374. if ( texname[0] == '\0' ||
  1375. stricmp( texname, "null.bmp" ) == 0 ||
  1376. stricmp( texname, "null.tga" ) == 0 )
  1377. {
  1378. is.getline( line, MAXLINE );
  1379. is.getline( line, MAXLINE );
  1380. is.getline( line, MAXLINE );
  1381. continue;
  1382. }
  1383. // find mesh with matching texture - starting with last one created
  1384. int mi;
  1385. for ( mi = meshes.size() - 1; mi >= 0; --mi )
  1386. {
  1387. if ( stricmp( meshes[mi]->texname.c_str(), texname ) == 0 )
  1388. break;
  1389. }
  1390. // if no mesh with texname found, create a new one
  1391. if ( mi < 0 )
  1392. {
  1393. mi = meshes.size();
  1394. meshes.push_back( new submesh_t( texname ) );
  1395. }
  1396. submesh_t *mesh = meshes[mi];
  1397. mesh->indices.push_back( ReadVertexFromSMD( mesh->vertices, numbones, is ) );
  1398. mesh->indices.push_back( ReadVertexFromSMD( mesh->vertices, numbones, is ) );
  1399. mesh->indices.push_back( ReadVertexFromSMD( mesh->vertices, numbones, is ) );
  1400. #if 0
  1401. // flip triangle - the default in studiomdl
  1402. int numIndices = mesh->indices.size();
  1403. std::swap( mesh->indices[numIndices-1], mesh->indices[numIndices-2] );
  1404. #endif
  1405. }
  1406. }
  1407. void RemapBonesOnSubmesh( submesh_t *pMesh, std::vector< CDmeTransform* > &bones )
  1408. {
  1409. std::vector<int> vertsPerBone( bones.size() ); // initializes all counts to 0
  1410. // find vertex-per-bone counts
  1411. int vn = pMesh->vertices.size();
  1412. for ( int vi = 0; vi < vn; ++vi )
  1413. {
  1414. vertex_t &vert = pMesh->vertices[vi];
  1415. int bn = vert.skinning.size();
  1416. for ( int bi = 0; bi < bn; ++bi )
  1417. {
  1418. ++vertsPerBone[vert.skinning[bi].index];
  1419. }
  1420. }
  1421. std::vector<int> boneMap( bones.size() );
  1422. // copy only used bones into mesh's internal bone list and write mapping
  1423. int bn = vertsPerBone.size();
  1424. for ( int bi = 0; bi < bn; ++bi )
  1425. {
  1426. if ( vertsPerBone[bi] == 0 )
  1427. {
  1428. boneMap[bi] = -1;
  1429. }
  1430. else
  1431. {
  1432. boneMap[bi] = pMesh->bones.size();
  1433. pMesh->bones.push_back( bones[bi] );
  1434. }
  1435. }
  1436. // remap mesh's verts to use the interal bone indexing
  1437. for ( int vi = 0; vi < vn; ++vi )
  1438. {
  1439. vertex_t &vert = pMesh->vertices[vi];
  1440. int bn = vert.skinning.size();
  1441. for ( int bi = 0; bi < bn; ++bi )
  1442. {
  1443. vert.skinning[bi].index = boneMap[vert.skinning[bi].index];
  1444. }
  1445. }
  1446. }
  1447. CDmeTestMesh *CDmeTestMesh::ReadMeshFromSMD( char *pFilename, DmFileId_t fileid )
  1448. {
  1449. std::ifstream is( pFilename );
  1450. if ( !is )
  1451. {
  1452. Warning( "Unable to open file %s\n", pFilename );
  1453. return NULL;
  1454. }
  1455. CDmeTestMesh *pMesh = CreateElement< CDmeTestMesh >( "New Mesh", fileid );
  1456. char line[ MAXLINE ];
  1457. char cmd[ MAXCMD ];
  1458. int option;
  1459. while ( is.getline( line, MAXLINE ) )
  1460. {
  1461. int numRead = sscanf( line, "%1023s %d", cmd, &option );
  1462. if ( ( numRead == EOF ) || ( numRead == 0 ) )
  1463. continue; // blank line
  1464. if ( strcmp( cmd, "version" ) == 0 )
  1465. {
  1466. if ( option != 1 )
  1467. {
  1468. Error( "ReadMeshFromSMD: bad version\n" );
  1469. }
  1470. }
  1471. else if ( strcmp( cmd, "nodes" ) == 0 )
  1472. {
  1473. pMesh->m_bones.clear();
  1474. ReadBonesFromSMD( pMesh->m_bones, is, fileid );
  1475. }
  1476. else if ( strcmp( cmd, "skeleton" ) == 0 )
  1477. {
  1478. ReadSkeletalAnimationFromSMD( pMesh->m_bones, is );
  1479. }
  1480. else if ( strcmp( cmd, "triangles" ) == 0 )
  1481. {
  1482. ReadTrianglesFromSMD( pMesh->m_submeshes, pMesh->m_bones.size(), is );
  1483. }
  1484. else if ( strcmp( cmd, "vertexanimation" ) == 0 )
  1485. {
  1486. // Grab_Vertexanimation( psource );
  1487. return pMesh; // TODO - implement Grab_Vertexanimation!!!
  1488. }
  1489. else
  1490. {
  1491. Warning( "unknown studio command\n" );
  1492. }
  1493. }
  1494. #if 0
  1495. // remap only the needed bones to hopefully fit within maxbone contraints
  1496. int mn = pMesh->m_submeshes.size();
  1497. for ( int mi = 0; mi < mn; ++mi)
  1498. {
  1499. RemapBonesOnSubmesh( pMesh->m_submeshes[mi], pMesh->m_bones );
  1500. Msg( "remapping %d bones on mesh to %d bones on submesh %d\n",
  1501. pMesh->m_bones.size(),
  1502. pMesh->m_submeshes[mi]->bones.size(),
  1503. mi );
  1504. }
  1505. #endif
  1506. return pMesh;
  1507. }