//========= Copyright © 1996-2013, Valve Corporation, All rights reserved. ============// // // Purpose: Provide custom texture generation (compositing) // // $NoKeywords: $ //=============================================================================// #ifndef COMPOSITE_TEXTURE_H #define COMPOSITE_TEXTURE_H #include "materialsystem/MaterialSystemUtil.h" #include "materialsystem/itexture.h" #include "materialsystem/icompositetexturegenerator.h" #include "utllinkedlist.h" #include "utlbuffer.h" class IVisualsDataProcessor; class ITextureInternal; // // Render Targets for Custom Materials // class IMaterialSystem; class IMaterialSystemHardwareConfig; struct SCompositeTextureRTData_t { const char* pName; int nSize; bool bSRGB; bool bAvailable; // true if the RT was created and can be used. IVTFTexture *pScratch; }; // this should match the s_compositeTextureRTData array in composite_texture.cpp enum CompositeTextureRTSizes_t { #if !defined( PLATFORM_OSX ) COMPOSITE_TEXTURE_RT_2048, #endif COMPOSITE_TEXTURE_RT_1024, COMPOSITE_TEXTURE_RT_512, COMPOSITE_TEXTURE_RT_256, COMPOSITE_TEXTURE_RT_128, COMPOSITE_TEXTURE_RT_COUNT }; // // Texture Regenerator for Custom Materials // // This is where the compositing material is created and used to make the procedural textures // used with custom materials. It also holds the result vtfs that are copied into the // actual textures used for rendering. // enum CompositeTextureStages_t { COMPOSITE_TEXTURE_STATE_NOT_STARTED = 0, COMPOSITE_TEXTURE_STATE_ASYNC_TEXTURE_LOAD, COMPOSITE_TEXTURE_STATE_WAITING_FOR_ASYNC_TEXTURE_LOAD_FINISH, COMPOSITE_TEXTURE_STATE_NEEDS_INIT, COMPOSITE_TEXTURE_STATE_WAITING_FOR_RENDER_TO_RT, COMPOSITE_TEXTURE_STATE_RENDERED_TO_RT, COMPOSITE_TEXTURE_STATE_WAITING_FOR_READ_RT, COMPOSITE_TEXTURE_STATE_REQUESTED_READ, COMPOSITE_TEXTURE_STATE_WAITING_FOR_GETRESULT, COMPOSITE_TEXTURE_STATE_REQUESTED_GETRESULT, COMPOSITE_TEXTURE_STATE_COPY_TO_VTF_COMPLETE, COMPOSITE_TEXTURE_STATE_WAITING_FOR_MATERIAL_CLEANUP, COMPOSITE_TEXTURE_STATE_COMPLETE }; #define NUM_PRELOAD_TEXTURES 20 class CCompositeTexture; class CCompositeTextureResult : public ITextureRegenerator { public: CCompositeTextureResult( CCompositeTexture *pOwner ) : m_pOwner( pOwner ), m_pTexture( NULL ) {} virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ); virtual void Release(); CCompositeTexture *m_pOwner; ITexture *m_pTexture; }; class CCompositeTexture : public ICompositeTexture, public CRefCounted<> { public: CCompositeTexture( const CUtlBuffer &compareBlob, KeyValues *pCompositingMaterialKeyValues, CompositeTextureSize_t size, CompositeTextureFormat_t format, int nMaterialParamNameId, bool bSRGB, bool bIgnorePicMip ); bool Init(); void Refresh() { m_nRegenerateStage = COMPOSITE_TEXTURE_STATE_NOT_STARTED; m_bNeedsRegenerate = false; m_bNeedsFinalize = true; } bool IsReady() const { return ( !NeedsFinalize() && GenerationComplete() ); } bool GenerationComplete() const { return ( m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_COMPLETE ); } void Usage( int &nTextures, int &nBackingTextures ); bool NeedsAsyncTextureLoad() const { return m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_ASYNC_TEXTURE_LOAD; } void DoAsyncTextureLoad(); bool NeedsCompositingMaterial() const { return m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_NEEDS_INIT; } void CreateCompositingMaterial(); bool NeedsRender() const { return m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_WAITING_FOR_RENDER_TO_RT; } void RenderToRT(); bool HasRendered() const { return ( m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_RENDERED_TO_RT ); } void AdvanceToReadRT(); bool NeedsReadRT() const { return m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_WAITING_FOR_READ_RT; } void ReadRT(); bool NeedsGetResult() const { return m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_WAITING_FOR_GETRESULT; } void GetReadRTResult(); bool NeedsMaterialCleanup() const { return m_nRegenerateStage == COMPOSITE_TEXTURE_STATE_WAITING_FOR_MATERIAL_CLEANUP; } void CleanupCompositingMaterial(); void GenerationStep(); bool NeedsRegenerate() const { return m_bNeedsRegenerate; } void ForceRegenerate(); CompositeTextureFormat_t Format() const { return m_format; } CompositeTextureSize_t Size() const { return m_size; } int ActualSize() const { return m_nActualSize; } int GetMaterialParamNameId() const { return m_nMaterialParamNameId; } const char *GetName() { return m_szTextureName; } bool NeedsFinalize() const { return m_bNeedsFinalize; } void Finalize(); IVTFTexture *GetResultVTF() { return m_pResultVTF; } bool ShouldRelease() { return ( ( GetRefCount() == 1 ) && IsReady() ); } const CUtlBuffer &GetVisualsDataCompareBlob() { return m_compareBlob; } void ReleaseResult() { m_ResultTexture.Release(); } bool IsSRGB() const { return m_bSRGB; } bool Compare( const SCompositeTextureInfo &textureInfo ); protected: virtual ~CCompositeTexture(); void GenerateComposite(); void ReleasePreloadedTextures(); char m_szTextureName[ MAX_PATH ]; CompositeTextureSize_t m_size; CompositeTextureFormat_t m_format; // DXT1 or DXT5 only int m_nMaterialParamNameId; // the material parameter that this texture will fill/replace in the eventual Custom Material, also used to interact with the VisualsDataProcessor bool m_bSRGB; CompositeTextureStages_t m_nRegenerateStage; CUtlBuffer m_compareBlob; IVTFTexture *m_pResultVTF; CCompositeTextureResult m_ResultTexture; int m_nActualSize; bool m_bNeedsRegenerate; bool m_bNeedsFinalize; IVTFTexture *m_pScratchVTF; ITexture *m_pCustomMaterialRT; KeyValues *m_pCompositingMaterialKeyValues; IMaterial *m_pCompositingMaterial; int m_nLastFrameCount; CThreadEvent *m_pPixelsReadEvent; bool m_bIgnorePicMip; static int m_nTextureCount; private: CCompositeTexture( CCompositeTexture &); ITextureInternal* m_pPreLoadTextures[ NUM_PRELOAD_TEXTURES ]; }; // // Composite Texture Generator // // This is the class that the game talks to in order to make composite textures // You need a IVisualsDataProcessor based class to feed this. // class CCompositeTextureGenerator : public ICompositeTextureGenerator { public: CCompositeTextureGenerator( void ); virtual ~CCompositeTextureGenerator( void ); bool Init( void ); void Shutdown( void ); virtual bool Process( void ); virtual ICompositeTexture *GetCompositeTexture( IVisualsDataProcessor *pVisualsDataProcessor, int nMaterialParamNameId, CompositeTextureSize_t size, CompositeTextureFormat_t format, bool bSRGB, bool bIgnorePicMip = false , bool bAllowCreate = true ); virtual ICompositeTexture *GetCompositeTexture( const SCompositeTextureInfo &textureInfo, bool bIgnorePicMip = false , bool bAllowCreate = true ); virtual bool ForceRegenerate( ICompositeTexture *pTexture ); private: CUtlVector< CCompositeTexture * > m_pCompositeTextures; CUtlVector< CCompositeTexture * > m_pPendingCompositeTextures; void DestroyTextures( void ); void GenerateThread(); // never call this directly, it's running as another thread void CreateGenerateThread(); void DestroyGenerateThread(); CUtlLinkedList< CCompositeTexture * > m_pGenerateQueue; CThreadFastMutex m_GenerateQueueMutex; ThreadHandle_t m_hGenerateThread; bool m_bGenerateThreadExit; CTextureReference m_CompositeTextureManagerRTs[COMPOSITE_TEXTURE_RT_COUNT]; ITextureInternal* m_pGunGrimeTexture; ITextureInternal* m_pPaintWearTexture; }; #endif // COMPOSITE_TEXTURE_H