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.

719 lines
18 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Supports sprite preview and sprite icons for entities.
  4. //
  5. //===========================================================================//
  6. #include "stdafx.h"
  7. #include "hammer_mathlib.h"
  8. #include "Box3D.h"
  9. #include "BSPFile.h"
  10. #include "const.h"
  11. #include "MapDefs.h" // dvs: For COORD_NOTINIT
  12. #include "MapDoc.h"
  13. #include "MapEntity.h"
  14. #include "MapSprite.h"
  15. #include "Render2D.h"
  16. #include "Render3D.h"
  17. #include "hammer.h"
  18. #include "Texture.h"
  19. #include "TextureSystem.h"
  20. #include "materialsystem/IMesh.h"
  21. #include "Material.h"
  22. #include "Options.h"
  23. #include "camera.h"
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include <tier0/memdbgon.h>
  26. IMPLEMENT_MAPCLASS(CMapSprite)
  27. //-----------------------------------------------------------------------------
  28. // Purpose: Factory function. Used for creating a CMapSprite from a set
  29. // of string parameters from the FGD file.
  30. // Input : *pInfo - Pointer to helper info class which gives us information
  31. // about how to create the class.
  32. // Output : Returns a pointer to the class, NULL if an error occurs.
  33. //-----------------------------------------------------------------------------
  34. CMapClass *CMapSprite::CreateMapSprite(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  35. {
  36. const char *pszSprite = pHelperInfo->GetParameter(0);
  37. //
  38. // If we weren't passed a sprite name as an argument, get it from our parent
  39. // entity's "model" key.
  40. //
  41. if (pszSprite == NULL)
  42. {
  43. pszSprite = pParent->GetKeyValue("model");
  44. }
  45. // HACK?
  46. // When loading sprites, it can be the case that 'materials' is prepended
  47. // This is because we have to look in the materials directory for sprites
  48. // Remove the materials prefix...
  49. if (pszSprite)
  50. {
  51. if (!strnicmp(pszSprite, "materials", 9) && ((pszSprite[9] == '/') || (pszSprite[9] == '\\')) )
  52. {
  53. pszSprite += 10;
  54. }
  55. }
  56. //
  57. // If we have a sprite name, create a sprite object.
  58. //
  59. CMapSprite *pSprite = NULL;
  60. if (pszSprite != NULL)
  61. {
  62. pSprite = CreateMapSprite(pszSprite);
  63. if (pSprite != NULL)
  64. {
  65. //
  66. // Icons are alpha tested.
  67. //
  68. if (!stricmp(pHelperInfo->GetName(), "iconsprite"))
  69. {
  70. pSprite->SetRenderMode( kRenderTransAlpha );
  71. pSprite->m_bIsIcon = true;
  72. }
  73. else
  74. {
  75. // FIXME: Gotta do this a little better
  76. // This initializes the render mode in the sprite
  77. pSprite->SetRenderMode( pSprite->m_eRenderMode );
  78. }
  79. }
  80. }
  81. return(pSprite);
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose: Factory. Use this to construct CMapSprite objects, since the
  85. // constructor is protected.
  86. //-----------------------------------------------------------------------------
  87. CMapSprite *CMapSprite::CreateMapSprite(const char *pszSpritePath)
  88. {
  89. CMapSprite *pSprite = new CMapSprite;
  90. if (pSprite != NULL)
  91. {
  92. char szPath[MAX_PATH];
  93. pSprite->Initialize();
  94. // HACK: Remove the extension, this is for backward compatability
  95. // It's trying to load a .spr, but we're giving it a .vmt.
  96. strcpy( szPath, pszSpritePath );
  97. char* pDot = strrchr( szPath, '.' );
  98. if (pDot)
  99. *pDot = 0;
  100. pSprite->m_pSpriteInfo = CSpriteCache::CreateSprite(szPath);
  101. if (pSprite->m_pSpriteInfo)
  102. {
  103. pSprite->CalcBounds();
  104. }
  105. }
  106. return(pSprite);
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose: Constructor.
  110. //-----------------------------------------------------------------------------
  111. CMapSprite::CMapSprite(void)
  112. {
  113. Initialize();
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose: Destructor.
  117. //-----------------------------------------------------------------------------
  118. CMapSprite::~CMapSprite(void)
  119. {
  120. CSpriteCache::Release(m_pSpriteInfo);
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Sets the render mode
  124. //-----------------------------------------------------------------------------
  125. void CMapSprite::SetRenderMode( int eRenderMode )
  126. {
  127. m_eRenderMode = eRenderMode;
  128. if (m_pSpriteInfo)
  129. m_pSpriteInfo->SetRenderMode( m_eRenderMode );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose: Calculates our bounding box based on the sprite dimensions.
  133. // Input : bFullUpdate - Whether we should recalculate our childrens' bounds.
  134. //-----------------------------------------------------------------------------
  135. void CMapSprite::CalcBounds(BOOL bFullUpdate)
  136. {
  137. CMapClass::CalcBounds(bFullUpdate);
  138. float fRadius = 8;
  139. if (m_pSpriteInfo)
  140. {
  141. fRadius = max(m_pSpriteInfo->GetWidth(), m_pSpriteInfo->GetHeight()) * m_fScale / 2.0;
  142. if (fRadius == 0)
  143. {
  144. fRadius = 8;
  145. }
  146. }
  147. //
  148. // Build our bounds for frustum culling in the 3D view.
  149. //
  150. Vector Mins = m_Origin - Vector(fRadius, fRadius, fRadius);
  151. Vector Maxs = m_Origin + Vector(fRadius, fRadius, fRadius);
  152. m_CullBox.UpdateBounds(Mins, Maxs);
  153. m_BoundingBox = m_CullBox;
  154. //
  155. // Build our bounds for 2D rendering. We keep sprites small in the 2D views no
  156. // matter how large they are scaled.
  157. //
  158. if (!m_bIsIcon)
  159. {
  160. fRadius = 2;
  161. }
  162. Mins = m_Origin - Vector(fRadius, fRadius, fRadius);
  163. Maxs = m_Origin + Vector(fRadius, fRadius, fRadius);
  164. m_Render2DBox.UpdateBounds(Mins, Maxs);
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose: Returns a copy of this object.
  168. // Output : Pointer to the new object.
  169. //-----------------------------------------------------------------------------
  170. CMapClass *CMapSprite::Copy(bool bUpdateDependencies)
  171. {
  172. CMapSprite *pCopy = new CMapSprite;
  173. if (pCopy != NULL)
  174. {
  175. pCopy->CopyFrom(this, bUpdateDependencies);
  176. }
  177. return(pCopy);
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: Turns this into a duplicate of the given object.
  181. // Input : pObject - Pointer to the object to copy from.
  182. // Output : Returns a pointer to this object.
  183. //-----------------------------------------------------------------------------
  184. CMapClass *CMapSprite::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
  185. {
  186. CMapSprite *pFrom = dynamic_cast<CMapSprite *>(pObject);
  187. Assert(pObject != NULL);
  188. if (pObject != NULL)
  189. {
  190. CMapClass::CopyFrom(pObject, bUpdateDependencies);
  191. m_Angles = pFrom->m_Angles;
  192. m_pSpriteInfo = pFrom->m_pSpriteInfo;
  193. CSpriteCache::AddRef(pFrom->m_pSpriteInfo);
  194. m_nCurrentFrame = pFrom->m_nCurrentFrame;
  195. m_fSecondsPerFrame = pFrom->m_fSecondsPerFrame;
  196. m_fElapsedTimeThisFrame = pFrom->m_fElapsedTimeThisFrame;
  197. m_fScale = pFrom->m_fScale;
  198. SetRenderMode( pFrom->m_eRenderMode );
  199. m_RenderColor = pFrom->m_RenderColor;
  200. m_bIsIcon = pFrom->m_bIsIcon;
  201. }
  202. return(this);
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Purpose:
  206. // Input : bEnable -
  207. //-----------------------------------------------------------------------------
  208. void CMapSprite::EnableAnimation(BOOL bEnable)
  209. {
  210. //m_bAnimateModels = bEnable;
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose:
  214. // Input : Angles -
  215. //-----------------------------------------------------------------------------
  216. void CMapSprite::GetAngles(QAngle &Angles)
  217. {
  218. Angles = m_Angles;
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose:
  222. //-----------------------------------------------------------------------------
  223. void CMapSprite::Initialize(void)
  224. {
  225. m_Angles.Init();
  226. m_eRenderMode = kRenderNormal;
  227. m_RenderColor.r = 255;
  228. m_RenderColor.g = 255;
  229. m_RenderColor.b = 255;
  230. m_fSecondsPerFrame = 1;
  231. m_fElapsedTimeThisFrame = 0;
  232. m_nCurrentFrame = 0;
  233. m_fScale = 0.25;
  234. m_bIsIcon = false;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Updates time and returns the next frame
  238. //-----------------------------------------------------------------------------
  239. int CMapSprite::GetNextSpriteFrame( CRender3D* pRender )
  240. {
  241. //
  242. // Determine whether we need to advance to the next frame based on our
  243. // sprite framerate and the elapsed time.
  244. //
  245. int nNumFrames = m_pSpriteInfo->GetFrameCount();
  246. if (nNumFrames > 1)
  247. {
  248. float fElapsedTime = pRender->GetElapsedTime();
  249. m_fElapsedTimeThisFrame += fElapsedTime;
  250. while (m_fElapsedTimeThisFrame > m_fSecondsPerFrame)
  251. {
  252. m_nCurrentFrame++;
  253. m_fElapsedTimeThisFrame -= m_fSecondsPerFrame;
  254. }
  255. m_nCurrentFrame %= nNumFrames;
  256. }
  257. return m_nCurrentFrame;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. // Input : pRender -
  262. //-----------------------------------------------------------------------------
  263. void CMapSprite::Render3D(CRender3D *pRender)
  264. {
  265. int nPasses;
  266. if ((GetSelectionState() != SELECT_NONE) && (!m_bIsIcon))
  267. {
  268. if (pRender->NeedsOverlay())
  269. nPasses = 3;
  270. else
  271. nPasses = 2;
  272. }
  273. else
  274. {
  275. nPasses = 1;
  276. }
  277. //
  278. // If we have a sprite, render it.
  279. //
  280. if (m_pSpriteInfo)
  281. {
  282. //
  283. // Only sprite icons can be clicked on, sprite preview objects cannot.
  284. //
  285. if (m_bIsIcon)
  286. {
  287. pRender->BeginRenderHitTarget(this);
  288. }
  289. m_pSpriteInfo->SetOrigin(m_Origin);
  290. m_pSpriteInfo->SetAngles(m_Angles);
  291. m_pSpriteInfo->Bind(pRender, GetNextSpriteFrame(pRender));
  292. for (int nPass = 0; nPass < nPasses; nPass++)
  293. {
  294. if (nPass == 0)
  295. {
  296. // First pass uses the default rendering mode.
  297. // unless that mode is texture
  298. if (pRender->GetCurrentRenderMode() == RENDER_MODE_LIGHTMAP_GRID)
  299. pRender->PushRenderMode( RENDER_MODE_TEXTURED);
  300. else
  301. pRender->PushRenderMode( RENDER_MODE_CURRENT );
  302. }
  303. else
  304. {
  305. if (nPass == nPasses - 1)
  306. {
  307. // last pass uses wireframe rendering mode.
  308. pRender->PushRenderMode( RENDER_MODE_WIREFRAME);
  309. }
  310. else
  311. {
  312. pRender->PushRenderMode( RENDER_MODE_SELECTION_OVERLAY );
  313. }
  314. }
  315. m_pSpriteInfo->SetScale(m_fScale > 0 ? m_fScale : 1.0 );
  316. float fBlend;
  317. // dvs: lots of things contribute to blend factor. See r_blend in engine.
  318. //if (m_eRenderMode == kRenderNormal)
  319. {
  320. fBlend = 1.0;
  321. }
  322. unsigned char color[4];
  323. SpriteColor( color, m_eRenderMode, m_RenderColor, fBlend * 255);
  324. //
  325. // If selected, render a yellow wireframe box.
  326. //
  327. if (GetSelectionState() != SELECT_NONE)
  328. {
  329. if (m_bIsIcon)
  330. {
  331. pRender->RenderWireframeBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, 255, 255, 0);
  332. }
  333. else
  334. {
  335. color[0] = 255;
  336. color[1] = color[2] = 0;
  337. }
  338. //
  339. // If selected, render the sprite with a yellow wireframe around it.
  340. //
  341. if ( nPass > 0 )
  342. {
  343. color[0] = color[1] = 255;
  344. color[2] = 0;
  345. }
  346. }
  347. MaterialPrimitiveType_t type = (nPass > 0) ? MATERIAL_LINE_LOOP : MATERIAL_POLYGON;
  348. m_pSpriteInfo->SetMaterialPrimitiveType( type );
  349. m_pSpriteInfo->DrawSprite3D( pRender, color );
  350. pRender->PopRenderMode();
  351. }
  352. //
  353. // Only sprite icons can be clicked on, sprite preview objects cannot.
  354. //
  355. if (m_bIsIcon)
  356. {
  357. pRender->EndRenderHitTarget();
  358. }
  359. }
  360. //
  361. // Else no sprite, render as a bounding box.
  362. //
  363. else if (m_bIsIcon)
  364. {
  365. pRender->BeginRenderHitTarget(this);
  366. pRender->RenderBox(m_Render2DBox.bmins, m_Render2DBox.bmaxs, r, g, b, GetSelectionState());
  367. pRender->EndRenderHitTarget();
  368. }
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose:
  372. // Input : &File -
  373. // bRMF -
  374. // Output : int
  375. //-----------------------------------------------------------------------------
  376. int CMapSprite::SerializeRMF(std::fstream &File, BOOL bRMF)
  377. {
  378. return(0);
  379. }
  380. //-----------------------------------------------------------------------------
  381. // Purpose:
  382. // Input : &File -
  383. // bRMF -
  384. // Output : int
  385. //-----------------------------------------------------------------------------
  386. int CMapSprite::SerializeMAP(std::fstream &File, BOOL bRMF)
  387. {
  388. return(0);
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Purpose:
  392. // Input : pTransBox -
  393. //-----------------------------------------------------------------------------
  394. void CMapSprite::DoTransform(const VMatrix &matrix)
  395. {
  396. BaseClass::DoTransform(matrix);
  397. matrix3x4_t fCurrentMatrix,fMatrixNew;
  398. AngleMatrix(m_Angles, fCurrentMatrix);
  399. ConcatTransforms(matrix.As3x4(), fCurrentMatrix, fMatrixNew);
  400. MatrixAngles(fMatrixNew, m_Angles);
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose:
  404. // Input : pColor -
  405. // pEntity -
  406. // alpha -
  407. //-----------------------------------------------------------------------------
  408. void CMapSprite::SpriteColor(unsigned char *pColor, int eRenderMode, colorVec RenderColor, int alpha)
  409. {
  410. int a;
  411. if ((eRenderMode == kRenderTransAdd) || (eRenderMode == kRenderGlow) || (eRenderMode == kRenderWorldGlow))
  412. {
  413. a = alpha;
  414. }
  415. else
  416. {
  417. a = 256;
  418. }
  419. if ((RenderColor.r == 0) && (RenderColor.g == 0) && (RenderColor.b == 0))
  420. {
  421. pColor[0] = pColor[1] = pColor[2] = (255 * a) >> 8;
  422. }
  423. else
  424. {
  425. pColor[0] = ((int)RenderColor.r * a)>>8;
  426. pColor[1] = ((int)RenderColor.g * a)>>8;
  427. pColor[2] = ((int)RenderColor.b * a)>>8;
  428. }
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose: Notifies that this object's parent entity has had a key value change.
  432. // Input : szKey - The key that changed.
  433. // szValue - The new value of the key.
  434. //-----------------------------------------------------------------------------
  435. void CMapSprite::OnParentKeyChanged(const char* szKey, const char* szValue)
  436. {
  437. if (!stricmp(szKey, "framerate"))
  438. {
  439. float fFramesPerSecond = atof(szValue);
  440. if (fabs(fFramesPerSecond) > 0.001)
  441. {
  442. m_fSecondsPerFrame = 1 / fFramesPerSecond;
  443. }
  444. }
  445. else if (!stricmp(szKey, "scale"))
  446. {
  447. m_fScale = atof(szValue);
  448. if (m_fScale == 0)
  449. {
  450. m_fScale = 1;
  451. }
  452. m_pSpriteInfo->SetScale(m_fScale);
  453. PostUpdate(Notify_Changed);
  454. }
  455. else if (!stricmp(szKey, "rendermode"))
  456. {
  457. switch (atoi(szValue))
  458. {
  459. case 0: // "Normal"
  460. {
  461. SetRenderMode( kRenderNormal );
  462. break;
  463. }
  464. case 1: // "Color"
  465. {
  466. SetRenderMode( kRenderTransColor );
  467. break;
  468. }
  469. case 2: // "Texture"
  470. {
  471. SetRenderMode( kRenderNormal );
  472. break;
  473. }
  474. case 3: // "Glow"
  475. {
  476. SetRenderMode( kRenderGlow );
  477. break;
  478. }
  479. case 4: // "Solid"
  480. {
  481. SetRenderMode( kRenderNormal );
  482. break;
  483. }
  484. case 5: // "Additive"
  485. {
  486. SetRenderMode( kRenderTransAdd );
  487. break;
  488. }
  489. case 7: // "Additive Fractional Frame"
  490. {
  491. SetRenderMode( kRenderTransAddFrameBlend );
  492. break;
  493. }
  494. case 9: // "World Space Glow"
  495. {
  496. SetRenderMode( kRenderWorldGlow );
  497. break;
  498. }
  499. }
  500. }
  501. //
  502. // If we are the child of a light entity and its color is changing, change our render color.
  503. //
  504. else if (!stricmp(szKey, "_light"))
  505. {
  506. sscanf(szValue, "%d %d %d", &m_RenderColor.r, &m_RenderColor.g, &m_RenderColor.b);
  507. }
  508. else if (!stricmp(szKey, "angles"))
  509. {
  510. sscanf(szValue, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]);
  511. PostUpdate(Notify_Changed);
  512. }
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Purpose:
  516. // Output : Returns true on success, false on failure.
  517. //-----------------------------------------------------------------------------
  518. bool CMapSprite::ShouldRenderLast(void)
  519. {
  520. return(true);
  521. }
  522. //-----------------------------------------------------------------------------
  523. // Purpose:
  524. //-----------------------------------------------------------------------------
  525. void CMapSprite::Render2D(CRender2D *pRender)
  526. {
  527. Vector vecMins;
  528. Vector vecMaxs;
  529. GetRender2DBox(vecMins, vecMaxs);
  530. Vector2D pt,pt2;
  531. pRender->TransformPoint(pt, vecMins);
  532. pRender->TransformPoint(pt2, vecMaxs);
  533. if ( !IsSelected() )
  534. {
  535. pRender->SetDrawColor( r, g, b );
  536. pRender->SetHandleColor( r, g, b );
  537. }
  538. else
  539. {
  540. pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  541. pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
  542. }
  543. // Draw the bounding box.
  544. pRender->DrawBox( vecMins, vecMaxs );
  545. //
  546. // Draw center handle.
  547. //
  548. if ( pRender->IsActiveView() )
  549. {
  550. int sizex = abs(pt.x - pt2.x)+1;
  551. int sizey = abs(pt.y - pt2.y)+1;
  552. // dont draw handle if object is too small
  553. if ( sizex > 6 && sizey > 6 )
  554. {
  555. pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_CROSS );
  556. pRender->DrawHandle( (vecMins+vecMaxs)/2 );
  557. }
  558. }
  559. }
  560. //-----------------------------------------------------------------------------
  561. // Called by entity code to render sprites
  562. //-----------------------------------------------------------------------------
  563. void CMapSprite::RenderLogicalAt(CRender2D *pRender, const Vector2D &vecMins, const Vector2D &vecMaxs )
  564. {
  565. // If we have a sprite, render it.
  566. if (!m_pSpriteInfo)
  567. return;
  568. m_pSpriteInfo->Bind( pRender, 0 );
  569. pRender->PushRenderMode( RENDER_MODE_TEXTURED);
  570. unsigned char color[4] = { 255, 255, 255, 255 };
  571. SpriteColor( color, m_eRenderMode, m_RenderColor, 255);
  572. // If selected, render a yellow wireframe box.
  573. if ( GetSelectionState() != SELECT_NONE )
  574. {
  575. color[0] = 255;
  576. color[1] = color[2] = 0;
  577. }
  578. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  579. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  580. CMeshBuilder meshBuilder;
  581. meshBuilder.Begin( pMesh, MATERIAL_POLYGON, 4 );
  582. meshBuilder.Position3f( vecMins.x, vecMins.y, 0.0f );
  583. meshBuilder.TexCoord2f(0, 0, 1);
  584. meshBuilder.Color3ub( color[0], color[1], color[2] );
  585. meshBuilder.AdvanceVertex();
  586. meshBuilder.Position3f( vecMins.x, vecMaxs.y, 0.0f );
  587. meshBuilder.TexCoord2f(0, 0, 0);
  588. meshBuilder.Color3ub( color[0], color[1], color[2] );
  589. meshBuilder.AdvanceVertex();
  590. meshBuilder.Position3f( vecMaxs.x, vecMaxs.y, 0.0f );
  591. meshBuilder.TexCoord2f(0, 1, 0);
  592. meshBuilder.Color3ub( color[0], color[1], color[2] );
  593. meshBuilder.AdvanceVertex();
  594. meshBuilder.Position3f( vecMaxs.x, vecMins.y, 0.0f );
  595. meshBuilder.TexCoord2f(0, 1, 1);
  596. meshBuilder.Color3ub( color[0], color[1], color[2] );
  597. meshBuilder.AdvanceVertex();
  598. meshBuilder.End();
  599. pMesh->Draw();
  600. pRender->PopRenderMode();
  601. }