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.

1175 lines
29 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <malloc.h>
  11. #include "mapdoc.h"
  12. #include "MapWorld.h"
  13. #include "Material.h"
  14. #include "Render2D.h"
  15. #include "Render3D.h"
  16. #include "StudioModel.h"
  17. #include "ViewerSettings.h"
  18. #include "materialsystem/imesh.h"
  19. #include "TextureSystem.h"
  20. #include "bone_setup.h"
  21. #include "IStudioRender.h"
  22. #include "GlobalFunctions.h"
  23. #include "UtlMemory.h"
  24. #include "utldict.h"
  25. #include "bone_accessor.h"
  26. #include "optimize.h"
  27. #include "filesystem.h"
  28. #include "Hammer.h"
  29. #include "HammerVGui.h"
  30. #include <VGuiMatSurface/IMatSystemSurface.h>
  31. #include "mapview2d.h"
  32. #include "mapdefs.h"
  33. #include "camera.h"
  34. #include "options.h"
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include <tier0/memdbgon.h>
  37. #pragma warning(disable : 4244) // double to float
  38. //-----------------------------------------------------------------------------
  39. // Purpose: Monitors the filesystem for changes to model files and flushes
  40. // any stuff in memory for the model if necessary.
  41. //-----------------------------------------------------------------------------
  42. class CStudioFileChangeWatcher : private CFileChangeWatcher::ICallbacks
  43. {
  44. public:
  45. void Init();
  46. void Update(); // Call this periodically to update.
  47. private:
  48. // CFileChangeWatcher::ICallbacks..
  49. virtual void OnFileChange( const char *pRelativeFilename, const char *pFullFilename );
  50. private:
  51. CFileChangeWatcher m_Watcher;
  52. CUtlDict<int,int> m_ChangedModels;
  53. };
  54. static CStudioFileChangeWatcher g_StudioFileChangeWatcher;
  55. Vector g_lightvec; // light vector in model reference frame
  56. Vector g_blightvec[MAXSTUDIOBONES]; // light vectors in bone reference frames
  57. int g_ambientlight; // ambient world light
  58. float g_shadelight; // direct world light
  59. Vector g_lightcolor;
  60. bool g_bUpdateBones2D = true;
  61. //-----------------------------------------------------------------------------
  62. // Model meshes themselves are cached to avoid redundancy. There should never be
  63. // more than one copy of a given studio model in memory at once.
  64. //-----------------------------------------------------------------------------
  65. ModelCache_t CStudioModelCache::m_Cache[1024];
  66. int CStudioModelCache::m_nItems = 0;
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Find a model in the cache. Returns null if it's not in the cache.
  69. //-----------------------------------------------------------------------------
  70. StudioModel *CStudioModelCache::FindModel(const char *pszModelPath)
  71. {
  72. char testPath[MAX_PATH];
  73. V_strncpy( testPath, pszModelPath, sizeof( testPath ) );
  74. V_FixSlashes( testPath );
  75. //
  76. // First look for the model in the cache. If it's there, increment the
  77. // reference count and return a pointer to the cached model.
  78. //
  79. for (int i = 0; i < m_nItems; i++)
  80. {
  81. char testPath2[MAX_PATH];
  82. V_strncpy( testPath2, m_Cache[i].pszPath, sizeof( testPath2 ) );
  83. V_FixSlashes( testPath2 );
  84. if (!stricmp(testPath, testPath2))
  85. {
  86. m_Cache[i].nRefCount++;
  87. return(m_Cache[i].pModel);
  88. }
  89. }
  90. return NULL;
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose: Returns an instance of a particular studio model. If the model is
  94. // in the cache, a pointer to that model is returned. If not, a new one
  95. // is created and added to the cache.
  96. // Input : pszModelPath - Full path of the .MDL file.
  97. //-----------------------------------------------------------------------------
  98. StudioModel *CStudioModelCache::CreateModel(const char *pszModelPath)
  99. {
  100. StudioModel *pTest = FindModel( pszModelPath );
  101. if ( pTest )
  102. return pTest;
  103. //
  104. // If it isn't there, try to create one.
  105. //
  106. StudioModel *pModel = new StudioModel;
  107. if (pModel != NULL)
  108. {
  109. bool bLoaded = pModel->LoadModel(pszModelPath);
  110. if (bLoaded)
  111. {
  112. bLoaded = pModel->PostLoadModel(pszModelPath);
  113. }
  114. if (!bLoaded)
  115. {
  116. delete pModel;
  117. pModel = NULL;
  118. }
  119. }
  120. //
  121. // If we successfully created it, add it to the cache.
  122. //
  123. if (pModel != NULL)
  124. {
  125. CStudioModelCache::AddModel(pModel, pszModelPath);
  126. }
  127. return(pModel);
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose: Adds the model to the cache, setting the reference count to one.
  131. // Input : pModel - Model to add to the cache.
  132. // pszModelPath - The full path of the .MDL file, which is used as a
  133. // key in the model cache.
  134. // Output : Returns TRUE if the model was successfully added, FALSE if we ran
  135. // out of memory trying to add the model to the cache.
  136. //-----------------------------------------------------------------------------
  137. BOOL CStudioModelCache::AddModel(StudioModel *pModel, const char *pszModelPath)
  138. {
  139. //
  140. // Copy the model pointer.
  141. //
  142. m_Cache[m_nItems].pModel = pModel;
  143. //
  144. // Allocate space for and copy the model path.
  145. //
  146. m_Cache[m_nItems].pszPath = new char [strlen(pszModelPath) + 1];
  147. if (m_Cache[m_nItems].pszPath != NULL)
  148. {
  149. strcpy(m_Cache[m_nItems].pszPath, pszModelPath);
  150. }
  151. else
  152. {
  153. return(FALSE);
  154. }
  155. m_Cache[m_nItems].nRefCount = 1;
  156. m_nItems++;
  157. return(TRUE);
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose: Advances the animation of all models in the cache for the given interval.
  161. // Input : flInterval - delta time in seconds.
  162. //-----------------------------------------------------------------------------
  163. void CStudioModelCache::AdvanceAnimation(float flInterval)
  164. {
  165. for (int i = 0; i < m_nItems; i++)
  166. {
  167. m_Cache[i].pModel->AdvanceFrame(flInterval);
  168. }
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose: Increments the reference count on a model in the cache. Called by
  172. // client code when a pointer to the model is copied, making that
  173. // reference independent.
  174. // Input : pModel - Model for which to increment the reference count.
  175. //-----------------------------------------------------------------------------
  176. void CStudioModelCache::AddRef(StudioModel *pModel)
  177. {
  178. for (int i = 0; i < m_nItems; i++)
  179. {
  180. if (m_Cache[i].pModel == pModel)
  181. {
  182. m_Cache[i].nRefCount++;
  183. return;
  184. }
  185. }
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose: Called by client code to release an instance of a model. If the
  189. // model's reference count is zero, the model is freed.
  190. // Input : pModel - Pointer to the model to release.
  191. //-----------------------------------------------------------------------------
  192. void CStudioModelCache::Release(StudioModel *pModel)
  193. {
  194. for (int i = 0; i < m_nItems; i++)
  195. {
  196. if (m_Cache[i].pModel == pModel)
  197. {
  198. m_Cache[i].nRefCount--;
  199. Assert(m_Cache[i].nRefCount >= 0);
  200. //
  201. // If this model is no longer referenced, free it and remove it
  202. // from the cache.
  203. //
  204. if (m_Cache[i].nRefCount <= 0)
  205. {
  206. //
  207. // Free the path, which was allocated by AddModel.
  208. //
  209. delete [] m_Cache[i].pszPath;
  210. delete m_Cache[i].pModel;
  211. //
  212. // Decrement the item count and copy the last element in the cache over
  213. // this element.
  214. //
  215. m_nItems--;
  216. m_Cache[i].pModel = m_Cache[m_nItems].pModel;
  217. m_Cache[i].pszPath = m_Cache[m_nItems].pszPath;
  218. m_Cache[i].nRefCount = m_Cache[m_nItems].nRefCount;
  219. }
  220. break;
  221. }
  222. }
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose: Watch for changes to studio models and reload them if necessary.
  226. //-----------------------------------------------------------------------------
  227. void CStudioFileChangeWatcher::Init()
  228. {
  229. m_Watcher.Init( this );
  230. char searchPaths[1024 * 16];
  231. if ( g_pFullFileSystem->GetSearchPath( "GAME", false, searchPaths, sizeof( searchPaths ) ) > 0 )
  232. {
  233. CUtlVector<char*> searchPathList;
  234. V_SplitString( searchPaths, ";", searchPathList );
  235. for ( int i=0; i < searchPathList.Count(); i++ )
  236. {
  237. m_Watcher.AddDirectory( searchPathList[i], "models", true );
  238. }
  239. searchPathList.PurgeAndDeleteElements();
  240. }
  241. else
  242. {
  243. Warning( "Error in GetSearchPath. Hammer will not automatically reload modified models." );
  244. }
  245. }
  246. void CStudioFileChangeWatcher::OnFileChange( const char *pRelativeFilename, const char *pFullFilename )
  247. {
  248. char relativeFilename[MAX_PATH];
  249. V_ComposeFileName( "models", pRelativeFilename, relativeFilename, sizeof( relativeFilename ) );
  250. V_FixSlashes( relativeFilename );
  251. // Check the cache.
  252. const char *pExt = V_GetFileExtension( relativeFilename );
  253. if ( !pExt )
  254. return;
  255. if ( V_stricmp( pExt, "mdl" ) == 0 ||
  256. V_stricmp( pExt, "vtx" ) == 0 ||
  257. V_stricmp( pExt, "phy" ) == 0 ||
  258. V_stricmp( pExt, "vvd" ) == 0 )
  259. {
  260. // Ok, it's at least related to a model. Flush out the model.
  261. char tempFilename[MAX_PATH];
  262. V_strncpy( tempFilename, relativeFilename, pExt - relativeFilename );
  263. // Now it might have a "dx80" or "dx90" or some other extension. Get rid of that too.
  264. const char *pTestFilename = V_UnqualifiedFileName( tempFilename );
  265. pExt = V_GetFileExtension( pTestFilename );
  266. char filename[MAX_PATH];
  267. if ( pExt )
  268. V_strncpy( filename, tempFilename, pExt - tempFilename );
  269. else
  270. V_strncpy( filename, tempFilename, sizeof( filename ) );
  271. // Now we've got the filename with any extension or "dx80"-type stuff at the end.
  272. V_strncat( filename, ".mdl", sizeof( filename ) );
  273. // Queue up the list of changes because if they copied all the files for a model,
  274. // we'd like to only reload it once.
  275. if ( m_ChangedModels.Find( filename ) == m_ChangedModels.InvalidIndex() )
  276. m_ChangedModels.Insert( filename );
  277. }
  278. }
  279. void CStudioFileChangeWatcher::Update()
  280. {
  281. if ( !g_pMDLCache )
  282. return;
  283. m_Watcher.Update();
  284. if ( m_ChangedModels.Count() > 0 )
  285. {
  286. // Reload whatever models were changed.
  287. for ( int i=m_ChangedModels.First(); i != m_ChangedModels.InvalidIndex(); i=m_ChangedModels.Next( i ) )
  288. {
  289. const char *pName = m_ChangedModels.GetElementName( i );
  290. MDLHandle_t hModel = g_pMDLCache->FindMDL( pName );
  291. g_pMDLCache->Flush( hModel );
  292. g_pMDLCache->ResetErrorModelStatus( hModel );
  293. // If we have it in the StudioModel cache, flush its data.
  294. StudioModel *pTest = CStudioModelCache::FindModel( pName );
  295. if ( pTest )
  296. {
  297. pTest->FreeModel();
  298. pTest->LoadModel( pName );
  299. }
  300. }
  301. m_ChangedModels.Purge();
  302. for ( int i=0; i < CMapDoc::GetDocumentCount(); i++ )
  303. {
  304. CMapDoc *pDoc = CMapDoc::GetDocument( i );
  305. pDoc->GetMapWorld()->CalcBounds( true );
  306. }
  307. }
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose: Loads up the IStudioRender interface.
  311. // Output : Returns true on success, false on failure.
  312. //-----------------------------------------------------------------------------
  313. bool StudioModel::Initialize()
  314. {
  315. return true;
  316. }
  317. void StudioModel::Shutdown( void )
  318. {
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: Constructor.
  322. //-----------------------------------------------------------------------------
  323. StudioModel::StudioModel(void) : m_pModelName(0)
  324. {
  325. int i;
  326. m_origin.Init();
  327. m_angles.Init();
  328. m_sequence = 0;
  329. m_cycle = 0;
  330. m_bodynum = 0;
  331. m_skinnum = 0;
  332. for (i = 0; i < sizeof(m_controller) / sizeof(m_controller[0]); i++)
  333. {
  334. m_controller[i] = 0;
  335. }
  336. for (i = 0; i < sizeof(m_poseParameter) / sizeof(m_poseParameter[0]); i++)
  337. {
  338. m_poseParameter[i] = 0;
  339. }
  340. m_mouth = 0;
  341. m_MDLHandle = MDLHANDLE_INVALID;
  342. m_pModel = NULL;
  343. m_pStudioHdr = NULL;
  344. m_pPosePos = NULL;
  345. m_pPoseAng = NULL;
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose: Destructor. Frees dynamically allocated data.
  349. //-----------------------------------------------------------------------------
  350. StudioModel::~StudioModel(void)
  351. {
  352. FreeModel();
  353. if (m_pModelName)
  354. {
  355. delete[] m_pModelName;
  356. }
  357. delete m_pStudioHdr;
  358. delete []m_pPosePos;
  359. delete []m_pPoseAng;
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose: Sets the Euler angles for the model.
  363. // Input : fAngles - A pointer to engine PITCH, YAW, and ROLL angles.
  364. //-----------------------------------------------------------------------------
  365. void StudioModel::SetAngles(QAngle& pfAngles)
  366. {
  367. m_angles[PITCH] = pfAngles[PITCH];
  368. m_angles[YAW] = pfAngles[YAW];
  369. m_angles[ROLL] = pfAngles[ROLL];
  370. }
  371. void StudioModel::AdvanceFrame( float dt )
  372. {
  373. if (dt > 0.1)
  374. dt = 0.1f;
  375. CStudioHdr *pStudioHdr = GetStudioHdr();
  376. float t = Studio_Duration( pStudioHdr, m_sequence, m_poseParameter );
  377. if (t > 0)
  378. {
  379. m_cycle += dt / t;
  380. // wrap
  381. m_cycle -= (int)(m_cycle);
  382. }
  383. else
  384. {
  385. m_cycle = 0;
  386. }
  387. }
  388. void StudioModel::SetUpBones( bool bUpdatePose, matrix3x4_t *pBoneToWorld )
  389. {
  390. CStudioHdr *pStudioHdr = GetStudioHdr();
  391. if ( m_pPosePos == NULL )
  392. {
  393. bUpdatePose = true;
  394. m_pPosePos = new Vector[pStudioHdr->numbones()] ;
  395. m_pPoseAng = new Quaternion[pStudioHdr->numbones()];
  396. }
  397. if ( bUpdatePose )
  398. {
  399. IBoneSetup boneSetup( pStudioHdr, BONE_USED_BY_ANYTHING, m_poseParameter );
  400. boneSetup.InitPose( m_pPosePos, m_pPoseAng );
  401. boneSetup.AccumulatePose( m_pPosePos, m_pPoseAng, m_sequence, m_cycle, 1.0f, 0.0f, NULL );
  402. }
  403. mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
  404. matrix3x4_t cameraTransform;
  405. AngleMatrix( m_angles, cameraTransform );
  406. cameraTransform[0][3] = m_origin[0];
  407. cameraTransform[1][3] = m_origin[1];
  408. cameraTransform[2][3] = m_origin[2];
  409. for (int i = 0; i < pStudioHdr->numbones(); i++)
  410. {
  411. if ( CalcProceduralBone( pStudioHdr, i, CBoneAccessor( pBoneToWorld ) ))
  412. continue;
  413. matrix3x4_t bonematrix;
  414. QuaternionMatrix( m_pPoseAng[i], bonematrix );
  415. bonematrix[0][3] = m_pPosePos[i][0];
  416. bonematrix[1][3] = m_pPosePos[i][1];
  417. bonematrix[2][3] = m_pPosePos[i][2];
  418. if (pbones[i].parent == -1)
  419. {
  420. ConcatTransforms( cameraTransform, bonematrix, pBoneToWorld[ i ] );
  421. }
  422. else
  423. {
  424. ConcatTransforms ( pBoneToWorld[ pbones[i].parent ], bonematrix, pBoneToWorld[ i ] );
  425. }
  426. }
  427. }
  428. /*
  429. =================
  430. StudioModel::SetupModel
  431. based on the body part, figure out which mesh it should be using.
  432. inputs:
  433. currententity
  434. outputs:
  435. pstudiomesh
  436. pmdl
  437. =================
  438. */
  439. void StudioModel::SetupModel ( int bodypart )
  440. {
  441. int index;
  442. CStudioHdr *pStudioHdr = GetStudioHdr();
  443. if (bodypart > pStudioHdr->numbodyparts())
  444. {
  445. // Con_DPrintf ("StudioModel::SetupModel: no such bodypart %d\n", bodypart);
  446. bodypart = 0;
  447. }
  448. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( bodypart );
  449. index = m_bodynum / pbodypart->base;
  450. index = index % pbodypart->nummodels;
  451. m_pModel = pbodypart->pModel( index );
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. //-----------------------------------------------------------------------------
  456. void StudioModel::DrawModel3D( CRender3D *pRender, float flAlpha, bool bWireframe )
  457. {
  458. studiohdr_t *pStudioHdr = GetStudioRenderHdr();
  459. if (!pStudioHdr)
  460. return;
  461. if (pStudioHdr->numbodyparts == 0)
  462. return;
  463. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  464. DrawModelInfo_t info;
  465. info.m_pStudioHdr = pStudioHdr;
  466. info.m_pHardwareData = GetHardwareData();
  467. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  468. info.m_Skin = m_skinnum;
  469. info.m_Body = m_bodynum;
  470. info.m_HitboxSet = 0;
  471. info.m_pClientEntity = NULL;
  472. info.m_Lod = -1;
  473. info.m_pColorMeshes = NULL;
  474. if ( pRender->IsInLocalTransformMode() )
  475. {
  476. // WHACKY HACKY
  477. Vector orgOrigin = m_origin;
  478. QAngle orgAngles = m_angles;
  479. VMatrix matrix;
  480. pRender->GetLocalTranform(matrix);
  481. // baseclass rotates the origin
  482. matrix.V3Mul( orgOrigin, m_origin );
  483. matrix3x4_t fCurrentMatrix,fMatrixNew;
  484. AngleMatrix(m_angles, fCurrentMatrix);
  485. ConcatTransforms(matrix.As3x4(), fCurrentMatrix, fMatrixNew);
  486. QAngle newAngles;
  487. MatrixAngles(fMatrixNew, m_angles);
  488. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  489. SetUpBones( false, boneToWorld );
  490. pRender->DrawModel( &info, boneToWorld, m_origin, flAlpha, bWireframe );
  491. m_origin = orgOrigin;
  492. m_angles = orgAngles;
  493. }
  494. else
  495. {
  496. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  497. SetUpBones( true, boneToWorld );
  498. pRender->DrawModel( &info, boneToWorld, m_origin, flAlpha, bWireframe );
  499. if ( Options.general.bShowCollisionModels )
  500. {
  501. VMatrix mViewMatrix = SetupMatrixOrgAngles( m_origin, m_angles );
  502. pRender->DrawCollisionModel( m_MDLHandle, mViewMatrix );
  503. }
  504. }
  505. }
  506. void StudioModel::DrawModel2D( CRender2D *pRender, float flAlpha, bool bWireFrame )
  507. {
  508. studiohdr_t *pStudioHdr = GetStudioRenderHdr();
  509. if (!pStudioHdr)
  510. return;
  511. if (pStudioHdr->numbodyparts == 0)
  512. return;
  513. Vector orgOrigin = m_origin;
  514. QAngle orgAngles = m_angles;
  515. DrawModelInfo_t info;
  516. info.m_pStudioHdr = pStudioHdr;
  517. info.m_pHardwareData = GetHardwareData();
  518. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  519. info.m_Skin = m_skinnum;
  520. info.m_Body = m_bodynum;
  521. info.m_HitboxSet = 0;
  522. info.m_pClientEntity = NULL;
  523. info.m_Lod = -1;
  524. info.m_pColorMeshes = NULL;
  525. bool bTransform = pRender->IsInLocalTransformMode();
  526. if ( bTransform )
  527. {
  528. // WHACKY HACKY
  529. VMatrix matrix; pRender->GetLocalTranform(matrix);
  530. // baseclass rotates the origin
  531. matrix.V3Mul( orgOrigin, m_origin );
  532. matrix3x4_t fCurrentMatrix,fMatrixNew;
  533. AngleMatrix(m_angles, fCurrentMatrix);
  534. ConcatTransforms(matrix.As3x4(), fCurrentMatrix, fMatrixNew);
  535. QAngle newAngles;
  536. MatrixAngles(fMatrixNew, m_angles);
  537. }
  538. if ( Options.general.bShowCollisionModels )
  539. {
  540. VMatrix mViewMatrix = SetupMatrixOrgAngles( orgOrigin, orgAngles );
  541. pRender->DrawCollisionModel( m_MDLHandle, mViewMatrix );
  542. }
  543. else
  544. {
  545. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  546. SetUpBones( false, boneToWorld );
  547. pRender->DrawModel( &info, boneToWorld, m_origin, flAlpha, bWireFrame );
  548. }
  549. if ( bTransform )
  550. {
  551. // restore original position and angles
  552. m_origin = orgOrigin;
  553. m_angles = orgAngles;
  554. }
  555. }
  556. //-----------------------------------------------------------------------------
  557. // It's translucent if all its materials are translucent
  558. //-----------------------------------------------------------------------------
  559. bool StudioModel::IsTranslucent()
  560. {
  561. // garymcthack - shouldn't crack hardwaredata
  562. studiohwdata_t *pHardwareData = GetHardwareData();
  563. if ( pHardwareData == NULL )
  564. return false;
  565. int lodID;
  566. for( lodID = pHardwareData->m_RootLOD; lodID < pHardwareData->m_NumLODs; lodID++ )
  567. {
  568. for (int i = 0; i < pHardwareData->m_pLODs[lodID].numMaterials; ++i)
  569. {
  570. if (!pHardwareData->m_pLODs[lodID].ppMaterials[i]->IsTranslucent())
  571. return false;
  572. }
  573. }
  574. return true;
  575. }
  576. //-----------------------------------------------------------------------------
  577. // Purpose: Frees the model data and releases textures from OpenGL.
  578. //-----------------------------------------------------------------------------
  579. void StudioModel::FreeModel(void)
  580. {
  581. /*int nRef = */g_pMDLCache->Release( m_MDLHandle );
  582. // Assert( nRef == 0 );
  583. m_MDLHandle = MDLHANDLE_INVALID;
  584. m_pModel = NULL;
  585. }
  586. CStudioHdr *StudioModel::GetStudioHdr() const
  587. {
  588. // return g_pMDLCache->GetStudioHdr( m_MDLHandle );
  589. if (m_pStudioHdr->IsValid())
  590. return m_pStudioHdr;
  591. studiohdr_t *hdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  592. m_pStudioHdr->Init( hdr );
  593. Assert(m_pStudioHdr->IsValid());
  594. return m_pStudioHdr;
  595. }
  596. studiohdr_t *StudioModel::GetStudioRenderHdr() const
  597. {
  598. CStudioHdr *pStudioHdr = GetStudioHdr();
  599. if (pStudioHdr)
  600. {
  601. return (studiohdr_t *)pStudioHdr->GetRenderHdr();
  602. }
  603. return NULL;
  604. }
  605. studiohwdata_t* StudioModel::GetHardwareData()
  606. {
  607. return g_pMDLCache->GetHardwareData( m_MDLHandle );
  608. }
  609. bool StudioModel::LoadModel( const char *modelname )
  610. {
  611. // Load the MDL file data
  612. Assert( m_MDLHandle == MDLHANDLE_INVALID );
  613. // for easier fall through cleanup
  614. m_MDLHandle = MDLHANDLE_INVALID;
  615. if ( !g_pStudioRender || !modelname )
  616. return false;
  617. // In the case of restore, m_pModelName == modelname
  618. if (m_pModelName != modelname)
  619. {
  620. // Copy over the model name; we'll need it later...
  621. if (m_pModelName)
  622. {
  623. delete[] m_pModelName;
  624. }
  625. m_pModelName = new char[strlen(modelname) + 1];
  626. strcpy( m_pModelName, modelname );
  627. }
  628. m_MDLHandle = g_pMDLCache->FindMDL( modelname );
  629. if (m_MDLHandle == MDLHANDLE_INVALID)
  630. return false;
  631. // Cache a bunch of stuff into memory
  632. g_pMDLCache->GetStudioHdr( m_MDLHandle );
  633. g_pMDLCache->GetHardwareData( m_MDLHandle );
  634. if (m_pStudioHdr)
  635. {
  636. delete m_pStudioHdr;
  637. m_pStudioHdr = NULL;
  638. }
  639. m_pStudioHdr = new CStudioHdr;
  640. return true;
  641. }
  642. bool StudioModel::PostLoadModel(const char *modelname)
  643. {
  644. CStudioHdr *pStudioHdr = GetStudioHdr();
  645. if (pStudioHdr == NULL)
  646. {
  647. return(false);
  648. }
  649. SetSequence (0);
  650. for (int n = 0; n < pStudioHdr->numbodyparts(); n++)
  651. {
  652. if (SetBodygroup (n, 0) < 0)
  653. {
  654. return false;
  655. }
  656. }
  657. SetSkin (0);
  658. /*
  659. Vector mins, maxs;
  660. ExtractBbox (mins, maxs);
  661. if (mins[2] < 5.0f)
  662. m_origin[2] = -mins[2];
  663. */
  664. return true;
  665. }
  666. //-----------------------------------------------------------------------------
  667. // Purpose:
  668. //-----------------------------------------------------------------------------
  669. int StudioModel::GetSequenceCount( void )
  670. {
  671. CStudioHdr *pStudioHdr = GetStudioHdr();
  672. return pStudioHdr->GetNumSeq();
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Purpose:
  676. // Input : nIndex -
  677. // szName -
  678. //-----------------------------------------------------------------------------
  679. void StudioModel::GetSequenceName( int nIndex, char *szName )
  680. {
  681. CStudioHdr *pStudioHdr = GetStudioHdr();
  682. if (nIndex < pStudioHdr->GetNumSeq())
  683. {
  684. strcpy(szName, pStudioHdr->pSeqdesc(nIndex).pszLabel());
  685. }
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose: Returns the index of the current sequence.
  689. //-----------------------------------------------------------------------------
  690. int StudioModel::GetSequence( )
  691. {
  692. return m_sequence;
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose: Sets the current sequence by index.
  696. //-----------------------------------------------------------------------------
  697. int StudioModel::SetSequence( int iSequence )
  698. {
  699. CStudioHdr *pStudioHdr = GetStudioHdr();
  700. if (iSequence > pStudioHdr->GetNumSeq())
  701. return m_sequence;
  702. m_sequence = iSequence;
  703. m_cycle = 0;
  704. return m_sequence;
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Purpose: Rotates the given bounding box by the given angles and computes the
  708. // bounds of the rotated box. This is used to take the rotation angles
  709. // into consideration when returning the bounding box. Note that this
  710. // can produce a larger than optimal bounding box.
  711. // Input : Mins -
  712. // Maxs -
  713. // Angles -
  714. //-----------------------------------------------------------------------------
  715. void StudioModel::RotateBbox(Vector &Mins, Vector &Maxs, const QAngle &Angles)
  716. {
  717. Vector Points[8];
  718. PointsFromBox( Mins, Maxs, Points );
  719. //
  720. // Rotate the corner points by the specified angles, in the same
  721. // order that our Render code uses.
  722. //
  723. VMatrix mMatrix;
  724. mMatrix.SetupMatrixOrgAngles( vec3_origin, Angles );
  725. matrix3x4_t fMatrix2 = mMatrix.As3x4();
  726. Vector RotatedPoints[8];
  727. for (int i = 0; i < 8; i++)
  728. {
  729. VectorRotate(Points[i], fMatrix2, RotatedPoints[i]);
  730. }
  731. //
  732. // Calculate the new mins and maxes.
  733. //
  734. for (int i = 0; i < 8; i++)
  735. {
  736. for (int nDim = 0; nDim < 3; nDim++)
  737. {
  738. if ((i == 0) || (RotatedPoints[i][nDim] < Mins[nDim]))
  739. {
  740. Mins[nDim] = RotatedPoints[i][nDim];
  741. }
  742. if ((i == 0) || (RotatedPoints[i][nDim] > Maxs[nDim]))
  743. {
  744. Maxs[nDim] = RotatedPoints[i][nDim];
  745. }
  746. }
  747. }
  748. }
  749. //-----------------------------------------------------------------------------
  750. // Purpose:
  751. // Input : mins -
  752. // maxs -
  753. //-----------------------------------------------------------------------------
  754. void StudioModel::ExtractBbox(Vector &mins, Vector &maxs)
  755. {
  756. CStudioHdr *pStudioHdr = GetStudioHdr();
  757. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( m_sequence );
  758. mins = seqdesc.bbmin;
  759. maxs = seqdesc.bbmax;
  760. RotateBbox(mins, maxs, m_angles);
  761. }
  762. void StudioModel::ExtractClippingBbox( Vector& mins, Vector& maxs )
  763. {
  764. studiohdr_t *pStudioHdr = GetStudioRenderHdr();
  765. mins[0] = pStudioHdr->view_bbmin[0];
  766. mins[1] = pStudioHdr->view_bbmin[1];
  767. mins[2] = pStudioHdr->view_bbmin[2];
  768. maxs[0] = pStudioHdr->view_bbmax[0];
  769. maxs[1] = pStudioHdr->view_bbmax[1];
  770. maxs[2] = pStudioHdr->view_bbmax[2];
  771. }
  772. void StudioModel::ExtractMovementBbox( Vector& mins, Vector& maxs )
  773. {
  774. studiohdr_t *pStudioHdr = GetStudioRenderHdr();
  775. mins[0] = pStudioHdr->hull_min[0];
  776. mins[1] = pStudioHdr->hull_min[1];
  777. mins[2] = pStudioHdr->hull_min[2];
  778. maxs[0] = pStudioHdr->hull_max[0];
  779. maxs[1] = pStudioHdr->hull_max[1];
  780. maxs[2] = pStudioHdr->hull_max[2];
  781. }
  782. void StudioModel::GetSequenceInfo( float *pflFrameRate, float *pflGroundSpeed )
  783. {
  784. CStudioHdr *pStudioHdr = GetStudioHdr();
  785. float t = Studio_Duration( pStudioHdr, m_sequence, m_poseParameter );
  786. if (t > 0)
  787. {
  788. *pflFrameRate = 1.0 / t;
  789. *pflGroundSpeed = 0; // sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] );
  790. // *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1);
  791. }
  792. else
  793. {
  794. *pflFrameRate = 1.0;
  795. *pflGroundSpeed = 0.0;
  796. }
  797. }
  798. void StudioModel::SetOrigin( float x, float y, float z )
  799. {
  800. m_origin[0] = x;
  801. m_origin[1] = y;
  802. m_origin[2] = z;
  803. }
  804. void StudioModel::SetOrigin( const Vector &v )
  805. {
  806. m_origin = v;
  807. }
  808. void StudioModel::GetOrigin( float &x, float &y, float &z )
  809. {
  810. x = m_origin[0];
  811. y = m_origin[1];
  812. z = m_origin[2];
  813. }
  814. void StudioModel::GetOrigin( Vector &v )
  815. {
  816. v = m_origin;
  817. }
  818. int StudioModel::SetBodygroup( int iGroup, int iValue )
  819. {
  820. CStudioHdr *pStudioHdr = GetStudioHdr();
  821. if (!pStudioHdr)
  822. return 0;
  823. if (iGroup > pStudioHdr->numbodyparts())
  824. return -1;
  825. mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( iGroup );
  826. if ((pbodypart->base == 0) || (pbodypart->nummodels == 0))
  827. {
  828. return -1;
  829. }
  830. int iCurrent = (m_bodynum / pbodypart->base) % pbodypart->nummodels;
  831. if (iValue >= pbodypart->nummodels)
  832. return iCurrent;
  833. m_bodynum = (m_bodynum - (iCurrent * pbodypart->base) + (iValue * pbodypart->base));
  834. return iValue;
  835. }
  836. int StudioModel::SetSkin( int iValue )
  837. {
  838. CStudioHdr *pStudioHdr = GetStudioHdr();
  839. if (!pStudioHdr)
  840. return 0;
  841. if (iValue >= pStudioHdr->numskinfamilies())
  842. {
  843. iValue = 0;
  844. }
  845. m_skinnum = iValue;
  846. return iValue;
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Purpose:
  850. // Input : pRender -
  851. //-----------------------------------------------------------------------------
  852. /*void StudioModel::DrawModel2D(CRender2D *pRender)
  853. {
  854. studiohdr_t *pStudioHdr = GetStudioRenderHdr();
  855. CMapView2D *pView = (CMapView2D*) pRender->GetView();
  856. DrawModelInfo_t info;
  857. ZeroMemory(&info, sizeof(info));
  858. info.m_pStudioHdr = pStudioHdr;
  859. info.m_pHardwareData = GetHardwareData();
  860. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  861. info.m_Skin = m_skinnum;
  862. info.m_Body = m_bodynum;
  863. info.m_HitboxSet = 0;
  864. info.m_pClientEntity = NULL;
  865. info.m_Lod = -1;
  866. info.m_ppColorMeshes = NULL;
  867. if ( pView->m_fZoom < 3 )
  868. info.m_Lod = 3;
  869. matrix3x4_t *pBoneToWorld = SetUpBones( g_bUpdateBones2D );
  870. GetTriangles_Output_t tris;
  871. g_pStudioRender->GetTriangles( info, tris );
  872. for ( int batchID = 0; batchID < tris.m_MaterialBatches.Count(); batchID++ )
  873. {
  874. GetTriangles_MaterialBatch_t &materialBatch = tris.m_MaterialBatches[batchID];
  875. int numStrips = materialBatch.m_TriListIndices.Count() / 3;
  876. int numVertices = materialBatch.m_Verts.Count();
  877. POINT *points = (POINT*)_alloca( sizeof(POINT) * numVertices );
  878. // translate all vertices
  879. for ( int vertID = 0; vertID < numVertices; vertID++)
  880. {
  881. GetTriangles_Vertex_t &vert = materialBatch.m_Verts[vertID];
  882. const Vector &pos = vert.m_Position;
  883. Vector newPos(0,0,0);
  884. for ( int k = 0; k < vert.m_NumBones; k++ )
  885. {
  886. const matrix3x4_t &poseToWorld = tris.m_PoseToWorld[ vert.m_BoneIndex[k] ];
  887. Vector tmp;
  888. VectorTransform( pos, poseToWorld, tmp );
  889. newPos += vert.m_BoneWeight[k] * tmp;
  890. }
  891. pView->WorldToClient( points[vertID], newPos );
  892. // pRender->TransformPoint3D( points[vertID], newPos );
  893. }
  894. // Send the vertices down to the hardware.
  895. int stripIndex = 0;
  896. for ( int strip = 0; strip < numStrips; strip++ )
  897. {
  898. int ptx[3];
  899. int pty[3];
  900. int numPoints = 0;
  901. POINT lastPt; lastPt.x = lastPt.y = -99999;
  902. for ( int i = 0; i<3; i++ )
  903. {
  904. POINT pt = points[ materialBatch.m_TriListIndices[stripIndex++] ];
  905. if ( pt.x == lastPt.x && pt.y == lastPt.y )
  906. continue;
  907. ptx[numPoints] = pt.x;
  908. pty[numPoints] = pt.y;
  909. lastPt = pt;
  910. numPoints++;
  911. }
  912. // for performance sake bypass the renderer interface, buuuhhh
  913. if ( numPoints == 2 )
  914. {
  915. g_pMatSystemSurface->DrawLine( ptx[0], pty[0], ptx[1], pty[1] );
  916. }
  917. else if ( numPoints == 3 )
  918. {
  919. g_pMatSystemSurface->DrawPolyLine( ptx, pty, 3 );
  920. }
  921. }
  922. }
  923. } */
  924. void InitStudioFileChangeWatcher()
  925. {
  926. g_StudioFileChangeWatcher.Init();
  927. }
  928. void UpdateStudioFileChangeWatcher()
  929. {
  930. g_StudioFileChangeWatcher.Update();
  931. }