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.

1231 lines
30 KiB

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