Team Fortress 2 Source Code as on 22/4/2020
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.

2280 lines
73 KiB

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