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.

1061 lines
29 KiB

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