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.

904 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "Box3D.h"
  8. #include "GlobalFunctions.h"
  9. #include "MapDefs.h" // dvs: For COORD_NOTINIT
  10. #include "MapDoc.h"
  11. #include "MapEntity.h"
  12. #include "MapStudioModel.h"
  13. #include "Render2D.h"
  14. #include "Render3D.h"
  15. #include "ViewerSettings.h"
  16. #include "hammer.h"
  17. #include "materialsystem/imesh.h"
  18. #include "TextureSystem.h"
  19. #include "Material.h"
  20. #include "Options.h"
  21. #include "camera.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include <tier0/memdbgon.h>
  24. #define STUDIO_RENDER_DISTANCE 400
  25. IMPLEMENT_MAPCLASS(CMapStudioModel)
  26. float CMapStudioModel::m_fRenderDistance = STUDIO_RENDER_DISTANCE;
  27. BOOL CMapStudioModel::m_bAnimateModels = TRUE;
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Factory function. Used for creating a CMapStudioModel from a set
  30. // of string parameters from the FGD file.
  31. // Input : pInfo - Pointer to helper info class which gives us information
  32. // about how to create the class.
  33. // Output : Returns a pointer to the class, NULL if an error occurs.
  34. //-----------------------------------------------------------------------------
  35. CMapClass *CMapStudioModel::CreateMapStudioModel(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  36. {
  37. const char *pszModel = pHelperInfo->GetParameter(0);
  38. //
  39. // If we weren't passed a model name as an argument, get it from our parent
  40. // entity's "model" key.
  41. //
  42. if (pszModel == NULL)
  43. {
  44. pszModel = pParent->GetKeyValue("model");
  45. }
  46. //
  47. // If we have a model name, create a studio model object.
  48. //
  49. if (pszModel != NULL)
  50. {
  51. bool bLightProp = !stricmp(pHelperInfo->GetName(), "lightprop");
  52. bool bOrientedBounds = (bLightProp | !stricmp(pHelperInfo->GetName(), "studioprop"));
  53. return CreateMapStudioModel(pszModel, bOrientedBounds, bLightProp);
  54. }
  55. return(NULL);
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Purpose: Factory function. Creates a CMapStudioModel object from a relative
  59. // path to an MDL file.
  60. // Input : pszModelPath - Relative path to the .MDL file. The path is appended
  61. // to each path in the application search path until the model is found.
  62. // bOrientedBounds - Whether the bounding box should consider the orientation of the model.
  63. // Output : Returns a pointer to the newly created CMapStudioModel object.
  64. //-----------------------------------------------------------------------------
  65. CMapStudioModel *CMapStudioModel::CreateMapStudioModel(const char *pszModelPath, bool bOrientedBounds, bool bReversePitch)
  66. {
  67. CMapStudioModel *pModel = new CMapStudioModel;
  68. pModel->m_pStudioModel = CStudioModelCache::CreateModel(pszModelPath);
  69. if ( pModel->m_pStudioModel )
  70. {
  71. pModel->SetOrientedBounds(bOrientedBounds);
  72. pModel->ReversePitch(bReversePitch);
  73. pModel->CalcBounds();
  74. }
  75. else
  76. {
  77. delete pModel;
  78. pModel = NULL;
  79. }
  80. return(pModel);
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Constructor.
  84. //-----------------------------------------------------------------------------
  85. CMapStudioModel::CMapStudioModel(void)
  86. {
  87. Initialize();
  88. InitViewerSettings();
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose: Destructor. Releases the studio model cache reference.
  92. //-----------------------------------------------------------------------------
  93. CMapStudioModel::~CMapStudioModel(void)
  94. {
  95. if (m_pStudioModel != NULL)
  96. {
  97. CStudioModelCache::Release(m_pStudioModel);
  98. }
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: Called by the renderer before every frame to animate the models.
  102. //-----------------------------------------------------------------------------
  103. void CMapStudioModel::AdvanceAnimation(float flInterval)
  104. {
  105. if (m_bAnimateModels)
  106. {
  107. CStudioModelCache::AdvanceAnimation(flInterval);
  108. }
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose:
  112. // Input : bFullUpdate -
  113. //-----------------------------------------------------------------------------
  114. void CMapStudioModel::CalcBounds(BOOL bFullUpdate)
  115. {
  116. CMapClass::CalcBounds(bFullUpdate);
  117. Vector Mins(0, 0, 0);
  118. Vector Maxs(0, 0, 0);
  119. if (m_pStudioModel != NULL)
  120. {
  121. //
  122. // The 3D bounds are the bounds of the oriented model's first sequence, so that
  123. // frustum culling works properly in the 3D view.
  124. //
  125. QAngle angles;
  126. GetRenderAngles(angles);
  127. m_pStudioModel->SetAngles(angles);
  128. m_pStudioModel->ExtractBbox(m_CullBox.bmins, m_CullBox.bmaxs);
  129. if (m_bOrientedBounds)
  130. {
  131. //
  132. // Oriented bounds - the 2D bounds are the same as the 3D bounds.
  133. //
  134. Mins = m_CullBox.bmins;
  135. Maxs = m_CullBox.bmaxs;
  136. }
  137. else
  138. {
  139. //
  140. // The 2D bounds are the movement bounding box of the model, which is not affected
  141. // by the entity's orientation. This is used for character models for which we want
  142. // to render a meaningful collision box in the editor.
  143. //
  144. m_pStudioModel->ExtractMovementBbox(Mins, Maxs);
  145. }
  146. Mins += m_Origin;
  147. Maxs += m_Origin;
  148. m_CullBox.bmins += m_Origin;
  149. m_CullBox.bmaxs += m_Origin;
  150. }
  151. //
  152. // If we do not yet have a valid bounding box, use a default box.
  153. //
  154. if ((Maxs - Mins) == Vector(0, 0, 0))
  155. {
  156. Mins = m_CullBox.bmins = m_Origin - Vector(10, 10, 10);
  157. Maxs = m_CullBox.bmaxs = m_Origin + Vector(10, 10, 10);
  158. }
  159. m_BoundingBox = m_CullBox;
  160. m_Render2DBox.UpdateBounds(Mins, Maxs);
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose:
  164. // Output : CMapClass
  165. //-----------------------------------------------------------------------------
  166. CMapClass *CMapStudioModel::Copy(bool bUpdateDependencies)
  167. {
  168. CMapStudioModel *pCopy = new CMapStudioModel;
  169. if (pCopy != NULL)
  170. {
  171. pCopy->CopyFrom(this, bUpdateDependencies);
  172. }
  173. return(pCopy);
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose: Makes this an exact duplicate of pObject.
  177. // Input : pObject - Object to copy.
  178. // Output : Returns this.
  179. //-----------------------------------------------------------------------------
  180. CMapClass *CMapStudioModel::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
  181. {
  182. Assert(pObject->IsMapClass(MAPCLASS_TYPE(CMapStudioModel)));
  183. CMapStudioModel *pFrom = (CMapStudioModel *)pObject;
  184. CMapClass::CopyFrom(pObject, bUpdateDependencies);
  185. m_pStudioModel = pFrom->m_pStudioModel;
  186. if (m_pStudioModel != NULL)
  187. {
  188. CStudioModelCache::AddRef(m_pStudioModel);
  189. }
  190. m_Angles = pFrom->m_Angles;
  191. m_Skin = pFrom->m_Skin;
  192. m_bOrientedBounds = pFrom->m_bOrientedBounds;
  193. m_bReversePitch = pFrom->m_bReversePitch;
  194. m_bPitchSet = pFrom->m_bPitchSet;
  195. m_flPitch = pFrom->m_flPitch;
  196. m_bScreenSpaceFade = pFrom->m_bScreenSpaceFade;
  197. m_flFadeScale = pFrom->m_flFadeScale;
  198. m_flFadeMinDist = pFrom->m_flFadeMinDist;
  199. m_flFadeMaxDist = pFrom->m_flFadeMaxDist;
  200. m_iSolid = pFrom->m_iSolid;
  201. return(this);
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. // Input : bEnable -
  206. //-----------------------------------------------------------------------------
  207. void CMapStudioModel::EnableAnimation(BOOL bEnable)
  208. {
  209. m_bAnimateModels = bEnable;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: Returns this object's pitch, yaw, and roll.
  213. //-----------------------------------------------------------------------------
  214. void CMapStudioModel::GetAngles(QAngle &Angles)
  215. {
  216. Angles = m_Angles;
  217. if (m_bPitchSet)
  218. {
  219. Angles[PITCH] = m_flPitch;
  220. }
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose: Returns this object's pitch, yaw, and roll for rendering.
  224. //-----------------------------------------------------------------------------
  225. void CMapStudioModel::GetRenderAngles(QAngle &Angles)
  226. {
  227. GetAngles(Angles);
  228. if (m_bReversePitch)
  229. {
  230. Angles[PITCH] *= -1;
  231. }
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Purpose:
  235. //-----------------------------------------------------------------------------
  236. void CMapStudioModel::Initialize(void)
  237. {
  238. m_Angles.Init();
  239. m_bPitchSet = false;
  240. m_flPitch = 0;
  241. m_bReversePitch = false;
  242. m_pStudioModel = NULL;
  243. m_Skin = 0;
  244. m_bScreenSpaceFade = false;
  245. m_flFadeScale = 1.0f;
  246. m_flFadeMinDist = 0.0f;
  247. m_flFadeMaxDist = 0.0f;
  248. m_iSolid = -1;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: Notifies that this object's parent entity has had a key value change.
  252. // Input : szKey - The key that changed.
  253. // szValue - The new value of the key.
  254. //-----------------------------------------------------------------------------
  255. void CMapStudioModel::OnParentKeyChanged(const char* szKey, const char* szValue)
  256. {
  257. if (!stricmp(szKey, "angles"))
  258. {
  259. sscanf(szValue, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]);
  260. PostUpdate(Notify_Changed);
  261. }
  262. else if (!stricmp(szKey, "pitch"))
  263. {
  264. m_flPitch = atof(szValue);
  265. m_bPitchSet = true;
  266. PostUpdate(Notify_Changed);
  267. }
  268. else if (!stricmp(szKey, "skin"))
  269. {
  270. m_Skin = atoi(szValue);
  271. PostUpdate(Notify_Changed);
  272. }
  273. else if (!stricmp(szKey, "fademindist"))
  274. {
  275. m_flFadeMinDist = atoi(szValue);
  276. }
  277. else if (!stricmp(szKey, "fademaxdist"))
  278. {
  279. m_flFadeMaxDist = atoi(szValue);
  280. }
  281. else if (!stricmp(szKey, "screenspacefade"))
  282. {
  283. m_bScreenSpaceFade = (atoi(szValue) != 0);
  284. }
  285. else if (!stricmp(szKey, "fadescale"))
  286. {
  287. m_flFadeScale = atof(szValue);
  288. }
  289. else if ( !stricmp( szKey, "solid") )
  290. {
  291. m_iSolid = atof( szValue );
  292. }
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose:
  296. // Input : pRender -
  297. //-----------------------------------------------------------------------------
  298. bool CMapStudioModel::RenderPreload(CRender3D *pRender, bool bNewContext)
  299. {
  300. return(m_pStudioModel != NULL);
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Draws basis vectors
  304. //-----------------------------------------------------------------------------
  305. static void DrawBasisVectors( CRender3D* pRender, const Vector &origin, const QAngle &angles)
  306. {
  307. matrix3x4_t fCurrentMatrix;
  308. AngleMatrix(angles, fCurrentMatrix);
  309. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  310. CMeshBuilder meshBuilder;
  311. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  312. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  313. meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
  314. meshBuilder.Color3ub(255, 0, 0);
  315. meshBuilder.Position3f(origin[0], origin[1], origin[2]);
  316. meshBuilder.AdvanceVertex();
  317. meshBuilder.Color3ub(255, 0, 0);
  318. meshBuilder.Position3f(origin[0] + (100 * fCurrentMatrix[0][0]),
  319. origin[1] + (100 * fCurrentMatrix[1][0]), origin[2] + (100 * fCurrentMatrix[2][0]));
  320. meshBuilder.AdvanceVertex();
  321. meshBuilder.Color3ub(0, 255, 0);
  322. meshBuilder.Position3f(origin[0], origin[1], origin[2]);
  323. meshBuilder.AdvanceVertex();
  324. meshBuilder.Color3ub(0, 255, 0);
  325. meshBuilder.Position3f(origin[0] + (100 * fCurrentMatrix[0][1]),
  326. origin[1] + (100 * fCurrentMatrix[1][1]), origin[2] + (100 * fCurrentMatrix[2][1]));
  327. meshBuilder.AdvanceVertex();
  328. meshBuilder.Color3ub(0, 0, 255);
  329. meshBuilder.Position3f(origin[0], origin[1], origin[2]);
  330. meshBuilder.AdvanceVertex();
  331. meshBuilder.Color3ub(0, 0, 255);
  332. meshBuilder.Position3f(origin[0] + (100 * fCurrentMatrix[0][2]),
  333. origin[1] + (100 * fCurrentMatrix[1][2]), origin[2] + (100 * fCurrentMatrix[2][2]));
  334. meshBuilder.AdvanceVertex();
  335. meshBuilder.End();
  336. pMesh->Draw();
  337. pRender->PopRenderMode();
  338. }
  339. //-----------------------------------------------------------------------------
  340. // It should render last if any of its materials are translucent, or if
  341. // we are previewing model fades.
  342. //-----------------------------------------------------------------------------
  343. bool CMapStudioModel::ShouldRenderLast()
  344. {
  345. return m_pStudioModel->IsTranslucent() || Options.view3d.bPreviewModelFade;
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Purpose: Renders the studio model in the 2D views.
  349. // Input : pRender - Interface to the 2D renderer.
  350. //-----------------------------------------------------------------------------
  351. void CMapStudioModel::Render2D(CRender2D *pRender)
  352. {
  353. Vector vecMins;
  354. Vector vecMaxs;
  355. GetRender2DBox(vecMins, vecMaxs);
  356. Vector2D pt,pt2;
  357. pRender->TransformPoint(pt, vecMins);
  358. pRender->TransformPoint(pt2, vecMaxs);
  359. color32 rgbColor = GetRenderColor();
  360. bool bIsEditable = IsEditable();
  361. if (GetSelectionState() != SELECT_NONE)
  362. {
  363. pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  364. pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  365. }
  366. else
  367. {
  368. pRender->SetDrawColor( rgbColor.r, rgbColor.g, rgbColor.b );
  369. pRender->SetHandleColor( rgbColor.r, rgbColor.g, rgbColor.b );
  370. }
  371. int sizeX = abs(pt2.x-pt.x);
  372. int sizeY = abs(pt2.y-pt.y);
  373. //
  374. // Don't draw the center handle if the model is smaller than the handle cross
  375. //
  376. if ( bIsEditable && sizeX >= 8 && sizeY >= 8 && pRender->IsActiveView() )
  377. {
  378. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_CROSS );
  379. pRender->DrawHandle( (vecMins+vecMaxs)/2 );
  380. }
  381. QAngle vecAngles;
  382. GetRenderAngles(vecAngles);
  383. bool bDrawAsModel = (Options.view2d.bDrawModels && ((sizeX+sizeY) > 50)) ||
  384. IsSelected() || ( pRender->IsInLocalTransformMode() && !pRender->GetInstanceRendering() );
  385. if ( !bDrawAsModel || IsSelected() )
  386. {
  387. // Draw the bounding box.
  388. pRender->DrawBox( vecMins, vecMaxs );
  389. }
  390. if ( bDrawAsModel )
  391. {
  392. //
  393. // Draw the model as wireframe.
  394. //
  395. m_pStudioModel->SetAngles(vecAngles);
  396. m_pStudioModel->SetOrigin(m_Origin[0], m_Origin[1], m_Origin[2]);
  397. m_pStudioModel->SetSkin(m_Skin);
  398. if ( GetSelectionState() == SELECT_NORMAL || ( pRender->IsInLocalTransformMode() && pRender->GetInstanceRendering() == false ) )
  399. {
  400. // draw textured model half translucent
  401. m_pStudioModel->DrawModel2D(pRender, 0.6 , false );
  402. }
  403. else
  404. {
  405. // just draw the wireframe
  406. m_pStudioModel->DrawModel2D(pRender, 1.0 , true );
  407. }
  408. }
  409. if ( IsSelected() )
  410. {
  411. //
  412. // Render the forward vector if the object is selected.
  413. //
  414. Vector Forward;
  415. AngleVectors(vecAngles, &Forward, NULL, NULL);
  416. pRender->SetDrawColor( 255, 255, 0 );
  417. pRender->DrawLine(m_Origin, m_Origin + Forward * 24);
  418. }
  419. }
  420. //-----------------------------------------------------------------------------
  421. //-----------------------------------------------------------------------------
  422. inline float CMapStudioModel::ComputeDistanceFade( CRender3D *pRender ) const
  423. {
  424. Vector vecViewPos;
  425. pRender->GetCamera()->GetViewPoint( vecViewPos );
  426. Vector vecDelta;
  427. vecDelta = m_Origin - vecViewPos;
  428. float flMin = min(m_flFadeMinDist, m_flFadeMaxDist);
  429. float flMax = max(m_flFadeMinDist, m_flFadeMaxDist);
  430. if (flMin < 0)
  431. {
  432. flMin = 0;
  433. }
  434. float alpha = 1.0f;
  435. if (flMax > 0)
  436. {
  437. float flDist = vecDelta.Length();
  438. if ( flDist > flMax )
  439. {
  440. alpha = 0.0f;
  441. }
  442. else if ( flDist > flMin )
  443. {
  444. alpha = RemapValClamped( flDist, flMin, flMax, 1.0f, 0 );
  445. }
  446. }
  447. return alpha;
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Computes fade alpha based on distance fade + screen fade
  451. //-----------------------------------------------------------------------------
  452. inline float CMapStudioModel::ComputeScreenFade( CRender3D *pRender ) const
  453. {
  454. return 1.0;
  455. }
  456. //-----------------------------------------------------------------------------
  457. //-----------------------------------------------------------------------------
  458. inline float CMapStudioModel::ComputeFade( CRender3D *pRender ) const
  459. {
  460. if ( m_bScreenSpaceFade )
  461. {
  462. return ComputeScreenFade( pRender );
  463. }
  464. else
  465. {
  466. return ComputeDistanceFade( pRender );
  467. }
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Purpose: Renders the studio model in the 3D views.
  471. // Input : pRender - Interface to the 3D renderer.
  472. //-----------------------------------------------------------------------------
  473. void CMapStudioModel::Render3D(CRender3D *pRender)
  474. {
  475. Color CurrentColor;
  476. CurrentColor.SetColor( r, g, b );
  477. //
  478. // Set to the default rendering mode, unless we're in lightmap mode
  479. //
  480. if (pRender->GetCurrentRenderMode() == RENDER_MODE_LIGHTMAP_GRID)
  481. pRender->PushRenderMode(RENDER_MODE_TEXTURED);
  482. else
  483. pRender->PushRenderMode(RENDER_MODE_CURRENT);
  484. //
  485. // Set up our angles for rendering.
  486. //
  487. QAngle vecAngles;
  488. GetRenderAngles(vecAngles);
  489. //
  490. // If we have a model, render it if it is close enough to the camera.
  491. //
  492. if (m_pStudioModel != NULL)
  493. {
  494. Vector ViewPoint;
  495. pRender->GetCamera()->GetViewPoint(ViewPoint);
  496. Vector Origin( m_Origin );
  497. if ( pRender->GetInstanceRendering() )
  498. {
  499. pRender->TransformInstanceVector( m_Origin, Origin );
  500. }
  501. if ((fabs(ViewPoint[0] - Origin[0]) < m_fRenderDistance) &&
  502. (fabs(ViewPoint[1] - Origin[1]) < m_fRenderDistance) &&
  503. (fabs(ViewPoint[2] - Origin[2]) < m_fRenderDistance))
  504. {
  505. color32 rgbColor = GetRenderColor();
  506. if (GetSelectionState() != SELECT_NONE)
  507. {
  508. pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  509. }
  510. else
  511. {
  512. // If the user disabled collisions on this instance of the model, color the wireframe differently
  513. if ( m_iSolid != -1 )
  514. {
  515. if ( m_iSolid == 0 )
  516. {
  517. rgbColor.r = GetRValue( Options.colors.clrModelCollisionWireframeDisabled );
  518. rgbColor.g = GetGValue( Options.colors.clrModelCollisionWireframeDisabled );
  519. rgbColor.b = GetBValue( Options.colors.clrModelCollisionWireframeDisabled );
  520. rgbColor.a = 255;
  521. }
  522. else
  523. {
  524. rgbColor.r = GetRValue( Options.colors.clrModelCollisionWireframe );
  525. rgbColor.g = GetGValue( Options.colors.clrModelCollisionWireframe );
  526. rgbColor.b = GetBValue( Options.colors.clrModelCollisionWireframe );
  527. rgbColor.a = 255;
  528. }
  529. }
  530. pRender->SetDrawColor( rgbColor.r, rgbColor.g, rgbColor.b );
  531. }
  532. //
  533. // Move the model to the proper place and orient it.
  534. //
  535. m_pStudioModel->SetAngles(vecAngles);
  536. m_pStudioModel->SetOrigin(m_Origin[0], m_Origin[1], m_Origin[2]);
  537. m_pStudioModel->SetSkin(m_Skin);
  538. float flAlpha = 1.0;
  539. if ( Options.view3d.bPreviewModelFade )
  540. {
  541. flAlpha = ComputeFade( pRender );
  542. }
  543. bool bWireframe = pRender->GetCurrentRenderMode() == RENDER_MODE_WIREFRAME;
  544. if ( GetSelectionState() == SELECT_MODIFY )
  545. bWireframe = true;
  546. pRender->BeginRenderHitTarget(this);
  547. m_pStudioModel->DrawModel3D(pRender, flAlpha, bWireframe );
  548. pRender->EndRenderHitTarget();
  549. if (IsSelected())
  550. {
  551. pRender->RenderWireframeBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, 255, 255, 0);
  552. }
  553. }
  554. else
  555. {
  556. pRender->BeginRenderHitTarget(this);
  557. pRender->RenderBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, CurrentColor.r(), CurrentColor.g(), CurrentColor.b(), GetSelectionState());
  558. pRender->EndRenderHitTarget();
  559. }
  560. }
  561. //
  562. // Else no model, render as a bounding box.
  563. //
  564. else
  565. {
  566. pRender->BeginRenderHitTarget(this);
  567. pRender->RenderBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, CurrentColor.r(), CurrentColor.g(), CurrentColor.b(), GetSelectionState());
  568. pRender->EndRenderHitTarget();
  569. }
  570. //
  571. // Draw our basis vectors.
  572. //
  573. if (IsSelected())
  574. {
  575. DrawBasisVectors( pRender, m_Origin, vecAngles );
  576. }
  577. pRender->PopRenderMode();
  578. }
  579. //-----------------------------------------------------------------------------
  580. // Purpose:
  581. // Input : &File -
  582. // bRMF -
  583. // Output : int
  584. //-----------------------------------------------------------------------------
  585. int CMapStudioModel::SerializeRMF(std::fstream &File, BOOL bRMF)
  586. {
  587. return(0);
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Purpose:
  591. // Input : &File -
  592. // bRMF -
  593. // Output : int
  594. //-----------------------------------------------------------------------------
  595. int CMapStudioModel::SerializeMAP(std::fstream &File, BOOL bRMF)
  596. {
  597. return(0);
  598. }
  599. //-----------------------------------------------------------------------------
  600. // Purpose:
  601. // Input : Angles -
  602. //-----------------------------------------------------------------------------
  603. void CMapStudioModel::SetAngles(QAngle &Angles)
  604. {
  605. m_Angles = Angles;
  606. //
  607. // Round very small angles to zero.
  608. //
  609. for (int nDim = 0; nDim < 3; nDim++)
  610. {
  611. if (fabs(m_Angles[nDim]) < 0.001)
  612. {
  613. m_Angles[nDim] = 0;
  614. }
  615. }
  616. while (m_Angles[YAW] < 0)
  617. {
  618. m_Angles[YAW] += 360;
  619. }
  620. if (m_bPitchSet)
  621. {
  622. m_flPitch = m_Angles[PITCH];
  623. }
  624. //
  625. // Update the angles of our parent entity.
  626. //
  627. CMapEntity *pEntity = dynamic_cast<CMapEntity *>(m_pParent);
  628. if (pEntity != NULL)
  629. {
  630. char szValue[80];
  631. sprintf(szValue, "%g %g %g", m_Angles[0], m_Angles[1], m_Angles[2]);
  632. pEntity->NotifyChildKeyChanged(this, "angles", szValue);
  633. if (m_bPitchSet)
  634. {
  635. sprintf(szValue, "%g", m_flPitch);
  636. pEntity->NotifyChildKeyChanged(this, "pitch", szValue);
  637. }
  638. }
  639. }
  640. //-----------------------------------------------------------------------------
  641. // Purpose: Sets the distance at which studio models become rendered as bounding
  642. // boxes. If this is set to zero, studio models are never rendered.
  643. // Input : fRenderDistance - Distance in world units.
  644. //-----------------------------------------------------------------------------
  645. void CMapStudioModel::SetRenderDistance(float fRenderDistance)
  646. {
  647. m_fRenderDistance = fRenderDistance;
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose:
  651. // Input : pTransBox -
  652. //-----------------------------------------------------------------------------
  653. void CMapStudioModel::DoTransform(const VMatrix &matrix)
  654. {
  655. BaseClass::DoTransform(matrix);
  656. // rotate model angles
  657. matrix3x4_t fRotateMatrix, fCurrentMatrix, fMatrixNew;
  658. fRotateMatrix = matrix.As3x4();
  659. // Light entities negate pitch again!
  660. if ( m_bReversePitch )
  661. {
  662. QAngle rotAngles;
  663. MatrixAngles(fRotateMatrix, rotAngles);
  664. rotAngles[PITCH] *= -1;
  665. rotAngles[ROLL] *= -1;
  666. AngleMatrix(rotAngles, fRotateMatrix);
  667. }
  668. QAngle angles;
  669. GetAngles( angles );
  670. AngleMatrix( angles, fCurrentMatrix);
  671. ConcatTransforms(fRotateMatrix, fCurrentMatrix, fMatrixNew);
  672. MatrixAngles( fMatrixNew, angles );
  673. SetAngles( angles );
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Purpose:
  677. // Output : int
  678. //-----------------------------------------------------------------------------
  679. int CMapStudioModel::GetFrame(void)
  680. {
  681. // TODO:
  682. return 0;
  683. }
  684. //-----------------------------------------------------------------------------
  685. // Purpose:
  686. // Input : nFrame -
  687. //-----------------------------------------------------------------------------
  688. void CMapStudioModel::SetFrame(int nFrame)
  689. {
  690. // TODO:
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Purpose: Returns the current sequence being used for rendering.
  694. //-----------------------------------------------------------------------------
  695. int CMapStudioModel::GetSequence(void)
  696. {
  697. if (!m_pStudioModel)
  698. {
  699. return 0;
  700. }
  701. return m_pStudioModel->GetSequence();
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Purpose:
  705. // Output : int
  706. //-----------------------------------------------------------------------------
  707. int CMapStudioModel::GetSequenceCount(void)
  708. {
  709. if (!m_pStudioModel)
  710. {
  711. return 0;
  712. }
  713. return m_pStudioModel->GetSequenceCount();
  714. }
  715. //-----------------------------------------------------------------------------
  716. // Purpose:
  717. // Input : nIndex -
  718. // szName -
  719. //-----------------------------------------------------------------------------
  720. void CMapStudioModel::GetSequenceName(int nIndex, char *szName)
  721. {
  722. if (m_pStudioModel)
  723. {
  724. m_pStudioModel->GetSequenceName(nIndex, szName);
  725. }
  726. }
  727. //-----------------------------------------------------------------------------
  728. // Purpose:
  729. // Input : nIndex -
  730. //-----------------------------------------------------------------------------
  731. void CMapStudioModel::SetSequence(int nIndex)
  732. {
  733. if (m_pStudioModel)
  734. {
  735. m_pStudioModel->SetSequence(nIndex);
  736. }
  737. }
  738. int CMapStudioModel::GetSequenceIndex( const char *pSequenceName ) const
  739. {
  740. if ( m_pStudioModel )
  741. {
  742. int cnt = m_pStudioModel->GetSequenceCount();
  743. for ( int i=0; i < cnt; i++ )
  744. {
  745. char name[2048];
  746. m_pStudioModel->GetSequenceName( i, name );
  747. if ( Q_stricmp( pSequenceName, name ) == 0 )
  748. return i;
  749. }
  750. }
  751. return -1;
  752. }