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.

477 lines
14 KiB

  1. //===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: sheet code for particles and other sprite functions
  4. //
  5. //===========================================================================//
  6. #include "bitmap/psheet.h"
  7. #include "tier1/UtlStringMap.h"
  8. #include "tier1/utlbuffer.h"
  9. #include "tier2/fileutils.h"
  10. // MOC_TODO: These probably shouldn't be here - maybe we should put CSheetExtended somewhere else, like materialsystem?
  11. #include "materialsystem/imesh.h"
  12. #include "materialsystem/imaterial.h"
  13. #include "materialsystem/imaterialvar.h"
  14. #include "materialsystem/itexture.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. CSheet::CSheet( void )
  18. {
  19. }
  20. CSheet::CSheet( CUtlBuffer &buf )
  21. {
  22. // lets read a sheet
  23. buf.ActivateByteSwappingIfBigEndian();
  24. int nVersion = buf.GetInt(); // version#
  25. int nNumCoordsPerFrame = (nVersion)?MAX_IMAGES_PER_FRAME_ON_DISK:1;
  26. int nNumSequences = buf.GetInt();
  27. int nNumToAllocate = nNumSequences;
  28. // The old hardcoded arrays were 64.
  29. // We will allocate 64 for now to handle content issues with
  30. // rendering system trying to get at empty sequences.
  31. if ( nNumToAllocate < 64 )
  32. nNumToAllocate = 64;
  33. m_SheetInfo.EnsureCapacity( nNumSequences );
  34. for ( int i = 0; i < nNumToAllocate; ++i )
  35. {
  36. m_SheetInfo.AddToTail();
  37. m_SheetInfo[i].m_pSamples = NULL;
  38. m_SheetInfo[i].m_SeqFlags = 0;
  39. m_SheetInfo[i].m_bSequenceIsCopyOfAnotherSequence = 0;
  40. m_SheetInfo[i].m_nNumFrames = 0;
  41. m_SheetInfo[i].m_flFrameSpan = 0.0f;
  42. }
  43. while ( nNumSequences-- )
  44. {
  45. int nSequenceIndex = buf.GetInt();
  46. if ( nSequenceIndex < 0 )
  47. {
  48. Warning( "Invalid sequence number (%d)!!!\n", nSequenceIndex );
  49. return;
  50. }
  51. else if ( nSequenceIndex >= m_SheetInfo.Count() )
  52. {
  53. // This can happen if users delete intermediate sequences.
  54. // For example you can wind up with n sequences if you delete a sequence between 0 and n
  55. // In this case we will pad out the vector.
  56. int i = -1;
  57. while ( i < nSequenceIndex )
  58. {
  59. i = m_SheetInfo.AddToTail();
  60. m_SheetInfo[i].m_pSamples = NULL;
  61. m_SheetInfo[i].m_SeqFlags = 0;
  62. m_SheetInfo[i].m_bSequenceIsCopyOfAnotherSequence = 0;
  63. m_SheetInfo[i].m_nNumFrames = 0;
  64. m_SheetInfo[i].m_flFrameSpan = 0.0f;
  65. }
  66. }
  67. m_SheetInfo[nSequenceIndex].m_SeqFlags = (uint8)(0xFF & buf.GetInt()); // reading an int, but not worth storing it all
  68. int nFrameCount = buf.GetInt();
  69. // Save off how many frames we have for this sequence
  70. m_SheetInfo[nSequenceIndex].m_nNumFrames = nFrameCount;
  71. Assert( nFrameCount >= 0 );
  72. bool bSingleFrameSequence = ( nFrameCount == 1 );
  73. int nTimeSamples = bSingleFrameSequence ? 1 : SEQUENCE_SAMPLE_COUNT;
  74. if ( m_SheetInfo[nSequenceIndex].m_pSamples )
  75. {
  76. Warning( "Invalid particle sheet sequence index. There are more than one items with a sequence index of %d. We are only using the last one we found..\n", nSequenceIndex );
  77. delete[] m_SheetInfo[nSequenceIndex].m_pSamples;
  78. }
  79. m_SheetInfo[nSequenceIndex].m_pSamples = new SheetSequenceSample_t[ nTimeSamples ];
  80. int fTotalSequenceTime = ( int )buf.GetFloat();
  81. float InterpKnot[SEQUENCE_SAMPLE_COUNT];
  82. float InterpValue[SEQUENCE_SAMPLE_COUNT];
  83. SheetSequenceSample_t Samples[SEQUENCE_SAMPLE_COUNT];
  84. float fCurTime = 0.;
  85. for( int nFrm = 0 ; nFrm < nFrameCount; nFrm++ )
  86. {
  87. float fThisDuration = buf.GetFloat();
  88. InterpValue[ nFrm ] = nFrm;
  89. InterpKnot [ nFrm ] = SEQUENCE_SAMPLE_COUNT*( fCurTime/ fTotalSequenceTime );
  90. SheetSequenceSample_t &seq = Samples[ nFrm ];
  91. seq.m_fBlendFactor = 0.0f;
  92. for(int nImage = 0 ; nImage< nNumCoordsPerFrame; nImage++ )
  93. {
  94. SequenceSampleTextureCoords_t &s=seq.m_TextureCoordData[nImage];
  95. s.m_fLeft_U0 = buf.GetFloat();
  96. s.m_fTop_V0 = buf.GetFloat();
  97. s.m_fRight_U0 = buf.GetFloat();
  98. s.m_fBottom_V0 = buf.GetFloat();
  99. }
  100. if ( nNumCoordsPerFrame == 1 )
  101. seq.CopyFirstFrameToOthers();
  102. fCurTime += fThisDuration;
  103. m_SheetInfo[nSequenceIndex].m_flFrameSpan = fCurTime;
  104. }
  105. // now, fill in the whole table
  106. for( int nIdx = 0; nIdx < nTimeSamples; nIdx++ )
  107. {
  108. float flIdxA, flIdxB, flInterp;
  109. GetInterpolationData( InterpKnot, InterpValue, nFrameCount,
  110. SEQUENCE_SAMPLE_COUNT,
  111. nIdx,
  112. ! ( m_SheetInfo[nSequenceIndex].m_SeqFlags & SEQ_FLAG_CLAMP ),
  113. &flIdxA, &flIdxB, &flInterp );
  114. SheetSequenceSample_t sA = Samples[(int) flIdxA];
  115. SheetSequenceSample_t sB = Samples[(int) flIdxB];
  116. SheetSequenceSample_t &oseq = m_SheetInfo[nSequenceIndex].m_pSamples[nIdx];
  117. oseq.m_fBlendFactor = flInterp;
  118. for(int nImage = 0 ; nImage< MAX_IMAGES_PER_FRAME_IN_MEMORY; nImage++ )
  119. {
  120. SequenceSampleTextureCoords_t &src0=sA.m_TextureCoordData[nImage];
  121. SequenceSampleTextureCoords_t &src1=sB.m_TextureCoordData[nImage];
  122. SequenceSampleTextureCoords_t &o=oseq.m_TextureCoordData[nImage];
  123. o.m_fLeft_U0 = src0.m_fLeft_U0;
  124. o.m_fTop_V0 = src0.m_fTop_V0;
  125. o.m_fRight_U0 = src0.m_fRight_U0;
  126. o.m_fBottom_V0 = src0.m_fBottom_V0;
  127. o.m_fLeft_U1 = src1.m_fLeft_U0;
  128. o.m_fTop_V1 = src1.m_fTop_V0;
  129. o.m_fRight_U1 = src1.m_fRight_U0;
  130. o.m_fBottom_V1 = src1.m_fBottom_V0;
  131. }
  132. }
  133. }
  134. // now, fill in all unseen sequences with copies of the first seen sequence to prevent crashes
  135. // while editing
  136. int nFirstSequence = -1;
  137. for(int i= 0 ; i < m_SheetInfo.Count(); i++)
  138. {
  139. if ( m_SheetInfo[i].m_pSamples )
  140. {
  141. nFirstSequence = i;
  142. break;
  143. }
  144. }
  145. if ( nFirstSequence != -1 )
  146. {
  147. for(int i=0 ; i < m_SheetInfo.Count(); i++)
  148. {
  149. if ( m_SheetInfo[i].m_pSamples == NULL )
  150. {
  151. m_SheetInfo[i].m_pSamples = m_SheetInfo[nFirstSequence].m_pSamples;
  152. m_SheetInfo[i].m_SeqFlags = m_SheetInfo[nFirstSequence].m_SeqFlags;
  153. m_SheetInfo[i].m_nNumFrames = m_SheetInfo[nFirstSequence].m_nNumFrames;
  154. Assert( m_SheetInfo[i].m_nNumFrames >= 1 );
  155. m_SheetInfo[i].m_bSequenceIsCopyOfAnotherSequence = true;
  156. }
  157. }
  158. }
  159. }
  160. CSheet::~CSheet( void )
  161. {
  162. for( int i = 0; i < m_SheetInfo.Count(); i++ )
  163. {
  164. if ( m_SheetInfo[i].m_pSamples && ( !m_SheetInfo[i].m_bSequenceIsCopyOfAnotherSequence ) )
  165. {
  166. delete[] m_SheetInfo[i].m_pSamples;
  167. }
  168. }
  169. }
  170. const SheetSequenceSample_t *CSheet::GetSampleForSequence( float flAge, float flAgeScale, int nSequence, bool bForceLoop )
  171. {
  172. if ( m_SheetInfo[nSequence].m_nNumFrames == 1 )
  173. return (const SheetSequenceSample_t *) &m_SheetInfo[nSequence].m_pSamples[0];
  174. flAge *= flAgeScale;
  175. unsigned int nFrame = ( int )flAge;
  176. if ( ( m_SheetInfo[nSequence].m_SeqFlags & SEQ_FLAG_CLAMP ) && !bForceLoop )
  177. {
  178. nFrame = MIN( nFrame, SEQUENCE_SAMPLE_COUNT-1 );
  179. }
  180. else
  181. {
  182. nFrame &= SEQUENCE_SAMPLE_COUNT-1;
  183. }
  184. return (const SheetSequenceSample_t *) &m_SheetInfo[nSequence].m_pSamples[nFrame];
  185. }
  186. //////////////////////////////////////////////////////////////////////////
  187. CSheetExtended::CSheetExtended( IMaterial* pMaterial )
  188. {
  189. m_Material.Init( pMaterial );
  190. m_pSheetData = NULL;
  191. LoadFromMaterial(pMaterial);
  192. }
  193. CSheetExtended::~CSheetExtended()
  194. {
  195. delete m_pSheetData;
  196. }
  197. void CSheetExtended::LoadFromMaterial( IMaterial* pMaterial )
  198. {
  199. if ( pMaterial == NULL )
  200. return;
  201. bool bFound = false;
  202. IMaterialVar *pVar = pMaterial->FindVar( "$basetexture", &bFound );
  203. if ( !pVar || !bFound || !pVar->IsDefined() )
  204. return;
  205. ITexture *pTex = pVar->GetTextureValue();
  206. if ( !pTex || pTex->IsError() )
  207. return;
  208. size_t nBytes;
  209. void const *pSheetData = pTex->GetResourceData( VTF_RSRC_SHEET, &nBytes );
  210. if ( pSheetData )
  211. {
  212. CUtlBuffer bufLoad( pSheetData, nBytes, CUtlBuffer::READ_ONLY );
  213. LoadFromBuffer( bufLoad );
  214. }
  215. }
  216. void CSheetExtended::LoadFromBuffer( CUtlBuffer& buf )
  217. {
  218. m_pSheetData = new CSheet(buf);
  219. }
  220. int CSheetExtended::GetSheetSequenceCount()
  221. {
  222. if ( m_pSheetData == NULL )
  223. {
  224. return 0;
  225. }
  226. int nUniqueSequences = 0;
  227. for ( int i = 0; i < m_pSheetData->m_SheetInfo.Count(); ++i )
  228. {
  229. if ( !m_pSheetData->m_SheetInfo[i].m_bSequenceIsCopyOfAnotherSequence )
  230. {
  231. nUniqueSequences++;
  232. }
  233. }
  234. return nUniqueSequences;
  235. }
  236. int CSheetExtended::GetNthSequenceIndex( int nSequenceNumber )
  237. {
  238. if ( m_pSheetData == NULL )
  239. {
  240. return 0;
  241. }
  242. int nCountValidSequences = 0;
  243. for ( int i = 0; i < m_pSheetData->m_SheetInfo.Count(); ++i )
  244. {
  245. if ( !m_pSheetData->m_SheetInfo[i].m_bSequenceIsCopyOfAnotherSequence )
  246. {
  247. if ( nCountValidSequences == nSequenceNumber )
  248. {
  249. return i;
  250. }
  251. else
  252. {
  253. nCountValidSequences++;
  254. }
  255. }
  256. }
  257. return 0;
  258. }
  259. static SheetSequenceSample_t s_DefaultSheetSequence =
  260. {
  261. 0.0f, 0.0f, 1.0f, 1.0f,
  262. 0.0f, 0.0f, 1.0f, 1.0f,
  263. 0.0f, 0.0f, 1.0f, 1.0f,
  264. 0.0f, 0.0f, 1.0f, 1.0f,
  265. 1.0f,
  266. };
  267. const SheetSequenceSample_t *CSheetExtended::GetSampleForSequence( float flAge, float flAgeScale, int nSequence, bool bForceLoop )
  268. {
  269. if ( m_pSheetData == NULL )
  270. return &s_DefaultSheetSequence;
  271. return m_pSheetData->GetSampleForSequence( flAge, flAgeScale, nSequence, bForceLoop );
  272. }
  273. float CSheetExtended::GetSequenceTimeSpan( int nSequenceIndex )
  274. {
  275. if ( m_pSheetData == NULL )
  276. {
  277. return 0.f;
  278. }
  279. return m_pSheetData->m_SheetInfo[nSequenceIndex].m_flFrameSpan;
  280. }
  281. bool CSheetExtended::ValidSheetData()
  282. {
  283. return (m_pSheetData != NULL);
  284. }
  285. bool CSheetExtended::SequenceHasAlphaData( int nSequenceIndex )
  286. {
  287. return !(m_pSheetData->m_SheetInfo[nSequenceIndex].m_SeqFlags & SEQ_FLAG_NO_ALPHA);
  288. }
  289. bool CSheetExtended::SequenceHasColorData( int nSequenceIndex )
  290. {
  291. return !(m_pSheetData->m_SheetInfo[nSequenceIndex].m_SeqFlags & SEQ_FLAG_NO_COLOR);
  292. }
  293. inline void TexCoords0( CMeshBuilder& meshBuilder, int nChannel, const SequenceSampleTextureCoords_t* pSample )
  294. {
  295. meshBuilder.TexCoord4f( nChannel, pSample->m_fLeft_U0, pSample->m_fTop_V0, pSample->m_fRight_U0, pSample->m_fBottom_V0 );
  296. }
  297. inline void TexCoords1( CMeshBuilder& meshBuilder, int nChannel, const SequenceSampleTextureCoords_t* pSample )
  298. {
  299. meshBuilder.TexCoord4f( nChannel, pSample->m_fLeft_U1, pSample->m_fTop_V1, pSample->m_fRight_U1, pSample->m_fBottom_V1 );
  300. }
  301. inline void SpriteCardVert( CMeshBuilder& meshBuilder,
  302. const Vector &vCenter,
  303. const float flRadius,
  304. const SheetSequenceSample_t * pSample,
  305. const SequenceSampleTextureCoords_t *pSample0,
  306. const SequenceSampleTextureCoords_t *pSecondTexture0,
  307. const SheetSequenceSample_t *pSample1Data,
  308. const SequenceSampleTextureCoords_t *pSample1,
  309. float flChannel3U, float flChannel3V )
  310. {
  311. meshBuilder.Position3fv( vCenter.Base() );
  312. TexCoords0( meshBuilder, 0, pSample0 );
  313. TexCoords1( meshBuilder, 1, pSample0 );
  314. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, 0.0f, flRadius, 0.0f );
  315. meshBuilder.TexCoord2f( 3, flChannel3U, flChannel3V );
  316. TexCoords0( meshBuilder, 4, pSecondTexture0 );
  317. if ( pSample1 )
  318. {
  319. TexCoords0( meshBuilder, 5, pSample1 );
  320. TexCoords1( meshBuilder, 6, pSample1 );
  321. meshBuilder.TexCoord4f( 7, pSample1Data->m_fBlendFactor, 0, 0, 0 );
  322. }
  323. }
  324. void CSheetExtended::DrawSheet( IMesh *pMesh, const Vector &vCenter, float flRadius, int nSheetSequence, float flAge, float flSheetPreviewSpeed, bool bLoopSheetPreview, int nSecondarySequence, bool bOverrideSpriteCard )
  325. {
  326. // nSecondarySequence
  327. bool bSpriteCardMaterial = false;
  328. bSpriteCardMaterial = !bOverrideSpriteCard && m_Material && m_Material->IsSpriteCard();
  329. const SheetSequenceSample_t *pSample = GetSampleForSequence( flAge, flSheetPreviewSpeed, nSheetSequence, bLoopSheetPreview );
  330. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  331. const SequenceSampleTextureCoords_t *pSecondTexture0 = &(pSample->m_TextureCoordData[1]);
  332. const SheetSequenceSample_t *pSample1Data = NULL;
  333. const SequenceSampleTextureCoords_t *pSample1 = NULL;
  334. if ( (nSecondarySequence != -1) && IsMaterialDualSequence( m_Material ) )
  335. {
  336. const float SECONDARY_AGE_MULTIPLIER = 0.1f; // hardcoded 'best guess' at relative speed, since we don't want a whole UI for a second speed
  337. float flSecondaryAge = flAge * SECONDARY_AGE_MULTIPLIER;
  338. pSample1Data = GetSampleForSequence( flSecondaryAge, flSheetPreviewSpeed, nSecondarySequence, bLoopSheetPreview );
  339. pSample1 = &(pSample1Data->m_TextureCoordData[0]);
  340. }
  341. CMeshBuilder meshBuilder;
  342. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  343. if ( bSpriteCardMaterial )
  344. {
  345. SpriteCardVert( meshBuilder, vCenter, flRadius, pSample, pSample0, pSecondTexture0, pSample1Data, pSample1, 0, 0 );
  346. }
  347. else
  348. {
  349. meshBuilder.Position3fv( (vCenter + Vector(-flRadius,-flRadius,0)).Base() );
  350. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  351. }
  352. meshBuilder.Color4ub( 255, 255, 255, 255 );
  353. meshBuilder.AdvanceVertex();
  354. if ( bSpriteCardMaterial )
  355. {
  356. SpriteCardVert( meshBuilder, vCenter, flRadius, pSample, pSample0, pSecondTexture0, pSample1Data, pSample1, 1, 0 );
  357. }
  358. else
  359. {
  360. meshBuilder.Position3fv( (vCenter + Vector(+flRadius,-flRadius,0)).Base() );
  361. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  362. }
  363. meshBuilder.Color4ub( 255, 255, 255, 255 );
  364. meshBuilder.AdvanceVertex();
  365. if ( bSpriteCardMaterial )
  366. {
  367. SpriteCardVert( meshBuilder, vCenter, flRadius, pSample, pSample0, pSecondTexture0, pSample1Data, pSample1, 1, 1 );
  368. }
  369. else
  370. {
  371. meshBuilder.Position3fv( (vCenter + Vector(+flRadius,+flRadius,0)).Base() );
  372. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  373. }
  374. meshBuilder.Color4ub( 255, 255, 255, 255 );
  375. meshBuilder.AdvanceVertex();
  376. if ( bSpriteCardMaterial )
  377. {
  378. SpriteCardVert( meshBuilder, vCenter, flRadius, pSample, pSample0, pSecondTexture0, pSample1Data, pSample1, 0, 1 );
  379. }
  380. else
  381. {
  382. meshBuilder.Position3fv( (vCenter + Vector(-flRadius,+flRadius,0)).Base() );
  383. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  384. }
  385. meshBuilder.Color4ub( 255, 255, 255, 255 );
  386. meshBuilder.AdvanceVertex();
  387. meshBuilder.End();
  388. pMesh->Draw();
  389. }
  390. bool CSheetExtended::IsMaterialDualSequence( IMaterial* pMat )
  391. {
  392. if ( !pMat )
  393. {
  394. return false;
  395. }
  396. bool bFound = false;
  397. IMaterialVar *pVar = pMat->FindVar( "$DUALSEQUENCE", &bFound );
  398. return ( pVar && bFound && pVar->IsDefined() && pVar->GetIntValue() );
  399. }
  400. bool CSheetExtended::IsMaterialSeparateAlphaColorMaterial( IMaterial* pMat )
  401. {
  402. if ( !pMat || !IsMaterialDualSequence(pMat) )
  403. {
  404. return false;
  405. }
  406. bool bFound = false;
  407. IMaterialVar *pVar = pMat->FindVar( "$SEQUENCE_BLEND_MODE", &bFound );
  408. if ( !pVar || !bFound || !pVar->IsDefined() )
  409. return false;
  410. return (pVar->GetIntValue() == 1);
  411. }