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.

606 lines
17 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "stdafx.h"
  8. #include "const.h"
  9. #include "Sprite.h"
  10. #include "Material.h" // FIXME: we need to work only with IEditorTexture!
  11. #include "materialsystem/IMaterial.h"
  12. #include "materialsystem/IMaterialSystem.h"
  13. #include "Render3d.h"
  14. #include "camera.h"
  15. #include "tier1/utldict.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include <tier0/memdbgon.h>
  18. class CSpriteDataCache
  19. {
  20. public:
  21. CMaterial *m_pMaterial;
  22. IMaterialVar *m_pFrameVar;
  23. IMaterialVar *m_pRenderModeVar;
  24. IMaterialVar *m_pOrientationVar;
  25. IMaterialVar *m_pOriginVar;
  26. int m_Width;
  27. int m_Height;
  28. bool m_bOriginVarFound;
  29. bool m_bOrientationVarFound;
  30. };
  31. CUtlDict<CSpriteDataCache*, int> g_SpriteDataCache;
  32. SpriteCache_t CSpriteCache::m_Cache[SPRITE_CACHE_SIZE];
  33. int CSpriteCache::m_nItems = 0;
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Returns an instance of a particular studio model. If the model is
  36. // in the cache, a pointer to that model is returned. If not, a new one
  37. // is created and added to the cache.
  38. // Input : pszModelPath - Full path of the .MDL file.
  39. //-----------------------------------------------------------------------------
  40. CSpriteModel *CSpriteCache::CreateSprite(const char *pszSpritePath)
  41. {
  42. //
  43. // First look for the sprite in the cache. If it's there, increment the
  44. // reference count and return a pointer to the cached sprite.
  45. //
  46. for (int i = 0; i < m_nItems; i++)
  47. {
  48. if (!stricmp(pszSpritePath, m_Cache[i].pszPath))
  49. {
  50. m_Cache[i].nRefCount++;
  51. return(m_Cache[i].pSprite);
  52. }
  53. }
  54. //
  55. // If it isn't there, try to create one.
  56. //
  57. CSpriteModel *pSprite = new CSpriteModel;
  58. if (pSprite != NULL)
  59. {
  60. if (!pSprite->LoadSprite(pszSpritePath))
  61. {
  62. delete pSprite;
  63. pSprite = NULL;
  64. }
  65. }
  66. //
  67. // If we successfully created it, add it to the cache.
  68. //
  69. if (pSprite != NULL)
  70. {
  71. CSpriteCache::AddSprite(pSprite, pszSpritePath);
  72. }
  73. return(pSprite);
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Adds the model to the cache, setting the reference count to one.
  77. // Input : pModel - Model to add to the cache.
  78. // pszSpritePath - The full path of the .MDL file, which is used as a
  79. // key in the sprite cache.
  80. // Output : Returns TRUE if the sprite was successfully added, FALSE if we ran
  81. // out of memory trying to add the sprite to the cache.
  82. //-----------------------------------------------------------------------------
  83. bool CSpriteCache::AddSprite(CSpriteModel *pSprite, const char *pszSpritePath)
  84. {
  85. //
  86. // Copy the sprite pointer.
  87. //
  88. m_Cache[m_nItems].pSprite = pSprite;
  89. //
  90. // Allocate space for and copy the model path.
  91. //
  92. m_Cache[m_nItems].pszPath = new char [strlen(pszSpritePath) + 1];
  93. if (m_Cache[m_nItems].pszPath != NULL)
  94. {
  95. strcpy(m_Cache[m_nItems].pszPath, pszSpritePath);
  96. }
  97. else
  98. {
  99. return(false);
  100. }
  101. m_Cache[m_nItems].nRefCount = 1;
  102. m_nItems++;
  103. return(true);
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Increments the reference count on a sprite in the cache. Called by
  107. // client code when a pointer to the sprite is copied, making that
  108. // reference independent.
  109. // Input : pModel - Sprite for which to increment the reference count.
  110. //-----------------------------------------------------------------------------
  111. void CSpriteCache::AddRef(CSpriteModel *pSprite)
  112. {
  113. for (int i = 0; i < m_nItems; i++)
  114. {
  115. if (m_Cache[i].pSprite == pSprite)
  116. {
  117. m_Cache[i].nRefCount++;
  118. return;
  119. }
  120. }
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose: Called by client code to release an instance of a model. If the
  124. // model's reference count is zero, the model is freed.
  125. // Input : pModel - Pointer to the model to release.
  126. //-----------------------------------------------------------------------------
  127. void CSpriteCache::Release(CSpriteModel *pSprite)
  128. {
  129. for (int i = 0; i < m_nItems; i++)
  130. {
  131. if (m_Cache[i].pSprite == pSprite)
  132. {
  133. m_Cache[i].nRefCount--;
  134. Assert(m_Cache[i].nRefCount >= 0);
  135. //
  136. // If this model is no longer referenced, free it and remove it
  137. // from the cache.
  138. //
  139. if (m_Cache[i].nRefCount <= 0)
  140. {
  141. //
  142. // Free the path, which was allocated by AddModel.
  143. //
  144. delete [] m_Cache[i].pszPath;
  145. delete m_Cache[i].pSprite;
  146. //
  147. // Decrement the item count and copy the last element in the cache over
  148. // this element.
  149. //
  150. m_nItems--;
  151. m_Cache[i].pSprite = m_Cache[m_nItems].pSprite;
  152. m_Cache[i].pszPath = m_Cache[m_nItems].pszPath;
  153. m_Cache[i].nRefCount = m_Cache[m_nItems].nRefCount;
  154. }
  155. break;
  156. }
  157. }
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose: Constructor.
  161. //-----------------------------------------------------------------------------
  162. CSpriteModel::CSpriteModel(void) :
  163. m_pMaterial(0), m_NumFrames(-1), m_fScale(1.0), m_Origin(0,0,0), m_UL(0,0), m_LR(0,0), m_TexUL(0,1), m_TexLR(1,0), m_bInvert(false)
  164. {
  165. m_Normal = Vector( 0, 0, 1 );
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose: Destructor. Frees the sprite image and descriptor.
  169. //-----------------------------------------------------------------------------
  170. CSpriteModel::~CSpriteModel(void)
  171. {
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Sets the render mode
  175. //-----------------------------------------------------------------------------
  176. void CSpriteModel::SetRenderMode( const int mode )
  177. {
  178. if (m_pMaterial && m_pRenderModeVar)
  179. {
  180. if ( mode != m_pRenderModeVar->GetIntValue() )
  181. {
  182. m_pRenderModeVar->SetIntValue( mode );
  183. m_pMaterial->GetMaterial()->RecomputeStateSnapshots();
  184. }
  185. }
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose:
  189. // Input : pEntity -
  190. // type -
  191. // forward -
  192. // right -
  193. // up -
  194. //-----------------------------------------------------------------------------
  195. void CSpriteModel::GetSpriteAxes(QAngle& Angles, int type, Vector& forward, Vector& right, Vector& up, Vector& ViewUp, Vector& ViewRight, Vector& ViewForward)
  196. {
  197. int i;
  198. float dot, angle, sr, cr;
  199. Vector tvec;
  200. // Automatically roll parallel sprites if requested
  201. if (Angles[2] != 0 && type == SPR_VP_PARALLEL )
  202. {
  203. type = SPR_VP_PARALLEL_ORIENTED;
  204. }
  205. switch (type)
  206. {
  207. case SPR_FACING_UPRIGHT:
  208. {
  209. // generate the sprite's axes, with vup straight up in worldspace, and
  210. // r_spritedesc.vright perpendicular to modelorg.
  211. // This will not work if the view direction is very close to straight up or
  212. // down, because the cross product will be between two nearly parallel
  213. // vectors and starts to approach an undefined state, so we don't draw if
  214. // the two vectors are less than 1 degree apart
  215. tvec[0] = -m_Origin[0];
  216. tvec[1] = -m_Origin[1];
  217. tvec[2] = -m_Origin[2];
  218. VectorNormalize (tvec);
  219. dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because
  220. // r_spritedesc.vup is 0, 0, 1
  221. if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
  222. return;
  223. up[0] = 0;
  224. up[1] = 0;
  225. up[2] = 1;
  226. right[0] = tvec[1];
  227. // CrossProduct(r_spritedesc.vup, -modelorg,
  228. right[1] = -tvec[0];
  229. // r_spritedesc.vright)
  230. right[2] = 0;
  231. VectorNormalize (right);
  232. forward[0] = -right[1];
  233. forward[1] = right[0];
  234. forward[2] = 0;
  235. // CrossProduct (r_spritedesc.vright, r_spritedesc.vup,
  236. // r_spritedesc.vpn)
  237. break;
  238. }
  239. case SPR_VP_PARALLEL:
  240. {
  241. // generate the sprite's axes, completely parallel to the viewplane. There
  242. // are no problem situations, because the sprite is always in the same
  243. // position relative to the viewer
  244. for (i=0 ; i<3 ; i++)
  245. {
  246. up[i] = ViewUp[i];
  247. right[i] = ViewRight[i];
  248. forward[i] = ViewForward[i];
  249. }
  250. break;
  251. }
  252. case SPR_VP_PARALLEL_UPRIGHT:
  253. {
  254. // generate the sprite's axes, with vup straight up in worldspace, and
  255. // r_spritedesc.vright parallel to the viewplane.
  256. // This will not work if the view direction is very close to straight up or
  257. // down, because the cross product will be between two nearly parallel
  258. // vectors and starts to approach an undefined state, so we don't draw if
  259. // the two vectors are less than 1 degree apart
  260. dot = ViewForward[2]; // same as DotProduct (vpn, r_spritedesc.vup) because
  261. // r_spritedesc.vup is 0, 0, 1
  262. if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848
  263. return;
  264. up[0] = 0;
  265. up[1] = 0;
  266. up[2] = 1;
  267. right[0] = ViewForward[1];
  268. right[1] = -ViewForward[0];
  269. right[2] = 0;
  270. VectorNormalize (right);
  271. forward[0] = -right[1];
  272. forward[1] = right[0];
  273. forward[2] = 0;
  274. break;
  275. }
  276. case SPR_ORIENTED:
  277. {
  278. // generate the sprite's axes, according to the sprite's world orientation
  279. AngleVectors(Angles, &forward, &right, &up);
  280. break;
  281. }
  282. case SPR_VP_PARALLEL_ORIENTED:
  283. {
  284. // generate the sprite's axes, parallel to the viewplane, but rotated in
  285. // that plane around the center according to the sprite entity's roll
  286. // angle. So vpn stays the same, but vright and vup rotate
  287. angle = Angles[ROLL] * (M_PI*2 / 360);
  288. sr = sin(angle);
  289. cr = cos(angle);
  290. for (i=0 ; i<3 ; i++)
  291. {
  292. forward[i] = ViewForward[i];
  293. right[i] = ViewRight[i] * cr + ViewUp[i] * sr;
  294. up[i] = ViewRight[i] * -sr + ViewUp[i] * cr;
  295. }
  296. break;
  297. }
  298. default:
  299. {
  300. //Sys_Error ("R_DrawSprite: Bad sprite type %d", type);
  301. break;
  302. }
  303. }
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Sets the sprite's scale
  307. //-----------------------------------------------------------------------------
  308. void CSpriteModel::SetScale( const float fScale )
  309. {
  310. m_fScale = fScale;
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Sets the sprite's origin
  314. //-----------------------------------------------------------------------------
  315. void CSpriteModel::SetOrigin( const Vector &v )
  316. {
  317. m_Origin = v;
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Sets the sprite's origin
  321. //-----------------------------------------------------------------------------
  322. void CSpriteModel::GetOrigin( Vector &v )
  323. {
  324. v = m_Origin;
  325. }
  326. //-----------------------------------------------------------------------------
  327. // Sets the sprite's vertical inversion
  328. //-----------------------------------------------------------------------------
  329. void CSpriteModel::SetInvert( const bool b )
  330. {
  331. m_bInvert = b;
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose: Sets the Euler angles for the model.
  335. // Input : fAngles - A pointer to engine PITCH, YAW, and ROLL angles.
  336. //-----------------------------------------------------------------------------
  337. void CSpriteModel::SetAngles( const QAngle& pfAngles )
  338. {
  339. m_Angles[PITCH] = pfAngles[PITCH];
  340. m_Angles[YAW] = pfAngles[YAW];
  341. m_Angles[ROLL] = pfAngles[ROLL];
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Sets the material's primative type
  345. //-----------------------------------------------------------------------------
  346. void CSpriteModel::SetMaterialPrimitiveType( const MaterialPrimitiveType_t type )
  347. {
  348. m_MaterialPrimitiveType = type;
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Renders the sprite in 3D mode
  352. //-----------------------------------------------------------------------------
  353. void CSpriteModel::DrawSprite3D( CRender3D *pRender, unsigned char color[3] )
  354. {
  355. Vector corner, spritex, spritey, spritez;
  356. Vector ViewUp;
  357. Vector ViewRight;
  358. Vector ViewForward;
  359. pRender->GetViewUp( ViewUp );
  360. pRender->GetViewRight( ViewRight );
  361. pRender->GetViewForward( ViewForward );
  362. GetSpriteAxes(m_Angles, GetType(), spritez, spritex, spritey, ViewUp, ViewRight, ViewForward);
  363. Vector2D ul, lr;
  364. Vector2DMultiply( m_UL, m_fScale, ul );
  365. Vector2DMultiply( m_LR, m_fScale, lr );
  366. VectorMA( m_Origin, ul.x, spritex, corner );
  367. VectorMA( corner, lr.y, spritey, corner );
  368. spritex *= (lr.x - ul.x);
  369. spritey *= (ul.y - lr.y);
  370. Vector2D texul, texlr;
  371. texul.x = m_TexUL.x;
  372. texul.y = m_bInvert ? m_TexLR.y : m_TexUL.y;
  373. texlr.x = m_TexLR.x;
  374. texlr.y = m_bInvert ? m_TexUL.y : m_TexLR.y;
  375. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  376. pRender->BindTexture( m_pMaterial );
  377. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  378. CMeshBuilder meshBuilder;
  379. meshBuilder.Begin( pMesh, m_MaterialPrimitiveType, 4 );
  380. meshBuilder.Position3fv(corner.Base());
  381. meshBuilder.TexCoord2f(0, texul.x, texul.y);
  382. meshBuilder.Color3ub( color[0], color[1], color[2] );
  383. meshBuilder.Normal3fv( m_Normal.Base() );
  384. meshBuilder.AdvanceVertex();
  385. corner += spritey;
  386. meshBuilder.Position3fv(corner.Base());
  387. meshBuilder.TexCoord2f(0, texul.x, texlr.y);
  388. meshBuilder.Color3ub( color[0], color[1], color[2] );
  389. meshBuilder.Normal3fv( m_Normal.Base() );
  390. meshBuilder.AdvanceVertex();
  391. corner += spritex;
  392. meshBuilder.Position3fv(corner.Base());
  393. meshBuilder.TexCoord2f(0, texlr.x, texlr.y);
  394. meshBuilder.Color3ub( color[0], color[1], color[2] );
  395. meshBuilder.Normal3fv( m_Normal.Base() );
  396. meshBuilder.AdvanceVertex();
  397. corner -= spritey;
  398. meshBuilder.Position3fv(corner.Base());
  399. meshBuilder.TexCoord2f(0, texlr.x, texul.y);
  400. meshBuilder.Color3ub( color[0], color[1], color[2] );
  401. meshBuilder.Normal3fv( m_Normal.Base() );
  402. meshBuilder.AdvanceVertex();
  403. meshBuilder.End();
  404. pMesh->Draw();
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Binds a sprite
  408. //-----------------------------------------------------------------------------
  409. void CSpriteModel::Bind( CRender* pRender, int frame )
  410. {
  411. if (m_pMaterial && m_pFrameVar)
  412. {
  413. m_pFrameVar->SetIntValue( frame );
  414. pRender->BindTexture( m_pMaterial );
  415. }
  416. }
  417. CSpriteDataCache* LookupSpriteDataCache( const char *pSpritePath )
  418. {
  419. char filename[MAX_PATH];
  420. V_strncpy( filename, pSpritePath, sizeof( filename ) );
  421. V_FixSlashes( filename );
  422. CSpriteDataCache *pData;
  423. int i = g_SpriteDataCache.Find( filename );
  424. if ( i == g_SpriteDataCache.InvalidIndex() )
  425. {
  426. pData = new CSpriteDataCache;
  427. memset( pData, 0, sizeof( *pData ) );
  428. g_SpriteDataCache.Insert( filename, pData );
  429. pData->m_pMaterial = CMaterial::CreateMaterial( filename, true );
  430. if ( pData->m_pMaterial && pData->m_pMaterial->GetMaterial() )
  431. {
  432. bool bFound;
  433. pData->m_Width = pData->m_pMaterial->GetWidth();
  434. pData->m_Height = pData->m_pMaterial->GetHeight();
  435. pData->m_pFrameVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriteFrame", &bFound );
  436. if ( !bFound )
  437. {
  438. pData->m_pFrameVar = NULL;
  439. }
  440. pData->m_pRenderModeVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriterendermode", &bFound );
  441. if ( !bFound )
  442. {
  443. pData->m_pRenderModeVar = NULL;
  444. }
  445. pData->m_pOrientationVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriteOrientation", &pData->m_bOrientationVarFound, false );
  446. pData->m_pOriginVar = pData->m_pMaterial->GetMaterial()->FindVar( "$spriteorigin", &pData->m_bOriginVarFound );
  447. }
  448. }
  449. else
  450. {
  451. pData = g_SpriteDataCache[i];
  452. }
  453. return pData;
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Purpose: Loads a sprite material.
  457. // Input : pszSpritePath -
  458. // Output : Returns true on success, false on failure.
  459. //-----------------------------------------------------------------------------
  460. bool CSpriteModel::LoadSprite(const char *pszSpritePath)
  461. {
  462. CSpriteDataCache *pCache = LookupSpriteDataCache( pszSpritePath );
  463. m_pMaterial = pCache->m_pMaterial;
  464. if( m_pMaterial && m_pMaterial->GetMaterial() )
  465. {
  466. m_Width = pCache->m_Width;
  467. m_Height = pCache->m_Height;
  468. // FIXME: m_NumFrames = m_pMaterial->GetMaterial()->GetNumAnimationFrames();
  469. m_pFrameVar = pCache->m_pFrameVar;
  470. m_pRenderModeVar = pCache->m_pRenderModeVar;
  471. IMaterialVar *orientationVar = pCache->m_pOrientationVar;
  472. bool found = pCache->m_bOrientationVarFound;
  473. if( found )
  474. {
  475. m_Type = orientationVar->GetIntValue();
  476. }
  477. else
  478. {
  479. m_Type = SPR_VP_PARALLEL_UPRIGHT;
  480. }
  481. IMaterialVar *pOriginVar = pCache->m_pOriginVar;
  482. Vector origin;
  483. found = pCache->m_bOriginVarFound;
  484. if( !found || ( pOriginVar->GetType() != MATERIAL_VAR_TYPE_VECTOR ) )
  485. {
  486. origin[0] = -m_Width * 0.5f;
  487. origin[1] = m_Height * 0.5f;
  488. }
  489. else
  490. {
  491. Vector originVarValue;
  492. pOriginVar->GetVecValue( originVarValue.Base(), 3);
  493. origin[0] = -m_Width * originVarValue[0];
  494. origin[1] = m_Height * originVarValue[1];
  495. }
  496. m_UL.y = origin[1];
  497. m_LR.y = origin[1] - m_Height;
  498. m_UL.x = origin[0];
  499. m_LR.x = m_Width + origin[0];
  500. return true;
  501. }
  502. else
  503. {
  504. return false;
  505. }
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Kind of a hack...
  509. //-----------------------------------------------------------------------------
  510. int CSpriteModel::GetFrameCount()
  511. {
  512. // FIXME: Figure out the correct time to cache in this info
  513. if ((m_NumFrames < 0) && m_pMaterial)
  514. {
  515. m_NumFrames = m_pMaterial->GetMaterial()->GetNumAnimationFrames();
  516. }
  517. return (m_NumFrames < 0) ? 0 : m_NumFrames;
  518. }