Counter Strike : Global Offensive Source Code
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.

1461 lines
39 KiB

  1. //====== Copyright � 1996-2006, Valve Corporation, All rights reserved. =======
  2. //
  3. // Serialize and Unserialize Wavefront OBJ <-> DME Data
  4. //
  5. //=============================================================================
  6. // Valve includes
  7. #include "tier1/characterset.h"
  8. #include "movieobjects/dmedag.h"
  9. #include "movieobjects/dmemesh.h"
  10. #include "movieobjects/dmefaceset.h"
  11. #include "movieobjects/dmematerial.h"
  12. #include "movieobjects/dmobjserializer.h"
  13. #include "movieobjects/dmecombinationoperator.h"
  14. #include "movieobjects/dmemodel.h"
  15. #include "filesystem.h"
  16. #include "tier2/tier2.h"
  17. #include "tier1/UtlStringMap.h"
  18. #include "mathlib/mathlib.h"
  19. //-----------------------------------------------------------------------------
  20. //
  21. //-----------------------------------------------------------------------------
  22. class CFaceSetData
  23. {
  24. public:
  25. void Clear();
  26. inline CUtlVector< int > *GetFaceSetIndices( const char *pFaceSetName )
  27. {
  28. return &m_faceSetIndices[ pFaceSetName ];
  29. }
  30. void AddToMesh( CDmeMesh *pMesh );
  31. protected:
  32. CUtlStringMap< CUtlVector< int > > m_faceSetIndices;
  33. };
  34. //-----------------------------------------------------------------------------
  35. //
  36. //-----------------------------------------------------------------------------
  37. void CFaceSetData::Clear()
  38. {
  39. m_faceSetIndices.Clear();
  40. }
  41. //-----------------------------------------------------------------------------
  42. //
  43. //-----------------------------------------------------------------------------
  44. void CFaceSetData::AddToMesh( CDmeMesh *pMesh )
  45. {
  46. const int nFaceSets( m_faceSetIndices.GetNumStrings() );
  47. for ( int i( 0 ); i < nFaceSets; ++i )
  48. {
  49. const char *pName( m_faceSetIndices.String( i ) );
  50. CUtlVector< int > &faceSetIndices( m_faceSetIndices[ pName ] );
  51. if ( faceSetIndices.Count() )
  52. {
  53. CDmeFaceSet *pFaceSet = CreateElement< CDmeFaceSet >( pName, pMesh->GetFileId() );
  54. CDmeMaterial *pMaterial = CreateElement< CDmeMaterial >( pName, pMesh->GetFileId() );
  55. pMaterial->SetMaterial( pName );
  56. pFaceSet->AddIndices( faceSetIndices.Count() );
  57. pFaceSet->SetIndices( 0, faceSetIndices.Count(), faceSetIndices.Base() );
  58. pFaceSet->SetMaterial( pMaterial );
  59. pMesh->AddFaceSet( pFaceSet );
  60. }
  61. }
  62. Clear();
  63. }
  64. //-----------------------------------------------------------------------------
  65. //
  66. //-----------------------------------------------------------------------------
  67. class CVertexData
  68. {
  69. public:
  70. void Clear();
  71. inline void AddPosition( const Vector &p ) { m_positions.AddToTail( p ); }
  72. inline void AddPositionIndex( int i ) { m_pIndices.AddToTail( i ); }
  73. inline void AddNormal( const Vector &n ) { m_normals.AddToTail( n ); }
  74. inline void AddNormalIndex( int i ) { m_nIndices.AddToTail( i ); }
  75. inline void AddUV( const Vector2D &uv ) { AddUniqueValue( uv, m_uvs, m_uvIndexMap, FLT_EPSILON * 0.1f ); }
  76. inline void AddUVIndex( int i ) { Assert( i < m_uvIndexMap.Count() ); m_uvIndices.AddToTail( m_uvIndexMap[ i ] ); }
  77. inline int VertexCount() const { return m_pIndices.Count(); }
  78. CDmeVertexDataBase *AddToMesh( CDmeMesh *pMesh, bool bAbsolute, const char *pName, bool bDelta );
  79. protected:
  80. template < class T_t > void AddUniqueValue(
  81. const T_t &v,
  82. CUtlVector< T_t > &vs,
  83. CUtlVector< int > &map,
  84. float flThresh = FLT_EPSILON )
  85. {
  86. const int nVs( vs.Count() );
  87. for ( int i( 0 ); i < nVs; ++i )
  88. {
  89. if ( v.DistToSqr( vs[ i ] ) < flThresh )
  90. {
  91. map.AddToTail( i );
  92. return;
  93. }
  94. }
  95. map.AddToTail( vs.Count() );
  96. vs.AddToTail( v );
  97. }
  98. CDmeVertexDataBase *Add( CDmeMesh *pMesh, const char *pName = "bind" );
  99. CDmeVertexDeltaData *AddDelta( CDmeMesh *pMesh, bool bAbsolute, const char *pName = "bind" );
  100. CUtlVector< Vector > m_positions;
  101. CUtlVector< int > m_pIndices;
  102. CUtlVector< Vector > m_normals;
  103. CUtlVector< int > m_nIndices;
  104. CUtlVector< Vector2D > m_uvs;
  105. CUtlVector< int > m_uvIndexMap;
  106. CUtlVector< int > m_uvIndices;
  107. };
  108. //-----------------------------------------------------------------------------
  109. //
  110. //-----------------------------------------------------------------------------
  111. void CVertexData::Clear()
  112. {
  113. m_positions.RemoveAll();
  114. m_pIndices.RemoveAll();
  115. m_normals.RemoveAll();
  116. m_nIndices.RemoveAll();
  117. m_uvs.RemoveAll();
  118. m_uvIndexMap.RemoveAll();
  119. m_uvIndices.RemoveAll();
  120. }
  121. //-----------------------------------------------------------------------------
  122. //
  123. //-----------------------------------------------------------------------------
  124. CDmeVertexDataBase *CVertexData::AddToMesh( CDmeMesh *pMesh, bool bAbsolute, const char *pName, bool delta )
  125. {
  126. if ( delta )
  127. return AddDelta( pMesh, bAbsolute, pName );
  128. return Add( pMesh, pName );
  129. }
  130. //-----------------------------------------------------------------------------
  131. //
  132. //-----------------------------------------------------------------------------
  133. CDmeVertexDataBase *CVertexData::Add( CDmeMesh *pMesh, const char *pName )
  134. {
  135. CDmeVertexDataBase *pVertexData( NULL );
  136. if ( m_positions.Count() && m_pIndices.Count() )
  137. {
  138. {
  139. CDmeVertexData *pBaseVertexData = pMesh->FindOrCreateBaseState( pName );
  140. pMesh->SetCurrentBaseState( pName );
  141. pBaseVertexData->AddVertexIndices( m_pIndices.Count() );
  142. pVertexData = pBaseVertexData;
  143. }
  144. pVertexData->FlipVCoordinate( true );
  145. const FieldIndex_t pIndex( pVertexData->CreateField( CDmeVertexData::FIELD_POSITION ) );
  146. pVertexData->AddVertexData( pIndex, m_positions.Count() );
  147. pVertexData->SetVertexData( pIndex, 0, m_positions.Count(), AT_VECTOR3, m_positions.Base() );
  148. pVertexData->SetVertexIndices( pIndex, 0, m_pIndices.Count(), m_pIndices.Base() );
  149. if ( pVertexData && m_normals.Count() && m_nIndices.Count() )
  150. {
  151. Assert( m_pIndices.Count() == m_nIndices.Count() );
  152. const FieldIndex_t nIndex( pVertexData->CreateField( CDmeVertexData::FIELD_NORMAL ) );
  153. pVertexData->AddVertexData( nIndex, m_normals.Count() );
  154. pVertexData->SetVertexData( nIndex, 0, m_normals.Count(), AT_VECTOR3, m_normals.Base() );
  155. pVertexData->SetVertexIndices( nIndex, 0, m_nIndices.Count(), m_nIndices.Base() );
  156. }
  157. if ( pVertexData && m_uvs.Count() && m_uvIndices.Count() )
  158. {
  159. Assert( m_pIndices.Count() == m_uvIndices.Count() );
  160. const FieldIndex_t uvIndex( pVertexData->CreateField( CDmeVertexData::FIELD_TEXCOORD ) );
  161. pVertexData->AddVertexData( uvIndex, m_uvs.Count() );
  162. pVertexData->SetVertexData( uvIndex, 0, m_uvs.Count(), AT_VECTOR2, m_uvs.Base() );
  163. pVertexData->SetVertexIndices( uvIndex, 0, m_uvIndices.Count(), m_uvIndices.Base() );
  164. }
  165. }
  166. return pVertexData;
  167. }
  168. //-----------------------------------------------------------------------------
  169. //
  170. //-----------------------------------------------------------------------------
  171. CDmeVertexDeltaData *CVertexData::AddDelta( CDmeMesh *pMesh, bool bAbsolute, const char *pName )
  172. {
  173. CDmeVertexDeltaData *pDelta( NULL );
  174. if ( m_positions.Count() )
  175. {
  176. CDmeVertexData *pBind = pMesh->FindBaseState( "bind" );
  177. if ( pBind == NULL )
  178. return NULL;
  179. const FieldIndex_t pBindIndex( pBind->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) );
  180. if ( pBindIndex < 0 )
  181. return NULL;
  182. CDmrArrayConst< Vector > pBindData( pBind->GetVertexData( pBindIndex ) );
  183. const int pCount( m_positions.Count() );
  184. if ( pBindData.Count() != pCount )
  185. return NULL;
  186. for ( int i( 0 ); i < pCount; ++i )
  187. {
  188. m_positions[ i ] -= pBindData[ i ];
  189. }
  190. int *pIndices = reinterpret_cast< int * >( alloca( pCount * sizeof( int ) ) );
  191. int nNonZero( 0 );
  192. for ( int i( 0 ); i < pCount; ++i )
  193. {
  194. const Vector &v( m_positions[ i ] );
  195. // Kind of a magic number but it's because of 16 bit compression of the delta values
  196. if ( fabs( v.x ) >= ( 1 / 4096.0f ) || fabs( v.y ) >= ( 1 / 4096.0f ) || fabs( v.z ) >= ( 1 / 4096.0f ) )
  197. {
  198. m_positions[ nNonZero ] = v;
  199. pIndices[ nNonZero ] = i;
  200. ++nNonZero;
  201. }
  202. }
  203. pDelta = pMesh->FindOrCreateDeltaState( pName );
  204. pDelta->FlipVCoordinate( true );
  205. pDelta->SetValue( "corrected", !bAbsolute );
  206. const FieldIndex_t pIndex( pDelta->CreateField( CDmeVertexData::FIELD_POSITION ) );
  207. pDelta->AddVertexData( pIndex, nNonZero );
  208. pDelta->SetVertexData( pIndex, 0, nNonZero, AT_VECTOR3, m_positions.Base() );
  209. pDelta->SetVertexIndices( pIndex, 0, nNonZero, pIndices );
  210. const FieldIndex_t nBindNormalIndex = pBind->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  211. if ( nBindNormalIndex >= 0 )
  212. {
  213. CDmrArrayConst< Vector > bindNormalData( pBind->GetVertexData( nBindNormalIndex ) );
  214. const int nNormalCount = m_normals.Count();
  215. if ( bindNormalData.Count() == nNormalCount )
  216. {
  217. for ( int i = 0; i < nNormalCount; ++i )
  218. {
  219. m_normals[ i ] -= bindNormalData[ i ];
  220. }
  221. int *pNormalIndices = reinterpret_cast< int * >( stackalloc( nNormalCount * sizeof( int ) ) );
  222. int nNormalDeltaCount = 0;
  223. for ( int i = 0; i < nNormalCount; ++i )
  224. {
  225. const Vector &n = m_normals[ i ];
  226. // Kind of a magic number but it's because of 16 bit compression of the delta values
  227. if ( fabs( n.x ) >= ( 1 / 4096.0f ) || fabs( n.y ) >= ( 1 / 4096.0f ) || fabs( n.z ) >= ( 1 / 4096.0f ) )
  228. {
  229. m_normals[ nNormalDeltaCount ] = n;
  230. pNormalIndices[ nNormalDeltaCount ] = i;
  231. ++nNormalDeltaCount;
  232. }
  233. }
  234. }
  235. }
  236. }
  237. return pDelta;
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Convert from DME -> OBJ
  241. //-----------------------------------------------------------------------------
  242. bool CDmObjSerializer::Serialize( CUtlBuffer &buf, CDmElement *pRoot )
  243. {
  244. return false; // For now
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Convert from OBJ -> DME
  248. //-----------------------------------------------------------------------------
  249. bool CDmObjSerializer::Unserialize( CUtlBuffer &buf, const char *pEncodingName, int nEncodingVersion,
  250. const char *pSourceFormatName, int nSourceFormatVersion,
  251. DmFileId_t fileid, DmConflictResolution_t idConflictResolution, CDmElement **ppRoot )
  252. {
  253. *ppRoot = ReadOBJ( buf, fileid, "bind" );
  254. return *ppRoot != NULL;
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Convert from OBJ -> DME
  258. // If mesh is not NULL, the OBJ is added as a delta state to the mesh
  259. //-----------------------------------------------------------------------------
  260. CDmElement *CDmObjSerializer::ReadOBJ(
  261. const char *pFilename,
  262. CDmeMesh **ppCreatedMesh,
  263. bool bLoadAllDeltas /* = true */,
  264. bool bAbsolute /* = true */ )
  265. {
  266. char filename[ MAX_PATH ];
  267. Q_strncpy( filename, pFilename, sizeof( filename ) );
  268. Q_FixSlashes( filename );
  269. CUtlBuffer utlBuf;
  270. if ( !g_pFullFileSystem->ReadFile( filename, NULL, utlBuf ) )
  271. return NULL;
  272. char baseFile[ MAX_PATH ];
  273. Q_FileBase( filename, baseFile, sizeof( baseFile ) );
  274. CDmeMesh *pMesh( NULL );
  275. CDmElement *pRoot = ReadOBJ( utlBuf, DMFILEID_INVALID, baseFile, filename, NULL, &pMesh, bAbsolute );
  276. if ( pRoot && pMesh )
  277. {
  278. if ( ppCreatedMesh )
  279. {
  280. *ppCreatedMesh = pMesh;
  281. }
  282. CDmeCombinationOperator *pCombo( NULL );
  283. // Check if there are deltas in the directory with the same prefix
  284. // But only if the rest of the file is <prefix>=<suffix>.obj or is <prefix>_zero.obj
  285. char *pSuffix = Q_strrchr( baseFile, '=' );
  286. if ( !pSuffix || !*pSuffix )
  287. {
  288. pSuffix = Q_strrchr( baseFile, '_' );
  289. if ( !pSuffix || !*pSuffix )
  290. return pRoot;
  291. if ( Q_stricmp( pSuffix, "_zero" ) )
  292. return pRoot;
  293. }
  294. char findGlob[ MAX_PATH ];
  295. Q_strncpy( findGlob, baseFile, sizeof( findGlob ) );
  296. pSuffix = findGlob + ( pSuffix - baseFile );
  297. *( pSuffix + 0 ) = '_'; // Just in case it was <prefix>=<suffix>.obj
  298. *( pSuffix + 1 ) = '*';
  299. *( pSuffix + 2 ) = '.';
  300. Q_strncpy( pSuffix + 3, Q_GetFileExtension( filename ), sizeof( findGlob ) - ( pSuffix - findGlob + 3 ) );
  301. char path[ MAX_PATH ];
  302. Q_ExtractFilePath( filename, path, sizeof( path ) );
  303. m_objDirectory = path;
  304. char findPath[ MAX_PATH ];
  305. Q_ComposeFileName( path, findGlob, findPath, sizeof( findPath ) );
  306. FileFindHandle_t hFind;
  307. char deltaFile[ MAX_PATH ];
  308. char deltaPath[ MAX_PATH ];
  309. for ( const char *pFindFile( g_pFullFileSystem->FindFirst( findPath, &hFind ) ); pFindFile && *pFindFile; pFindFile = g_pFullFileSystem->FindNext( hFind ) )
  310. {
  311. Q_FileBase( pFindFile, deltaFile, sizeof( deltaFile ) );
  312. if ( Q_stricmp( baseFile, deltaFile ) )
  313. {
  314. Q_ComposeFileName( path, pFindFile, deltaPath, sizeof( deltaPath ) );
  315. if ( !g_pFullFileSystem->FileExists( deltaPath ) )
  316. continue;
  317. char *pControlName = strchr( deltaFile, '_' );
  318. if ( pControlName && *( pControlName + 1 ) )
  319. {
  320. ++pControlName;
  321. char *pDeltaName( pControlName );
  322. for ( char *pPlus( strchr( pDeltaName, '+' ) ); pPlus; pPlus = strchr( pPlus, '+' ) )
  323. {
  324. *pPlus = '_';
  325. }
  326. }
  327. if ( !strchr( pControlName, '_' ) )
  328. {
  329. if ( pCombo == NULL )
  330. {
  331. pCombo = CreateElement< CDmeCombinationOperator >( "combinationOperator", pRoot->GetFileId() );
  332. pRoot->SetValue( "combinationOperator", pCombo );
  333. }
  334. }
  335. DeltaInfo_t &deltaInfo = m_deltas[ pControlName ];
  336. deltaInfo.m_filename = pFindFile;
  337. deltaInfo.m_pMesh = pMesh;
  338. deltaInfo.m_pComboOp = pCombo;
  339. if ( bLoadAllDeltas )
  340. {
  341. GetDelta( pControlName, bAbsolute );
  342. }
  343. }
  344. }
  345. g_pFullFileSystem->FindClose( hFind );
  346. if ( pCombo )
  347. {
  348. pCombo->AddTarget( pMesh );
  349. pMesh->ComputeAllCorrectedPositionsFromActualPositions();
  350. }
  351. }
  352. return pRoot;
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Common function both ReadOBJ & Unserialize can call
  356. //-----------------------------------------------------------------------------
  357. CDmElement *CDmObjSerializer::ReadOBJ( CUtlBuffer &buf,
  358. DmFileId_t dmFileId,
  359. const char *pName,
  360. const char *pFilename /* = NULL */,
  361. CDmeMesh *pBaseMesh /* = NULL */,
  362. CDmeMesh **ppCreatedMesh /* = NULL */,
  363. bool bAbsolute /* = true */ )
  364. {
  365. CDmElement *pRoot( NULL );
  366. CDmeModel *pModel( NULL );
  367. if ( !pBaseMesh )
  368. {
  369. pRoot = CreateElement< CDmElement >( "root", dmFileId );
  370. pModel = CreateElement< CDmeModel >( "model", dmFileId );
  371. pRoot->SetValue( "skeleton", pModel );
  372. pRoot->SetValue( "model", pModel );
  373. }
  374. m_mtlLib.RemoveAll();
  375. char tmpBuf0[ 4096 ];
  376. char tmpBuf1[ 4096 ];
  377. characterset_t breakSet;
  378. CharacterSetBuild( &breakSet, "/\\" );
  379. const char *pBuf;
  380. Vector p;
  381. Vector2D uv;
  382. CVertexData vertexData;
  383. CFaceSetData faceSetData;
  384. CUtlString groupName;
  385. CDmeDag *pDmeDag( NULL );
  386. CDmeMesh *pDmeMesh( NULL );
  387. CUtlVector< int > *pFaceIndices( NULL );
  388. while ( buf.IsValid() )
  389. {
  390. buf.GetLine( tmpBuf0, sizeof( tmpBuf0 ) );
  391. pBuf = SkipSpace( tmpBuf0 );
  392. if ( sscanf( tmpBuf0, "v %f %f %f", &p.x, &p.y, &p.z ) == 3 )
  393. {
  394. if ( pDmeDag )
  395. {
  396. vertexData.AddToMesh( pDmeMesh, bAbsolute, "bind", false );
  397. faceSetData.AddToMesh( pDmeMesh );
  398. pDmeDag = NULL;
  399. pDmeMesh = NULL;
  400. pFaceIndices = NULL;
  401. }
  402. vertexData.AddPosition( p );
  403. continue;
  404. }
  405. if ( sscanf( pBuf, "vn %f %f %f", &p.x, &p.y, &p.z ) == 3 )
  406. {
  407. vertexData.AddNormal( p );
  408. continue;
  409. }
  410. if ( !pBaseMesh )
  411. {
  412. if ( sscanf( pBuf, "vt %f %f", &uv.x, &uv.y ) == 2 )
  413. {
  414. vertexData.AddUV( uv );
  415. continue;
  416. }
  417. if ( pFilename && sscanf( pBuf, "mtllib %4096s", tmpBuf1 ) == 1 )
  418. {
  419. CUtlString mtlLib( tmpBuf1 );
  420. Q_strncpy( tmpBuf0, pFilename, sizeof( tmpBuf0 ) );
  421. Q_FixSlashes( tmpBuf0 );
  422. Q_StripFilename( tmpBuf0 );
  423. char mtlLibPath[ MAX_PATH ];
  424. Q_ComposeFileName( tmpBuf0, tmpBuf1, mtlLibPath, sizeof( mtlLibPath ) );
  425. CUtlBuffer utlBuf;
  426. if ( g_pFullFileSystem->ReadFile( mtlLibPath, NULL, utlBuf ) )
  427. {
  428. ParseMtlLib( utlBuf );
  429. }
  430. continue;
  431. }
  432. if ( sscanf( pBuf, "usemtl %4096s", tmpBuf1 ) == 1 )
  433. {
  434. // Remove any 'SG' suffix from the material
  435. const uint sLen = Q_strlen( tmpBuf1 );
  436. if ( sLen && !Q_strcmp( tmpBuf1 + sLen - 2, "SG" ) )
  437. {
  438. tmpBuf1[ sLen - 2 ] = '\0';
  439. }
  440. const char *pTexture( FindMtlEntry( tmpBuf1 ) );
  441. if ( pTexture )
  442. {
  443. pFaceIndices = faceSetData.GetFaceSetIndices( pTexture );
  444. }
  445. else
  446. {
  447. pFaceIndices = faceSetData.GetFaceSetIndices( tmpBuf1 );
  448. }
  449. continue;
  450. }
  451. if ( sscanf( pBuf, "g %4096s", tmpBuf1 ) == 1 )
  452. {
  453. groupName = tmpBuf1;
  454. if ( pFaceIndices == NULL )
  455. {
  456. pFaceIndices = faceSetData.GetFaceSetIndices( tmpBuf1 );
  457. }
  458. continue;
  459. }
  460. if ( *pBuf == 'f' && ( *( pBuf + 1 ) == ' ' || *( pBuf + 1 ) == '\t' ) )
  461. {
  462. if ( pDmeDag == NULL )
  463. {
  464. pDmeDag = CreateElement< CDmeDag >( pName ? pName : ( groupName.IsEmpty() ? "obj" : groupName.Get() ), pRoot->GetFileId() );
  465. Assert( pDmeDag );
  466. pDmeMesh = CreateElement< CDmeMesh >( pName ? pName : ( groupName.IsEmpty() ? "obj" : groupName.Get() ), pRoot->GetFileId() );
  467. if ( ppCreatedMesh && *ppCreatedMesh == NULL )
  468. {
  469. // Only the first mesh created...
  470. *ppCreatedMesh = pDmeMesh;
  471. }
  472. pDmeDag->SetShape( pDmeMesh );
  473. if ( pModel )
  474. {
  475. pModel->AddJoint( pDmeDag );
  476. pModel->AddChild( pDmeDag );
  477. }
  478. }
  479. if ( pFaceIndices == NULL )
  480. {
  481. pFaceIndices = faceSetData.GetFaceSetIndices( "facetSet" );
  482. }
  483. int v;
  484. int t;
  485. int n;
  486. pBuf = SkipSpace( pBuf + 1 );
  487. int nLen = Q_strlen( pBuf );
  488. CUtlBuffer bufParse( pBuf, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  489. while ( bufParse.IsValid() )
  490. {
  491. if ( !ParseVertex( bufParse, breakSet, v, t, n ) )
  492. break;
  493. pFaceIndices->AddToTail( vertexData.VertexCount() );
  494. if ( v > 0 )
  495. {
  496. vertexData.AddPositionIndex( v - 1 );
  497. }
  498. if ( n > 0 )
  499. {
  500. vertexData.AddNormalIndex( n - 1 );
  501. }
  502. if ( t > 0 )
  503. {
  504. vertexData.AddUVIndex( t - 1 );
  505. }
  506. }
  507. pFaceIndices->AddToTail( -1 );
  508. continue;
  509. }
  510. }
  511. }
  512. CDmeVertexDataBase *pVertexData( NULL );
  513. if ( pBaseMesh )
  514. {
  515. pVertexData = vertexData.AddToMesh( pBaseMesh, bAbsolute, pName, true );
  516. }
  517. else
  518. {
  519. pVertexData = vertexData.AddToMesh( pDmeMesh, bAbsolute, "bind", false );
  520. faceSetData.AddToMesh( pDmeMesh );
  521. }
  522. if ( pModel )
  523. {
  524. pModel->CaptureJointsToBaseState( "bind" );
  525. }
  526. if ( pBaseMesh )
  527. return pVertexData;
  528. return pRoot;
  529. }
  530. //-----------------------------------------------------------------------------
  531. //
  532. //-----------------------------------------------------------------------------
  533. int CDmObjSerializer::OutputVectors(
  534. CUtlBuffer &b,
  535. const char *pPrefix,
  536. const CUtlVector< Vector > &vData,
  537. const matrix3x4_t &matrix )
  538. {
  539. Vector v;
  540. const int nv( vData.Count() );
  541. for ( int i( 0 ); i < nv; ++i )
  542. {
  543. VectorTransform( vData[ i ], matrix, v );
  544. b << pPrefix << v << "\n";
  545. }
  546. return nv;
  547. }
  548. //-----------------------------------------------------------------------------
  549. //
  550. //-----------------------------------------------------------------------------
  551. int CDmObjSerializer::OutputVectors(
  552. CUtlBuffer &b,
  553. const char *pPrefix,
  554. const CUtlVector< Vector2D > &vData )
  555. {
  556. Vector v;
  557. const int nv( vData.Count() );
  558. for ( int i( 0 ); i < nv; ++i )
  559. {
  560. b << pPrefix << vData[ i ] << "\n";
  561. }
  562. return nv;
  563. }
  564. //-----------------------------------------------------------------------------
  565. //
  566. //-----------------------------------------------------------------------------
  567. void CDmObjSerializer::MeshToObj(
  568. CUtlBuffer &b,
  569. const matrix3x4_t &parentWorldMatrix,
  570. CDmeMesh *pMesh,
  571. const char *pDeltaName,
  572. bool absolute )
  573. {
  574. CUtlVector< CDmeMesh::DeltaComputation_t > compList;
  575. if ( pDeltaName )
  576. {
  577. pMesh->ComputeDependentDeltaStateList( compList );
  578. }
  579. const int nCompList( compList.Count() );
  580. CDmeVertexData *pBase( pMesh->FindBaseState( "bind" ) );
  581. if ( !pBase )
  582. return;
  583. const FieldIndex_t pIndex( pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) );
  584. if ( pIndex < 0 )
  585. return;
  586. int nPositionCount = 0;
  587. int nTextureCount = 0;
  588. int nNormalCount = 0;
  589. b << "g " << pMesh->GetName() << "\n";
  590. CDmrArrayConst< Vector > pArray( pBase->GetVertexData( pIndex ) );
  591. const CUtlVector< int > *ppIndices( &pBase->GetVertexIndexData( pIndex ) );
  592. const CUtlVector< Vector > &pConstData( pArray.Get() );
  593. if ( nCompList )
  594. {
  595. CUtlVector< Vector > pData;
  596. pData.CopyArray( pConstData.Base(), pConstData.Count() );
  597. if ( absolute )
  598. {
  599. for ( int i ( 0 ); i < nCompList; ++i )
  600. {
  601. CDmeVertexDeltaData *pTmpDeltaState( pMesh->GetDeltaState( compList[ i ].m_nDeltaIndex ) );
  602. if ( Q_strcmp( pTmpDeltaState->GetName(), pDeltaName ) )
  603. continue;
  604. b << "# Delta: " << pTmpDeltaState->GetName() << "\n";
  605. pMesh->AddDelta( pTmpDeltaState, pData.Base(), pData.Count(), CDmeVertexData::FIELD_POSITION, 1.0f );
  606. const CUtlVector< int > &depDeltas( compList[ i ].m_DependentDeltas );
  607. const int nDepDeltas( depDeltas.Count() );
  608. for ( int j( 0 ); j < nDepDeltas; ++j )
  609. {
  610. pTmpDeltaState = pMesh->GetDeltaState( depDeltas[ j ] );
  611. b << "# Dependent Delta: " << pTmpDeltaState->GetName() << "\n";
  612. pMesh->AddDelta( pTmpDeltaState, pData.Base(), pData.Count(), CDmeVertexData::FIELD_POSITION, 1.0f );
  613. }
  614. }
  615. }
  616. else
  617. {
  618. for ( int i ( 0 ); i < nCompList; ++i )
  619. {
  620. CDmeVertexDeltaData *pTmpDeltaState( pMesh->GetDeltaState( compList[ i ].m_nDeltaIndex ) );
  621. if ( Q_strcmp( pTmpDeltaState->GetName(), pDeltaName ) )
  622. continue;
  623. b << "# Delta: " << pTmpDeltaState->GetName() << "\n";
  624. pMesh->AddDelta( pTmpDeltaState, pData.Base(), pData.Count(), CDmeVertexData::FIELD_POSITION, 1.0f );
  625. }
  626. }
  627. nPositionCount = OutputVectors( b, "v ", pData, parentWorldMatrix );
  628. }
  629. else
  630. {
  631. nPositionCount = OutputVectors( b, "v ", pConstData, parentWorldMatrix );
  632. }
  633. const CUtlVector< int > *puvIndices( NULL );
  634. const FieldIndex_t uvIndex( pBase->FindFieldIndex( CDmeVertexData::FIELD_TEXCOORD ) );
  635. if ( uvIndex >= 0 )
  636. {
  637. CDmrArrayConst< Vector2D > uvArray( pBase->GetVertexData( uvIndex ) );
  638. const CUtlVector< Vector2D > &uvData( uvArray.Get() );
  639. puvIndices = &pBase->GetVertexIndexData( uvIndex );
  640. nTextureCount = OutputVectors( b, "vt ", uvData );
  641. }
  642. const CUtlVector< int > *pnIndices( NULL );
  643. const FieldIndex_t nIndex( pBase->FindFieldIndex( CDmeVertexData::FIELD_NORMAL ) );
  644. if ( nIndex >= 0 )
  645. {
  646. matrix3x4_t normalMatrix;
  647. MatrixInverseTranspose( parentWorldMatrix, normalMatrix );
  648. CDmrArrayConst< Vector > nArray( pBase->GetVertexData( nIndex ) );
  649. const CUtlVector< Vector > &nConstData( nArray.Get() );
  650. pnIndices = &pBase->GetVertexIndexData( nIndex );
  651. if ( nCompList )
  652. {
  653. CUtlVector< Vector > nData;
  654. nData.CopyArray( nConstData.Base(), nConstData.Count() );
  655. if ( absolute )
  656. {
  657. for ( int i ( 0 ); i < nCompList; ++i )
  658. {
  659. CDmeVertexDeltaData *pTmpDeltaState( pMesh->GetDeltaState( compList[ i ].m_nDeltaIndex ) );
  660. if ( Q_strcmp( pTmpDeltaState->GetName(), pDeltaName ) )
  661. continue;
  662. b << "# Delta: " << pTmpDeltaState->GetName() << "\n";
  663. pMesh->AddDelta( pTmpDeltaState, nData.Base(), nData.Count(), CDmeVertexData::FIELD_NORMAL, 1.0f );
  664. const CUtlVector< int > &depDeltas( compList[ i ].m_DependentDeltas );
  665. const int nDepDeltas( depDeltas.Count() );
  666. for ( int j( 0 ); j < nDepDeltas; ++j )
  667. {
  668. pTmpDeltaState = pMesh->GetDeltaState( depDeltas[ j ] );
  669. b << "# Dependent Delta: " << pTmpDeltaState->GetName() << "\n";
  670. pMesh->AddDelta( pTmpDeltaState, nData.Base(), nData.Count(), CDmeVertexData::FIELD_NORMAL, 1.0f );
  671. }
  672. }
  673. }
  674. else
  675. {
  676. for ( int i ( 0 ); i < nCompList; ++i )
  677. {
  678. CDmeVertexDeltaData *pTmpDeltaState( pMesh->GetDeltaState( compList[ i ].m_nDeltaIndex ) );
  679. if ( Q_strcmp( pTmpDeltaState->GetName(), pDeltaName ) )
  680. continue;
  681. b << "# Delta: " << pTmpDeltaState->GetName() << "\n";
  682. pMesh->AddDelta( pTmpDeltaState, nData.Base(), nData.Count(), CDmeVertexData::FIELD_NORMAL, 1.0f );
  683. }
  684. }
  685. nNormalCount = OutputVectors( b, "vn ", nData, normalMatrix );
  686. }
  687. else
  688. {
  689. nNormalCount = OutputVectors( b, "vn ", nConstData, normalMatrix );
  690. }
  691. }
  692. const int pCount( ppIndices->Count() );
  693. const int uvCount( puvIndices ? puvIndices->Count() : 0 );
  694. const int nCount( pnIndices ? pnIndices->Count() : 0 );
  695. const int nFaceSets( pMesh->FaceSetCount() );
  696. for ( int i( 0 ); i < nFaceSets; ++i )
  697. {
  698. CDmeFaceSet *pFaceSet( pMesh->GetFaceSet( i ) );
  699. CDmeMaterial *pMaterial( pFaceSet->GetMaterial() );
  700. if ( pMaterial )
  701. {
  702. b << "usemtl " << pMaterial->GetMaterialName() << "\n";
  703. }
  704. const int nIndices( pFaceSet->NumIndices() );
  705. const int *pIndex( pFaceSet->GetIndices() );
  706. const int *const pEnd( pIndex + nIndices );
  707. int fIndex;
  708. const char *const pFaceStart( "f " );
  709. const char *const pFaceNext( " " );
  710. const char *pFaceSep( pFaceStart );
  711. if ( pCount == uvCount && pCount == nCount )
  712. {
  713. const CUtlVector< int > &pIndices( *ppIndices );
  714. const CUtlVector< int > &uvIndices( *puvIndices );
  715. const CUtlVector< int > &nIndices( *pnIndices );
  716. while ( pIndex < pEnd )
  717. {
  718. fIndex = *pIndex++;
  719. if ( fIndex < 0 )
  720. {
  721. b << "\n";
  722. pFaceSep = pFaceStart;
  723. continue;
  724. }
  725. b << pFaceSep << ( pIndices[ fIndex ] + m_nPositionOffset ) << '/' << ( uvIndices[ fIndex ] + m_nTextureOffset ) << '/' << ( nIndices[ fIndex ] + m_nNormalOffset );
  726. pFaceSep = pFaceNext;
  727. }
  728. }
  729. else if ( pCount == uvCount )
  730. {
  731. const CUtlVector< int > &pIndices( *ppIndices );
  732. const CUtlVector< int > &uvIndices( *puvIndices );
  733. while ( pIndex < pEnd )
  734. {
  735. fIndex = *pIndex++;
  736. if ( fIndex < 0 )
  737. {
  738. b << "\n";
  739. pFaceSep = pFaceStart;
  740. continue;
  741. }
  742. b << pFaceSep << ( pIndices[ fIndex ] + m_nPositionOffset ) << '/' << ( uvIndices[ fIndex ] + m_nTextureOffset ) << '/';
  743. pFaceSep = pFaceNext;
  744. }
  745. }
  746. else if ( pCount == nCount )
  747. {
  748. const CUtlVector< int > &pIndices( *ppIndices );
  749. const CUtlVector< int > &nIndices( *pnIndices );
  750. while ( pIndex < pEnd )
  751. {
  752. fIndex = *pIndex++;
  753. if ( fIndex < 0 )
  754. {
  755. b << "\n";
  756. pFaceSep = pFaceStart;
  757. continue;
  758. }
  759. b << pFaceSep << ( pIndices[ fIndex ] + m_nPositionOffset ) << "//" << ( nIndices[ fIndex ] + m_nNormalOffset );
  760. pFaceSep = pFaceNext;
  761. }
  762. }
  763. else
  764. {
  765. const CUtlVector< int > &pIndices( *ppIndices );
  766. while ( pIndex < pEnd )
  767. {
  768. fIndex = *pIndex++;
  769. if ( fIndex < 0 )
  770. {
  771. b << "\n";
  772. pFaceSep = pFaceStart;
  773. continue;
  774. }
  775. b << pFaceSep << ( pIndices[ fIndex ] + m_nPositionOffset ) << "//";
  776. pFaceSep = pFaceNext;
  777. }
  778. }
  779. }
  780. m_nPositionOffset += nPositionCount;
  781. m_nTextureOffset += nTextureCount;
  782. m_nNormalOffset += nNormalCount;
  783. }
  784. //-----------------------------------------------------------------------------
  785. //
  786. //-----------------------------------------------------------------------------
  787. void CDmObjSerializer::DagToObj(
  788. CUtlBuffer &b,
  789. const matrix3x4_t &parentWorldMatrix,
  790. CDmeDag *pDag,
  791. const char *pDeltaName,
  792. bool absolute )
  793. {
  794. matrix3x4_t inclusiveMatrix;
  795. pDag->GetTransform()->GetTransform( inclusiveMatrix );
  796. ConcatTransforms( parentWorldMatrix, inclusiveMatrix, inclusiveMatrix );
  797. CDmeMesh *pMesh( CastElement< CDmeMesh >( pDag->GetShape() ) );
  798. if ( pMesh )
  799. {
  800. MeshToObj( b, inclusiveMatrix, pMesh, pDeltaName, absolute );
  801. }
  802. const int nChildren( pDag->GetChildCount() );
  803. for ( int i( 0 ); i < nChildren; ++i )
  804. {
  805. DagToObj( b, inclusiveMatrix, pDag->GetChild( i ), pDeltaName, absolute );
  806. }
  807. }
  808. //-----------------------------------------------------------------------------
  809. //
  810. //-----------------------------------------------------------------------------
  811. void CDmObjSerializer::FindDeltaMeshes( CDmeDag *pDag, CUtlVector< CDmeMesh * > &meshes )
  812. {
  813. CDmeMesh *pMesh( CastElement< CDmeMesh >( pDag->GetShape() ) );
  814. if ( pMesh && pMesh->DeltaStateCount() )
  815. {
  816. meshes.AddToTail( pMesh );
  817. }
  818. const int nChildren( pDag->GetChildCount() );
  819. for ( int i( 0 ); i < nChildren; ++i )
  820. {
  821. FindDeltaMeshes( pDag->GetChild( i ), meshes );
  822. }
  823. }
  824. //-----------------------------------------------------------------------------
  825. // Convert from OBJ -> DME
  826. //-----------------------------------------------------------------------------
  827. bool CDmObjSerializer::WriteOBJ( const char *pFilename, CDmElement *pRoot, bool bWriteOBJs, const char *pDeltaName, bool absolute )
  828. {
  829. CDmeDag *pModel = pRoot->GetValueElement< CDmeDag >( "model" );
  830. if ( !pModel )
  831. return false;
  832. matrix3x4_t identityMatrix;
  833. SetIdentityMatrix( identityMatrix );
  834. if ( !pDeltaName )
  835. {
  836. CUtlBuffer b( 0, 0, CUtlBuffer::TEXT_BUFFER );
  837. b << "# OBJ\n";
  838. b << "#\n";
  839. m_nPositionOffset = 1; // OBJs start indexing at 1
  840. m_nTextureOffset = 1;
  841. m_nNormalOffset = 1;
  842. DagToObj( b, identityMatrix, pModel, pDeltaName, absolute );
  843. g_pFullFileSystem->WriteFile( pFilename, NULL, b );
  844. // Filesystem is silly
  845. // On WIN32 filesystem changes all of the characters to lowercase grrrr.....
  846. rename( pFilename, pFilename );
  847. }
  848. if ( !bWriteOBJs )
  849. return true;
  850. CUtlVector< CDmeMesh * > deltaMeshes;
  851. FindDeltaMeshes( pModel, deltaMeshes );
  852. if ( deltaMeshes.Count() )
  853. {
  854. char base[ MAX_PATH ];
  855. Q_FileBase( pFilename, base, sizeof( base ) );
  856. char path[ MAX_PATH ];
  857. Q_ExtractFilePath( pFilename, path, sizeof( path ) );
  858. char *pSuffix = strchr( base, '=' );
  859. if ( !pSuffix )
  860. {
  861. pSuffix = strchr( base, '_' );
  862. }
  863. if ( pSuffix )
  864. {
  865. *( pSuffix + 0 ) = '_';
  866. *( pSuffix + 1 ) = '\0';
  867. }
  868. char filename[ MAX_PATH ];
  869. const int nDeltaMeshes( deltaMeshes.Count() );
  870. for ( int i( 0 ); i < nDeltaMeshes; ++i )
  871. {
  872. CDmeMesh *pDeltaMesh( deltaMeshes[ i ] );
  873. const int nDeltas( pDeltaMesh->DeltaStateCount() );
  874. for ( int j( 0 ); j < nDeltas; ++j )
  875. {
  876. CDmeVertexDeltaData *pDelta( pDeltaMesh->GetDeltaState( j ) );
  877. if ( !pDeltaName || !Q_strcmp( pDeltaName, pDelta->GetName() ) )
  878. {
  879. CUtlBuffer b( 0, 0, CUtlBuffer::TEXT_BUFFER );
  880. b << "# Delta OBJ: " << pDelta->GetName() << "\n";
  881. b << "#\n";
  882. Q_strncpy( filename, pDelta->GetName(), sizeof( filename ) );
  883. // Change _ to +
  884. const char *const pEnd( filename + sizeof( filename ) );
  885. for ( char *pChar = filename; *pChar && pChar < pEnd; ++pChar )
  886. {
  887. if ( *pChar == '_' )
  888. {
  889. *pChar = '+';
  890. }
  891. }
  892. CUtlString deltaFile( base );
  893. deltaFile += filename;
  894. deltaFile += ".obj";
  895. m_nPositionOffset = 1; // OBJs use 1 based indexes
  896. m_nTextureOffset = 1;
  897. m_nNormalOffset = 1;
  898. DagToObj( b, identityMatrix, pModel, pDelta->GetName(), absolute );
  899. Q_ComposeFileName( path, deltaFile.Get(), filename, sizeof( filename ) );
  900. g_pFullFileSystem->WriteFile( filename, NULL, b );
  901. // On WIN32 filesystem changes all of the characters to lowercase grrrr.....
  902. rename( filename, filename );
  903. }
  904. }
  905. }
  906. }
  907. return true;
  908. }
  909. //-----------------------------------------------------------------------------
  910. //
  911. //-----------------------------------------------------------------------------
  912. void CDmObjSerializer::ParseMtlLib( CUtlBuffer &buf )
  913. {
  914. char tmpBuf0[ 4096 ];
  915. int nCurrentMtl = -1;
  916. while ( buf.IsValid() )
  917. {
  918. buf.GetLine( tmpBuf0, sizeof(tmpBuf0) );
  919. if ( StringHasPrefix( tmpBuf0, "newmtl " ) )
  920. {
  921. char mtlName[1024];
  922. if ( sscanf( tmpBuf0, "newmtl %s", mtlName ) == 1 )
  923. {
  924. // Remove any 'SG' suffix from the material
  925. const uint sLen = Q_strlen( mtlName );
  926. if ( sLen > 2 && !Q_strcmp( mtlName + sLen - 2, "SG" ) )
  927. {
  928. mtlName[ sLen - 2 ] = '\0';
  929. }
  930. nCurrentMtl = m_mtlLib.AddToTail( );
  931. m_mtlLib[nCurrentMtl].m_MtlName = mtlName;
  932. m_mtlLib[nCurrentMtl].m_TgaName = "debugempty";
  933. }
  934. continue;
  935. }
  936. if ( StringHasPrefix( tmpBuf0, "map_Kd " ) )
  937. {
  938. if ( nCurrentMtl < 0 )
  939. continue;
  940. char tgaPath[MAX_PATH];
  941. char tgaName[1024];
  942. if ( sscanf( tmpBuf0, "map_Kd %s", tgaPath ) == 1 )
  943. {
  944. // Try a cheesy hack - look for /materialsrc/ and set the material name off the entire path minus extension
  945. Q_strncpy( tmpBuf0, tgaPath, sizeof( tmpBuf0 ) );
  946. Q_FixSlashes( tmpBuf0, '/' );
  947. const char *pMaterialSrc = Q_strstr( tmpBuf0, "/materialsrc/" );
  948. if ( pMaterialSrc )
  949. {
  950. pMaterialSrc += Q_strlen( "/materialsrc/" );
  951. Q_StripExtension( pMaterialSrc, tgaName, sizeof( tgaName) );
  952. m_mtlLib[ nCurrentMtl ].m_TgaName = tgaName;
  953. }
  954. else
  955. {
  956. Q_FileBase( tgaPath, tgaName, sizeof(tgaName) );
  957. m_mtlLib[nCurrentMtl].m_TgaName = tgaName;
  958. }
  959. }
  960. continue;
  961. }
  962. }
  963. }
  964. //-----------------------------------------------------------------------------
  965. //
  966. //-----------------------------------------------------------------------------
  967. const char *CDmObjSerializer::FindMtlEntry( const char *pTgaName )
  968. {
  969. int nCount = m_mtlLib.Count();
  970. for ( int i = 0; i < nCount; ++i )
  971. {
  972. if ( !Q_stricmp( m_mtlLib[i].m_MtlName, pTgaName ) )
  973. return m_mtlLib[i].m_TgaName;
  974. }
  975. return pTgaName;
  976. }
  977. //-----------------------------------------------------------------------------
  978. //
  979. //-----------------------------------------------------------------------------
  980. bool CDmObjSerializer::ParseVertex( CUtlBuffer& bufParse, characterset_t &breakSet, int &v, int &t, int &n )
  981. {
  982. char cmd[1024];
  983. int nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
  984. if ( nLen <= 0 )
  985. return false;
  986. v = atoi( cmd );
  987. n = 0;
  988. t = 0;
  989. char c = *(char*)bufParse.PeekGet();
  990. bool bHasTexCoord = IN_CHARACTERSET( breakSet, c ) != 0;
  991. bool bHasNormal = false;
  992. if ( bHasTexCoord )
  993. {
  994. // Snag the '/'
  995. nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
  996. Assert( nLen == 1 );
  997. c = *(char*)bufParse.PeekGet();
  998. if ( !IN_CHARACTERSET( breakSet, c ) )
  999. {
  1000. nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
  1001. Assert( nLen > 0 );
  1002. t = atoi( cmd );
  1003. c = *(char*)bufParse.PeekGet();
  1004. bHasNormal = IN_CHARACTERSET( breakSet, c ) != 0;
  1005. }
  1006. else
  1007. {
  1008. bHasNormal = true;
  1009. bHasTexCoord = false;
  1010. }
  1011. if ( bHasNormal )
  1012. {
  1013. // Snag the '/'
  1014. nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
  1015. Assert( nLen == 1 );
  1016. nLen = bufParse.ParseToken( &breakSet, cmd, sizeof(cmd), false );
  1017. Assert( nLen > 0 );
  1018. n = atoi( cmd );
  1019. }
  1020. }
  1021. return true;
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. //
  1025. //-----------------------------------------------------------------------------
  1026. const char *CDmObjSerializer::SkipSpace(
  1027. const char *pBuf )
  1028. {
  1029. while ( *pBuf == ' ' || *pBuf == '\t' )
  1030. ++pBuf;
  1031. return pBuf;
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. //
  1035. //-----------------------------------------------------------------------------
  1036. CDmeVertexDeltaData *CDmObjSerializer::GetDelta( const char *pDeltaName, bool bAbsolute )
  1037. {
  1038. if ( !m_deltas.Defined( pDeltaName ) )
  1039. return NULL;
  1040. DeltaInfo_t &deltaInfo( m_deltas[ pDeltaName ] );
  1041. if ( deltaInfo.m_pDeltaData )
  1042. return deltaInfo.m_pDeltaData;
  1043. if ( !LoadDependentDeltas( pDeltaName ) )
  1044. return NULL;
  1045. CUtlBuffer utlBuf;
  1046. char deltaPath[ MAX_PATH ];
  1047. Q_ComposeFileName( m_objDirectory, deltaInfo.m_filename, deltaPath, sizeof( deltaPath ) );
  1048. Q_FixSlashes( deltaPath );
  1049. if ( !g_pFullFileSystem->ReadFile( deltaPath, NULL, utlBuf ) )
  1050. return NULL;
  1051. if ( deltaInfo.m_pComboOp && !strchr( pDeltaName, '_' ) )
  1052. {
  1053. deltaInfo.m_pComboOp->FindOrCreateControl( pDeltaName, false, true );
  1054. }
  1055. deltaInfo.m_pDeltaData = CastElement< CDmeVertexDeltaData >( ReadOBJ( utlBuf, deltaInfo.m_pMesh->GetFileId(), pDeltaName, deltaPath, deltaInfo.m_pMesh, NULL, bAbsolute ) );
  1056. return deltaInfo.m_pDeltaData;
  1057. }
  1058. //-----------------------------------------------------------------------------
  1059. //
  1060. //-----------------------------------------------------------------------------
  1061. bool CDmObjSerializer::LoadDependentDeltas( const char *pDeltaName )
  1062. {
  1063. // TODO: Load Dependent Deltas
  1064. return true;
  1065. }
  1066. //-----------------------------------------------------------------------------
  1067. // Counts the number of _'s in a string
  1068. //-----------------------------------------------------------------------------
  1069. int ComputeDimensionality( const char *pDeltaName )
  1070. {
  1071. const char *pUnderBar = pDeltaName;
  1072. int nDimensions = 0;
  1073. while ( pUnderBar )
  1074. {
  1075. ++nDimensions;
  1076. pUnderBar = strchr( pUnderBar, '_' );
  1077. if ( pUnderBar )
  1078. {
  1079. ++pUnderBar;
  1080. }
  1081. }
  1082. return nDimensions;
  1083. }
  1084. /*
  1085. //-----------------------------------------------------------------------------
  1086. // Generates a sorted list in order of dimensionality of the delta states
  1087. // NOTE: This assumes a naming scheme where delta state names have _ that separate control names
  1088. //-----------------------------------------------------------------------------
  1089. void CDmObjSerializer::ComputeDeltaStateComputationList( CUtlVector< CUtlVector< int > > &dependentDeltaList )
  1090. {
  1091. // Do all combinations in order of dimensionality, lowest dimension first
  1092. for ( int i = 0; i < nDeltas; ++i )
  1093. {
  1094. compList[i].m_nDeltaIndex = i;
  1095. compList[i].m_nDimensionality = ComputeDeltaStateDimensionality( i );
  1096. }
  1097. qsort( compList.Base(), nCount, sizeof(DeltaComputation_t), DeltaStateLessFunc );
  1098. }
  1099. {
  1100. CUtlVector< CUtlString > atomicControls;
  1101. deltaStateUsage.SetCount( nCount );
  1102. // Build a list of atomic controls
  1103. int nCurrentDelta;
  1104. for ( nCurrentDelta = 0; nCurrentDelta < nCount; ++nCurrentDelta )
  1105. {
  1106. if ( pInfo[nCurrentDelta].m_nDimensionality != 1 )
  1107. break;
  1108. int j = atomicControls.AddToTail( GetDeltaState( pInfo[nCurrentDelta].m_nDeltaIndex )->GetName() );
  1109. deltaStateUsage[ nCurrentDelta ].AddToTail( j );
  1110. }
  1111. for ( ; nCurrentDelta < nCount; ++nCurrentDelta )
  1112. {
  1113. CDmeVertexDeltaData *pDeltaState = GetDeltaState( pInfo[nCurrentDelta].m_nDeltaIndex );
  1114. int nLen = Q_strlen( pDeltaState->GetName() );
  1115. char *pTempBuf = (char*)_alloca( nLen + 1 );
  1116. memcpy( pTempBuf, pDeltaState->GetName(), nLen+1 );
  1117. char *pNext;
  1118. for ( char *pUnderBar = pTempBuf; pUnderBar; pUnderBar = pNext )
  1119. {
  1120. pNext = strchr( pUnderBar, '_' );
  1121. if ( pNext )
  1122. {
  1123. *pNext = 0;
  1124. ++pNext;
  1125. }
  1126. // Find this name in the list of strings
  1127. int j;
  1128. int nControlCount = atomicControls.Count();
  1129. for ( j = 0; j < nControlCount; ++j )
  1130. {
  1131. if ( !Q_stricmp( pUnderBar, atomicControls[j] ) )
  1132. break;
  1133. }
  1134. if ( j == nControlCount )
  1135. {
  1136. j = atomicControls.AddToTail( pUnderBar );
  1137. }
  1138. deltaStateUsage[ nCurrentDelta ].AddToTail( j );
  1139. }
  1140. deltaStateUsage[ nCurrentDelta ].Sort( DeltaStateUsageLessFunc );
  1141. }
  1142. }
  1143. //-----------------------------------------------------------------------------
  1144. //
  1145. //-----------------------------------------------------------------------------
  1146. void CDmObjSerializer::ComputeDependentUsage( CUtlVector< CUtlVector< int > > &deltaUsage )
  1147. {
  1148. const int nDeltas = m_deltas.GetNumStrings();
  1149. compList.EnsureCount( nDeltas );
  1150. CUtlVector< CUtlVector< int > > deltaStateUsage;
  1151. const int nCount( compList.Count() );
  1152. BuildAtomicControlLists( nCount, compList.Base(), deltaStateUsage );
  1153. // Now build up a list of dependent delta states based on usage
  1154. // NOTE: Usage is sorted in ascending order.
  1155. for ( int i = 1; i < nCount; ++i )
  1156. {
  1157. int nUsageCount1 = deltaStateUsage[i].Count();
  1158. for ( int j = 0; j < i; ++j )
  1159. {
  1160. // At the point they have the same dimensionality, no more need to check
  1161. if ( compList[j].m_nDimensionality == compList[i].m_nDimensionality )
  1162. break;
  1163. int ii = 0;
  1164. bool bSubsetFound = true;
  1165. int nUsageCount2 = deltaStateUsage[j].Count();
  1166. for ( int ji = 0; ji < nUsageCount2; ++ji )
  1167. {
  1168. for ( bSubsetFound = false; ii < nUsageCount1; ++ii )
  1169. {
  1170. if ( deltaStateUsage[j][ji] == deltaStateUsage[i][ii] )
  1171. {
  1172. ++ii;
  1173. bSubsetFound = true;
  1174. break;
  1175. }
  1176. if ( deltaStateUsage[j][ji] < deltaStateUsage[i][ii] )
  1177. break;
  1178. }
  1179. if ( !bSubsetFound )
  1180. break;
  1181. }
  1182. if ( bSubsetFound )
  1183. {
  1184. compList[i].m_DependentDeltas.AddToTail( compList[j].m_nDeltaIndex );
  1185. }
  1186. }
  1187. }
  1188. }
  1189. */