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.

2283 lines
73 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "imorphinternal.h"
  7. #include "tier0/dbg.h"
  8. #include "materialsystem/imaterialsystem.h"
  9. #include "materialsystem/MaterialSystemUtil.h"
  10. #include "materialsystem/itexture.h"
  11. #include "materialsystem/imesh.h"
  12. #include "utlsortvector.h"
  13. #include "materialsystem_global.h"
  14. #include "IHardwareConfigInternal.h"
  15. #include "pixelwriter.h"
  16. #include "itextureinternal.h"
  17. #include "tier1/keyvalues.h"
  18. #include "texturemanager.h"
  19. #include "imaterialsysteminternal.h"
  20. #include "imatrendercontextinternal.h"
  21. #include "studio.h"
  22. #include "tier0/vprof.h"
  23. #include "renderparm.h"
  24. #include "tier2/renderutils.h"
  25. #include "bitmap/imageformat.h"
  26. #include "materialsystem/IShader.h"
  27. #include "imaterialinternal.h"
  28. #include "tier0/memdbgon.h"
  29. //-----------------------------------------------------------------------------
  30. // Activate to get stats
  31. //-----------------------------------------------------------------------------
  32. //#define REPORT_MORPH_STATS 1
  33. //-----------------------------------------------------------------------------
  34. // Used to collapse quads with small gaps
  35. //-----------------------------------------------------------------------------
  36. #define MIN_SEGMENT_GAP_SIZE 12
  37. //-----------------------------------------------------------------------------
  38. // Used to compile the morph data into a vertex texture
  39. //-----------------------------------------------------------------------------
  40. class CVertexMorphDict
  41. {
  42. public:
  43. CVertexMorphDict();
  44. // Adds a morph to the dictionary
  45. void AddMorph( const MorphVertexInfo_t &info );
  46. // Sets up, cleans up the morph information
  47. void Setup( );
  48. void CleanUp();
  49. // Gets at morph info
  50. int MorphCount() const;
  51. int GetMorphTargetId( int nMorphTargetIndex ) const;
  52. int GetMorphVertexCount( int nMorphTargetIndex ) const;
  53. const MorphVertexInfo_t &GetMorphVertexInfo( int nMorphTargetIndex, int nIndex ) const;
  54. // Sorts deltas by destination vertex
  55. void SortDeltas();
  56. private:
  57. // Sort method for each morph target's vertices
  58. class CMorphVertexListLess
  59. {
  60. public:
  61. bool Less( const MorphVertexInfo_t& src1, const MorphVertexInfo_t& src2, void *pCtx )
  62. {
  63. return src1.m_nVertexId < src2.m_nVertexId;
  64. }
  65. };
  66. // A list of all vertices affecting a particular morph target
  67. struct MorphVertexList_t
  68. {
  69. MorphVertexList_t() {}
  70. MorphVertexList_t( const MorphVertexList_t& src ) : m_nMorphTargetId( src.m_nMorphTargetId ) {}
  71. int m_nMorphTargetId;
  72. CUtlSortVector< MorphVertexInfo_t, CMorphVertexListLess > m_MorphInfo;
  73. };
  74. // Sort function for the morph lists
  75. class VertexMorphDictLess
  76. {
  77. public:
  78. bool Less( const MorphVertexList_t& src1, const MorphVertexList_t& src2, void *pCtx );
  79. };
  80. // For each morph, store all target vertex indices
  81. // List of all morphs affecting all vertices, used for constructing the morph only
  82. CUtlSortVector< MorphVertexList_t, VertexMorphDictLess > m_MorphLists;
  83. };
  84. //-----------------------------------------------------------------------------
  85. // Used to sort the morphs affecting a particular vertex
  86. //-----------------------------------------------------------------------------
  87. bool CVertexMorphDict::VertexMorphDictLess::Less( const CVertexMorphDict::MorphVertexList_t& src1, const CVertexMorphDict::MorphVertexList_t& src2, void *pCtx )
  88. {
  89. return src1.m_nMorphTargetId < src2.m_nMorphTargetId;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Dictionary of morphs affecting a particular vertex
  93. //-----------------------------------------------------------------------------
  94. CVertexMorphDict::CVertexMorphDict() : m_MorphLists()
  95. {
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Adds a morph to the dictionary
  99. //-----------------------------------------------------------------------------
  100. void CVertexMorphDict::AddMorph( const MorphVertexInfo_t &info )
  101. {
  102. Assert( info.m_nVertexId != 65535 );
  103. MorphVertexList_t find;
  104. find.m_nMorphTargetId = info.m_nMorphTargetId;
  105. int nIndex = m_MorphLists.Find( find );
  106. if ( nIndex == m_MorphLists.InvalidIndex() )
  107. {
  108. m_MorphLists.Insert( find );
  109. nIndex = m_MorphLists.Find( find );
  110. }
  111. m_MorphLists[nIndex].m_MorphInfo.InsertNoSort( info );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Sets up, cleans up the morph information
  115. //-----------------------------------------------------------------------------
  116. void CVertexMorphDict::Setup( )
  117. {
  118. m_MorphLists.Purge();
  119. }
  120. void CVertexMorphDict::CleanUp( )
  121. {
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Gets at the dictionary elemenst
  125. //-----------------------------------------------------------------------------
  126. int CVertexMorphDict::MorphCount() const
  127. {
  128. return m_MorphLists.Count();
  129. }
  130. int CVertexMorphDict::GetMorphTargetId( int i ) const
  131. {
  132. if ( i >= m_MorphLists.Count() )
  133. return -1;
  134. return m_MorphLists[i].m_nMorphTargetId;
  135. }
  136. int CVertexMorphDict::GetMorphVertexCount( int nMorphTarget ) const
  137. {
  138. return m_MorphLists[nMorphTarget].m_MorphInfo.Count();
  139. }
  140. const MorphVertexInfo_t &CVertexMorphDict::GetMorphVertexInfo( int nMorphTarget, int j ) const
  141. {
  142. return m_MorphLists[nMorphTarget].m_MorphInfo[j];
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Sorts deltas by destination vertex
  146. //-----------------------------------------------------------------------------
  147. void CVertexMorphDict::SortDeltas()
  148. {
  149. int nMorphTargetCount = m_MorphLists.Count();
  150. for ( int i = 0; i < nMorphTargetCount; ++i )
  151. {
  152. m_MorphLists[i].m_MorphInfo.RedoSort();
  153. }
  154. }
  155. //-----------------------------------------------------------------------------
  156. //
  157. // Morph data class
  158. //
  159. //-----------------------------------------------------------------------------
  160. class CMorph : public IMorphInternal, public ITextureRegenerator
  161. {
  162. public:
  163. // Constructor, destructor
  164. CMorph();
  165. ~CMorph();
  166. // Inherited from IMorph
  167. virtual void Lock( float flFloatToFixedScale );
  168. virtual void AddMorph( const MorphVertexInfo_t &info );
  169. virtual void Unlock( );
  170. // Inherited from IMorphInternal
  171. virtual void Init( MorphFormat_t format, const char *pDebugName );
  172. virtual bool Bind( IMorphMgrRenderContext *pRenderContext );
  173. virtual MorphFormat_t GetMorphFormat() const;
  174. // Other public methods
  175. bool RenderMorphWeights( IMatRenderContext *pRenderContext, int nRenderId, int nWeightCount, const MorphWeight_t* pWeights );
  176. void AccumulateMorph( int nRenderId );
  177. private:
  178. // A list of all morphs affecting a particular vertex
  179. // Assume that consecutive morphs are stored under each other in V coordinates
  180. // both in the src texture and destination texture (which is the morph accumulation texture).
  181. struct MorphSegment_t
  182. {
  183. unsigned int m_nFirstSrc;
  184. unsigned short m_nFirstDest;
  185. unsigned short m_nCount;
  186. };
  187. struct MorphQuad_t
  188. {
  189. unsigned int m_nFirstSrc;
  190. unsigned short m_nFirstDest;
  191. unsigned short m_nCount;
  192. unsigned short m_nQuadIndex;
  193. };
  194. enum MorphTextureId_t
  195. {
  196. MORPH_TEXTURE_POS_NORMAL_DELTA = 0,
  197. MORPH_TEXTURE_SPEED_SIDE_MAP,
  198. MORPH_TEXTURE_COUNT
  199. };
  200. typedef void (CMorph::*MorphPixelWriter_t)( CPixelWriter &pixelWriter, int x, int y, const MorphVertexInfo_t &info );
  201. typedef CUtlVector< MorphSegment_t > MorphSegmentList_t;
  202. typedef CUtlVector< MorphQuad_t > MorphQuadList_t;
  203. private:
  204. // Inherited from ITextureRegenerator
  205. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
  206. virtual void Release() {}
  207. // Packs all morph data in the dictionary into a vertex texture layout
  208. void PackMorphData( );
  209. // Builds the list of segments to render, returns total # of src texels to read from
  210. void BuildSegmentList( CUtlVector< MorphSegmentList_t > &morphSegments );
  211. // Builds the list of quads to render
  212. void BuildQuadList( const CUtlVector< MorphSegmentList_t > &morphSegments );
  213. // Computes the vertex texture width
  214. void ComputeTextureDimensions( const CUtlVector< MorphSegmentList_t > &morphSegments );
  215. // Writes a morph delta into the texture
  216. void WriteDeltaPositionNormalToTexture( CPixelWriter &pixelWriter, int x, int y, const MorphVertexInfo_t &info );
  217. void WriteSideSpeedToTexture( CPixelWriter &pixelWriter, int x, int y, const MorphVertexInfo_t &info );
  218. // Computes the morph target 4tuple count
  219. int Get4TupleCount( MorphFormat_t format ) const;
  220. // Cleans up vertex textures
  221. void CleanUp( );
  222. // Is the morph locked?
  223. bool IsLocked() const;
  224. // Creates a material for use to do the morph accumulation
  225. void CreateAccumulatorMaterial( int nMaterialIndex );
  226. // Renders to the morph accumulator texture
  227. void RenderMorphQuads( IMatRenderContext *pRenderContext, int nRenderId, int nTotalQuadCount, int nWeightCount, int *pWeightLookup, const MorphWeight_t* pWeights );
  228. // Displays static morph data statistics
  229. void DisplayMorphStats();
  230. // Dynamic stat data
  231. void ClearMorphStats();
  232. void AccumulateMorphStats( int nActiveMorphCount, int nQuadsRendered, int nTexelsRendered );
  233. void ReportMorphStats( );
  234. void HandleMorphStats( int nActiveMorphCount, int nQuadsRendered, int nTexelsRendered );
  235. // Computes morph texture size in bytes
  236. int ComputeMorphTextureSizeInBytes( ) const;
  237. // Counts the total number of vertices to place in the static mesh
  238. int CountStaticMeshVertices() const;
  239. // Determines mesh vertex format
  240. VertexFormat_t ComputeVertexFormat( IMaterial * pMaterial ) const;
  241. // Builds the list of quads to render
  242. void CreateStaticMesh();
  243. // Builds a list of non-zero morph targets
  244. int BuildNonZeroMorphList( int *pWeightIndices, int nWeightCount, const MorphWeight_t* pWeights );
  245. // Determines the total number of deltas
  246. int DetermineTotalDeltaCount( const CUtlVector< MorphSegmentList_t > &morphSegments ) const;
  247. // Binds the morph weight texture
  248. void BindMorphWeight( int nRenderId );
  249. private:
  250. // Used when constructing the morph targets
  251. CVertexMorphDict m_MorphDict;
  252. bool m_bLocked;
  253. // The morph format
  254. MorphFormat_t m_Format;
  255. // The compiled vertex textures
  256. ITextureInternal *m_pMorphTexture[MORPH_TEXTURE_COUNT];
  257. // The compiled vertex streams
  258. IMesh* m_pMorphBuffer;
  259. // Describes all morph line segments required to draw a particular morph
  260. CUtlVector< MorphQuadList_t > m_MorphQuads;
  261. CUtlVector< int > m_MorphTargetIdToQuadIndex;
  262. // Caches off the morph weights when in the middle of performing morph accumulation
  263. int m_nMaxMorphTargetCount;
  264. MorphWeight_t *m_pRenderMorphWeight;
  265. CMaterialReference m_MorphAccumulationMaterial;
  266. // Float->fixed scale
  267. float m_flFloatToFixedScale;
  268. // Morph input texture size
  269. int m_nTextureWidth;
  270. int m_nTextureHeight;
  271. #ifdef _DEBUG
  272. CUtlString m_pDebugName;
  273. #endif
  274. // Used to unique-ify morph texture names
  275. static int s_nUniqueId;
  276. };
  277. //-----------------------------------------------------------------------------
  278. // Render context for morphing. Only is used to determine
  279. // where in the morph accumulator to put the texture.
  280. //-----------------------------------------------------------------------------
  281. class CMorphMgrRenderContext : public IMorphMgrRenderContext
  282. {
  283. public:
  284. enum
  285. {
  286. MAX_MODEL_MORPHS = 4,
  287. };
  288. CMorphMgrRenderContext();
  289. int GetRenderId( CMorph* pMorph );
  290. public:
  291. int m_nMorphCount;
  292. CMorph *m_pMorphsToAccumulate[MAX_MODEL_MORPHS];
  293. #ifdef DBGFLAG_ASSERT
  294. bool m_bInMorphAccumulation;
  295. #endif
  296. };
  297. //-----------------------------------------------------------------------------
  298. // Morph manager class
  299. //-----------------------------------------------------------------------------
  300. class CMorphMgr : public IMorphMgr
  301. {
  302. public:
  303. CMorphMgr();
  304. // Methods of IMorphMgr
  305. virtual bool ShouldAllocateScratchTextures();
  306. virtual void AllocateScratchTextures();
  307. virtual void FreeScratchTextures();
  308. virtual void AllocateMaterials();
  309. virtual void FreeMaterials();
  310. virtual ITextureInternal *MorphAccumulator();
  311. virtual ITextureInternal *MorphWeights();
  312. virtual IMorphInternal *CreateMorph();
  313. virtual void DestroyMorph( IMorphInternal *pMorphData );
  314. virtual int MaxHWMorphBatchCount() const;
  315. virtual void BeginMorphAccumulation( IMorphMgrRenderContext *pIRenderContext );
  316. virtual void EndMorphAccumulation( IMorphMgrRenderContext *pIRenderContext );
  317. virtual void AccumulateMorph( IMorphMgrRenderContext *pIRenderContext, IMorph* pMorph, int nMorphCount, const MorphWeight_t* pWeights );
  318. virtual void AdvanceFrame();
  319. virtual bool GetMorphAccumulatorTexCoord( IMorphMgrRenderContext *pRenderContext, Vector2D *pTexCoord, IMorph *pMorph, int nVertex );
  320. virtual IMorphMgrRenderContext *AllocateRenderContext();
  321. virtual void FreeRenderContext( IMorphMgrRenderContext *pRenderContext );
  322. // Other public methods
  323. public:
  324. // Computes texel offsets for the upper corner of the morph accumulator for a particular block
  325. void ComputeAccumulatorSubrect( int *pXOffset, int *pYOffset, int *pWidth, int *pHeight, int nMorphAccumBlockId );
  326. void GetAccumulatorSubrectDimensions( int *pWidth, int *pHeight );
  327. int GetAccumulator4TupleCount() const;
  328. // Computes texel offsets for the upper corner of the morph weight texture for a particular block
  329. void ComputeWeightSubrect( int *pXOffset, int *pYOffset, int *pWidth, int *pHeight, int nMorphAccumBlockId );
  330. // Used to compute stats of memory used
  331. void RegisterMorphSizeInBytes( int nSizeInBytes );
  332. int GetTotalMemoryUsage() const;
  333. // Are we using the constant register method?
  334. bool IsUsingConstantRegisters() const { return m_bUsingConstantRegisters; }
  335. private:
  336. // Displays 32bit float texture data
  337. void Display32FTextureData( float *pBuf, int nTexelID, int *pSubRect, ITexture *pTexture, int n4TupleCount );
  338. // A debugging utility to display the morph accumulator
  339. void DebugMorphAccumulator( IMatRenderContext *pRenderContext );
  340. // A debugging utility to display the morph weights
  341. void DebugMorphWeights( IMatRenderContext *pRenderContext );
  342. // Draws the morph accumulator + morph weights
  343. void DrawMorphTempTexture( IMatRenderContext *pRenderContext, IMaterial *pMaterial, ITexture *pTexture );
  344. private:
  345. enum
  346. {
  347. MAX_MORPH_ACCUMULATOR_VERTICES = 32768,
  348. MORPH_ACCUMULATOR_4TUPLES = 2, // 1 for pos + wrinkle, 1 for normal
  349. };
  350. int m_nAccumulatorWidth;
  351. int m_nAccumulatorHeight;
  352. int m_nSubrectVerticalCount;
  353. int m_nWeightWidth;
  354. int m_nWeightHeight;
  355. int m_nFrameCount;
  356. int m_nTotalMorphSizeInBytes;
  357. IMaterial *m_pPrevMaterial;
  358. void *m_pPrevProxy;
  359. int m_nPrevBoneCount;
  360. MaterialHeightClipMode_t m_nPrevClipMode;
  361. bool m_bPrevClippingEnabled;
  362. bool m_bUsingConstantRegisters;
  363. bool m_bFlashlightMode;
  364. ITextureInternal *m_pMorphAccumTexture;
  365. ITextureInternal *m_pMorphWeightTexture;
  366. IMaterial *m_pVisualizeMorphAccum;
  367. IMaterial *m_pVisualizeMorphWeight;
  368. IMaterial *m_pRenderMorphWeight;
  369. };
  370. //-----------------------------------------------------------------------------
  371. // Singleton
  372. //-----------------------------------------------------------------------------
  373. static CMorphMgr s_MorphMgr;
  374. IMorphMgr *g_pMorphMgr = &s_MorphMgr;
  375. //-----------------------------------------------------------------------------
  376. // Globals
  377. //-----------------------------------------------------------------------------
  378. int CMorph::s_nUniqueId = 0;
  379. //-----------------------------------------------------------------------------
  380. // Constructor, destructor
  381. //-----------------------------------------------------------------------------
  382. CMorph::CMorph()
  383. {
  384. memset( m_pMorphTexture, 0, sizeof(m_pMorphTexture) );
  385. m_pMorphBuffer = NULL;
  386. m_nTextureWidth = 0;
  387. m_nTextureHeight = 0;
  388. m_bLocked = false;
  389. m_Format = 0;
  390. m_flFloatToFixedScale = 1.0f;
  391. m_pRenderMorphWeight = 0;
  392. m_nMaxMorphTargetCount = 0;
  393. }
  394. CMorph::~CMorph()
  395. {
  396. CleanUp();
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Initialization
  400. //-----------------------------------------------------------------------------
  401. void CMorph::Init( MorphFormat_t format, const char *pDebugName )
  402. {
  403. m_Format = format;
  404. #ifdef _DEBUG
  405. m_pDebugName = pDebugName;
  406. #endif
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Returns the morph format
  410. //-----------------------------------------------------------------------------
  411. MorphFormat_t CMorph::GetMorphFormat() const
  412. {
  413. return m_Format;
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Binds morph accumulator, morph weights
  417. //-----------------------------------------------------------------------------
  418. bool CMorph::Bind( IMorphMgrRenderContext *pIRenderContext )
  419. {
  420. CMorphMgrRenderContext *pMorphRenderContext = static_cast< CMorphMgrRenderContext* >( pIRenderContext );
  421. int nRenderId = pMorphRenderContext->GetRenderId( this );
  422. if ( nRenderId < 0 )
  423. return false;
  424. int nXOffset, nYOffset, nWidth, nHeight;
  425. s_MorphMgr.ComputeAccumulatorSubrect( &nXOffset, &nYOffset, &nWidth, &nHeight, nRenderId );
  426. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_ACCUMULATOR_4TUPLE_COUNT, s_MorphMgr.GetAccumulator4TupleCount() );
  427. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_ACCUMULATOR_X_OFFSET, nXOffset );
  428. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_ACCUMULATOR_Y_OFFSET, nYOffset );
  429. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_ACCUMULATOR_SUBRECT_WIDTH, nWidth );
  430. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_ACCUMULATOR_SUBRECT_HEIGHT, nHeight );
  431. return true;
  432. }
  433. void CMorph::BindMorphWeight( int nRenderId )
  434. {
  435. int nXOffset, nYOffset, nWidth, nHeight;
  436. s_MorphMgr.ComputeWeightSubrect( &nXOffset, &nYOffset, &nWidth, &nHeight, nRenderId );
  437. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_WEIGHT_X_OFFSET, nXOffset );
  438. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_WEIGHT_Y_OFFSET, nYOffset );
  439. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_WEIGHT_SUBRECT_WIDTH, nWidth );
  440. g_pShaderAPI->SetIntRenderingParameter( INT_RENDERPARM_MORPH_WEIGHT_SUBRECT_HEIGHT, nHeight );
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Computes morph texture size in bytes
  444. //-----------------------------------------------------------------------------
  445. int CMorph::ComputeMorphTextureSizeInBytes( ) const
  446. {
  447. int nSize = 0;
  448. if ( m_pMorphTexture[MORPH_TEXTURE_POS_NORMAL_DELTA] )
  449. {
  450. int nTotal4Tuples = Get4TupleCount( m_Format );
  451. nSize += m_nTextureWidth * m_nTextureHeight * nTotal4Tuples * ImageLoader::SizeInBytes( IMAGE_FORMAT_RGBA16161616 );
  452. }
  453. if ( m_pMorphTexture[MORPH_TEXTURE_SPEED_SIDE_MAP] )
  454. {
  455. nSize += m_nTextureWidth * m_nTextureHeight * ImageLoader::SizeInBytes( IMAGE_FORMAT_RGBA8888 );
  456. }
  457. // NOTE: Vertex size here is kind of a hack, but whatever.
  458. int nVertexCount = CountStaticMeshVertices();
  459. nSize += nVertexCount * 5 * sizeof(float);
  460. return nSize;
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Cleans up vertex textures
  464. //-----------------------------------------------------------------------------
  465. void CMorph::CleanUp( )
  466. {
  467. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  468. int nMorphTextureSize = ComputeMorphTextureSizeInBytes();
  469. s_MorphMgr.RegisterMorphSizeInBytes( -nMorphTextureSize );
  470. IMaterial *pMat = m_MorphAccumulationMaterial;
  471. m_MorphAccumulationMaterial.Shutdown();
  472. if ( pMat )
  473. {
  474. pMat->DeleteIfUnreferenced();
  475. }
  476. if ( m_pMorphBuffer )
  477. {
  478. pRenderContext->DestroyStaticMesh( m_pMorphBuffer );
  479. m_pMorphBuffer = NULL;
  480. }
  481. for ( int i = 0; i < MORPH_TEXTURE_COUNT; ++i )
  482. {
  483. if ( m_pMorphTexture[i] )
  484. {
  485. m_pMorphTexture[i]->SetTextureRegenerator( NULL );
  486. m_pMorphTexture[i]->DecrementReferenceCount( );
  487. m_pMorphTexture[i]->DeleteIfUnreferenced();
  488. m_pMorphTexture[i] = NULL;
  489. }
  490. }
  491. if ( m_pRenderMorphWeight )
  492. {
  493. delete[] m_pRenderMorphWeight;
  494. m_pRenderMorphWeight = NULL;
  495. }
  496. m_nMaxMorphTargetCount = 0;
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Is the morph locked?
  500. //-----------------------------------------------------------------------------
  501. bool CMorph::IsLocked() const
  502. {
  503. return m_bLocked;
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Locks the morph data
  507. //-----------------------------------------------------------------------------
  508. void CMorph::Lock( float flFloatToFixedScale )
  509. {
  510. Assert( !IsLocked() );
  511. m_bLocked = true;
  512. CleanUp();
  513. m_flFloatToFixedScale = flFloatToFixedScale;
  514. m_MorphQuads.Purge();
  515. m_MorphTargetIdToQuadIndex.RemoveAll();
  516. m_MorphDict.Setup( );
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Adds morph data to the morph dictionary
  520. //-----------------------------------------------------------------------------
  521. void CMorph::AddMorph( const MorphVertexInfo_t &info )
  522. {
  523. Assert( IsLocked() );
  524. m_MorphDict.AddMorph( info );
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Unlocks the morph data, builds the vertex textures
  528. //-----------------------------------------------------------------------------
  529. void CMorph::Unlock( )
  530. {
  531. Assert( IsLocked() );
  532. // Sort the deltas by destination vertex
  533. m_MorphDict.SortDeltas();
  534. // Now lay out morph data as if it were in a vertex texture
  535. PackMorphData( );
  536. // Free up temporary memory used in building
  537. m_MorphDict.CleanUp();
  538. m_bLocked = false;
  539. // Gather stats
  540. int nMorphTextureSize = ComputeMorphTextureSizeInBytes();
  541. s_MorphMgr.RegisterMorphSizeInBytes( nMorphTextureSize );
  542. }
  543. //-----------------------------------------------------------------------------
  544. // Creates a material for use to do the morph accumulation
  545. //-----------------------------------------------------------------------------
  546. void CMorph::CreateAccumulatorMaterial( int nMaterialIndex )
  547. {
  548. // NOTE: Delta scale is a little tricky. The numbers are store in fixed-point 16 bit.
  549. // The pixel shader will interpret 65536 as 1.0, and 0 as 0.0. In the pixel shader,
  550. // we will read the delta, multiply it by 2, and subtract 1 to get a -1 to 1 range.
  551. // The float to fixed scale is applied prior to writing it in (delta * scale + 32768).
  552. // Therefore the max representable positive value =
  553. // 65536 = max positive delta * scale + 32768
  554. // max positive delta = 32768 / scale
  555. // This is what we will multiply our -1 to 1 values by in the pixel shader.
  556. char pTemp[256];
  557. KeyValues *pVMTKeyValues = new KeyValues( "MorphAccumulate" );
  558. pVMTKeyValues->SetInt( "$nocull", 1 );
  559. pVMTKeyValues->SetFloat( "$deltascale", ( m_flFloatToFixedScale != 0.0f ) ? 32768.0f / m_flFloatToFixedScale : 1.0f );
  560. if ( m_pMorphTexture[MORPH_TEXTURE_POS_NORMAL_DELTA] )
  561. {
  562. pVMTKeyValues->SetString( "$delta", m_pMorphTexture[MORPH_TEXTURE_POS_NORMAL_DELTA]->GetName() );
  563. }
  564. if ( m_pMorphTexture[MORPH_TEXTURE_SPEED_SIDE_MAP] )
  565. {
  566. pVMTKeyValues->SetString( "$sidespeed", m_pMorphTexture[MORPH_TEXTURE_SPEED_SIDE_MAP]->GetName() );
  567. }
  568. Q_snprintf( pTemp, sizeof(pTemp), "[%d %d %d]", m_nTextureWidth, m_nTextureHeight, Get4TupleCount(m_Format) );
  569. pVMTKeyValues->SetString( "$dimensions", pTemp );
  570. Q_snprintf( pTemp, sizeof(pTemp), "___AccumulateMorph%d.vmt", nMaterialIndex );
  571. m_MorphAccumulationMaterial.Init( pTemp, pVMTKeyValues );
  572. }
  573. //-----------------------------------------------------------------------------
  574. // Computes the morph target field count
  575. //-----------------------------------------------------------------------------
  576. int CMorph::Get4TupleCount( MorphFormat_t format ) const
  577. {
  578. int nSize = 0;
  579. if ( format & ( MORPH_POSITION | MORPH_WRINKLE ) )
  580. {
  581. ++nSize;
  582. }
  583. if ( format & MORPH_NORMAL )
  584. {
  585. ++nSize;
  586. }
  587. return nSize;
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Determines the total number of deltas
  591. //-----------------------------------------------------------------------------
  592. int CMorph::DetermineTotalDeltaCount( const CUtlVector< MorphSegmentList_t > &morphSegments ) const
  593. {
  594. int nDeltaCount = 0;
  595. int nMorphCount = morphSegments.Count();
  596. for ( int i = 0; i < nMorphCount; ++i )
  597. {
  598. const MorphSegmentList_t& list = morphSegments[i];
  599. int nSegmentCount = list.Count();
  600. for ( int j = 0; j < nSegmentCount; ++j )
  601. {
  602. nDeltaCount += list[j].m_nCount;
  603. }
  604. }
  605. return nDeltaCount;
  606. }
  607. //-----------------------------------------------------------------------------
  608. // Computes the texture width
  609. //-----------------------------------------------------------------------------
  610. void CMorph::ComputeTextureDimensions( const CUtlVector< MorphSegmentList_t > &morphSegments )
  611. {
  612. int nTotalDeltas = DetermineTotalDeltaCount( morphSegments );
  613. m_nTextureHeight = ceil( sqrt( (float)nTotalDeltas ) );
  614. // Round the dimension up to a multiple of 4
  615. m_nTextureHeight = ( m_nTextureHeight + 3 ) & ( ~0x3 );
  616. m_nTextureWidth = ( m_nTextureHeight != 0 ) ? ( nTotalDeltas + ( m_nTextureHeight - 1 ) ) / m_nTextureHeight : 0;
  617. m_nTextureWidth = ( m_nTextureWidth + 3 ) & ( ~0x3 );
  618. int nTotal4Tuples = Get4TupleCount( m_Format );
  619. // Make sure it obeys bounds
  620. int nMaxTextureWidth = HardwareConfig()->MaxTextureWidth();
  621. int nMaxTextureHeight = HardwareConfig()->MaxTextureHeight();
  622. while( m_nTextureWidth * nTotal4Tuples > nMaxTextureWidth )
  623. {
  624. m_nTextureWidth >>= 1;
  625. m_nTextureHeight <<= 1;
  626. if ( m_nTextureHeight > nMaxTextureHeight )
  627. {
  628. Warning( "Morph texture is too big!!! Make brian add support for morphs having multiple textures.\n" );
  629. Assert( 0 );
  630. m_nTextureHeight = nMaxTextureHeight;
  631. break;
  632. }
  633. }
  634. }
  635. //-----------------------------------------------------------------------------
  636. // Displays morph data statistics
  637. //-----------------------------------------------------------------------------
  638. void CMorph::DisplayMorphStats()
  639. {
  640. ITexture *pDest = g_pMorphMgr->MorphAccumulator( );
  641. int nDestTextureHeight = pDest->GetActualHeight();
  642. #ifdef _DEBUG
  643. Msg( "Morph %s:\n", m_pDebugName.String() );
  644. #else
  645. Msg( "Morph :\n" );
  646. #endif
  647. int nMorphCount = m_MorphQuads.Count();
  648. Msg( "\tMorph Target Count : %d\n", nMorphCount );
  649. int nTotalQuadCount = 0;
  650. int nTotalVertexCount = 0;
  651. CUtlVector<int> quadHisto;
  652. CUtlVector<int> vertexHisto;
  653. CUtlVector<int> gapSizeHisto;
  654. for ( int i = 0; i < nMorphCount; ++i )
  655. {
  656. MorphQuadList_t &list = m_MorphQuads[i];
  657. int nQuadCount = list.Count();
  658. int nVertexCount = 0;
  659. for ( int j = 0; j < nQuadCount; ++j )
  660. {
  661. nVertexCount += list[j].m_nCount;
  662. if ( j != 0 )
  663. {
  664. // Filter out src gaps + wraparound gaps
  665. if ( ( list[j].m_nFirstDest / nDestTextureHeight == list[j-1].m_nFirstDest / nDestTextureHeight ) &&
  666. ( list[j].m_nFirstSrc / m_nTextureHeight == list[j-1].m_nFirstSrc / m_nTextureHeight ) )
  667. {
  668. int nGapSize = list[j].m_nFirstDest - ( list[j-1].m_nFirstDest + list[j-1].m_nCount );
  669. while ( nGapSize >= gapSizeHisto.Count() )
  670. {
  671. gapSizeHisto.AddToTail( 0 );
  672. }
  673. gapSizeHisto[nGapSize] += 1;
  674. }
  675. }
  676. }
  677. while ( nQuadCount >= quadHisto.Count() )
  678. {
  679. quadHisto.AddToTail( 0 );
  680. }
  681. while ( nVertexCount >= vertexHisto.Count() )
  682. {
  683. vertexHisto.AddToTail( 0 );
  684. }
  685. quadHisto[nQuadCount]+=1;
  686. vertexHisto[nVertexCount]+=1;
  687. nTotalQuadCount += nQuadCount;
  688. nTotalVertexCount += nVertexCount;
  689. }
  690. Msg( "\tAverage # of vertices per target: %d\n", nTotalVertexCount / nMorphCount );
  691. Msg( "\tAverage # of quad draws per target: %d\n", nTotalQuadCount / nMorphCount );
  692. Msg( "\tQuad Count Histogram :\n\t\t" );
  693. for ( int i = 0; i < quadHisto.Count(); ++i )
  694. {
  695. if ( quadHisto[i] == 0 )
  696. continue;
  697. Msg( "[%d : %d] ", i, quadHisto[i] );
  698. }
  699. Msg( "\n\tVertex Count Histogram :\n\t\t" );
  700. for ( int i = 0; i < vertexHisto.Count(); ++i )
  701. {
  702. if ( vertexHisto[i] == 0 )
  703. continue;
  704. Msg( "[%d : %d] ", i, vertexHisto[i] );
  705. }
  706. Msg( "\n\tGap size Count Histogram :\n\t\t" );
  707. for ( int i = 0; i < gapSizeHisto.Count(); ++i )
  708. {
  709. if ( gapSizeHisto[i] == 0 )
  710. continue;
  711. Msg( "[%d : %d] ", i, gapSizeHisto[i] );
  712. }
  713. Msg( "\n" );
  714. }
  715. //-----------------------------------------------------------------------------
  716. // Packs all morph data in the dictionary into a vertex texture layout
  717. //-----------------------------------------------------------------------------
  718. void CMorph::PackMorphData( )
  719. {
  720. CUtlVector< MorphSegmentList_t > morphSegments;
  721. BuildSegmentList( morphSegments );
  722. ComputeTextureDimensions( morphSegments );
  723. BuildQuadList( morphSegments );
  724. if ( m_nTextureWidth == 0 || m_nTextureHeight == 0 )
  725. return;
  726. char pTemp[512];
  727. if ( m_Format & ( MORPH_POSITION | MORPH_WRINKLE | MORPH_NORMAL ) )
  728. {
  729. Q_snprintf( pTemp, sizeof(pTemp), "__morphtarget[%d]: pos/norm", s_nUniqueId );
  730. int nTotal4Tuples = Get4TupleCount( m_Format );
  731. ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture( pTemp, TEXTURE_GROUP_MORPH_TARGETS,
  732. m_nTextureWidth * nTotal4Tuples, m_nTextureHeight, IMAGE_FORMAT_RGBA16161616,
  733. TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NODEBUGOVERRIDE |
  734. TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_POINTSAMPLE );
  735. m_pMorphTexture[MORPH_TEXTURE_POS_NORMAL_DELTA] = static_cast<ITextureInternal*>( pTexture );
  736. }
  737. if ( m_Format & ( MORPH_SIDE | MORPH_SPEED ) )
  738. {
  739. Q_snprintf( pTemp, sizeof(pTemp), "__morphtarget[%d]: side/speed", s_nUniqueId );
  740. ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture( pTemp, TEXTURE_GROUP_MORPH_TARGETS,
  741. m_nTextureWidth, m_nTextureHeight, IMAGE_FORMAT_RGBA8888,
  742. TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NODEBUGOVERRIDE |
  743. TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_POINTSAMPLE );
  744. m_pMorphTexture[MORPH_TEXTURE_SPEED_SIDE_MAP] = static_cast<ITextureInternal*>( pTexture );
  745. }
  746. for ( int i = 0; i < MORPH_TEXTURE_COUNT; ++i )
  747. {
  748. if ( m_pMorphTexture[i] )
  749. {
  750. m_pMorphTexture[i]->SetTextureRegenerator( this );
  751. m_pMorphTexture[i]->Download();
  752. }
  753. }
  754. CreateAccumulatorMaterial( s_nUniqueId );
  755. ++s_nUniqueId;
  756. CreateStaticMesh();
  757. #ifdef REPORT_MORPH_STATS
  758. DisplayMorphStats( );
  759. #endif
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Writes a morph delta into the texture
  763. //-----------------------------------------------------------------------------
  764. void CMorph::WriteDeltaPositionNormalToTexture( CPixelWriter &pixelWriter, int x, int y, const MorphVertexInfo_t &info )
  765. {
  766. // NOTE: 0 = -max range, 32767 = 0, 65534, 65535 = maxrange.
  767. // This way we can encode +/- maxrange and 0 exactly
  768. Assert ( m_Format & ( MORPH_POSITION | MORPH_WRINKLE | MORPH_NORMAL ) );
  769. int n4TupleCount = Get4TupleCount( m_Format );
  770. pixelWriter.Seek( x*n4TupleCount, y );
  771. // NOTE: int cast is where it is to force round-to-zero prior to offset
  772. if ( m_Format & ( MORPH_POSITION | MORPH_WRINKLE ) )
  773. {
  774. int r = 32767, g = 32767, b = 32767, a = 32767;
  775. if ( m_Format & MORPH_POSITION )
  776. {
  777. r = (int)( info.m_PositionDelta.x * m_flFloatToFixedScale ) + 32767;
  778. g = (int)( info.m_PositionDelta.y * m_flFloatToFixedScale ) + 32767;
  779. b = (int)( info.m_PositionDelta.z * m_flFloatToFixedScale ) + 32767;
  780. r = clamp( r, 0, 65534 );
  781. g = clamp( g, 0, 65534 );
  782. b = clamp( b, 0, 65534 );
  783. }
  784. if ( m_Format & MORPH_WRINKLE )
  785. {
  786. a = (int)( info.m_flWrinkleDelta * m_flFloatToFixedScale ) + 32767;
  787. a = clamp( a, 0, 65534 );
  788. }
  789. pixelWriter.WritePixel( r, g, b, a );
  790. }
  791. if ( m_Format & MORPH_NORMAL )
  792. {
  793. int r = 32767, g = 32767, b = 32767, a = 32767;
  794. r = (int)( info.m_NormalDelta.x * m_flFloatToFixedScale ) + 32767;
  795. g = (int)( info.m_NormalDelta.y * m_flFloatToFixedScale ) + 32767;
  796. b = (int)( info.m_NormalDelta.z * m_flFloatToFixedScale ) + 32767;
  797. r = clamp( r, 0, 65534 );
  798. g = clamp( g, 0, 65534 );
  799. b = clamp( b, 0, 65534 );
  800. pixelWriter.WritePixel( r, g, b, a );
  801. }
  802. }
  803. void CMorph::WriteSideSpeedToTexture( CPixelWriter &pixelWriter, int x, int y, const MorphVertexInfo_t &info )
  804. {
  805. Assert ( m_Format & ( MORPH_SPEED | MORPH_SIDE ) );
  806. // Speed + size go from 0 to 1.
  807. int r = 0, g = 0, b = 0, a = 0;
  808. if ( m_Format & MORPH_SIDE )
  809. {
  810. r = info.m_flSide * 255;
  811. }
  812. if ( m_Format & MORPH_SPEED )
  813. {
  814. g = info.m_flSpeed * 255;
  815. }
  816. r = clamp( r, 0, 255 );
  817. g = clamp( g, 0, 255 );
  818. pixelWriter.Seek( x, y );
  819. pixelWriter.WritePixel( r, g, b, a );
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Builds the list of segments to render
  823. //-----------------------------------------------------------------------------
  824. void CMorph::BuildSegmentList( CUtlVector< MorphSegmentList_t > &morphSegments )
  825. {
  826. // Find the dimensions of the destination texture
  827. int nDestTextureWidth, nDestTextureHeight;
  828. s_MorphMgr.GetAccumulatorSubrectDimensions( &nDestTextureWidth, &nDestTextureHeight );
  829. // Prepares the morph segments array
  830. m_nMaxMorphTargetCount = 0;
  831. int nMorphTargetCount = m_MorphDict.MorphCount();
  832. for ( int i = 0; i < nMorphTargetCount; ++i )
  833. {
  834. if ( m_nMaxMorphTargetCount <= m_MorphDict.GetMorphTargetId(i) )
  835. {
  836. m_nMaxMorphTargetCount = m_MorphDict.GetMorphTargetId(i) + 1;
  837. }
  838. }
  839. // Allocate space to cache off the morph weights when in the middle of performing morph accumulation
  840. Assert( !m_pRenderMorphWeight );
  841. m_pRenderMorphWeight = new MorphWeight_t[ m_nMaxMorphTargetCount ];
  842. Assert( m_nMaxMorphTargetCount < 1024 ); // This algorithm of storing a full array is bogus if this isn't true
  843. m_MorphTargetIdToQuadIndex.SetCount( m_nMaxMorphTargetCount );
  844. memset( m_MorphTargetIdToQuadIndex.Base(), 0xFF, m_nMaxMorphTargetCount * sizeof(int) );
  845. // Builds the segment list
  846. int nSrcIndex = 0;
  847. for ( int i = 0; i < nMorphTargetCount; ++i )
  848. {
  849. int nMorphTargetId = m_MorphDict.GetMorphTargetId( i );
  850. m_MorphTargetIdToQuadIndex[nMorphTargetId] = i;
  851. int nSegmentIndex = morphSegments.AddToTail();
  852. MorphSegmentList_t &list = morphSegments[nSegmentIndex];
  853. Assert( nSegmentIndex == i );
  854. MorphSegment_t segment;
  855. segment.m_nCount = 0;
  856. int nVertexCount = m_MorphDict.GetMorphVertexCount( i );
  857. int nLastDestIndex = -1;
  858. for ( int j = 0; j < nVertexCount; ++j )
  859. {
  860. const MorphVertexInfo_t &info = m_MorphDict.GetMorphVertexInfo( i, j );
  861. // Check for segment break conditions
  862. if ( segment.m_nCount )
  863. {
  864. // Vertical overflow, non-contiguous destination verts, or contiguous dest
  865. // verts which happen to lie in different columns are the break conditions
  866. if ( ( nLastDestIndex < 0 ) || ( info.m_nVertexId > nLastDestIndex + MIN_SEGMENT_GAP_SIZE ) ||
  867. ( info.m_nVertexId / nDestTextureHeight != nLastDestIndex / nDestTextureHeight ) )
  868. {
  869. list.AddToTail( segment );
  870. nLastDestIndex = -1;
  871. }
  872. }
  873. // Start new segment, or append to existing segment
  874. if ( nLastDestIndex < 0 )
  875. {
  876. segment.m_nFirstSrc = nSrcIndex;
  877. segment.m_nFirstDest = info.m_nVertexId;
  878. segment.m_nCount = 1;
  879. ++nSrcIndex;
  880. }
  881. else
  882. {
  883. int nSegmentCount = info.m_nVertexId - nLastDestIndex;
  884. segment.m_nCount += nSegmentCount;
  885. nSrcIndex += nSegmentCount;
  886. }
  887. nLastDestIndex = info.m_nVertexId;
  888. }
  889. // Add any trailing segment
  890. if ( segment.m_nCount )
  891. {
  892. list.AddToTail( segment );
  893. }
  894. }
  895. }
  896. //-----------------------------------------------------------------------------
  897. // Builds the list of quads to render
  898. //-----------------------------------------------------------------------------
  899. void CMorph::BuildQuadList( const CUtlVector< MorphSegmentList_t > &morphSegments )
  900. {
  901. m_MorphQuads.RemoveAll();
  902. int nQuadIndex = 0;
  903. int nMorphCount = morphSegments.Count();
  904. for ( int i = 0; i < nMorphCount; ++i )
  905. {
  906. int k = m_MorphQuads.AddToTail();
  907. MorphQuadList_t &quadList = m_MorphQuads[k];
  908. const MorphSegmentList_t& segmentList = morphSegments[i];
  909. int nSegmentCount = segmentList.Count();
  910. for ( int j = 0; j < nSegmentCount; ++j )
  911. {
  912. const MorphSegment_t &segment = segmentList[j];
  913. int nSrc = segment.m_nFirstSrc;
  914. int nDest = segment.m_nFirstDest;
  915. int nTotalCount = segment.m_nCount;
  916. do
  917. {
  918. int sx = nSrc / m_nTextureHeight;
  919. int sy = nSrc - sx * m_nTextureHeight;
  920. int nMaxCount = m_nTextureHeight - sy;
  921. int nCount = MIN( nMaxCount, nTotalCount );
  922. nTotalCount -= nCount;
  923. int l = quadList.AddToTail();
  924. MorphQuad_t &quad = quadList[l];
  925. quad.m_nQuadIndex = nQuadIndex++;
  926. quad.m_nCount = nCount;
  927. quad.m_nFirstSrc = nSrc;
  928. quad.m_nFirstDest = nDest;
  929. nSrc += nCount;
  930. nDest += nCount;
  931. } while ( nTotalCount > 0 );
  932. }
  933. }
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Counts the total number of vertices to place in the static mesh
  937. //-----------------------------------------------------------------------------
  938. int CMorph::CountStaticMeshVertices() const
  939. {
  940. // FIXME: I'm doing the simple thing here of 4 verts per segment.
  941. // I believe I should be able to share any edge that isn't on the edges of the texture
  942. // so I should be able to get down to nearly 2 (or is it 1?) verts per segment.
  943. int nVertexCount = 0;
  944. int nMorphCount = m_MorphQuads.Count();
  945. for ( int i = 0; i < nMorphCount; ++i )
  946. {
  947. const MorphQuadList_t& quadList = m_MorphQuads[i];
  948. nVertexCount += quadList.Count() * 4;
  949. }
  950. return nVertexCount;
  951. }
  952. //-----------------------------------------------------------------------------
  953. // Determines mesh vertex format
  954. //-----------------------------------------------------------------------------
  955. VertexFormat_t CMorph::ComputeVertexFormat( IMaterial * pMaterial ) const
  956. {
  957. // We believe this material's vertex format is reliable (unlike many others as of June 07)
  958. VertexFormat_t vertexFormat = pMaterial->GetVertexFormat();
  959. // UNDONE: optimize the vertex format to compress or remove elements where possible
  960. vertexFormat &= ~VERTEX_FORMAT_COMPRESSED;
  961. return vertexFormat;
  962. }
  963. //-----------------------------------------------------------------------------
  964. // Builds the list of segments to render
  965. //-----------------------------------------------------------------------------
  966. void CMorph::CreateStaticMesh()
  967. {
  968. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  969. m_MorphAccumulationMaterial->Refresh();
  970. VertexFormat_t vertexFormat = ComputeVertexFormat( m_MorphAccumulationMaterial );
  971. m_pMorphBuffer = pRenderContext->CreateStaticMesh( vertexFormat, TEXTURE_GROUP_MORPH_TARGETS, m_MorphAccumulationMaterial );
  972. int nVertexCount = CountStaticMeshVertices();
  973. if ( nVertexCount >= 65535 )
  974. {
  975. Warning( "Too many morph vertices! Call brian\n" );
  976. }
  977. Assert( nVertexCount < 65535 );
  978. int n4TupleCount = Get4TupleCount( m_Format );
  979. float flOOTexWidth = 1.0f / ( n4TupleCount * m_nTextureWidth );
  980. float flOOTexHeight = 1.0f / m_nTextureHeight;
  981. int nDestTextureWidth, nDestTextureHeight;
  982. s_MorphMgr.GetAccumulatorSubrectDimensions( &nDestTextureWidth, &nDestTextureHeight );
  983. float flOODestWidth = 1.0f / nDestTextureWidth;
  984. float flOODestHeight = 1.0f / nDestTextureHeight;
  985. // NOTE: zero index count implies no index buffer
  986. CMeshBuilder meshBuilder;
  987. meshBuilder.Begin( m_pMorphBuffer, MATERIAL_TRIANGLES, nVertexCount, 0 );
  988. int nMorphCount = m_MorphQuads.Count();
  989. for ( int i = 0; i < nMorphCount; ++i )
  990. {
  991. MorphQuadList_t& quadList = m_MorphQuads[i];
  992. int nQuadCount = quadList.Count();
  993. for ( int j = 0; j < nQuadCount; ++j )
  994. {
  995. MorphQuad_t &quad = quadList[j];
  996. int sx = quad.m_nFirstSrc / m_nTextureHeight;
  997. int sy = quad.m_nFirstSrc - sx * m_nTextureHeight;
  998. int dx = quad.m_nFirstDest / nDestTextureHeight;
  999. int dy = quad.m_nFirstDest - dx * nDestTextureHeight;
  1000. sx *= n4TupleCount; dx *= n4TupleCount;
  1001. meshBuilder.TexCoord4f( 0, sx * flOOTexWidth, sy * flOOTexHeight,
  1002. ( dx - 0.5f ) * flOODestWidth, ( dy - 0.5f ) * flOODestHeight ); // Stores the source to read from
  1003. meshBuilder.TexCoord1f( 1, i );
  1004. meshBuilder.AdvanceVertex();
  1005. meshBuilder.TexCoord4f( 0, sx * flOOTexWidth, ( sy + quad.m_nCount ) * flOOTexHeight,
  1006. ( dx - 0.5f ) * flOODestWidth, ( dy + quad.m_nCount - 0.5f ) * flOODestHeight ); // Stores the source to read from
  1007. meshBuilder.TexCoord1f( 1, i );
  1008. meshBuilder.AdvanceVertex();
  1009. meshBuilder.TexCoord4f( 0, (sx + n4TupleCount) * flOOTexWidth, ( sy + quad.m_nCount ) * flOOTexHeight,
  1010. ( dx + n4TupleCount - 0.5f ) * flOODestWidth, ( dy + quad.m_nCount - 0.5f ) * flOODestHeight ); // Stores the source to read from
  1011. meshBuilder.TexCoord1f( 1, i );
  1012. meshBuilder.AdvanceVertex();
  1013. meshBuilder.TexCoord4f( 0, (sx + n4TupleCount) * flOOTexWidth, sy * flOOTexHeight,
  1014. ( dx + n4TupleCount - 0.5f ) * flOODestWidth, ( dy - 0.5f ) * flOODestHeight ); // Stores the source to read from
  1015. meshBuilder.TexCoord1f( 1, i );
  1016. meshBuilder.AdvanceVertex();
  1017. }
  1018. }
  1019. meshBuilder.End();
  1020. }
  1021. //-----------------------------------------------------------------------------
  1022. // Inherited from ITextureRegenerator
  1023. //-----------------------------------------------------------------------------
  1024. void CMorph::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  1025. {
  1026. Assert( pVTFTexture->FrameCount() == 1 && pVTFTexture->FaceCount() == 1 );
  1027. Assert( pVTFTexture->Height() == m_nTextureHeight );
  1028. int nTextureType;
  1029. for ( nTextureType = 0; nTextureType < MORPH_TEXTURE_COUNT; ++nTextureType )
  1030. {
  1031. if ( pTexture == m_pMorphTexture[nTextureType] )
  1032. break;
  1033. }
  1034. Assert( nTextureType < MORPH_TEXTURE_COUNT );
  1035. MorphPixelWriter_t pWriteFuncs[MORPH_TEXTURE_COUNT] =
  1036. {
  1037. &CMorph::WriteDeltaPositionNormalToTexture,
  1038. &CMorph::WriteSideSpeedToTexture,
  1039. };
  1040. MorphPixelWriter_t writeFunc = pWriteFuncs[nTextureType];
  1041. CPixelWriter pixelWriter;
  1042. pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
  1043. // Clear the buffer
  1044. MorphVertexInfo_t zeroDelta;
  1045. zeroDelta.m_PositionDelta.Init();
  1046. zeroDelta.m_NormalDelta.Init();
  1047. zeroDelta.m_flWrinkleDelta = 0.0f;
  1048. zeroDelta.m_flSpeed = 1.0f;
  1049. zeroDelta.m_flSide = 0.5f;
  1050. int nWidth = pVTFTexture->Width() / Get4TupleCount( m_Format );
  1051. int nHeight = pVTFTexture->Height();
  1052. for ( int i = 0; i < nHeight; ++i )
  1053. {
  1054. for ( int j = 0; j < nWidth; ++j )
  1055. {
  1056. (this->*writeFunc)( pixelWriter, j, i, zeroDelta );
  1057. }
  1058. }
  1059. int nQuadListCount = m_MorphQuads.Count();
  1060. for ( int i = 0; i < nQuadListCount; ++i )
  1061. {
  1062. MorphQuadList_t &quadList = m_MorphQuads[i];
  1063. int nQuadCount = quadList.Count();
  1064. int nVertIndex = 0;
  1065. for ( int j = 0; j < nQuadCount; ++j )
  1066. {
  1067. MorphQuad_t &quad = quadList[j];
  1068. int sx = quad.m_nFirstSrc / m_nTextureHeight;
  1069. int sy = quad.m_nFirstSrc - sx * m_nTextureHeight;
  1070. int nDest = quad.m_nFirstDest;
  1071. for ( int k = 0; k < quad.m_nCount; ++k )
  1072. {
  1073. const MorphVertexInfo_t &info = m_MorphDict.GetMorphVertexInfo( i, nVertIndex );
  1074. if ( info.m_nVertexId > nDest )
  1075. {
  1076. (this->*writeFunc)( pixelWriter, sx, sy+k, zeroDelta );
  1077. }
  1078. else
  1079. {
  1080. (this->*writeFunc)( pixelWriter, sx, sy+k, info );
  1081. ++nVertIndex;
  1082. }
  1083. ++nDest;
  1084. }
  1085. }
  1086. }
  1087. }
  1088. //-----------------------------------------------------------------------------
  1089. // Deals with morph stats
  1090. //-----------------------------------------------------------------------------
  1091. static ConVar mat_morphstats( "mat_morphstats", "0", FCVAR_CHEAT );
  1092. static CUtlVector<int> s_ActiveMorphHisto;
  1093. static CUtlVector<int> s_RenderedQuadHisto;
  1094. static CUtlVector<int> s_RenderedTexelHisto;
  1095. static int s_nStatFrameCount = 0;
  1096. static int s_nStatMorphCount = 0;
  1097. static int s_nTotalMorphCount = 0;
  1098. static int s_nTotalQuadCount = 0;
  1099. static int s_nTotalTexelCount = 0;
  1100. void CMorph::ClearMorphStats()
  1101. {
  1102. s_ActiveMorphHisto.Purge();
  1103. s_RenderedQuadHisto.Purge();
  1104. s_RenderedTexelHisto.Purge();
  1105. s_nStatFrameCount = 0;
  1106. s_nTotalMorphCount = 0;
  1107. s_nTotalQuadCount = 0;
  1108. s_nTotalTexelCount = 0;
  1109. }
  1110. void CMorph::AccumulateMorphStats( int nActiveMorphCount, int nQuadsRendered, int nTexelsRendered )
  1111. {
  1112. while ( nActiveMorphCount >= s_ActiveMorphHisto.Count() )
  1113. {
  1114. s_ActiveMorphHisto.AddToTail( 0 );
  1115. }
  1116. while ( nQuadsRendered >= s_RenderedQuadHisto.Count() )
  1117. {
  1118. s_RenderedQuadHisto.AddToTail( 0 );
  1119. }
  1120. while ( nTexelsRendered >= s_RenderedTexelHisto.Count() )
  1121. {
  1122. s_RenderedTexelHisto.AddToTail( 0 );
  1123. }
  1124. s_ActiveMorphHisto[nActiveMorphCount] += 1;
  1125. s_RenderedQuadHisto[nQuadsRendered] += 1;
  1126. s_RenderedTexelHisto[nTexelsRendered] += 1;
  1127. s_nStatMorphCount++;
  1128. s_nTotalMorphCount += nActiveMorphCount;
  1129. s_nTotalQuadCount += nQuadsRendered;
  1130. s_nTotalTexelCount += nTexelsRendered;
  1131. }
  1132. void CMorph::ReportMorphStats( )
  1133. {
  1134. Msg( "Morph stats:\n" );
  1135. if ( s_nStatMorphCount == 0 )
  1136. {
  1137. Msg( "\tNo morphing done\n" );
  1138. return;
  1139. }
  1140. Msg( "\tAverage # of active morph targets per mesh group: %d\n", s_nTotalMorphCount / s_nStatMorphCount );
  1141. Msg( "\tAverage # of actual quad draws per morph: %d\n", s_nTotalQuadCount / s_nStatMorphCount );
  1142. Msg( "\tAverage # of actual rendered texels per morph: %d\n", s_nTotalTexelCount / s_nStatMorphCount );
  1143. Msg( "\tRendered Quad Count Histogram :\n\t\t" );
  1144. for ( int i = 0; i < s_RenderedQuadHisto.Count(); ++i )
  1145. {
  1146. if ( s_RenderedQuadHisto[i] == 0 )
  1147. continue;
  1148. Msg( "[%d : %d] ", i, s_RenderedQuadHisto[i] );
  1149. }
  1150. Msg( "\n\tRendered Texel Count Histogram :\n\t\t" );
  1151. for ( int i = 0; i < s_RenderedTexelHisto.Count(); ++i )
  1152. {
  1153. if ( s_RenderedTexelHisto[i] == 0 )
  1154. continue;
  1155. Msg( "[%d : %d] ", i, s_RenderedTexelHisto[i] );
  1156. }
  1157. Msg( "\n\tActive morph target Count Histogram :\n\t\t" );
  1158. for ( int i = 0; i < s_ActiveMorphHisto.Count(); ++i )
  1159. {
  1160. if ( s_ActiveMorphHisto[i] == 0 )
  1161. continue;
  1162. Msg( "[%d : %d] ", i, s_ActiveMorphHisto[i] );
  1163. }
  1164. Msg( "\n" );
  1165. }
  1166. void CMorph::HandleMorphStats( int nActiveMorphCount, int nQuadsRendered, int nTexelsRendered )
  1167. {
  1168. static bool s_bLastMorphStats = false;
  1169. bool bDoStats = mat_morphstats.GetInt() != 0;
  1170. if ( bDoStats )
  1171. {
  1172. if ( !s_bLastMorphStats )
  1173. {
  1174. ClearMorphStats();
  1175. }
  1176. AccumulateMorphStats( nActiveMorphCount, nQuadsRendered, nTexelsRendered );
  1177. }
  1178. else
  1179. {
  1180. if ( s_bLastMorphStats )
  1181. {
  1182. ReportMorphStats();
  1183. ClearMorphStats();
  1184. }
  1185. }
  1186. s_bLastMorphStats = bDoStats;
  1187. }
  1188. //-----------------------------------------------------------------------------
  1189. // Renders to the morph accumulator texture
  1190. //-----------------------------------------------------------------------------
  1191. void CMorph::RenderMorphQuads( IMatRenderContext *pRenderContext, int nRenderId, int nTotalQuadCount, int nWeightCount, int *pWeightLookup, const MorphWeight_t* pWeights )
  1192. {
  1193. if ( s_MorphMgr.IsUsingConstantRegisters() )
  1194. {
  1195. pRenderContext->SetFlexWeights( 0, m_nMaxMorphTargetCount, m_pRenderMorphWeight );
  1196. }
  1197. else
  1198. {
  1199. BindMorphWeight( nRenderId );
  1200. }
  1201. int nXOffset, nYOffset, nWidth, nHeight;
  1202. s_MorphMgr.ComputeAccumulatorSubrect( &nXOffset, &nYOffset, &nWidth, &nHeight, nRenderId );
  1203. pRenderContext->Viewport( nXOffset, nYOffset, nWidth, nHeight );
  1204. CMeshBuilder meshBuilder;
  1205. IMesh *pMesh = pRenderContext->GetDynamicMesh( false, m_pMorphBuffer );
  1206. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 0, nTotalQuadCount * 6 );
  1207. #ifdef REPORT_MORPH_STATS
  1208. int nTexelsRendered = 0;
  1209. #endif
  1210. for ( int i = 0; i < nWeightCount; ++i )
  1211. {
  1212. int nMorphIndex = m_MorphTargetIdToQuadIndex[ pWeightLookup[i] ];
  1213. if ( nMorphIndex < 0 )
  1214. continue;
  1215. const MorphQuadList_t& quadList = m_MorphQuads[nMorphIndex];
  1216. int nQuadCount = quadList.Count();
  1217. for ( int j = 0; j < nQuadCount; ++j )
  1218. {
  1219. const MorphQuad_t &quad = quadList[j];
  1220. #ifdef _DEBUG
  1221. static int s_nMinDest = -1, s_nMaxDest = -1;
  1222. if ( s_nMinDest >= 0 && quad.m_nFirstDest + quad.m_nCount <= s_nMinDest )
  1223. continue;
  1224. if ( s_nMaxDest >= 0 && quad.m_nFirstDest > s_nMaxDest )
  1225. continue;
  1226. #endif
  1227. #ifdef REPORT_MORPH_STATS
  1228. nTexelsRendered += Get4TupleCount( m_Format ) * quad.m_nCount;
  1229. #endif
  1230. int nBaseIndex = quad.m_nQuadIndex * 4;
  1231. meshBuilder.FastIndex( nBaseIndex );
  1232. meshBuilder.FastIndex( nBaseIndex+1 );
  1233. meshBuilder.FastIndex( nBaseIndex+2 );
  1234. meshBuilder.FastIndex( nBaseIndex );
  1235. meshBuilder.FastIndex( nBaseIndex+2 );
  1236. meshBuilder.FastIndex( nBaseIndex+3 );
  1237. }
  1238. }
  1239. meshBuilder.End();
  1240. pMesh->Draw();
  1241. #ifdef REPORT_MORPH_STATS
  1242. HandleMorphStats( nWeightCount, nTotalQuadCount, nTexelsRendered );
  1243. #endif
  1244. }
  1245. //-----------------------------------------------------------------------------
  1246. // Should a morph weight be treated as zero
  1247. //-----------------------------------------------------------------------------
  1248. static inline bool IsMorphWeightZero( const MorphWeight_t &weight )
  1249. {
  1250. return ( FloatMakePositive( weight.m_pWeight[MORPH_WEIGHT] ) < 0.001 &&
  1251. FloatMakePositive( weight.m_pWeight[MORPH_WEIGHT_LAGGED] ) < 0.001 &&
  1252. FloatMakePositive( weight.m_pWeight[MORPH_WEIGHT_STEREO] ) < 0.001 &&
  1253. FloatMakePositive( weight.m_pWeight[MORPH_WEIGHT_STEREO_LAGGED] ) < 0.001 );
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. // Builds a list of non-zero morph targets
  1257. //-----------------------------------------------------------------------------
  1258. int CMorph::BuildNonZeroMorphList( int *pWeightIndices, int nWeightCount, const MorphWeight_t* pWeights )
  1259. {
  1260. int nWeightIndexCount = 0;
  1261. for ( int i = 0; i < m_nMaxMorphTargetCount; ++i )
  1262. {
  1263. const MorphWeight_t& weight = pWeights[i];
  1264. // Don't bother with weights that aren't represented in the morph
  1265. if ( m_MorphTargetIdToQuadIndex[i] < 0 )
  1266. continue;
  1267. // Don't bother with small weights
  1268. if ( IsMorphWeightZero( weight ) )
  1269. continue;
  1270. pWeightIndices[nWeightIndexCount++] = i;
  1271. }
  1272. return nWeightIndexCount;
  1273. }
  1274. //-----------------------------------------------------------------------------
  1275. // Renders to the morph weight texture
  1276. //-----------------------------------------------------------------------------
  1277. bool CMorph::RenderMorphWeights( IMatRenderContext *pRenderContext, int nRenderId, int nWeightCount, const MorphWeight_t* pWeights )
  1278. {
  1279. VPROF_BUDGET( "CMorph::RenderMorphWeights", _T("HW Morphing") );
  1280. if ( m_nMaxMorphTargetCount == 0 )
  1281. return false;
  1282. // Cache off the weights, we need them when we accumulate the morphs later.
  1283. int nCountToCopy = MIN( nWeightCount, m_nMaxMorphTargetCount );
  1284. memcpy( m_pRenderMorphWeight, pWeights, nCountToCopy * sizeof(MorphWeight_t) );
  1285. int nCountToClear = m_nMaxMorphTargetCount - nWeightCount;
  1286. if ( nCountToClear > 0 )
  1287. {
  1288. memset( &m_pRenderMorphWeight[nCountToCopy], 0, nCountToClear * sizeof(MorphWeight_t) );
  1289. }
  1290. int *pWeightIndices = (int*)stackalloc( nCountToCopy * sizeof(int) );
  1291. int nIndexCount = BuildNonZeroMorphList( pWeightIndices, nCountToCopy, pWeights );
  1292. if ( nIndexCount == 0 )
  1293. return false;
  1294. if ( s_MorphMgr.IsUsingConstantRegisters() )
  1295. return true;
  1296. int x, y, w, h;
  1297. s_MorphMgr.ComputeWeightSubrect( &x, &y, &w, &h, nRenderId );
  1298. ITexture *pMorphWeightTexture = s_MorphMgr.MorphWeights();
  1299. int nWidth = pMorphWeightTexture->GetActualWidth();
  1300. int nHeight = pMorphWeightTexture->GetActualHeight();
  1301. float flOOWidth = ( nWidth != 0 ) ? 1.0f / nWidth : 1.0f;
  1302. float flOOHeight = ( nHeight != 0 ) ? 1.0f / nHeight : 1.0f;
  1303. // Render the weights into the morph weight texture
  1304. CMeshBuilder meshBuilder;
  1305. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  1306. meshBuilder.Begin( pMesh, MATERIAL_POINTS, nCountToCopy );
  1307. for ( int i = 0; i < nIndexCount; ++i )
  1308. {
  1309. int nMorphId = pWeightIndices[i];
  1310. const MorphWeight_t& weight = pWeights[ nMorphId ];
  1311. int nLocalX = nMorphId / h;
  1312. int nLocalY = nMorphId - nLocalX * h;
  1313. meshBuilder.TexCoord2f( 0, ( nLocalX + x ) * flOOWidth, ( nLocalY + y ) * flOOHeight );
  1314. meshBuilder.TexCoord4fv( 1, weight.m_pWeight );
  1315. meshBuilder.AdvanceVertex();
  1316. }
  1317. meshBuilder.End();
  1318. pMesh->Draw();
  1319. return true;
  1320. }
  1321. //-----------------------------------------------------------------------------
  1322. // This will generate an accumulated morph target based on the passed-in weights
  1323. //-----------------------------------------------------------------------------
  1324. void CMorph::AccumulateMorph( int nRenderId )
  1325. {
  1326. VPROF_BUDGET( "CMorph::AccumulateMorph", _T("HW Morphing") );
  1327. // Build a non-zero weight list and a total quad count
  1328. int *pTargets = (int*)stackalloc( m_nMaxMorphTargetCount * sizeof(int) );
  1329. int nTargetCount = BuildNonZeroMorphList( pTargets, m_nMaxMorphTargetCount, m_pRenderMorphWeight );
  1330. // Count the total number of quads to draw
  1331. int nTotalQuadCount = 0;
  1332. for ( int i = 0; i < nTargetCount; ++i )
  1333. {
  1334. int nMorphIndex = m_MorphTargetIdToQuadIndex[ pTargets[i] ];
  1335. if ( nMorphIndex < 0 )
  1336. continue;
  1337. const MorphQuadList_t& quadList = m_MorphQuads[ nMorphIndex ];
  1338. nTotalQuadCount += quadList.Count();
  1339. }
  1340. // Clear the morph accumulator
  1341. // FIXME: Can I avoid even changing the render target if I know the last time
  1342. // the morph accumulator was used that it was also cleared to black? Yes, but
  1343. // I need to deal with alt-tab.
  1344. bool bRenderQuads = ( nTotalQuadCount != 0 ) && ( m_nTextureWidth != 0 ) && ( m_nTextureHeight != 0 );
  1345. if ( !bRenderQuads )
  1346. return;
  1347. // Next, iterate over all non-zero morphs and add them in.
  1348. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1349. pRenderContext->Bind( m_MorphAccumulationMaterial );
  1350. RenderMorphQuads( pRenderContext, nRenderId, nTotalQuadCount, nTargetCount, pTargets, m_pRenderMorphWeight );
  1351. }
  1352. //-----------------------------------------------------------------------------
  1353. //
  1354. // Morph mgr render context
  1355. //
  1356. //-----------------------------------------------------------------------------
  1357. CMorphMgrRenderContext::CMorphMgrRenderContext()
  1358. {
  1359. m_nMorphCount = 0;
  1360. #ifdef DBGFLAG_ASSERT
  1361. m_bInMorphAccumulation = false;
  1362. #endif
  1363. }
  1364. int CMorphMgrRenderContext::GetRenderId( CMorph* pMorph )
  1365. {
  1366. // FIXME: This could be done without all these comparisons, at the cost of memory + complexity.
  1367. // NOTE: m_nMorphCount <= 4.
  1368. for ( int i = 0; i < m_nMorphCount; ++i )
  1369. {
  1370. if ( m_pMorphsToAccumulate[i] == pMorph )
  1371. return i;
  1372. }
  1373. return -1;
  1374. }
  1375. //-----------------------------------------------------------------------------
  1376. //
  1377. // Morph manager implementation starts here
  1378. //
  1379. //-----------------------------------------------------------------------------
  1380. //-----------------------------------------------------------------------------
  1381. // Constructor
  1382. //-----------------------------------------------------------------------------
  1383. CMorphMgr::CMorphMgr()
  1384. {
  1385. m_pMorphAccumTexture = NULL;
  1386. m_pMorphWeightTexture = NULL;
  1387. m_pVisualizeMorphAccum = NULL;
  1388. m_pVisualizeMorphWeight = NULL;
  1389. m_pRenderMorphWeight = NULL;
  1390. m_nFrameCount = 0;
  1391. m_nTotalMorphSizeInBytes = 0;
  1392. m_bUsingConstantRegisters = false;
  1393. }
  1394. //-----------------------------------------------------------------------------
  1395. // Should we allocate textures?
  1396. //-----------------------------------------------------------------------------
  1397. bool CMorphMgr::ShouldAllocateScratchTextures()
  1398. {
  1399. return g_pMaterialSystemHardwareConfig->ActualHasFastVertexTextures() && !IsOpenGL();
  1400. }
  1401. //-----------------------------------------------------------------------------
  1402. // Allocates scratch textures used in hw morphing
  1403. //-----------------------------------------------------------------------------
  1404. void CMorphMgr::AllocateScratchTextures()
  1405. {
  1406. // Debug using 32323232F because we can read that back reasonably.
  1407. #if defined(_DEBUG)
  1408. ImageFormat fmt = IMAGE_FORMAT_RGBA32323232F;
  1409. #else
  1410. ImageFormat fmt = IMAGE_FORMAT_RGBA16161616F;
  1411. #endif
  1412. // NOTE: I'm not writing code to compute an appropriate width and height
  1413. // given a MAX_MORPH_ACCUMULATOR_VERTICES and MORPH_ACCUMULATOR_4TUPLES
  1414. // because this will rarely change. Just hard code it to something that will fit it.
  1415. m_nAccumulatorWidth = 256;
  1416. m_nAccumulatorHeight = 256;
  1417. Assert( m_nAccumulatorWidth * m_nAccumulatorHeight == MAX_MORPH_ACCUMULATOR_VERTICES * MORPH_ACCUMULATOR_4TUPLES );
  1418. Assert( IsPowerOfTwo( CMorphMgrRenderContext::MAX_MODEL_MORPHS ) );
  1419. int nMultFactor = sqrt( (float)CMorphMgrRenderContext::MAX_MODEL_MORPHS );
  1420. m_nSubrectVerticalCount = nMultFactor;
  1421. m_pMorphAccumTexture = TextureManager()->CreateRenderTargetTexture( "_rt_MorphAccumulator",
  1422. m_nAccumulatorWidth * nMultFactor, m_nAccumulatorHeight * nMultFactor,
  1423. RT_SIZE_OFFSCREEN, fmt, RENDER_TARGET_NO_DEPTH,
  1424. TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NODEBUGOVERRIDE |
  1425. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_VERTEXTEXTURE,
  1426. 0, false );
  1427. m_pMorphAccumTexture->IncrementReferenceCount();
  1428. int nDim = (int)sqrt( (float)MAXSTUDIOFLEXDESC );
  1429. while( nDim * nDim < MAXSTUDIOFLEXDESC )
  1430. {
  1431. ++nDim;
  1432. }
  1433. m_nWeightWidth = m_nWeightHeight = nDim;
  1434. // FIXME: Re-enable if NVidia gets a fast implementation using more shader constants
  1435. m_bUsingConstantRegisters = false; //( g_pMaterialSystemHardwareConfig->NumVertexShaderConstants() >= VERTEX_SHADER_FLEX_WEIGHTS + VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT );
  1436. if ( !m_bUsingConstantRegisters )
  1437. {
  1438. m_pMorphWeightTexture = TextureManager()->CreateRenderTargetTexture( "_rt_MorphWeight",
  1439. m_nWeightWidth * nMultFactor, m_nWeightHeight * nMultFactor,
  1440. RT_SIZE_OFFSCREEN, fmt, RENDER_TARGET_NO_DEPTH,
  1441. TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NODEBUGOVERRIDE |
  1442. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_POINTSAMPLE,
  1443. 0, false );
  1444. m_pMorphWeightTexture->IncrementReferenceCount();
  1445. }
  1446. }
  1447. void CMorphMgr::FreeScratchTextures()
  1448. {
  1449. if ( m_pMorphAccumTexture )
  1450. {
  1451. m_pMorphAccumTexture->DecrementReferenceCount();
  1452. m_pMorphAccumTexture->DeleteIfUnreferenced();
  1453. m_pMorphAccumTexture = NULL;
  1454. }
  1455. if ( m_pMorphWeightTexture )
  1456. {
  1457. m_pMorphWeightTexture->DecrementReferenceCount();
  1458. m_pMorphWeightTexture->DeleteIfUnreferenced();
  1459. m_pMorphWeightTexture = NULL;
  1460. }
  1461. }
  1462. //-----------------------------------------------------------------------------
  1463. // Allocates, frees materials used in hw morphing
  1464. //-----------------------------------------------------------------------------
  1465. void CMorphMgr::AllocateMaterials()
  1466. {
  1467. KeyValues *pVMTKeyValues = new KeyValues( "debugmorphaccumulator" );
  1468. pVMTKeyValues->SetString( "$basetexture", "_rt_MorphAccumulator" );
  1469. pVMTKeyValues->SetString( "$nocull", "1" );
  1470. pVMTKeyValues->SetString( "$ignorez", "1" );
  1471. m_pVisualizeMorphAccum = g_pMaterialSystem->CreateMaterial( "___visualizeMorphAccum.vmt", pVMTKeyValues );
  1472. if ( !m_bUsingConstantRegisters )
  1473. {
  1474. pVMTKeyValues = new KeyValues( "morphweight" );
  1475. pVMTKeyValues->SetString( "$model", "0" );
  1476. pVMTKeyValues->SetString( "$nocull", "1" );
  1477. pVMTKeyValues->SetString( "$ignorez", "1" );
  1478. m_pRenderMorphWeight = g_pMaterialSystem->CreateMaterial( "___morphweight.vmt", pVMTKeyValues );
  1479. pVMTKeyValues = new KeyValues( "debugmorphaccumulator" );
  1480. pVMTKeyValues->SetString( "$basetexture", "_rt_MorphWeight" );
  1481. pVMTKeyValues->SetString( "$nocull", "1" );
  1482. pVMTKeyValues->SetString( "$ignorez", "1" );
  1483. m_pVisualizeMorphWeight = g_pMaterialSystem->CreateMaterial( "___visualizeMorphWeight.vmt", pVMTKeyValues );
  1484. }
  1485. }
  1486. void CMorphMgr::FreeMaterials()
  1487. {
  1488. if ( m_pVisualizeMorphAccum )
  1489. {
  1490. m_pVisualizeMorphAccum->DecrementReferenceCount();
  1491. m_pVisualizeMorphAccum->DeleteIfUnreferenced();
  1492. m_pVisualizeMorphAccum = NULL;
  1493. }
  1494. if ( m_pVisualizeMorphWeight )
  1495. {
  1496. m_pVisualizeMorphWeight->DecrementReferenceCount();
  1497. m_pVisualizeMorphWeight->DeleteIfUnreferenced();
  1498. m_pVisualizeMorphWeight = NULL;
  1499. }
  1500. if ( m_pRenderMorphWeight )
  1501. {
  1502. m_pRenderMorphWeight->DecrementReferenceCount();
  1503. m_pRenderMorphWeight->DeleteIfUnreferenced();
  1504. m_pRenderMorphWeight = NULL;
  1505. }
  1506. }
  1507. //-----------------------------------------------------------------------------
  1508. // Morph render context
  1509. //-----------------------------------------------------------------------------
  1510. IMorphMgrRenderContext *CMorphMgr::AllocateRenderContext()
  1511. {
  1512. return new CMorphMgrRenderContext;
  1513. }
  1514. void CMorphMgr::FreeRenderContext( IMorphMgrRenderContext *pRenderContext )
  1515. {
  1516. delete static_cast< CMorphMgrRenderContext* >( pRenderContext );
  1517. }
  1518. //-----------------------------------------------------------------------------
  1519. // Returns the morph accumulation texture
  1520. //-----------------------------------------------------------------------------
  1521. ITextureInternal *CMorphMgr::MorphAccumulator()
  1522. {
  1523. return m_pMorphAccumTexture;
  1524. }
  1525. ITextureInternal *CMorphMgr::MorphWeights()
  1526. {
  1527. return m_pMorphWeightTexture;
  1528. }
  1529. //-----------------------------------------------------------------------------
  1530. // Class factory
  1531. //-----------------------------------------------------------------------------
  1532. IMorphInternal *CMorphMgr::CreateMorph()
  1533. {
  1534. return new CMorph;
  1535. }
  1536. void CMorphMgr::DestroyMorph( IMorphInternal *pMorphData )
  1537. {
  1538. if ( pMorphData )
  1539. {
  1540. delete static_cast< CMorph*>( pMorphData );
  1541. }
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Advances the frame (for debugging)
  1545. //-----------------------------------------------------------------------------
  1546. void CMorphMgr::AdvanceFrame()
  1547. {
  1548. ++m_nFrameCount;
  1549. }
  1550. //-----------------------------------------------------------------------------
  1551. // Computes texel offsets for the upper corner of the morph weight texture for a particular block
  1552. //-----------------------------------------------------------------------------
  1553. void CMorphMgr::ComputeWeightSubrect( int *pXOffset, int *pYOffset, int *pWidth, int *pHeight, int nMorphAccumBlockId )
  1554. {
  1555. *pXOffset = nMorphAccumBlockId / m_nSubrectVerticalCount;
  1556. *pYOffset = nMorphAccumBlockId - m_nSubrectVerticalCount * (*pXOffset);
  1557. *pXOffset *= m_nWeightWidth;
  1558. *pYOffset *= m_nWeightHeight;
  1559. *pWidth = m_nWeightWidth;
  1560. *pHeight = m_nWeightHeight;
  1561. }
  1562. //-----------------------------------------------------------------------------
  1563. // Computes texel offsets for the upper corner of the morph accumulator for a particular block
  1564. //-----------------------------------------------------------------------------
  1565. void CMorphMgr::ComputeAccumulatorSubrect( int *pXOffset, int *pYOffset, int *pWidth, int *pHeight, int nMorphAccumBlockId )
  1566. {
  1567. *pXOffset = nMorphAccumBlockId / m_nSubrectVerticalCount;
  1568. *pYOffset = nMorphAccumBlockId - m_nSubrectVerticalCount * (*pXOffset);
  1569. *pXOffset *= m_nAccumulatorWidth;
  1570. *pYOffset *= m_nAccumulatorHeight;
  1571. *pWidth = m_nAccumulatorWidth;
  1572. *pHeight = m_nAccumulatorHeight;
  1573. }
  1574. void CMorphMgr::GetAccumulatorSubrectDimensions( int *pWidth, int *pHeight )
  1575. {
  1576. *pWidth = m_nAccumulatorWidth;
  1577. *pHeight = m_nAccumulatorHeight;
  1578. }
  1579. int CMorphMgr::GetAccumulator4TupleCount() const
  1580. {
  1581. return MORPH_ACCUMULATOR_4TUPLES;
  1582. }
  1583. //-----------------------------------------------------------------------------
  1584. // Used to compute stats of memory used
  1585. //-----------------------------------------------------------------------------
  1586. CON_COMMAND_F( mat_reporthwmorphmemory, "Reports the amount of size in bytes taken up by hardware morph textures.", FCVAR_CHEAT )
  1587. {
  1588. ConMsg( "Total HW Morph memory used: %dk\n", s_MorphMgr.GetTotalMemoryUsage() /1024 );
  1589. }
  1590. void CMorphMgr::RegisterMorphSizeInBytes( int nSizeInBytes )
  1591. {
  1592. m_nTotalMorphSizeInBytes += nSizeInBytes;
  1593. Assert( m_nTotalMorphSizeInBytes >= 0 );
  1594. }
  1595. int CMorphMgr::GetTotalMemoryUsage() const
  1596. {
  1597. int nSize = 0;
  1598. if ( m_pMorphAccumTexture )
  1599. {
  1600. nSize += m_pMorphAccumTexture->GetActualWidth() * m_pMorphAccumTexture->GetActualHeight() *
  1601. ImageLoader::SizeInBytes( m_pMorphAccumTexture->GetImageFormat() );
  1602. }
  1603. if ( m_pMorphWeightTexture )
  1604. {
  1605. nSize += m_pMorphWeightTexture->GetActualWidth() * m_pMorphWeightTexture->GetActualHeight() *
  1606. ImageLoader::SizeInBytes( m_pMorphWeightTexture->GetImageFormat() );
  1607. }
  1608. nSize += m_nTotalMorphSizeInBytes;
  1609. return nSize;
  1610. }
  1611. //-----------------------------------------------------------------------------
  1612. // Displays 32bit float texture data
  1613. //-----------------------------------------------------------------------------
  1614. void CMorphMgr::Display32FTextureData( float *pBuf, int nTexelID, int *pSubRect, ITexture *pTexture, int n4TupleCount )
  1615. {
  1616. int nColumn = nTexelID / pSubRect[3];
  1617. int nRow = nTexelID - nColumn * pSubRect[3];
  1618. nColumn *= n4TupleCount;
  1619. nColumn += pSubRect[0];
  1620. nRow += pSubRect[1];
  1621. Msg( "[%d] : ", nTexelID );
  1622. for ( int i = 0; i < n4TupleCount; ++i )
  1623. {
  1624. float *pBase;
  1625. pBase = &pBuf[ (nRow * pTexture->GetActualWidth() + nColumn + i ) * 4 ];
  1626. Msg( "[ %.4f %.4f %.4f %.4f ] ", pBase[0], pBase[1], pBase[2], pBase[3] );
  1627. }
  1628. Msg( "\n" );
  1629. }
  1630. //-----------------------------------------------------------------------------
  1631. // A debugging utility to display the morph accumulator
  1632. //-----------------------------------------------------------------------------
  1633. void CMorphMgr::DebugMorphAccumulator( IMatRenderContext *pRenderContext )
  1634. {
  1635. static bool s_bDebug = false;
  1636. if ( !s_bDebug )
  1637. return;
  1638. ITexture *pDest = g_pMorphMgr->MorphAccumulator( );
  1639. if ( pDest->GetImageFormat() != IMAGE_FORMAT_RGBA32323232F )
  1640. return;
  1641. int nDestWidth = pDest->GetActualWidth();
  1642. int nDestHeight = pDest->GetActualHeight();
  1643. float* pBuf = (float*)malloc( nDestWidth * nDestHeight * 4 * sizeof(float) );
  1644. pRenderContext->ReadPixels( 0, 0, nDestWidth, nDestHeight, (unsigned char*)pBuf, IMAGE_FORMAT_RGBA32323232F );
  1645. Msg( "Morph Accumulator:\n" );
  1646. static int s_nMinDisplay = 0;
  1647. static int s_nMaxDisplay = -1;
  1648. static int s_nMorphIndex = 0;
  1649. int pSubRect[4];
  1650. ComputeAccumulatorSubrect( &pSubRect[0], &pSubRect[1], &pSubRect[2], &pSubRect[3], s_nMorphIndex );
  1651. if ( s_nMaxDisplay < 0 )
  1652. {
  1653. Display32FTextureData( pBuf, s_nMinDisplay, pSubRect, pDest, MORPH_ACCUMULATOR_4TUPLES );
  1654. }
  1655. else
  1656. {
  1657. for ( int i = s_nMinDisplay; i <= s_nMaxDisplay; ++i )
  1658. {
  1659. Display32FTextureData( pBuf, i, pSubRect, pDest, MORPH_ACCUMULATOR_4TUPLES );
  1660. }
  1661. }
  1662. free( pBuf );
  1663. }
  1664. //-----------------------------------------------------------------------------
  1665. // A debugging utility to display the morph weights
  1666. //-----------------------------------------------------------------------------
  1667. void CMorphMgr::DebugMorphWeights( IMatRenderContext *pRenderContext )
  1668. {
  1669. static bool s_bDebug = false;
  1670. if ( !s_bDebug )
  1671. return;
  1672. ITexture *pTexture = MorphWeights();
  1673. int nWidth = pTexture->GetActualWidth();
  1674. int nHeight = pTexture->GetActualHeight();
  1675. if ( pTexture->GetImageFormat() != IMAGE_FORMAT_RGBA32323232F )
  1676. return;
  1677. pRenderContext->Flush();
  1678. float* pBuf = (float*)malloc( nWidth * nHeight * 4 * sizeof(float) );
  1679. pRenderContext->ReadPixels( 0, 0, nWidth, nHeight, (unsigned char*)pBuf, IMAGE_FORMAT_RGBA32323232F );
  1680. Msg( "Morph Weights:\n" );
  1681. static int s_nMinDisplay = 0;
  1682. static int s_nMaxDisplay = -1;
  1683. static int s_nMorphIndex = 0;
  1684. int pSubRect[4];
  1685. ComputeWeightSubrect( &pSubRect[0], &pSubRect[1], &pSubRect[2], &pSubRect[3], s_nMorphIndex );
  1686. if ( s_nMaxDisplay < 0 )
  1687. {
  1688. Display32FTextureData( pBuf, s_nMinDisplay, pSubRect, pTexture, 1 );
  1689. }
  1690. else
  1691. {
  1692. for ( int i = s_nMinDisplay; i <= s_nMaxDisplay; ++i )
  1693. {
  1694. Display32FTextureData( pBuf, i, pSubRect, pTexture, 1 );
  1695. }
  1696. }
  1697. free( pBuf );
  1698. }
  1699. //-----------------------------------------------------------------------------
  1700. // Draws the morph accumulator
  1701. //-----------------------------------------------------------------------------
  1702. #ifdef _DEBUG
  1703. ConVar mat_drawmorphaccumulator( "mat_drawmorphaccumulator", "0", FCVAR_CHEAT );
  1704. ConVar mat_drawmorphweights( "mat_drawmorphweights", "0", FCVAR_CHEAT );
  1705. #endif
  1706. void CMorphMgr::DrawMorphTempTexture( IMatRenderContext *pRenderContext, IMaterial *pMaterial, ITexture *pTexture )
  1707. {
  1708. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion(); //always work with the real time version of materials internally.
  1709. static int s_nLastFrameCount = -1;
  1710. static int s_nX = 0, s_nY = 0;
  1711. if ( s_nLastFrameCount != m_nFrameCount )
  1712. {
  1713. s_nX = 0; s_nY = 0;
  1714. s_nLastFrameCount = m_nFrameCount;
  1715. }
  1716. pRenderContext->Flush();
  1717. int nWidth = pTexture->GetActualWidth();
  1718. int nHeight = pTexture->GetActualHeight();
  1719. ::DrawScreenSpaceRectangle( pMaterial, s_nX, s_nY, nWidth, nHeight,
  1720. 0, 0, nWidth-1, nHeight-1, nWidth, nHeight );
  1721. s_nX += nWidth;
  1722. if ( s_nX > 1024 )
  1723. {
  1724. s_nX = 0;
  1725. s_nY += nHeight;
  1726. }
  1727. pRenderContext->Flush();
  1728. }
  1729. //-----------------------------------------------------------------------------
  1730. // Starts, ends morph accumulation.
  1731. //-----------------------------------------------------------------------------
  1732. int CMorphMgr::MaxHWMorphBatchCount() const
  1733. {
  1734. return CMorphMgrRenderContext::MAX_MODEL_MORPHS;
  1735. }
  1736. //-----------------------------------------------------------------------------
  1737. // Returns the texcoord associated with a morph
  1738. //-----------------------------------------------------------------------------
  1739. bool CMorphMgr::GetMorphAccumulatorTexCoord( IMorphMgrRenderContext *pRenderContext, Vector2D *pTexCoord, IMorph *pMorph, int nVertex )
  1740. {
  1741. CMorphMgrRenderContext *pMorphRenderContext = static_cast< CMorphMgrRenderContext* >( pRenderContext );
  1742. int nRenderId = pMorphRenderContext->GetRenderId( static_cast<CMorph*>( pMorph ) );
  1743. if ( nRenderId < 0 )
  1744. {
  1745. pTexCoord->Init();
  1746. return false;
  1747. }
  1748. int nWidth = m_pMorphAccumTexture->GetActualWidth();
  1749. int nHeight = m_pMorphAccumTexture->GetActualHeight();
  1750. if ( !nWidth || !nHeight )
  1751. {
  1752. pTexCoord->Init();
  1753. return false;
  1754. }
  1755. float flOOWidth = ( nWidth != 0 ) ? 1.0f / nWidth : 1.0f;
  1756. float flOOHeight = ( nHeight != 0 ) ? 1.0f / nHeight : 1.0f;
  1757. int x, y, w, h;
  1758. ComputeAccumulatorSubrect( &x, &y, &w, &h, nRenderId );
  1759. int nColumn = nVertex / h;
  1760. int nRow = nVertex - h * nColumn;
  1761. nColumn *= MORPH_ACCUMULATOR_4TUPLES;
  1762. pTexCoord->x = ( x + nColumn + 0.5f ) * flOOWidth;
  1763. pTexCoord->y = ( y + nRow + 0.5f ) * flOOHeight;
  1764. Assert( IsFinite( pTexCoord->x ) && IsFinite( pTexCoord->y ) );
  1765. return true;
  1766. }
  1767. //-----------------------------------------------------------------------------
  1768. // Starts, ends morph accumulation.
  1769. //-----------------------------------------------------------------------------
  1770. void CMorphMgr::BeginMorphAccumulation( IMorphMgrRenderContext *pIRenderContext )
  1771. {
  1772. VPROF_BUDGET( "CMorph::BeginMorphAccumulation", _T("HW Morphing") );
  1773. // Set up the render context
  1774. CMorphMgrRenderContext *pMorphRenderContext = static_cast< CMorphMgrRenderContext* >( pIRenderContext );
  1775. Assert( !pMorphRenderContext->m_bInMorphAccumulation );
  1776. pMorphRenderContext->m_nMorphCount = 0;
  1777. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1778. IMatRenderContextInternal *pRenderContextInternal = static_cast<IMatRenderContextInternal*>( (IMatRenderContext*)pRenderContext );
  1779. // Cache off the current material and other render state
  1780. // NOTE: We always have to do this because pushing the morph accumulator
  1781. // may cause it to be unbound; therefore we must force a rebind of the material.
  1782. m_pPrevMaterial = pRenderContextInternal->GetCurrentMaterial();
  1783. m_pPrevProxy = pRenderContextInternal->GetCurrentProxy();
  1784. m_nPrevBoneCount = pRenderContextInternal->GetCurrentNumBones();
  1785. m_nPrevClipMode = pRenderContext->GetHeightClipMode( );
  1786. m_bPrevClippingEnabled = pRenderContext->EnableClipping( false );
  1787. m_bFlashlightMode = pRenderContext->GetFlashlightMode();
  1788. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  1789. pRenderContext->SetNumBoneWeights( 0 );
  1790. pRenderContext->SetFlashlightMode( false );
  1791. if ( !m_bUsingConstantRegisters )
  1792. {
  1793. // FIXME: We could theoretically avoid pushing this if we copied off all the
  1794. // weights and set the weight texture only at the end if any non-zero weights
  1795. // were sent down
  1796. pRenderContext->PushRenderTargetAndViewport( m_pMorphWeightTexture );
  1797. #ifdef _DEBUG
  1798. // NOTE: No need to clear the texture; we will only be reading out of that
  1799. // texture at points where we've rendered to in this pass.
  1800. // But, we'll do it for debugging reasons.
  1801. // I believe this pattern of weights is the least likely to occur naturally.
  1802. pRenderContext->ClearColor4ub( 0, 0, 0, 0 );
  1803. pRenderContext->ClearBuffers( true, false, false );
  1804. #endif
  1805. }
  1806. #ifdef DBGFLAG_ASSERT
  1807. pMorphRenderContext->m_bInMorphAccumulation = true;
  1808. #endif
  1809. }
  1810. void CMorphMgr::EndMorphAccumulation( IMorphMgrRenderContext *pIRenderContext )
  1811. {
  1812. VPROF_BUDGET( "CMorph::EndMorphAccumulation", _T("HW Morphing") );
  1813. CMorphMgrRenderContext *pMorphRenderContext = static_cast< CMorphMgrRenderContext* >( pIRenderContext );
  1814. Assert( pMorphRenderContext->m_bInMorphAccumulation );
  1815. VPROF_INCREMENT_COUNTER( "HW Morph Count", pMorphRenderContext->m_nMorphCount );
  1816. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1817. #ifdef _DEBUG
  1818. if ( !m_bUsingConstantRegisters )
  1819. {
  1820. DebugMorphWeights( pRenderContext );
  1821. }
  1822. #endif
  1823. // Now that all the weights have been rendered, accumulate the morphs
  1824. // First, clear the morph accumulation texture
  1825. int nWidth = m_pMorphAccumTexture->GetActualWidth();
  1826. int nHeight = m_pMorphAccumTexture->GetActualHeight();
  1827. if ( !m_bUsingConstantRegisters )
  1828. {
  1829. pRenderContext->SetRenderTargetEx( 0, m_pMorphAccumTexture );
  1830. pRenderContext->Viewport( 0, 0, nWidth, nHeight );
  1831. }
  1832. else
  1833. {
  1834. pRenderContext->PushRenderTargetAndViewport( m_pMorphAccumTexture );
  1835. }
  1836. pRenderContext->ClearColor4ub( 0, 0, 0, 0 );
  1837. pRenderContext->ClearBuffers( true, false, false );
  1838. for ( int i = 0; i < pMorphRenderContext->m_nMorphCount; ++i )
  1839. {
  1840. pMorphRenderContext->m_pMorphsToAccumulate[i]->AccumulateMorph( i );
  1841. }
  1842. #ifdef _DEBUG
  1843. DebugMorphAccumulator( pRenderContext );
  1844. #endif
  1845. pRenderContext->PopRenderTargetAndViewport();
  1846. #ifdef _DEBUG
  1847. if ( mat_drawmorphweights.GetInt() )
  1848. {
  1849. if ( !m_bUsingConstantRegisters )
  1850. {
  1851. DrawMorphTempTexture( pRenderContext, m_pVisualizeMorphWeight, MorphWeights( ) );
  1852. }
  1853. }
  1854. if ( mat_drawmorphaccumulator.GetInt() )
  1855. {
  1856. DrawMorphTempTexture( pRenderContext, m_pVisualizeMorphAccum, MorphAccumulator( ) );
  1857. }
  1858. #endif
  1859. pRenderContext->Bind( m_pPrevMaterial, m_pPrevProxy );
  1860. pRenderContext->SetNumBoneWeights( m_nPrevBoneCount );
  1861. pRenderContext->SetHeightClipMode( m_nPrevClipMode );
  1862. pRenderContext->EnableClipping( m_bPrevClippingEnabled );
  1863. pRenderContext->SetFlashlightMode( m_bFlashlightMode );
  1864. #ifdef DBGFLAG_ASSERT
  1865. pMorphRenderContext->m_bInMorphAccumulation = false;
  1866. #endif
  1867. }
  1868. //-----------------------------------------------------------------------------
  1869. // Accumulates a morph target into the morph texture
  1870. //-----------------------------------------------------------------------------
  1871. void CMorphMgr::AccumulateMorph( IMorphMgrRenderContext *pIRenderContext, IMorph* pMorph, int nMorphCount, const MorphWeight_t* pWeights )
  1872. {
  1873. CMorphMgrRenderContext *pMorphRenderContext = static_cast< CMorphMgrRenderContext* >( pIRenderContext );
  1874. Assert( pMorphRenderContext->m_bInMorphAccumulation );
  1875. Assert( pMorphRenderContext->m_nMorphCount < CMorphMgrRenderContext::MAX_MODEL_MORPHS );
  1876. if ( pMorphRenderContext->m_nMorphCount >= CMorphMgrRenderContext::MAX_MODEL_MORPHS )
  1877. {
  1878. Warning( "Attempted to morph too many meshes in a single model!\n" );
  1879. Assert(0);
  1880. return;
  1881. }
  1882. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1883. CMorph *pMorphInternal = static_cast<CMorph*>( pMorph );
  1884. if ( !m_bUsingConstantRegisters )
  1885. {
  1886. pRenderContext->Bind( m_pRenderMorphWeight );
  1887. }
  1888. if ( pMorphInternal->RenderMorphWeights( pRenderContext, pMorphRenderContext->m_nMorphCount, nMorphCount, pWeights ) )
  1889. {
  1890. pMorphRenderContext->m_pMorphsToAccumulate[pMorphRenderContext->m_nMorphCount] = pMorphInternal;
  1891. ++pMorphRenderContext->m_nMorphCount;
  1892. }
  1893. }