From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/public/materialsystem/IColorCorrection.h | 73 + mp/src/public/materialsystem/IShader.h | 205 + .../public/materialsystem/MaterialSystemUtil.cpp | 255 ++ mp/src/public/materialsystem/MaterialSystemUtil.h | 99 + mp/src/public/materialsystem/deformations.h | 58 + mp/src/public/materialsystem/hardwareverts.h | 86 + mp/src/public/materialsystem/idebugtextureinfo.h | 69 + mp/src/public/materialsystem/imaterial.h | 612 +++ mp/src/public/materialsystem/imaterialproxy.h | 32 + .../public/materialsystem/imaterialproxyfactory.h | 25 + mp/src/public/materialsystem/imaterialsystem.h | 1758 +++++++++ .../materialsystem/imaterialsystemhardwareconfig.h | 212 + mp/src/public/materialsystem/imaterialsystemstub.h | 31 + mp/src/public/materialsystem/imaterialvar.h | 245 ++ mp/src/public/materialsystem/imesh.h | 4047 ++++++++++++++++++++ mp/src/public/materialsystem/imorph.h | 251 ++ mp/src/public/materialsystem/ishaderapi.h | 43 + mp/src/public/materialsystem/itexture.h | 132 + mp/src/public/materialsystem/ivballoctracker.h | 35 + .../public/materialsystem/materialsystem_config.h | 219 ++ mp/src/public/materialsystem/meshreader.h | 268 ++ mp/src/public/materialsystem/shader_vcs_version.h | 75 + 22 files changed, 8830 insertions(+) create mode 100644 mp/src/public/materialsystem/IColorCorrection.h create mode 100644 mp/src/public/materialsystem/IShader.h create mode 100644 mp/src/public/materialsystem/MaterialSystemUtil.cpp create mode 100644 mp/src/public/materialsystem/MaterialSystemUtil.h create mode 100644 mp/src/public/materialsystem/deformations.h create mode 100644 mp/src/public/materialsystem/hardwareverts.h create mode 100644 mp/src/public/materialsystem/idebugtextureinfo.h create mode 100644 mp/src/public/materialsystem/imaterial.h create mode 100644 mp/src/public/materialsystem/imaterialproxy.h create mode 100644 mp/src/public/materialsystem/imaterialproxyfactory.h create mode 100644 mp/src/public/materialsystem/imaterialsystem.h create mode 100644 mp/src/public/materialsystem/imaterialsystemhardwareconfig.h create mode 100644 mp/src/public/materialsystem/imaterialsystemstub.h create mode 100644 mp/src/public/materialsystem/imaterialvar.h create mode 100644 mp/src/public/materialsystem/imesh.h create mode 100644 mp/src/public/materialsystem/imorph.h create mode 100644 mp/src/public/materialsystem/ishaderapi.h create mode 100644 mp/src/public/materialsystem/itexture.h create mode 100644 mp/src/public/materialsystem/ivballoctracker.h create mode 100644 mp/src/public/materialsystem/materialsystem_config.h create mode 100644 mp/src/public/materialsystem/meshreader.h create mode 100644 mp/src/public/materialsystem/shader_vcs_version.h (limited to 'mp/src/public/materialsystem') diff --git a/mp/src/public/materialsystem/IColorCorrection.h b/mp/src/public/materialsystem/IColorCorrection.h new file mode 100644 index 00000000..b3bcbb98 --- /dev/null +++ b/mp/src/public/materialsystem/IColorCorrection.h @@ -0,0 +1,73 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef ICOLORCORRECTION_H +#define ICOLORCORRECTION_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "bitmap/imageformat.h" + +typedef unsigned int ColorCorrectionHandle_t; +struct ShaderColorCorrectionInfo_t; + +#define COLORCORRECTION_INTERFACE_VERSION "COLORCORRECTION_VERSION_1" + +abstract_class IColorCorrectionSystem +{ +public: + virtual void Init() = 0; + virtual void Shutdown() = 0; + + virtual ColorCorrectionHandle_t AddLookup( const char *pName ) = 0; + virtual bool RemoveLookup( ColorCorrectionHandle_t handle ) = 0; + + virtual void SetLookupWeight( ColorCorrectionHandle_t handle, float flWeight ) = 0; + virtual float GetLookupWeight( ColorCorrectionHandle_t handle ) = 0; + virtual float GetLookupWeight( int i ) = 0; + + virtual void LockLookup() = 0; + virtual void LockLookup( ColorCorrectionHandle_t handle ) = 0; + + virtual void UnlockLookup() = 0; + virtual void UnlockLookup( ColorCorrectionHandle_t handle ) = 0; + + virtual void SetLookup( RGBX5551_t inColor, color24 outColor ) = 0; + virtual void SetLookup( ColorCorrectionHandle_t handle, RGBX5551_t inColor, color24 outColor ) = 0; + + virtual color24 GetLookup( RGBX5551_t inColor ) = 0; + virtual color24 GetLookup( ColorCorrectionHandle_t handle, RGBX5551_t inColor ) = 0; + + virtual void LoadLookup( const char *pLookupName ) = 0; + virtual void LoadLookup( ColorCorrectionHandle_t handle, const char *pLookupName ) = 0; + + virtual void CopyLookup( const color24 *pSrcColorCorrection ) = 0; + virtual void CopyLookup( ColorCorrectionHandle_t handle, const color24 *pSrcColorCorrection ) = 0; + + virtual void ResetLookup( ColorCorrectionHandle_t handle ) = 0; + virtual void ResetLookup( ) = 0; + + virtual void ReleaseTextures( ) = 0; + virtual void RestoreTextures( ) = 0; + + virtual void ResetLookupWeights( ) = 0; + + virtual int GetNumLookups( ) = 0; + + virtual color24 ConvertToColor24( RGBX5551_t inColor ) = 0; + + virtual void SetResetable( ColorCorrectionHandle_t handle, bool bResetable ) = 0; + + virtual void EnableColorCorrection( bool bEnable ) = 0; + + // FIXME: Move this to a private interface only the material system can see? + virtual void GetCurrentColorCorrection( ShaderColorCorrectionInfo_t* pInfo ) = 0; +}; + +#endif diff --git a/mp/src/public/materialsystem/IShader.h b/mp/src/public/materialsystem/IShader.h new file mode 100644 index 00000000..5d6b22d2 --- /dev/null +++ b/mp/src/public/materialsystem/IShader.h @@ -0,0 +1,205 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#ifndef ISHADER_H +#define ISHADER_H + +#ifdef _WIN32 +#pragma once +#endif + +//================================================================================================== +// **this goes into both platforms which run the translator, either the real Mac client or +// the Windows client running with r_emulategl mode ** +// +// size of the VS register bank in ARB / GLSL we expose +// it's not 256, because you can't use all 256 slots in 10.5.x. +// use this constant everywhere you might normally use "256" in reference to a parameter array size. +// The highest shader constant is c218, plus we allocate c219 and c220 for two clip planes +#define DXABSTRACT_VS_PARAM_SLOTS 219 +#define DXABSTRACT_VS_FIRST_BONE_SLOT VERTEX_SHADER_MODEL + +// user clip plane 0 goes in DXABSTRACT_VS_CLIP_PLANE_BASE... plane 1 goes in the slot after that +// dxabstract uses these constants to check plane index limit and to deliver planes to shader for DP4 -> oCLP[n] +#define DXABSTRACT_VS_CLIP_PLANE_BASE (DXABSTRACT_VS_PARAM_SLOTS-2) + +//================================================================================================== + + +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/ishaderapi.h" + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterialVar; +class IShaderShadow; +class IShaderDynamicAPI; +class IShaderInit; +class CBasePerMaterialContextData; + +//----------------------------------------------------------------------------- +// Shader flags +//----------------------------------------------------------------------------- +enum ShaderFlags_t +{ + SHADER_NOT_EDITABLE = 0x1 +}; + + +//----------------------------------------------------------------------------- +// Shader parameter flags +//----------------------------------------------------------------------------- +enum ShaderParamFlags_t +{ + SHADER_PARAM_NOT_EDITABLE = 0x1 +}; + + +//----------------------------------------------------------------------------- +// Information about each shader parameter +//----------------------------------------------------------------------------- +struct ShaderParamInfo_t +{ + const char *m_pName; + const char *m_pHelp; + ShaderParamType_t m_Type; + const char *m_pDefaultValue; + int m_nFlags; +}; + + +//----------------------------------------------------------------------------- +// Standard vertex shader constants +//----------------------------------------------------------------------------- +enum +{ + // Standard vertex shader constants + VERTEX_SHADER_MATH_CONSTANTS0 = 0, + VERTEX_SHADER_MATH_CONSTANTS1 = 1, + VERTEX_SHADER_CAMERA_POS = 2, + VERTEX_SHADER_FLEXSCALE = 3, // used by DX9 only! + VERTEX_SHADER_LIGHT_INDEX = 3, // used by DX8 only! + VERTEX_SHADER_MODELVIEWPROJ = 4, + VERTEX_SHADER_VIEWPROJ = 8, + VERTEX_SHADER_MODELVIEWPROJ_THIRD_ROW = 12, + VERTEX_SHADER_VIEWPROJ_THIRD_ROW = 13, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_10 = 14, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_11 = 15, + VERTEX_SHADER_FOG_PARAMS = 16, + VERTEX_SHADER_VIEWMODEL = 17, + VERTEX_SHADER_AMBIENT_LIGHT = 21, + VERTEX_SHADER_LIGHTS = 27, + VERTEX_SHADER_LIGHT0_POSITION = 29, + VERTEX_SHADER_MODULATION_COLOR = 47, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_0 = 48, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_1 = 49, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_2 = 50, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_3 = 51, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_4 = 52, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_5 = 53, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_6 = 54, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_7 = 55, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_8 = 56, + VERTEX_SHADER_SHADER_SPECIFIC_CONST_9 = 57, + VERTEX_SHADER_MODEL = 58, + + // + // We reserve up through 216 for the 53 bones + // + + // 219 ClipPlane0 |------ OpenGL will jam clip planes into these two + // 220 ClipPlane1 | + + VERTEX_SHADER_FLEX_WEIGHTS = 1024, + VERTEX_SHADER_MAX_FLEX_WEIGHT_COUNT = 512, +}; + +#define VERTEX_SHADER_BONE_TRANSFORM( k ) ( VERTEX_SHADER_MODEL + 3 * (k) ) + +//----------------------------------------------------------------------------- +// Standard vertex shader constants +//----------------------------------------------------------------------------- +enum +{ + // Standard vertex shader constants + VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST = 0, + VERTEX_SHADER_LIGHT_ENABLE_BOOL_CONST_COUNT = 4, + + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_0 = 4, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_1 = 5, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_2 = 6, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_3 = 7, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_4 = 8, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_5 = 9, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_6 = 10, + VERTEX_SHADER_SHADER_SPECIFIC_BOOL_CONST_7 = 11, +}; +// The public methods exposed by each shader +//----------------------------------------------------------------------------- +abstract_class IShader +{ +public: + // Returns the shader name + virtual char const* GetName( ) const = 0; + + // returns the shader fallbacks + virtual char const* GetFallbackShader( IMaterialVar** params ) const = 0; + + // Shader parameters + virtual int GetNumParams( ) const = 0; + + // These functions must be implemented by the shader + virtual void InitShaderParams( IMaterialVar** ppParams, const char *pMaterialName ) = 0; + virtual void InitShaderInstance( IMaterialVar** ppParams, IShaderInit *pShaderInit, const char *pMaterialName, const char *pTextureGroupName ) = 0; + virtual void DrawElements( IMaterialVar **params, int nModulationFlags, + IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, CBasePerMaterialContextData **pContextDataPtr ) = 0; + + virtual char const* GetParamName( int paramIndex ) const = 0; + virtual char const* GetParamHelp( int paramIndex ) const = 0; + virtual ShaderParamType_t GetParamType( int paramIndex ) const = 0; + virtual char const* GetParamDefault( int paramIndex ) const = 0; + + // FIXME: Figure out a better way to do this? + virtual int ComputeModulationFlags( IMaterialVar** params, IShaderDynamicAPI* pShaderAPI ) = 0; + virtual bool NeedsPowerOfTwoFrameBufferTexture( IMaterialVar **params, bool bCheckSpecificToThisFrame = true ) const = 0; + virtual bool NeedsFullFrameBufferTexture( IMaterialVar **params, bool bCheckSpecificToThisFrame ) const = 0; + virtual bool IsTranslucent( IMaterialVar **params ) const = 0; + + virtual int GetParamFlags( int paramIndex ) const = 0; + + virtual int GetFlags() const = 0; + + // FIXME: Remove GetParamName, etc. above +// virtual const ShaderParamInfo_t& GetParamInfo( int paramIndex ) const = 0; +}; + + +//----------------------------------------------------------------------------- +// Shader dictionaries defined in DLLs +//----------------------------------------------------------------------------- +enum PrecompiledShaderType_t +{ + PRECOMPILED_VERTEX_SHADER = 0, + PRECOMPILED_PIXEL_SHADER, + + PRECOMPILED_SHADER_TYPE_COUNT, +}; + + +//----------------------------------------------------------------------------- +// Flags field of PrecompiledShader_t +//----------------------------------------------------------------------------- +enum +{ + // runtime flags + SHADER_DYNAMIC_COMPILE_IS_HLSL = 0x1, + SHADER_FAILED_LOAD = 0x2, +}; + +#endif // ISHADER_H diff --git a/mp/src/public/materialsystem/MaterialSystemUtil.cpp b/mp/src/public/materialsystem/MaterialSystemUtil.cpp new file mode 100644 index 00000000..669de23b --- /dev/null +++ b/mp/src/public/materialsystem/MaterialSystemUtil.cpp @@ -0,0 +1,255 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $NoKeywords: $ +//===========================================================================// + +#include "materialsystem/MaterialSystemUtil.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imaterialsystem.h" +#include "tier1/KeyValues.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Little utility class to deal with material references +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CMaterialReference::CMaterialReference( char const* pMaterialName, const char *pTextureGroupName, bool bComplain ) : m_pMaterial( 0 ) +{ + if ( pMaterialName ) + { + Assert( pTextureGroupName ); + Init( pMaterialName, pTextureGroupName, bComplain ); + } +} + +CMaterialReference::~CMaterialReference() +{ + Shutdown(); +} + +//----------------------------------------------------------------------------- +// Attach to a material +//----------------------------------------------------------------------------- +void CMaterialReference::Init( char const* pMaterialName, const char *pTextureGroupName, bool bComplain ) +{ + IMaterial *pMaterial = materials->FindMaterial( pMaterialName, pTextureGroupName, bComplain); + if( IsErrorMaterial( pMaterial ) ) + { + if (IsOSX()) + { + printf("\n ##### CMaterialReference::Init got error material for %s in tex group %s", pMaterialName, pTextureGroupName ); + } + } + + Assert( pMaterial ); + Init( pMaterial ); +} + +void CMaterialReference::Init( const char *pMaterialName, KeyValues *pVMTKeyValues ) +{ + // CreateMaterial has a refcount of 1 + Shutdown(); + m_pMaterial = materials->CreateMaterial( pMaterialName, pVMTKeyValues ); +} + +void CMaterialReference::Init( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues ) +{ + IMaterial *pMaterial = materials->FindProceduralMaterial( pMaterialName, pTextureGroupName, pVMTKeyValues ); + Assert( pMaterial ); + Init( pMaterial ); +} + +void CMaterialReference::Init( IMaterial* pMaterial ) +{ + if ( m_pMaterial != pMaterial ) + { + Shutdown(); + m_pMaterial = pMaterial; + if ( m_pMaterial ) + { + m_pMaterial->IncrementReferenceCount(); + } + } +} + +void CMaterialReference::Init( CMaterialReference& ref ) +{ + if ( m_pMaterial != ref.m_pMaterial ) + { + Shutdown(); + m_pMaterial = ref.m_pMaterial; + if (m_pMaterial) + { + m_pMaterial->IncrementReferenceCount(); + } + } +} + +//----------------------------------------------------------------------------- +// Detach from a material +//----------------------------------------------------------------------------- +void CMaterialReference::Shutdown( ) +{ + if ( m_pMaterial && materials ) + { + m_pMaterial->DecrementReferenceCount(); + m_pMaterial = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Little utility class to deal with texture references +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CTextureReference::CTextureReference( ) : m_pTexture(NULL) +{ +} + +CTextureReference::CTextureReference( const CTextureReference &ref ) +{ + m_pTexture = ref.m_pTexture; + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } +} + +void CTextureReference::operator=( CTextureReference &ref ) +{ + m_pTexture = ref.m_pTexture; + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } +} + +CTextureReference::~CTextureReference( ) +{ + Shutdown(); +} + +//----------------------------------------------------------------------------- +// Attach to a texture +//----------------------------------------------------------------------------- +void CTextureReference::Init( char const* pTextureName, const char *pTextureGroupName, bool bComplain ) +{ + Shutdown(); + m_pTexture = materials->FindTexture( pTextureName, pTextureGroupName, bComplain ); + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } +} + +void CTextureReference::Init( ITexture* pTexture ) +{ + Shutdown(); + + m_pTexture = pTexture; + if (m_pTexture) + { + m_pTexture->IncrementReferenceCount(); + } +} + +void CTextureReference::InitProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags ) +{ + Shutdown(); + + m_pTexture = materials->CreateProceduralTexture( pTextureName, pTextureGroupName, w, h, fmt, nFlags ); + + // NOTE: The texture reference is already incremented internally above! + /* + if ( m_pTexture ) + { + m_pTexture->IncrementReferenceCount(); + } + */ +} + +void CTextureReference::InitRenderTarget( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName /* = NULL */ ) +{ + Shutdown(); + + int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT; + if ( depth == MATERIAL_RT_DEPTH_ONLY ) + textureFlags |= TEXTUREFLAGS_POINTSAMPLE; + + int renderTargetFlags = bHDR ? CREATERENDERTARGETFLAGS_HDR : 0; + + // NOTE: Refcount returned by CreateRenderTargetTexture is 1 + m_pTexture = materials->CreateNamedRenderTargetTextureEx( pStrOptionalName, w, h, sizeMode, fmt, + depth, textureFlags, renderTargetFlags ); + + Assert( m_pTexture ); +} + +//----------------------------------------------------------------------------- +// Detach from a texture +//----------------------------------------------------------------------------- +void CTextureReference::Shutdown( bool bDeleteIfUnReferenced ) +{ + if ( m_pTexture && materials ) + { + m_pTexture->DecrementReferenceCount(); + if ( bDeleteIfUnReferenced ) + { + m_pTexture->DeleteIfUnreferenced(); + } + m_pTexture = NULL; + } +} + +//----------------------------------------------------------------------------- +// Builds ONLY the system ram render target. Used when caller is explicitly managing. +// The paired EDRAM surface can be built in an alternate format. +//----------------------------------------------------------------------------- +#if defined( _X360 ) +void CTextureReference::InitRenderTargetTexture( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName ) +{ + // other variants not implemented yet + Assert( depth == MATERIAL_RT_DEPTH_NONE || depth == MATERIAL_RT_DEPTH_SHARED ); + Assert( !bHDR ); + + int renderTargetFlags = CREATERENDERTARGETFLAGS_NOEDRAM; + + m_pTexture = materials->CreateNamedRenderTargetTextureEx( + pStrOptionalName, + w, + h, + sizeMode, + fmt, + depth, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + renderTargetFlags ); + Assert( m_pTexture ); +} +#endif + +//----------------------------------------------------------------------------- +// Builds ONLY the EDRAM render target surface. Used when caller is explicitly managing. +// The paired system memory texture can be built in an alternate format. +//----------------------------------------------------------------------------- +#if defined( _X360 ) +void CTextureReference::InitRenderTargetSurface( int width, int height, ImageFormat fmt, bool bSameAsTexture ) +{ + // texture has to be created first + Assert( m_pTexture && m_pTexture->IsRenderTarget() ); + + m_pTexture->CreateRenderTargetSurface( width, height, fmt, bSameAsTexture ); +} +#endif + diff --git a/mp/src/public/materialsystem/MaterialSystemUtil.h b/mp/src/public/materialsystem/MaterialSystemUtil.h new file mode 100644 index 00000000..6e5ab11d --- /dev/null +++ b/mp/src/public/materialsystem/MaterialSystemUtil.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//===========================================================================// +#ifndef MATERIALSYSTEMUTIL_H +#define MATERIALSYSTEMUTIL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" //ImageFormat enum definition +#include "materialsystem/imaterialsystem.h" // RenderTargetSizeMode_t and MaterialRenderTargetDepth_t definition + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class ITexture; +class KeyValues; + +class KeyValues; + + +//----------------------------------------------------------------------------- +// Little utility class to deal with material references +//----------------------------------------------------------------------------- +class CMaterialReference +{ +public: + // constructor, destructor + CMaterialReference( char const* pMaterialName = 0, const char *pTextureGroupName = 0, bool bComplain = true ); + ~CMaterialReference(); + + // Attach to a material + void Init( const char* pMaterialName, const char *pTextureGroupName, bool bComplain = true ); + void Init( const char *pMaterialName, KeyValues *pVMTKeyValues ); + void Init( IMaterial* pMaterial ); + void Init( CMaterialReference& ref ); + void Init( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues ); + + // Detach from a material + void Shutdown(); + bool IsValid() { return m_pMaterial != 0; } + + // Automatic casts to IMaterial + operator IMaterial*() { return m_pMaterial; } + operator IMaterial*() const { return m_pMaterial; } + operator IMaterial const*() const { return m_pMaterial; } + IMaterial* operator->() { return m_pMaterial; } + +private: + IMaterial* m_pMaterial; +}; + +//----------------------------------------------------------------------------- +// Little utility class to deal with texture references +//----------------------------------------------------------------------------- +class CTextureReference +{ +public: + // constructor, destructor + CTextureReference( ); + CTextureReference( const CTextureReference &ref ); + ~CTextureReference(); + + // Attach to a texture + void Init( char const* pTexture, const char *pTextureGroupName, bool bComplain = true ); + void InitProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags ); + void InitRenderTarget( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName = NULL ); +#if defined( _X360 ) + // used when RT coupling is disparate (texture is DDR based, surface is EDRAM based) + void InitRenderTargetTexture( int width, int height, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName = NULL ); + void InitRenderTargetSurface( int width, int height, ImageFormat fmt, bool bSameAsTexture ); +#endif + void Init( ITexture* pTexture ); + + // Detach from a texture + void Shutdown( bool bDeleteIfUnReferenced = false ); + bool IsValid() { return m_pTexture != 0; } + + // Automatic casts to ITexture + operator ITexture*() { return m_pTexture; } + operator ITexture const*() const { return m_pTexture; } + ITexture* operator->() { return m_pTexture; } + + // Assignment operator + void operator=( CTextureReference &ref ); + +private: + ITexture* m_pTexture; +}; + + +#endif // !MATERIALSYSTEMUTIL_H diff --git a/mp/src/public/materialsystem/deformations.h b/mp/src/public/materialsystem/deformations.h new file mode 100644 index 00000000..429ff297 --- /dev/null +++ b/mp/src/public/materialsystem/deformations.h @@ -0,0 +1,58 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef DEFORMATIONS_H +#define DEFORMATIONS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" + +// nonlinear transformations which may be applied to model vertices when rendering. must be powers of two +enum DeformationType_t +{ + DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE = 1, // minxyz.minsoftness / maxxyz.maxsoftness +}; + + +struct DeformationBase_t // base class. don't use this +{ + DeformationType_t m_eType; +}; + + +struct BoxDeformation_t : DeformationBase_t +{ + // don't change the layout without changing code in shaderapidx8!!!! + Vector m_SourceMins; // cube to clamp within + float m_flPad0; + Vector m_SourceMaxes; + float m_flPad1; + + Vector m_ClampMins; + float m_flPad2; + Vector m_ClampMaxes; + float m_flPad3; + + FORCEINLINE BoxDeformation_t( void ) + { + m_eType = DEFORMATION_CLAMP_TO_BOX_IN_WORLDSPACE; + // invalid cube + m_SourceMins.Init( 0,0,0 ); + m_SourceMaxes.Init( -1, -1, -1 ); + + // no clamp + m_ClampMins.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX ); + m_ClampMaxes.Init( FLT_MAX, FLT_MAX, FLT_MAX ); + } + +}; + + + +#endif diff --git a/mp/src/public/materialsystem/hardwareverts.h b/mp/src/public/materialsystem/hardwareverts.h new file mode 100644 index 00000000..6f335581 --- /dev/null +++ b/mp/src/public/materialsystem/hardwareverts.h @@ -0,0 +1,86 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Hardware Verts +// +// Contains data purposely formatted for a dma copy into a D3D Vertex Buffer. +// The file is divided into two partitions, the foremost contains the static +// portion (header), the latter contains the streamable compliant portion. +// The streamable component starts and ends on a sector (512) aligned boundary. +// The header identifies the vertex format of the data and the atomic sizes of each component. +// The hierarchial mesh is flattened for dma but the vertex counts are available +// per mesh to transfer each mesh individually. +//=============================================================================// + +#ifndef HARDWAREVERTS_H +#define HARDWAREVERTS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "datamap.h" + +// valve hardware vertexes +#define VHV_VERSION 2 + +namespace HardwareVerts +{ + +#pragma pack(1) + +struct MeshHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + + // this mesh is part of this lod + unsigned int m_nLod; + + // this mesh has this many vertexes + unsigned int m_nVertexes; + + // starting at this offset + unsigned int m_nOffset; + + unsigned int m_nUnused[4]; +}; + +struct FileHeader_t +{ + DECLARE_BYTESWAP_DATADESC(); + + // file version as defined by VHV_VERSION + int m_nVersion; + + // must match checkSum in the .mdl header + unsigned int m_nChecksum; + + // a vertex consists of these components + uint32 m_nVertexFlags; + + // the byte size of a single vertex + // this won't be adequate, need some concept of byte format i.e. rgbexp32 vs rgba8888 + unsigned int m_nVertexSize; + + // total number of vertexes + unsigned int m_nVertexes; + + int m_nMeshes; + inline MeshHeader_t *pMesh( int nMesh ) const + { + return (MeshHeader_t *)(((byte *)this) + sizeof(FileHeader_t)) + nMesh; + }; + + inline void *pVertexBase( int nMesh ) const + { + return (void *)((byte *)this + pMesh( nMesh )->m_nOffset); + }; + + unsigned int m_nUnused[4]; +}; + +#pragma pack() + +}; // end namespace + +#endif // HARDWAREVERTS_H + diff --git a/mp/src/public/materialsystem/idebugtextureinfo.h b/mp/src/public/materialsystem/idebugtextureinfo.h new file mode 100644 index 00000000..dee72a8b --- /dev/null +++ b/mp/src/public/materialsystem/idebugtextureinfo.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IDEBUGTEXTUREINFO_H +#define IDEBUGTEXTUREINFO_H +#ifdef _WIN32 +#pragma once +#endif + + +class KeyValues; + + +// This interface is actually exported by the shader API DLL. +#define DEBUG_TEXTURE_INFO_VERSION "DebugTextureInfo001" + + +abstract_class IDebugTextureInfo +{ +public: + + // Use this to turn on the mode where it builds the debug texture list. + // At the end of the next frame, GetDebugTextureList() will return a valid list of the textures. + virtual void EnableDebugTextureList( bool bEnable ) = 0; + + // If this is on, then it will return all textures that exist, not just the ones that were bound in the last frame. + // It is required to enable debug texture list to get this. + virtual void EnableGetAllTextures( bool bEnable ) = 0; + + // Use this to get the results of the texture list. + // Do NOT release the KeyValues after using them. + // There will be a bunch of subkeys, each with these values: + // Name - the texture's filename + // Binds - how many times the texture was bound + // Format - ImageFormat of the texture + // Width - Width of the texture + // Height - Height of the texture + // It is required to enable debug texture list to get this. + virtual KeyValues* GetDebugTextureList() = 0; + + // Texture memory usage + enum TextureMemoryType + { + MEMORY_RESERVED_MIN = 0, + MEMORY_BOUND_LAST_FRAME, // sums up textures bound last frame + MEMORY_TOTAL_LOADED, // total texture memory used + MEMORY_ESTIMATE_PICMIP_1, // estimate of running with "picmip 1" + MEMORY_ESTIMATE_PICMIP_2, // estimate of running with "picmip 2" + MEMORY_RESERVED_MAX + }; + + // This returns how much memory was used. + virtual int GetTextureMemoryUsed( TextureMemoryType eTextureMemory ) = 0; + + // Use this to determine if texture debug info was computed within last numFramesAllowed frames. + virtual bool IsDebugTextureListFresh( int numFramesAllowed = 1 ) = 0; + + // Enable debug texture rendering when texture binds should not count towards textures + // used during a frame. Returns the old state of debug texture rendering flag to use + // it for restoring the mode. + virtual bool SetDebugTextureRendering( bool bEnable ) = 0; + +}; + + +#endif // IDEBUGTEXTUREINFO_H diff --git a/mp/src/public/materialsystem/imaterial.h b/mp/src/public/materialsystem/imaterial.h new file mode 100644 index 00000000..8499dfb0 --- /dev/null +++ b/mp/src/public/materialsystem/imaterial.h @@ -0,0 +1,612 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IMATERIAL_H +#define IMATERIAL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "bitmap/imageformat.h" +#include "materialsystem/imaterialsystem.h" + +//----------------------------------------------------------------------------- +// forward declaraions +//----------------------------------------------------------------------------- + +class IMaterialVar; +class ITexture; +class IMaterialProxy; +class Vector; + +//----------------------------------------------------------------------------- +// Flags for GetVertexFormat +//----------------------------------------------------------------------------- +#define VERTEX_POSITION 0x0001 +#define VERTEX_NORMAL 0x0002 +#define VERTEX_COLOR 0x0004 +#define VERTEX_SPECULAR 0x0008 + +#define VERTEX_TANGENT_S 0x0010 +#define VERTEX_TANGENT_T 0x0020 +#define VERTEX_TANGENT_SPACE ( VERTEX_TANGENT_S | VERTEX_TANGENT_T ) + +// Indicates we're using wrinkle +#define VERTEX_WRINKLE 0x0040 + +// Indicates we're using bone indices +#define VERTEX_BONE_INDEX 0x0080 + +// Indicates this is a vertex shader +#define VERTEX_FORMAT_VERTEX_SHADER 0x0100 + +// Indicates this format shouldn't be bloated to cache align it +// (only used for VertexUsage) +#define VERTEX_FORMAT_USE_EXACT_FORMAT 0x0200 + +// Indicates that compressed vertex elements are to be used (see also VertexCompressionType_t) +#define VERTEX_FORMAT_COMPRESSED 0x400 + +// Update this if you add or remove bits... +#define VERTEX_LAST_BIT 10 + +#define VERTEX_BONE_WEIGHT_BIT (VERTEX_LAST_BIT + 1) +#define USER_DATA_SIZE_BIT (VERTEX_LAST_BIT + 4) +#define TEX_COORD_SIZE_BIT (VERTEX_LAST_BIT + 7) + +#define VERTEX_BONE_WEIGHT_MASK ( 0x7 << VERTEX_BONE_WEIGHT_BIT ) +#define USER_DATA_SIZE_MASK ( 0x7 << USER_DATA_SIZE_BIT ) + +#define VERTEX_FORMAT_FIELD_MASK 0x0FF + +// If everything is off, it's an unknown vertex format +#define VERTEX_FORMAT_UNKNOWN 0 + + + +//----------------------------------------------------------------------------- +// Macros for construction.. +//----------------------------------------------------------------------------- +#define VERTEX_BONEWEIGHT( _n ) ((_n) << VERTEX_BONE_WEIGHT_BIT) +#define VERTEX_USERDATA_SIZE( _n ) ((_n) << USER_DATA_SIZE_BIT) +#define VERTEX_TEXCOORD_MASK( _coord ) (( 0x7ULL ) << ( TEX_COORD_SIZE_BIT + 3 * (_coord) )) + +inline VertexFormat_t VERTEX_TEXCOORD_SIZE( int nIndex, int nNumCoords ) +{ + uint64 n64=nNumCoords; + uint64 nShift=TEX_COORD_SIZE_BIT + (3*nIndex); + return n64 << nShift; +} + + + +//----------------------------------------------------------------------------- +// Gets at various vertex format info... +//----------------------------------------------------------------------------- +inline int VertexFlags( VertexFormat_t vertexFormat ) +{ + return static_cast ( vertexFormat & ( (1 << (VERTEX_LAST_BIT+1)) - 1 ) ); +} + +inline int NumBoneWeights( VertexFormat_t vertexFormat ) +{ + return static_cast ( (vertexFormat >> VERTEX_BONE_WEIGHT_BIT) & 0x7 ); +} + +inline int UserDataSize( VertexFormat_t vertexFormat ) +{ + return static_cast ( (vertexFormat >> USER_DATA_SIZE_BIT) & 0x7 ); +} + +inline int TexCoordSize( int nTexCoordIndex, VertexFormat_t vertexFormat ) +{ + return static_cast ( (vertexFormat >> (TEX_COORD_SIZE_BIT + 3*nTexCoordIndex) ) & 0x7 ); +} + +inline bool UsesVertexShader( VertexFormat_t vertexFormat ) +{ + return (vertexFormat & VERTEX_FORMAT_VERTEX_SHADER) != 0; +} + +inline VertexCompressionType_t CompressionType( VertexFormat_t vertexFormat ) +{ + // This is trivial now, but we may add multiple flavours of compressed vertex later on + if ( vertexFormat & VERTEX_FORMAT_COMPRESSED ) + return VERTEX_COMPRESSION_ON; + else + return VERTEX_COMPRESSION_NONE; +} + + +//----------------------------------------------------------------------------- +// VertexElement_t (enumerates all usable vertex elements) +//----------------------------------------------------------------------------- +// FIXME: unify this with VertexFormat_t (i.e. construct the lower bits of VertexFormat_t with "1 << (VertexElement_t)element") +enum VertexElement_t +{ + VERTEX_ELEMENT_NONE = -1, + + // Deliberately explicitly numbered so it's a pain in the ass to change, so you read this: + // #!#!#NOTE#!#!# update GetVertexElementSize, VertexElementToDeclType and + // CVBAllocTracker (elementTable) when you update this! + VERTEX_ELEMENT_POSITION = 0, + VERTEX_ELEMENT_NORMAL = 1, + VERTEX_ELEMENT_COLOR = 2, + VERTEX_ELEMENT_SPECULAR = 3, + VERTEX_ELEMENT_TANGENT_S = 4, + VERTEX_ELEMENT_TANGENT_T = 5, + VERTEX_ELEMENT_WRINKLE = 6, + VERTEX_ELEMENT_BONEINDEX = 7, + VERTEX_ELEMENT_BONEWEIGHTS1 = 8, + VERTEX_ELEMENT_BONEWEIGHTS2 = 9, + VERTEX_ELEMENT_BONEWEIGHTS3 = 10, + VERTEX_ELEMENT_BONEWEIGHTS4 = 11, + VERTEX_ELEMENT_USERDATA1 = 12, + VERTEX_ELEMENT_USERDATA2 = 13, + VERTEX_ELEMENT_USERDATA3 = 14, + VERTEX_ELEMENT_USERDATA4 = 15, + VERTEX_ELEMENT_TEXCOORD1D_0 = 16, + VERTEX_ELEMENT_TEXCOORD1D_1 = 17, + VERTEX_ELEMENT_TEXCOORD1D_2 = 18, + VERTEX_ELEMENT_TEXCOORD1D_3 = 19, + VERTEX_ELEMENT_TEXCOORD1D_4 = 20, + VERTEX_ELEMENT_TEXCOORD1D_5 = 21, + VERTEX_ELEMENT_TEXCOORD1D_6 = 22, + VERTEX_ELEMENT_TEXCOORD1D_7 = 23, + VERTEX_ELEMENT_TEXCOORD2D_0 = 24, + VERTEX_ELEMENT_TEXCOORD2D_1 = 25, + VERTEX_ELEMENT_TEXCOORD2D_2 = 26, + VERTEX_ELEMENT_TEXCOORD2D_3 = 27, + VERTEX_ELEMENT_TEXCOORD2D_4 = 28, + VERTEX_ELEMENT_TEXCOORD2D_5 = 29, + VERTEX_ELEMENT_TEXCOORD2D_6 = 30, + VERTEX_ELEMENT_TEXCOORD2D_7 = 31, + VERTEX_ELEMENT_TEXCOORD3D_0 = 32, + VERTEX_ELEMENT_TEXCOORD3D_1 = 33, + VERTEX_ELEMENT_TEXCOORD3D_2 = 34, + VERTEX_ELEMENT_TEXCOORD3D_3 = 35, + VERTEX_ELEMENT_TEXCOORD3D_4 = 36, + VERTEX_ELEMENT_TEXCOORD3D_5 = 37, + VERTEX_ELEMENT_TEXCOORD3D_6 = 38, + VERTEX_ELEMENT_TEXCOORD3D_7 = 39, + VERTEX_ELEMENT_TEXCOORD4D_0 = 40, + VERTEX_ELEMENT_TEXCOORD4D_1 = 41, + VERTEX_ELEMENT_TEXCOORD4D_2 = 42, + VERTEX_ELEMENT_TEXCOORD4D_3 = 43, + VERTEX_ELEMENT_TEXCOORD4D_4 = 44, + VERTEX_ELEMENT_TEXCOORD4D_5 = 45, + VERTEX_ELEMENT_TEXCOORD4D_6 = 46, + VERTEX_ELEMENT_TEXCOORD4D_7 = 47, + + VERTEX_ELEMENT_NUMELEMENTS = 48 +}; + +inline void Detect_VertexElement_t_Changes( VertexElement_t element ) // GREPs for VertexElement_t will hit this +{ + // Make it harder for someone to change VertexElement_t without noticing that dependent code + // (GetVertexElementSize, VertexElementToDeclType, CVBAllocTracker) needs updating + Assert( VERTEX_ELEMENT_NUMELEMENTS == 48 ); + switch ( element ) + { + case VERTEX_ELEMENT_POSITION: Assert( VERTEX_ELEMENT_POSITION == 0 ); break; + case VERTEX_ELEMENT_NORMAL: Assert( VERTEX_ELEMENT_NORMAL == 1 ); break; + case VERTEX_ELEMENT_COLOR: Assert( VERTEX_ELEMENT_COLOR == 2 ); break; + case VERTEX_ELEMENT_SPECULAR: Assert( VERTEX_ELEMENT_SPECULAR == 3 ); break; + case VERTEX_ELEMENT_TANGENT_S: Assert( VERTEX_ELEMENT_TANGENT_S == 4 ); break; + case VERTEX_ELEMENT_TANGENT_T: Assert( VERTEX_ELEMENT_TANGENT_T == 5 ); break; + case VERTEX_ELEMENT_WRINKLE: Assert( VERTEX_ELEMENT_WRINKLE == 6 ); break; + case VERTEX_ELEMENT_BONEINDEX: Assert( VERTEX_ELEMENT_BONEINDEX == 7 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS1: Assert( VERTEX_ELEMENT_BONEWEIGHTS1 == 8 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS2: Assert( VERTEX_ELEMENT_BONEWEIGHTS2 == 9 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS3: Assert( VERTEX_ELEMENT_BONEWEIGHTS3 == 10 ); break; + case VERTEX_ELEMENT_BONEWEIGHTS4: Assert( VERTEX_ELEMENT_BONEWEIGHTS4 == 11 ); break; + case VERTEX_ELEMENT_USERDATA1: Assert( VERTEX_ELEMENT_USERDATA1 == 12 ); break; + case VERTEX_ELEMENT_USERDATA2: Assert( VERTEX_ELEMENT_USERDATA2 == 13 ); break; + case VERTEX_ELEMENT_USERDATA3: Assert( VERTEX_ELEMENT_USERDATA3 == 14 ); break; + case VERTEX_ELEMENT_USERDATA4: Assert( VERTEX_ELEMENT_USERDATA4 == 15 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_0: Assert( VERTEX_ELEMENT_TEXCOORD1D_0 == 16 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_1: Assert( VERTEX_ELEMENT_TEXCOORD1D_1 == 17 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_2: Assert( VERTEX_ELEMENT_TEXCOORD1D_2 == 18 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_3: Assert( VERTEX_ELEMENT_TEXCOORD1D_3 == 19 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_4: Assert( VERTEX_ELEMENT_TEXCOORD1D_4 == 20 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_5: Assert( VERTEX_ELEMENT_TEXCOORD1D_5 == 21 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_6: Assert( VERTEX_ELEMENT_TEXCOORD1D_6 == 22 ); break; + case VERTEX_ELEMENT_TEXCOORD1D_7: Assert( VERTEX_ELEMENT_TEXCOORD1D_7 == 23 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_0: Assert( VERTEX_ELEMENT_TEXCOORD2D_0 == 24 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_1: Assert( VERTEX_ELEMENT_TEXCOORD2D_1 == 25 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_2: Assert( VERTEX_ELEMENT_TEXCOORD2D_2 == 26 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_3: Assert( VERTEX_ELEMENT_TEXCOORD2D_3 == 27 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_4: Assert( VERTEX_ELEMENT_TEXCOORD2D_4 == 28 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_5: Assert( VERTEX_ELEMENT_TEXCOORD2D_5 == 29 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_6: Assert( VERTEX_ELEMENT_TEXCOORD2D_6 == 30 ); break; + case VERTEX_ELEMENT_TEXCOORD2D_7: Assert( VERTEX_ELEMENT_TEXCOORD2D_7 == 31 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_0: Assert( VERTEX_ELEMENT_TEXCOORD3D_0 == 32 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_1: Assert( VERTEX_ELEMENT_TEXCOORD3D_1 == 33 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_2: Assert( VERTEX_ELEMENT_TEXCOORD3D_2 == 34 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_3: Assert( VERTEX_ELEMENT_TEXCOORD3D_3 == 35 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_4: Assert( VERTEX_ELEMENT_TEXCOORD3D_4 == 36 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_5: Assert( VERTEX_ELEMENT_TEXCOORD3D_5 == 37 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_6: Assert( VERTEX_ELEMENT_TEXCOORD3D_6 == 38 ); break; + case VERTEX_ELEMENT_TEXCOORD3D_7: Assert( VERTEX_ELEMENT_TEXCOORD3D_7 == 39 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_0: Assert( VERTEX_ELEMENT_TEXCOORD4D_0 == 40 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_1: Assert( VERTEX_ELEMENT_TEXCOORD4D_1 == 41 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_2: Assert( VERTEX_ELEMENT_TEXCOORD4D_2 == 42 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_3: Assert( VERTEX_ELEMENT_TEXCOORD4D_3 == 43 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_4: Assert( VERTEX_ELEMENT_TEXCOORD4D_4 == 44 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_5: Assert( VERTEX_ELEMENT_TEXCOORD4D_5 == 45 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_6: Assert( VERTEX_ELEMENT_TEXCOORD4D_6 == 46 ); break; + case VERTEX_ELEMENT_TEXCOORD4D_7: Assert( VERTEX_ELEMENT_TEXCOORD4D_7 == 47 ); break; + default: + Assert( 0 ); // Invalid input or VertexElement_t has definitely changed + break; + } +} + +// We're testing 2 normal compression methods +// One compressed normals+tangents into a SHORT2 each (8 bytes total) +// The other compresses them together, into a single UBYTE4 (4 bytes total) +// FIXME: pick one or the other, compare lighting quality in important cases +#define COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 0 +#define COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 1 +//#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 +#define COMPRESSED_NORMALS_TYPE COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 + +inline int GetVertexElementSize( VertexElement_t element, VertexCompressionType_t compressionType ) +{ + Detect_VertexElement_t_Changes( element ); + + if ( compressionType == VERTEX_COMPRESSION_ON ) + { + // Compressed-vertex element sizes + switch ( element ) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + case VERTEX_ELEMENT_NORMAL: + return ( 2 * sizeof( short ) ); + case VERTEX_ELEMENT_USERDATA4: + return ( 2 * sizeof( short ) ); +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // Normals and tangents (userdata4) are combined into a single UBYTE4 vertex element + case VERTEX_ELEMENT_NORMAL: + return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_USERDATA4: + return ( 0 ); +#endif + // Compressed bone weights use a SHORT2 vertex element: + case VERTEX_ELEMENT_BONEWEIGHTS1: + case VERTEX_ELEMENT_BONEWEIGHTS2: + return ( 2 * sizeof( short ) ); + default: + break; + } + } + + // Uncompressed-vertex element sizes + switch ( element ) + { + case VERTEX_ELEMENT_POSITION: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_NORMAL: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_COLOR: return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_SPECULAR: return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_TANGENT_S: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TANGENT_T: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_WRINKLE: return ( 1 * sizeof( float ) ); // Packed into Position.W + case VERTEX_ELEMENT_BONEINDEX: return ( 4 * sizeof( unsigned char ) ); + case VERTEX_ELEMENT_BONEWEIGHTS1: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_BONEWEIGHTS2: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_BONEWEIGHTS3: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_BONEWEIGHTS4: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA1: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA2: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA3: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_USERDATA4: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_0: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_1: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_2: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_3: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_4: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_5: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_6: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD1D_7: return ( 1 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_0: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_1: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_2: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_3: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_4: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_5: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_6: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD2D_7: return ( 2 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_0: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_1: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_2: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_3: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_4: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_5: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_6: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD3D_7: return ( 3 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_0: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_1: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_2: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_3: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_4: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_5: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_6: return ( 4 * sizeof( float ) ); + case VERTEX_ELEMENT_TEXCOORD4D_7: return ( 4 * sizeof( float ) ); + default: + Assert(0); + return 0; + }; +} + + +//----------------------------------------------------------------------------- +// Shader state flags can be read from the FLAGS materialvar +// Also can be read or written to with the Set/GetMaterialVarFlags() call +// Also make sure you add/remove a string associated with each flag below to CShaderSystem::ShaderStateString in ShaderSystem.cpp +//----------------------------------------------------------------------------- +enum MaterialVarFlags_t +{ + MATERIAL_VAR_DEBUG = (1 << 0), + MATERIAL_VAR_NO_DEBUG_OVERRIDE = (1 << 1), + MATERIAL_VAR_NO_DRAW = (1 << 2), + MATERIAL_VAR_USE_IN_FILLRATE_MODE = (1 << 3), + + MATERIAL_VAR_VERTEXCOLOR = (1 << 4), + MATERIAL_VAR_VERTEXALPHA = (1 << 5), + MATERIAL_VAR_SELFILLUM = (1 << 6), + MATERIAL_VAR_ADDITIVE = (1 << 7), + MATERIAL_VAR_ALPHATEST = (1 << 8), + MATERIAL_VAR_MULTIPASS = (1 << 9), + MATERIAL_VAR_ZNEARER = (1 << 10), + MATERIAL_VAR_MODEL = (1 << 11), + MATERIAL_VAR_FLAT = (1 << 12), + MATERIAL_VAR_NOCULL = (1 << 13), + MATERIAL_VAR_NOFOG = (1 << 14), + MATERIAL_VAR_IGNOREZ = (1 << 15), + MATERIAL_VAR_DECAL = (1 << 16), + MATERIAL_VAR_ENVMAPSPHERE = (1 << 17), + MATERIAL_VAR_NOALPHAMOD = (1 << 18), + MATERIAL_VAR_ENVMAPCAMERASPACE = (1 << 19), + MATERIAL_VAR_BASEALPHAENVMAPMASK = (1 << 20), + MATERIAL_VAR_TRANSLUCENT = (1 << 21), + MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK = (1 << 22), + MATERIAL_VAR_NEEDS_SOFTWARE_SKINNING = (1 << 23), + MATERIAL_VAR_OPAQUETEXTURE = (1 << 24), + MATERIAL_VAR_ENVMAPMODE = (1 << 25), + MATERIAL_VAR_SUPPRESS_DECALS = (1 << 26), + MATERIAL_VAR_HALFLAMBERT = (1 << 27), + MATERIAL_VAR_WIREFRAME = (1 << 28), + MATERIAL_VAR_ALLOWALPHATOCOVERAGE = (1 << 29), + MATERIAL_VAR_IGNORE_ALPHA_MODULATION = (1 << 30), + + // NOTE: Only add flags here that either should be read from + // .vmts or can be set directly from client code. Other, internal + // flags should to into the flag enum in imaterialinternal.h +}; + + +//----------------------------------------------------------------------------- +// Internal flags not accessible from outside the material system. Stored in Flags2 +//----------------------------------------------------------------------------- +enum MaterialVarFlags2_t +{ + // NOTE: These are for $flags2!!!!! +// UNUSED = (1 << 0), + + MATERIAL_VAR2_LIGHTING_UNLIT = 0, + MATERIAL_VAR2_LIGHTING_VERTEX_LIT = (1 << 1), + MATERIAL_VAR2_LIGHTING_LIGHTMAP = (1 << 2), + MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP = (1 << 3), + MATERIAL_VAR2_LIGHTING_MASK = + ( MATERIAL_VAR2_LIGHTING_VERTEX_LIT | + MATERIAL_VAR2_LIGHTING_LIGHTMAP | + MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP ), + + // FIXME: Should this be a part of the above lighting enums? + MATERIAL_VAR2_DIFFUSE_BUMPMAPPED_MODEL = (1 << 4), + MATERIAL_VAR2_USES_ENV_CUBEMAP = (1 << 5), + MATERIAL_VAR2_NEEDS_TANGENT_SPACES = (1 << 6), + MATERIAL_VAR2_NEEDS_SOFTWARE_LIGHTING = (1 << 7), + // GR - HDR path puts lightmap alpha in separate texture... + MATERIAL_VAR2_BLEND_WITH_LIGHTMAP_ALPHA = (1 << 8), + MATERIAL_VAR2_NEEDS_BAKED_LIGHTING_SNAPSHOTS = (1 << 9), + MATERIAL_VAR2_USE_FLASHLIGHT = (1 << 10), + MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING = (1 << 11), + MATERIAL_VAR2_NEEDS_FIXED_FUNCTION_FLASHLIGHT = (1 << 12), + MATERIAL_VAR2_USE_EDITOR = (1 << 13), + MATERIAL_VAR2_NEEDS_POWER_OF_TWO_FRAME_BUFFER_TEXTURE = (1 << 14), + MATERIAL_VAR2_NEEDS_FULL_FRAME_BUFFER_TEXTURE = (1 << 15), + MATERIAL_VAR2_IS_SPRITECARD = (1 << 16), + MATERIAL_VAR2_USES_VERTEXID = (1 << 17), + MATERIAL_VAR2_SUPPORTS_HW_SKINNING = (1 << 18), + MATERIAL_VAR2_SUPPORTS_FLASHLIGHT = (1 << 19), +}; + + +//----------------------------------------------------------------------------- +// Preview image return values +//----------------------------------------------------------------------------- +enum PreviewImageRetVal_t +{ + MATERIAL_PREVIEW_IMAGE_BAD = 0, + MATERIAL_PREVIEW_IMAGE_OK, + MATERIAL_NO_PREVIEW_IMAGE, +}; + + +//----------------------------------------------------------------------------- +// material interface +//----------------------------------------------------------------------------- +abstract_class IMaterial +{ +public: + // Get the name of the material. This is a full path to + // the vmt file starting from "hl2/materials" (or equivalent) without + // a file extension. + virtual const char * GetName() const = 0; + virtual const char * GetTextureGroupName() const = 0; + + // Get the preferred size/bitDepth of a preview image of a material. + // This is the sort of image that you would use for a thumbnail view + // of a material, or in WorldCraft until it uses materials to render. + // separate this for the tools maybe + virtual PreviewImageRetVal_t GetPreviewImageProperties( int *width, int *height, + ImageFormat *imageFormat, bool* isTranslucent ) const = 0; + + // Get a preview image at the specified width/height and bitDepth. + // Will do resampling if necessary.(not yet!!! :) ) + // Will do color format conversion. (works now.) + virtual PreviewImageRetVal_t GetPreviewImage( unsigned char *data, + int width, int height, + ImageFormat imageFormat ) const = 0; + // + virtual int GetMappingWidth( ) = 0; + virtual int GetMappingHeight( ) = 0; + + virtual int GetNumAnimationFrames( ) = 0; + + // For material subrects (material pages). Offset(u,v) and scale(u,v) are normalized to texture. + virtual bool InMaterialPage( void ) = 0; + virtual void GetMaterialOffset( float *pOffset ) = 0; + virtual void GetMaterialScale( float *pScale ) = 0; + virtual IMaterial *GetMaterialPage( void ) = 0; + + // find a vmt variable. + // This is how game code affects how a material is rendered. + // The game code must know about the params that are used by + // the shader for the material that it is trying to affect. + virtual IMaterialVar * FindVar( const char *varName, bool *found, bool complain = true ) = 0; + + // The user never allocates or deallocates materials. Reference counting is + // used instead. Garbage collection is done upon a call to + // IMaterialSystem::UncacheUnusedMaterials. + virtual void IncrementReferenceCount( void ) = 0; + virtual void DecrementReferenceCount( void ) = 0; + + inline void AddRef() { IncrementReferenceCount(); } + inline void Release() { DecrementReferenceCount(); } + + // Each material is assigned a number that groups it with like materials + // for sorting in the application. + virtual int GetEnumerationID( void ) const = 0; + + virtual void GetLowResColorSample( float s, float t, float *color ) const = 0; + + // This computes the state snapshots for this material + virtual void RecomputeStateSnapshots() = 0; + + // Are we translucent? + virtual bool IsTranslucent() = 0; + + // Are we alphatested? + virtual bool IsAlphaTested() = 0; + + // Are we vertex lit? + virtual bool IsVertexLit() = 0; + + // Gets the vertex format + virtual VertexFormat_t GetVertexFormat() const = 0; + + // returns true if this material uses a material proxy + virtual bool HasProxy( void ) const = 0; + + virtual bool UsesEnvCubemap( void ) = 0; + + virtual bool NeedsTangentSpace( void ) = 0; + + virtual bool NeedsPowerOfTwoFrameBufferTexture( bool bCheckSpecificToThisFrame = true ) = 0; + virtual bool NeedsFullFrameBufferTexture( bool bCheckSpecificToThisFrame = true ) = 0; + + // returns true if the shader doesn't do skinning itself and requires + // the data that is sent to it to be preskinned. + virtual bool NeedsSoftwareSkinning( void ) = 0; + + // Apply constant color or alpha modulation + virtual void AlphaModulate( float alpha ) = 0; + virtual void ColorModulate( float r, float g, float b ) = 0; + + // Material Var flags... + virtual void SetMaterialVarFlag( MaterialVarFlags_t flag, bool on ) = 0; + virtual bool GetMaterialVarFlag( MaterialVarFlags_t flag ) const = 0; + + // Gets material reflectivity + virtual void GetReflectivity( Vector& reflect ) = 0; + + // Gets material property flags + virtual bool GetPropertyFlag( MaterialPropertyTypes_t type ) = 0; + + // Is the material visible from both sides? + virtual bool IsTwoSided() = 0; + + // Sets the shader associated with the material + virtual void SetShader( const char *pShaderName ) = 0; + + // Can't be const because the material might have to precache itself. + virtual int GetNumPasses( void ) = 0; + + // Can't be const because the material might have to precache itself. + virtual int GetTextureMemoryBytes( void ) = 0; + + // Meant to be used with materials created using CreateMaterial + // It updates the materials to reflect the current values stored in the material vars + virtual void Refresh() = 0; + + // GR - returns true is material uses lightmap alpha for blending + virtual bool NeedsLightmapBlendAlpha( void ) = 0; + + // returns true if the shader doesn't do lighting itself and requires + // the data that is sent to it to be prelighted + virtual bool NeedsSoftwareLighting( void ) = 0; + + // Gets at the shader parameters + virtual int ShaderParamCount() const = 0; + virtual IMaterialVar **GetShaderParams( void ) = 0; + + // Returns true if this is the error material you get back from IMaterialSystem::FindMaterial if + // the material can't be found. + virtual bool IsErrorMaterial() const = 0; + + virtual void SetUseFixedFunctionBakedLighting( bool bEnable ) = 0; + + // Gets the current alpha modulation + virtual float GetAlphaModulation() = 0; + virtual void GetColorModulation( float *r, float *g, float *b ) = 0; + + // Gets the morph format + virtual MorphFormat_t GetMorphFormat() const = 0; + + // fast find that stores the index of the found var in the string table in local cache + virtual IMaterialVar * FindVarFast( char const *pVarName, unsigned int *pToken ) = 0; + + // Sets new VMT shader parameters for the material + virtual void SetShaderAndParams( KeyValues *pKeyValues ) = 0; + virtual const char * GetShaderName() const = 0; + + virtual void DeleteIfUnreferenced() = 0; + + virtual bool IsSpriteCard() = 0; + + virtual void CallBindProxy( void *proxyData ) = 0; + + virtual IMaterial *CheckProxyReplacement( void *proxyData ) = 0; + + virtual void RefreshPreservingMaterialVars() = 0; + + virtual bool WasReloadedFromWhitelist() = 0; + + virtual bool IsPrecached() const = 0; +}; + + +inline bool IsErrorMaterial( IMaterial *pMat ) +{ + return !pMat || pMat->IsErrorMaterial(); +} + +#endif // IMATERIAL_H diff --git a/mp/src/public/materialsystem/imaterialproxy.h b/mp/src/public/materialsystem/imaterialproxy.h new file mode 100644 index 00000000..603ef03b --- /dev/null +++ b/mp/src/public/materialsystem/imaterialproxy.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMATERIALPROXY_H +#define IMATERIALPROXY_H +#pragma once + +#include "interface.h" + +#define IMATERIAL_PROXY_INTERFACE_VERSION "_IMaterialProxy003" + +class IMaterial; +class KeyValues; + +abstract_class IMaterialProxy +{ +public: + virtual bool Init( IMaterial* pMaterial, KeyValues *pKeyValues ) = 0; + virtual void OnBind( void * ) = 0; + virtual void Release() = 0; + virtual IMaterial * GetMaterial() = 0; + +protected: + // no one should call this directly + virtual ~IMaterialProxy() {} +}; + +#endif // IMATERIALPROXY_H diff --git a/mp/src/public/materialsystem/imaterialproxyfactory.h b/mp/src/public/materialsystem/imaterialproxyfactory.h new file mode 100644 index 00000000..e9d47ee6 --- /dev/null +++ b/mp/src/public/materialsystem/imaterialproxyfactory.h @@ -0,0 +1,25 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef IMATERIALPROXYFACTORY_H +#define IMATERIALPROXYFACTORY_H +#pragma once + +#include "interface.h" + +#define IMATERIAL_PROXY_FACTOR_INTERFACE_VERSION "IMaterialProxyFactory001" + +class IMaterialProxy; + +abstract_class IMaterialProxyFactory +{ +public: + virtual IMaterialProxy *CreateProxy( const char *proxyName ) = 0; + virtual void DeleteProxy( IMaterialProxy *pProxy ) = 0; +}; + +#endif // IMATERIALPROXYFACTORY_H diff --git a/mp/src/public/materialsystem/imaterialsystem.h b/mp/src/public/materialsystem/imaterialsystem.h new file mode 100644 index 00000000..cc125156 --- /dev/null +++ b/mp/src/public/materialsystem/imaterialsystem.h @@ -0,0 +1,1758 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IMATERIALSYSTEM_H +#define IMATERIALSYSTEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#define OVERBRIGHT 2.0f +#define OO_OVERBRIGHT ( 1.0f / 2.0f ) +#define GAMMA 2.2f +#define TEXGAMMA 2.2f + +#include "tier1/interface.h" +#include "tier1/refcount.h" +#include "mathlib/vector.h" +#include "mathlib/vector4d.h" +#include "mathlib/vmatrix.h" +#include "appframework/IAppSystem.h" +#include "bitmap/imageformat.h" +#include "texture_group_names.h" +#include "vtf/vtf.h" +#include "materialsystem/deformations.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/IColorCorrection.h" + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class IMesh; +class IVertexBuffer; +class IIndexBuffer; +struct MaterialSystem_Config_t; +class VMatrix; +struct matrix3x4_t; +class ITexture; +struct MaterialSystemHardwareIdentifier_t; +class KeyValues; +class IShader; +class IVertexTexture; +class IMorph; +class IMatRenderContext; +class ICallQueue; +struct MorphWeight_t; +class IFileList; + + +//----------------------------------------------------------------------------- +// The vertex format type +//----------------------------------------------------------------------------- +typedef uint64 VertexFormat_t; + +//----------------------------------------------------------------------------- +// important enumeration +//----------------------------------------------------------------------------- + +// NOTE NOTE NOTE!!!! If you up this, grep for "NEW_INTERFACE" to see if there is anything +// waiting to be enabled during an interface revision. +#define MATERIAL_SYSTEM_INTERFACE_VERSION "VMaterialSystem080" + +#ifdef POSIX +#define ABSOLUTE_MINIMUM_DXLEVEL 90 +#else +#define ABSOLUTE_MINIMUM_DXLEVEL 80 +#endif + +enum ShaderParamType_t +{ + SHADER_PARAM_TYPE_TEXTURE, + SHADER_PARAM_TYPE_INTEGER, + SHADER_PARAM_TYPE_COLOR, + SHADER_PARAM_TYPE_VEC2, + SHADER_PARAM_TYPE_VEC3, + SHADER_PARAM_TYPE_VEC4, + SHADER_PARAM_TYPE_ENVMAP, // obsolete + SHADER_PARAM_TYPE_FLOAT, + SHADER_PARAM_TYPE_BOOL, + SHADER_PARAM_TYPE_FOURCC, + SHADER_PARAM_TYPE_MATRIX, + SHADER_PARAM_TYPE_MATERIAL, + SHADER_PARAM_TYPE_STRING, +}; + +enum MaterialMatrixMode_t +{ + MATERIAL_VIEW = 0, + MATERIAL_PROJECTION, + + // Texture matrices + MATERIAL_TEXTURE0, + MATERIAL_TEXTURE1, + MATERIAL_TEXTURE2, + MATERIAL_TEXTURE3, + MATERIAL_TEXTURE4, + MATERIAL_TEXTURE5, + MATERIAL_TEXTURE6, + MATERIAL_TEXTURE7, + + MATERIAL_MODEL, + + // Total number of matrices + NUM_MATRIX_MODES = MATERIAL_MODEL+1, + + // Number of texture transforms + NUM_TEXTURE_TRANSFORMS = MATERIAL_TEXTURE7 - MATERIAL_TEXTURE0 + 1 +}; + +// FIXME: How do I specify the actual number of matrix modes? +const int NUM_MODEL_TRANSFORMS = 53; +const int MATERIAL_MODEL_MAX = MATERIAL_MODEL + NUM_MODEL_TRANSFORMS; + +enum MaterialPrimitiveType_t +{ + MATERIAL_POINTS = 0x0, + MATERIAL_LINES, + MATERIAL_TRIANGLES, + MATERIAL_TRIANGLE_STRIP, + MATERIAL_LINE_STRIP, + MATERIAL_LINE_LOOP, // a single line loop + MATERIAL_POLYGON, // this is a *single* polygon + MATERIAL_QUADS, + MATERIAL_INSTANCED_QUADS, // (X360) like MATERIAL_QUADS, but uses vertex instancing + + // This is used for static meshes that contain multiple types of + // primitive types. When calling draw, you'll need to specify + // a primitive type. + MATERIAL_HETEROGENOUS +}; + +enum MaterialPropertyTypes_t +{ + MATERIAL_PROPERTY_NEEDS_LIGHTMAP = 0, // bool + MATERIAL_PROPERTY_OPACITY, // int (enum MaterialPropertyOpacityTypes_t) + MATERIAL_PROPERTY_REFLECTIVITY, // vec3_t + MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS // bool +}; + +// acceptable property values for MATERIAL_PROPERTY_OPACITY +enum MaterialPropertyOpacityTypes_t +{ + MATERIAL_ALPHATEST = 0, + MATERIAL_OPAQUE, + MATERIAL_TRANSLUCENT +}; + +enum MaterialBufferTypes_t +{ + MATERIAL_FRONT = 0, + MATERIAL_BACK +}; + +enum MaterialCullMode_t +{ + MATERIAL_CULLMODE_CCW, // this culls polygons with counterclockwise winding + MATERIAL_CULLMODE_CW // this culls polygons with clockwise winding +}; + +enum MaterialIndexFormat_t +{ + MATERIAL_INDEX_FORMAT_UNKNOWN = -1, + MATERIAL_INDEX_FORMAT_16BIT = 0, + MATERIAL_INDEX_FORMAT_32BIT, +}; + +enum MaterialFogMode_t +{ + MATERIAL_FOG_NONE, + MATERIAL_FOG_LINEAR, + MATERIAL_FOG_LINEAR_BELOW_FOG_Z, +}; + +enum MaterialHeightClipMode_t +{ + MATERIAL_HEIGHTCLIPMODE_DISABLE, + MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT, + MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT +}; + +enum MaterialNonInteractiveMode_t +{ + MATERIAL_NON_INTERACTIVE_MODE_NONE = -1, + MATERIAL_NON_INTERACTIVE_MODE_STARTUP = 0, + MATERIAL_NON_INTERACTIVE_MODE_LEVEL_LOAD, + + MATERIAL_NON_INTERACTIVE_MODE_COUNT, +}; + + +//----------------------------------------------------------------------------- +// Special morph used in decalling pass +//----------------------------------------------------------------------------- +#define MATERIAL_MORPH_DECAL ( (IMorph*)1 ) + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +enum MaterialThreadMode_t +{ + MATERIAL_SINGLE_THREADED, + MATERIAL_QUEUED_SINGLE_THREADED, + MATERIAL_QUEUED_THREADED +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +enum MaterialContextType_t +{ + MATERIAL_HARDWARE_CONTEXT, + MATERIAL_QUEUED_CONTEXT, + MATERIAL_NULL_CONTEXT +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +enum MaterialFindContext_t +{ + MATERIAL_FINDCONTEXT_NONE, + MATERIAL_FINDCONTEXT_ISONAMODEL, +}; + +//----------------------------------------------------------------------------- +// Light structure +//----------------------------------------------------------------------------- +#include "mathlib/lightdesc.h" + +#if 0 +enum LightType_t +{ + MATERIAL_LIGHT_DISABLE = 0, + MATERIAL_LIGHT_POINT, + MATERIAL_LIGHT_DIRECTIONAL, + MATERIAL_LIGHT_SPOT, +}; + +enum LightType_OptimizationFlags_t +{ + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 = 1, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 = 2, + LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 = 4, +}; + + +struct LightDesc_t +{ + LightType_t m_Type; + Vector m_Color; + Vector m_Position; + Vector m_Direction; + float m_Range; + float m_Falloff; + float m_Attenuation0; + float m_Attenuation1; + float m_Attenuation2; + float m_Theta; + float m_Phi; + // These aren't used by DX8. . used for software lighting. + float m_ThetaDot; + float m_PhiDot; + unsigned int m_Flags; + + + LightDesc_t() {} + +private: + // No copy constructors allowed + LightDesc_t(const LightDesc_t& vOther); +}; +#endif + +#define CREATERENDERTARGETFLAGS_HDR 0x00000001 +#define CREATERENDERTARGETFLAGS_AUTOMIPMAP 0x00000002 +#define CREATERENDERTARGETFLAGS_UNFILTERABLE_OK 0x00000004 +// XBOX ONLY: +#define CREATERENDERTARGETFLAGS_NOEDRAM 0x00000008 // inhibit allocation in 360 EDRAM +#define CREATERENDERTARGETFLAGS_TEMP 0x00000010 // only allocates memory upon first resolve, destroyed at level end + + +//----------------------------------------------------------------------------- +// allowed stencil operations. These match the d3d operations +//----------------------------------------------------------------------------- +enum StencilOperation_t +{ +#if !defined( _X360 ) + STENCILOPERATION_KEEP = 1, + STENCILOPERATION_ZERO = 2, + STENCILOPERATION_REPLACE = 3, + STENCILOPERATION_INCRSAT = 4, + STENCILOPERATION_DECRSAT = 5, + STENCILOPERATION_INVERT = 6, + STENCILOPERATION_INCR = 7, + STENCILOPERATION_DECR = 8, +#else + STENCILOPERATION_KEEP = D3DSTENCILOP_KEEP, + STENCILOPERATION_ZERO = D3DSTENCILOP_ZERO, + STENCILOPERATION_REPLACE = D3DSTENCILOP_REPLACE, + STENCILOPERATION_INCRSAT = D3DSTENCILOP_INCRSAT, + STENCILOPERATION_DECRSAT = D3DSTENCILOP_DECRSAT, + STENCILOPERATION_INVERT = D3DSTENCILOP_INVERT, + STENCILOPERATION_INCR = D3DSTENCILOP_INCR, + STENCILOPERATION_DECR = D3DSTENCILOP_DECR, +#endif + STENCILOPERATION_FORCE_DWORD = 0x7fffffff +}; + +enum StencilComparisonFunction_t +{ +#if !defined( _X360 ) + STENCILCOMPARISONFUNCTION_NEVER = 1, + STENCILCOMPARISONFUNCTION_LESS = 2, + STENCILCOMPARISONFUNCTION_EQUAL = 3, + STENCILCOMPARISONFUNCTION_LESSEQUAL = 4, + STENCILCOMPARISONFUNCTION_GREATER = 5, + STENCILCOMPARISONFUNCTION_NOTEQUAL = 6, + STENCILCOMPARISONFUNCTION_GREATEREQUAL = 7, + STENCILCOMPARISONFUNCTION_ALWAYS = 8, +#else + STENCILCOMPARISONFUNCTION_NEVER = D3DCMP_NEVER, + STENCILCOMPARISONFUNCTION_LESS = D3DCMP_LESS, + STENCILCOMPARISONFUNCTION_EQUAL = D3DCMP_EQUAL, + STENCILCOMPARISONFUNCTION_LESSEQUAL = D3DCMP_LESSEQUAL, + STENCILCOMPARISONFUNCTION_GREATER = D3DCMP_GREATER, + STENCILCOMPARISONFUNCTION_NOTEQUAL = D3DCMP_NOTEQUAL, + STENCILCOMPARISONFUNCTION_GREATEREQUAL = D3DCMP_GREATEREQUAL, + STENCILCOMPARISONFUNCTION_ALWAYS = D3DCMP_ALWAYS, +#endif + + STENCILCOMPARISONFUNCTION_FORCE_DWORD = 0x7fffffff +}; + + +//----------------------------------------------------------------------------- +// Enumeration for the various fields capable of being morphed +//----------------------------------------------------------------------------- +enum MorphFormatFlags_t +{ + MORPH_POSITION = 0x0001, // 3D + MORPH_NORMAL = 0x0002, // 3D + MORPH_WRINKLE = 0x0004, // 1D + MORPH_SPEED = 0x0008, // 1D + MORPH_SIDE = 0x0010, // 1D +}; + + +//----------------------------------------------------------------------------- +// The morph format type +//----------------------------------------------------------------------------- +typedef unsigned int MorphFormat_t; + + +//----------------------------------------------------------------------------- +// Standard lightmaps +//----------------------------------------------------------------------------- +enum StandardLightmap_t +{ + MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE = -1, + MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP = -2, + MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED = -3 +}; + + +struct MaterialSystem_SortInfo_t +{ + IMaterial *material; + int lightmapPageID; +}; + + +#define MAX_FB_TEXTURES 4 + +//----------------------------------------------------------------------------- +// Information about each adapter +//----------------------------------------------------------------------------- +enum +{ + MATERIAL_ADAPTER_NAME_LENGTH = 512 +}; + +struct MaterialAdapterInfo_t +{ + char m_pDriverName[MATERIAL_ADAPTER_NAME_LENGTH]; + unsigned int m_VendorID; + unsigned int m_DeviceID; + unsigned int m_SubSysID; + unsigned int m_Revision; + int m_nDXSupportLevel; // This is the *preferred* dx support level + int m_nMaxDXSupportLevel; + unsigned int m_nDriverVersionHigh; + unsigned int m_nDriverVersionLow; +}; + + +//----------------------------------------------------------------------------- +// Video mode info.. +//----------------------------------------------------------------------------- +struct MaterialVideoMode_t +{ + int m_Width; // if width and height are 0 and you select + int m_Height; // windowed mode, it'll use the window size + ImageFormat m_Format; // use ImageFormats (ignored for windowed mode) + int m_RefreshRate; // 0 == default (ignored for windowed mode) +}; + +// fixme: should move this into something else. +struct FlashlightState_t +{ + FlashlightState_t() + { + m_bEnableShadows = false; // Provide reasonable defaults for shadow depth mapping parameters + m_bDrawShadowFrustum = false; + m_flShadowMapResolution = 1024.0f; + m_flShadowFilterSize = 3.0f; + m_flShadowSlopeScaleDepthBias = 16.0f; + m_flShadowDepthBias = 0.0005f; + m_flShadowJitterSeed = 0.0f; + m_flShadowAtten = 0.0f; + m_bScissor = false; + m_nLeft = -1; + m_nTop = -1; + m_nRight = -1; + m_nBottom = -1; + m_nShadowQuality = 0; + } + + Vector m_vecLightOrigin; + Quaternion m_quatOrientation; + float m_NearZ; + float m_FarZ; + float m_fHorizontalFOVDegrees; + float m_fVerticalFOVDegrees; + float m_fQuadraticAtten; + float m_fLinearAtten; + float m_fConstantAtten; + float m_Color[4]; + ITexture *m_pSpotlightTexture; + int m_nSpotlightTextureFrame; + + // Shadow depth mapping parameters + bool m_bEnableShadows; + bool m_bDrawShadowFrustum; + float m_flShadowMapResolution; + float m_flShadowFilterSize; + float m_flShadowSlopeScaleDepthBias; + float m_flShadowDepthBias; + float m_flShadowJitterSeed; + float m_flShadowAtten; + int m_nShadowQuality; + + // Getters for scissor members + bool DoScissor() { return m_bScissor; } + int GetLeft() { return m_nLeft; } + int GetTop() { return m_nTop; } + int GetRight() { return m_nRight; } + int GetBottom() { return m_nBottom; } + +private: + + friend class CShadowMgr; + + bool m_bScissor; + int m_nLeft; + int m_nTop; + int m_nRight; + int m_nBottom; +}; + +//----------------------------------------------------------------------------- +// Flags to be used with the Init call +//----------------------------------------------------------------------------- +enum MaterialInitFlags_t +{ + MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE = 0x2, + MATERIAL_INIT_REFERENCE_RASTERIZER = 0x4, +}; + +//----------------------------------------------------------------------------- +// Flags to specify type of depth buffer used with RT +//----------------------------------------------------------------------------- + +// GR - this is to add RT with no depth buffer bound + +enum MaterialRenderTargetDepth_t +{ + MATERIAL_RT_DEPTH_SHARED = 0x0, + MATERIAL_RT_DEPTH_SEPARATE = 0x1, + MATERIAL_RT_DEPTH_NONE = 0x2, + MATERIAL_RT_DEPTH_ONLY = 0x3, +}; + +//----------------------------------------------------------------------------- +// A function to be called when we need to release all vertex buffers +// NOTE: The restore function will tell the caller if all the vertex formats +// changed so that it can flush caches, etc. if it needs to (for dxlevel support) +//----------------------------------------------------------------------------- +enum RestoreChangeFlags_t +{ + MATERIAL_RESTORE_VERTEX_FORMAT_CHANGED = 0x1, +}; + + +// NOTE: All size modes will force the render target to be smaller than or equal to +// the size of the framebuffer. +enum RenderTargetSizeMode_t +{ + RT_SIZE_NO_CHANGE=0, // Only allowed for render targets that don't want a depth buffer + // (because if they have a depth buffer, the render target must be less than or equal to the size of the framebuffer). + RT_SIZE_DEFAULT=1, // Don't play with the specified width and height other than making sure it fits in the framebuffer. + RT_SIZE_PICMIP=2, // Apply picmip to the render target's width and height. + RT_SIZE_HDR=3, // frame_buffer_width / 4 + RT_SIZE_FULL_FRAME_BUFFER=4, // Same size as frame buffer, or next lower power of 2 if we can't do that. + RT_SIZE_OFFSCREEN=5, // Target of specified size, don't mess with dimensions + RT_SIZE_FULL_FRAME_BUFFER_ROUNDED_UP=6, // Same size as the frame buffer, rounded up if necessary for systems that can't do non-power of two textures. + RT_SIZE_REPLAY_SCREENSHOT = 7 // Rounded down to power of 2, essentially... +}; + +typedef void (*MaterialBufferReleaseFunc_t)( ); +typedef void (*MaterialBufferRestoreFunc_t)( int nChangeFlags ); // see RestoreChangeFlags_t +typedef void (*ModeChangeCallbackFunc_t)( void ); + +typedef int VertexBufferHandle_t; +typedef unsigned short MaterialHandle_t; + +DECLARE_POINTER_HANDLE( OcclusionQueryObjectHandle_t ); +#define INVALID_OCCLUSION_QUERY_OBJECT_HANDLE ( (OcclusionQueryObjectHandle_t)0 ) + +class IMaterialProxyFactory; +class ITexture; +class IMaterialSystemHardwareConfig; +class CShadowMgr; + +DECLARE_POINTER_HANDLE( MaterialLock_t ); + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +abstract_class IMaterialSystem : public IAppSystem +{ +public: + + // Placeholder for API revision + virtual bool Connect( CreateInterfaceFn factory ) = 0; + virtual void Disconnect() = 0; + virtual void *QueryInterface( const char *pInterfaceName ) = 0; + virtual InitReturnVal_t Init() = 0; + virtual void Shutdown() = 0; + + //--------------------------------------------------------- + // Initialization and shutdown + //--------------------------------------------------------- + + // Call this to initialize the material system + // returns a method to create interfaces in the shader dll + virtual CreateInterfaceFn Init( char const* pShaderAPIDLL, + IMaterialProxyFactory *pMaterialProxyFactory, + CreateInterfaceFn fileSystemFactory, + CreateInterfaceFn cvarFactory=NULL ) = 0; + + // Call this to set an explicit shader version to use + // Must be called before Init(). + virtual void SetShaderAPI( char const *pShaderAPIDLL ) = 0; + + // Must be called before Init(), if you're going to call it at all... + virtual void SetAdapter( int nAdapter, int nFlags ) = 0; + + // Call this when the mod has been set up, which may occur after init + // At this point, the game + gamebin paths have been set up + virtual void ModInit() = 0; + virtual void ModShutdown() = 0; + + //--------------------------------------------------------- + // + //--------------------------------------------------------- + virtual void SetThreadMode( MaterialThreadMode_t mode, int nServiceThread = -1 ) = 0; + virtual MaterialThreadMode_t GetThreadMode( ) = 0; + virtual bool IsRenderThreadSafe( ) = 0; + virtual void ExecuteQueued() = 0; + + //--------------------------------------------------------- + // Config management + //--------------------------------------------------------- + + virtual IMaterialSystemHardwareConfig *GetHardwareConfig( const char *pVersion, int *returnCode ) = 0; + + + // Call this before rendering each frame with the current config + // for the material system. + // Will do whatever is necessary to get the material system into the correct state + // upon configuration change. .doesn't much else otherwise. + virtual bool UpdateConfig( bool bForceUpdate ) = 0; + + // Force this to be the config; update all material system convars to match the state + // return true if lightmaps need to be redownloaded + virtual bool OverrideConfig( const MaterialSystem_Config_t &config, bool bForceUpdate ) = 0; + + // Get the current config for this video card (as last set by UpdateConfig) + virtual const MaterialSystem_Config_t &GetCurrentConfigForVideoCard() const = 0; + + // Gets *recommended* configuration information associated with the display card, + // given a particular dx level to run under. + // Use dxlevel 0 to use the recommended dx level. + // The function returns false if an invalid dxlevel was specified + + // UNDONE: To find out all convars affected by configuration, we'll need to change + // the dxsupport.pl program to output all column headers into a single keyvalue block + // and then we would read that in, and send it back to the client + virtual bool GetRecommendedConfigurationInfo( int nDXLevel, KeyValues * pKeyValues ) = 0; + + + // ----------------------------------------------------------- + // Device methods + // ----------------------------------------------------------- + + // Gets the number of adapters... + virtual int GetDisplayAdapterCount() const = 0; + + // Returns the current adapter in use + virtual int GetCurrentAdapter() const = 0; + + // Returns info about each adapter + virtual void GetDisplayAdapterInfo( int adapter, MaterialAdapterInfo_t& info ) const = 0; + + // Returns the number of modes + virtual int GetModeCount( int adapter ) const = 0; + + // Returns mode information.. + virtual void GetModeInfo( int adapter, int mode, MaterialVideoMode_t& info ) const = 0; + + virtual void AddModeChangeCallBack( ModeChangeCallbackFunc_t func ) = 0; + + // Returns the mode info for the current display device + virtual void GetDisplayMode( MaterialVideoMode_t& mode ) const = 0; + + // Sets the mode... + virtual bool SetMode( void* hwnd, const MaterialSystem_Config_t &config ) = 0; + + virtual bool SupportsMSAAMode( int nMSAAMode ) = 0; + + // FIXME: REMOVE! Get video card identitier + virtual const MaterialSystemHardwareIdentifier_t &GetVideoCardIdentifier( void ) const = 0; + + // Use this to spew information about the 3D layer + virtual void SpewDriverInfo() const = 0; + + virtual void GetDXLevelDefaults(uint &max_dxlevel,uint &recommended_dxlevel) = 0; + + // Get the image format of the back buffer. . useful when creating render targets, etc. + virtual void GetBackBufferDimensions( int &width, int &height) const = 0; + virtual ImageFormat GetBackBufferFormat() const = 0; + + virtual bool SupportsHDRMode( HDRType_t nHDRModede ) = 0; + + + // ----------------------------------------------------------- + // Window methods + // ----------------------------------------------------------- + + // Creates/ destroys a child window + virtual bool AddView( void* hwnd ) = 0; + virtual void RemoveView( void* hwnd ) = 0; + + // Sets the view + virtual void SetView( void* hwnd ) = 0; + + + // ----------------------------------------------------------- + // Control flow + // ----------------------------------------------------------- + + virtual void BeginFrame( float frameTime ) = 0; + virtual void EndFrame( ) = 0; + virtual void Flush( bool flushHardware = false ) = 0; + + /// FIXME: This stuff needs to be cleaned up and abstracted. + // Stuff that gets exported to the launcher through the engine + virtual void SwapBuffers( ) = 0; + + // Flushes managed textures from the texture cacher + virtual void EvictManagedResources() = 0; + + virtual void ReleaseResources(void) = 0; + virtual void ReacquireResources(void ) = 0; + + + // ----------------------------------------------------------- + // Device loss/restore + // ----------------------------------------------------------- + + // Installs a function to be called when we need to release vertex buffers + textures + virtual void AddReleaseFunc( MaterialBufferReleaseFunc_t func ) = 0; + virtual void RemoveReleaseFunc( MaterialBufferReleaseFunc_t func ) = 0; + + // Installs a function to be called when we need to restore vertex buffers + virtual void AddRestoreFunc( MaterialBufferRestoreFunc_t func ) = 0; + virtual void RemoveRestoreFunc( MaterialBufferRestoreFunc_t func ) = 0; + + // Release temporary HW memory... + virtual void ResetTempHWMemory( bool bExitingLevel = false ) = 0; + + // For dealing with device lost in cases where SwapBuffers isn't called all the time (Hammer) + virtual void HandleDeviceLost() = 0; + + + // ----------------------------------------------------------- + // Shaders + // ----------------------------------------------------------- + + // Used to iterate over all shaders for editing purposes + // GetShaders returns the number of shaders it actually found + virtual int ShaderCount() const = 0; + virtual int GetShaders( int nFirstShader, int nMaxCount, IShader **ppShaderList ) const = 0; + + // FIXME: Is there a better way of doing this? + // Returns shader flag names for editors to be able to edit them + virtual int ShaderFlagCount() const = 0; + virtual const char * ShaderFlagName( int nIndex ) const = 0; + + // Gets the actual shader fallback for a particular shader + virtual void GetShaderFallback( const char *pShaderName, char *pFallbackShader, int nFallbackLength ) = 0; + + + // ----------------------------------------------------------- + // Material proxies + // ----------------------------------------------------------- + + virtual IMaterialProxyFactory *GetMaterialProxyFactory() = 0; + + // Sets the material proxy factory. Calling this causes all materials to be uncached. + virtual void SetMaterialProxyFactory( IMaterialProxyFactory* pFactory ) = 0; + + + // ----------------------------------------------------------- + // Editor mode + // ----------------------------------------------------------- + + // Used to enable editor materials. Must be called before Init. + virtual void EnableEditorMaterials() = 0; + + + // ----------------------------------------------------------- + // Stub mode mode + // ----------------------------------------------------------- + + // Force it to ignore Draw calls. + virtual void SetInStubMode( bool bInStubMode ) = 0; + + + //--------------------------------------------------------- + // Debug support + //--------------------------------------------------------- + + virtual void DebugPrintUsedMaterials( const char *pSearchSubString, bool bVerbose ) = 0; + virtual void DebugPrintUsedTextures( void ) = 0; + + virtual void ToggleSuppressMaterial( char const* pMaterialName ) = 0; + virtual void ToggleDebugMaterial( char const* pMaterialName ) = 0; + + + //--------------------------------------------------------- + // Misc features + //--------------------------------------------------------- + //returns whether fast clipping is being used or not - needed to be exposed for better per-object clip behavior + virtual bool UsingFastClipping( void ) = 0; + + virtual int StencilBufferBits( void ) = 0; //number of bits per pixel in the stencil buffer + + + //--------------------------------------------------------- + // Material and texture management + //--------------------------------------------------------- + + // uncache all materials. . good for forcing reload of materials. + virtual void UncacheAllMaterials( ) = 0; + + // Remove any materials from memory that aren't in use as determined + // by the IMaterial's reference count. + virtual void UncacheUnusedMaterials( bool bRecomputeStateSnapshots = false ) = 0; + + // Load any materials into memory that are to be used as determined + // by the IMaterial's reference count. + virtual void CacheUsedMaterials( ) = 0; + + // Force all textures to be reloaded from disk. + virtual void ReloadTextures( ) = 0; + + // Reloads materials + virtual void ReloadMaterials( const char *pSubString = NULL ) = 0; + + // Create a procedural material. The keyvalues looks like a VMT file + virtual IMaterial * CreateMaterial( const char *pMaterialName, KeyValues *pVMTKeyValues ) = 0; + + // Find a material by name. + // The name of a material is a full path to + // the vmt file starting from "hl2/materials" (or equivalent) without + // a file extension. + // eg. "dev/dev_bumptest" refers to somethign similar to: + // "d:/hl2/hl2/materials/dev/dev_bumptest.vmt" + // + // Most of the texture groups for pTextureGroupName are listed in texture_group_names.h. + // + // Note: if the material can't be found, this returns a checkerboard material. You can + // find out if you have that material by calling IMaterial::IsErrorMaterial(). + // (Or use the global IsErrorMaterial function, which checks if it's null too). + virtual IMaterial * FindMaterial( char const* pMaterialName, const char *pTextureGroupName, bool complain = true, const char *pComplainPrefix = NULL ) = 0; + + // Query whether a material is loaded (eg, whether FindMaterial will be nonblocking) + virtual bool IsMaterialLoaded( char const* pMaterialName ) = 0; + + //--------------------------------- + // This is the interface for knowing what materials are available + // is to use the following functions to get a list of materials. The + // material names will have the full path to the material, and that is the + // only way that the directory structure of the materials will be seen through this + // interface. + // NOTE: This is mostly for worldcraft to get a list of materials to put + // in the "texture" browser.in Worldcraft + virtual MaterialHandle_t FirstMaterial() const = 0; + + // returns InvalidMaterial if there isn't another material. + // WARNING: you must call GetNextMaterial until it returns NULL, + // otherwise there will be a memory leak. + virtual MaterialHandle_t NextMaterial( MaterialHandle_t h ) const = 0; + + // This is the invalid material + virtual MaterialHandle_t InvalidMaterial() const = 0; + + // Returns a particular material + virtual IMaterial* GetMaterial( MaterialHandle_t h ) const = 0; + + // Get the total number of materials in the system. These aren't just the used + // materials, but the complete collection. + virtual int GetNumMaterials( ) const = 0; + + //--------------------------------- + + virtual void SetAsyncTextureLoadCache( void* hFileCache ) = 0; + + virtual ITexture * FindTexture( char const* pTextureName, const char *pTextureGroupName, bool complain = true, int nAdditionalCreationFlags = 0 ) = 0; + + // Checks to see if a particular texture is loaded + virtual bool IsTextureLoaded( char const* pTextureName ) const = 0; + + // Creates a procedural texture + virtual ITexture * CreateProceduralTexture( const char *pTextureName, + const char *pTextureGroupName, + int w, + int h, + ImageFormat fmt, + int nFlags ) = 0; + + // + // Render targets + // + virtual void BeginRenderTargetAllocation() = 0; + virtual void EndRenderTargetAllocation() = 0; // Simulate an Alt-Tab in here, which causes a release/restore of all resources + + // Creates a render target + // If depth == true, a depth buffer is also allocated. If not, then + // the screen's depth buffer is used. + // Creates a texture for use as a render target + virtual ITexture * CreateRenderTargetTexture( int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED ) = 0; + + virtual ITexture * CreateNamedRenderTargetTextureEx( const char *pRTName, // Pass in NULL here for an unnamed render target. + int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, + unsigned int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + unsigned int renderTargetFlags = 0 ) = 0; + + virtual ITexture * CreateNamedRenderTargetTexture( const char *pRTName, + int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, + bool bClampTexCoords = true, + bool bAutoMipMap = false ) = 0; + + // Must be called between the above Begin-End calls! + virtual ITexture * CreateNamedRenderTargetTextureEx2( const char *pRTName, // Pass in NULL here for an unnamed render target. + int w, + int h, + RenderTargetSizeMode_t sizeMode, // Controls how size is generated (and regenerated on video mode change). + ImageFormat format, + MaterialRenderTargetDepth_t depth = MATERIAL_RT_DEPTH_SHARED, + unsigned int textureFlags = TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, + unsigned int renderTargetFlags = 0 ) = 0; + + // ----------------------------------------------------------- + // Lightmaps + // ----------------------------------------------------------- + + // To allocate lightmaps, sort the whole world by material twice. + // The first time through, call AllocateLightmap for every surface. + // that has a lightmap. + // The second time through, call AllocateWhiteLightmap for every + // surface that expects to use shaders that expect lightmaps. + virtual void BeginLightmapAllocation( ) = 0; + virtual void EndLightmapAllocation( ) = 0; + + // returns the sorting id for this surface + virtual int AllocateLightmap( int width, int height, + int offsetIntoLightmapPage[2], + IMaterial *pMaterial ) = 0; + // returns the sorting id for this surface + virtual int AllocateWhiteLightmap( IMaterial *pMaterial ) = 0; + + // lightmaps are in linear color space + // lightmapPageID is returned by GetLightmapPageIDForSortID + // lightmapSize and offsetIntoLightmapPage are returned by AllocateLightmap. + // You should never call UpdateLightmap for a lightmap allocated through + // AllocateWhiteLightmap. + virtual void UpdateLightmap( int lightmapPageID, int lightmapSize[2], + int offsetIntoLightmapPage[2], + float *pFloatImage, float *pFloatImageBump1, + float *pFloatImageBump2, float *pFloatImageBump3 ) = 0; + + // fixme: could just be an array of ints for lightmapPageIDs since the material + // for a surface is already known. + virtual int GetNumSortIDs( ) = 0; + virtual void GetSortInfo( MaterialSystem_SortInfo_t *sortInfoArray ) = 0; + + // Read the page size of an existing lightmap by sort id (returned from AllocateLightmap()) + virtual void GetLightmapPageSize( int lightmap, int *width, int *height ) const = 0; + + virtual void ResetMaterialLightmapPageInfo() = 0; + + + + virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil = false ) = 0; + + // ----------------------------------------------------------- + // X360 specifics + // ----------------------------------------------------------- + +#if defined( _X360 ) + virtual void ListUsedMaterials( void ) = 0; + virtual HXUIFONT OpenTrueTypeFont( const char *pFontname, int tall, int style ) = 0; + virtual void CloseTrueTypeFont( HXUIFONT hFont ) = 0; + virtual bool GetTrueTypeFontMetrics( HXUIFONT hFont, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] ) = 0; + // Render a sequence of characters and extract the data into a buffer + // For each character, provide the width+height of the font texture subrect, + // an offset to apply when rendering the glyph, and an offset into a buffer to receive the RGBA data + virtual bool GetTrueTypeGlyphs( HXUIFONT hFont, int numChars, wchar_t *pWch, int *pOffsetX, int *pOffsetY, int *pWidth, int *pHeight, unsigned char *pRGBA, int *pRGBAOffset ) = 0; + virtual void PersistDisplay() = 0; + virtual void *GetD3DDevice() = 0; + virtual bool OwnGPUResources( bool bEnable ) = 0; +#endif + + // ----------------------------------------------------------- + // Access the render contexts + // ----------------------------------------------------------- + virtual IMatRenderContext * GetRenderContext() = 0; + + virtual bool SupportsShadowDepthTextures( void ) = 0; + virtual void BeginUpdateLightmaps( void ) = 0; + virtual void EndUpdateLightmaps( void ) = 0; + + // ----------------------------------------------------------- + // Methods to force the material system into non-threaded, non-queued mode + // ----------------------------------------------------------- + virtual MaterialLock_t Lock() = 0; + virtual void Unlock( MaterialLock_t ) = 0; + + // Vendor-dependent shadow depth texture format + virtual ImageFormat GetShadowDepthTextureFormat() = 0; + + virtual bool SupportsFetch4( void ) = 0; + + // Create a custom render context. Cannot be used to create MATERIAL_HARDWARE_CONTEXT + virtual IMatRenderContext *CreateRenderContext( MaterialContextType_t type ) = 0; + + // Set a specified render context to be the global context for the thread. Returns the prior context. + virtual IMatRenderContext *SetRenderContext( IMatRenderContext * ) = 0; + + virtual bool SupportsCSAAMode( int nNumSamples, int nQualityLevel ) = 0; + + virtual void RemoveModeChangeCallBack( ModeChangeCallbackFunc_t func ) = 0; + + // Finds or create a procedural material. + virtual IMaterial * FindProceduralMaterial( const char *pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues ) = 0; + + virtual ImageFormat GetNullTextureFormat() = 0; + + virtual void AddTextureAlias( const char *pAlias, const char *pRealName ) = 0; + virtual void RemoveTextureAlias( const char *pAlias ) = 0; + + // returns a lightmap page ID for this allocation, -1 if none available + // frameID is a number that should be changed every frame to prevent locking any textures that are + // being used to draw in the previous frame + virtual int AllocateDynamicLightmap( int lightmapSize[2], int *pOutOffsetIntoPage, int frameID ) = 0; + + virtual void SetExcludedTextures( const char *pScriptName ) = 0; + virtual void UpdateExcludedTextures( void ) = 0; + + virtual bool IsInFrame( ) const = 0; + + virtual void CompactMemory() = 0; + + // For sv_pure mode. The filesystem figures out which files the client needs to reload to be "pure" ala the server's preferences. + virtual void ReloadFilesInList( IFileList *pFilesToReload ) = 0; + virtual bool AllowThreading( bool bAllow, int nServiceThread ) = 0; + + // Extended version of FindMaterial(). + // Contains context in so it can make decisions (i.e. if it's a model, ignore certain cheat parameters) + virtual IMaterial * FindMaterialEx( char const* pMaterialName, const char *pTextureGroupName, int nContext, bool complain = true, const char *pComplainPrefix = NULL ) = 0; + +#ifdef DX_TO_GL_ABSTRACTION + virtual void DoStartupShaderPreloading( void ) = 0; +#endif +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +abstract_class IMatRenderContext : public IRefCounted +{ +public: + virtual void BeginRender() = 0; + virtual void EndRender() = 0; + + virtual void Flush( bool flushHardware = false ) = 0; + + virtual void BindLocalCubemap( ITexture *pTexture ) = 0; + + // pass in an ITexture (that is build with "rendertarget" "1") or + // pass in NULL for the regular backbuffer. + virtual void SetRenderTarget( ITexture *pTexture ) = 0; + virtual ITexture * GetRenderTarget( void ) = 0; + + virtual void GetRenderTargetDimensions( int &width, int &height) const = 0; + + // Bind a material is current for rendering. + virtual void Bind( IMaterial *material, void *proxyData = 0 ) = 0; + // Bind a lightmap page current for rendering. You only have to + // do this for materials that require lightmaps. + virtual void BindLightmapPage( int lightmapPageID ) = 0; + + // inputs are between 0 and 1 + virtual void DepthRange( float zNear, float zFar ) = 0; + + virtual void ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil = false ) = 0; + + // read to a unsigned char rgb image. + virtual void ReadPixels( int x, int y, int width, int height, unsigned char *data, ImageFormat dstFormat ) = 0; + + // Sets lighting + virtual void SetAmbientLight( float r, float g, float b ) = 0; + virtual void SetLight( int lightNum, const LightDesc_t& desc ) = 0; + + // The faces of the cube are specified in the same order as cubemap textures + virtual void SetAmbientLightCube( Vector4D cube[6] ) = 0; + + // Blit the backbuffer to the framebuffer texture + virtual void CopyRenderTargetToTexture( ITexture *pTexture ) = 0; + + // Set the current texture that is a copy of the framebuffer. + virtual void SetFrameBufferCopyTexture( ITexture *pTexture, int textureIndex = 0 ) = 0; + virtual ITexture *GetFrameBufferCopyTexture( int textureIndex ) = 0; + + // + // end vertex array api + // + + // matrix api + virtual void MatrixMode( MaterialMatrixMode_t matrixMode ) = 0; + virtual void PushMatrix( void ) = 0; + virtual void PopMatrix( void ) = 0; + virtual void LoadMatrix( VMatrix const& matrix ) = 0; + virtual void LoadMatrix( matrix3x4_t const& matrix ) = 0; + virtual void MultMatrix( VMatrix const& matrix ) = 0; + virtual void MultMatrix( matrix3x4_t const& matrix ) = 0; + virtual void MultMatrixLocal( VMatrix const& matrix ) = 0; + virtual void MultMatrixLocal( matrix3x4_t const& matrix ) = 0; + virtual void GetMatrix( MaterialMatrixMode_t matrixMode, VMatrix *matrix ) = 0; + virtual void GetMatrix( MaterialMatrixMode_t matrixMode, matrix3x4_t *matrix ) = 0; + virtual void LoadIdentity( void ) = 0; + virtual void Ortho( double left, double top, double right, double bottom, double zNear, double zFar ) = 0; + virtual void PerspectiveX( double fovx, double aspect, double zNear, double zFar ) = 0; + virtual void PickMatrix( int x, int y, int width, int height ) = 0; + virtual void Rotate( float angle, float x, float y, float z ) = 0; + virtual void Translate( float x, float y, float z ) = 0; + virtual void Scale( float x, float y, float z ) = 0; + // end matrix api + + // Sets/gets the viewport + virtual void Viewport( int x, int y, int width, int height ) = 0; + virtual void GetViewport( int& x, int& y, int& width, int& height ) const = 0; + + // The cull mode + virtual void CullMode( MaterialCullMode_t cullMode ) = 0; + + // end matrix api + + // This could easily be extended to a general user clip plane + virtual void SetHeightClipMode( MaterialHeightClipMode_t nHeightClipMode ) = 0; + // garymcthack : fog z is always used for heightclipz for now. + virtual void SetHeightClipZ( float z ) = 0; + + // Fog methods... + virtual void FogMode( MaterialFogMode_t fogMode ) = 0; + virtual void FogStart( float fStart ) = 0; + virtual void FogEnd( float fEnd ) = 0; + virtual void SetFogZ( float fogZ ) = 0; + virtual MaterialFogMode_t GetFogMode( void ) = 0; + + virtual void FogColor3f( float r, float g, float b ) = 0; + virtual void FogColor3fv( float const* rgb ) = 0; + virtual void FogColor3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void FogColor3ubv( unsigned char const* rgb ) = 0; + + virtual void GetFogColor( unsigned char *rgb ) = 0; + + // Sets the number of bones for skinning + virtual void SetNumBoneWeights( int numBones ) = 0; + + // Creates/destroys Mesh + virtual IMesh* CreateStaticMesh( VertexFormat_t fmt, const char *pTextureBudgetGroup, IMaterial * pMaterial = NULL ) = 0; + virtual void DestroyStaticMesh( IMesh* mesh ) = 0; + + // Gets the dynamic mesh associated with the currently bound material + // note that you've got to render the mesh before calling this function + // a second time. Clients should *not* call DestroyStaticMesh on the mesh + // returned by this call. + // Use buffered = false if you want to not have the mesh be buffered, + // but use it instead in the following pattern: + // meshBuilder.Begin + // meshBuilder.End + // Draw partial + // Draw partial + // Draw partial + // meshBuilder.Begin + // meshBuilder.End + // etc + // Use Vertex or Index Override to supply a static vertex or index buffer + // to use in place of the dynamic buffers. + // + // If you pass in a material in pAutoBind, it will automatically bind the + // material. This can be helpful since you must bind the material you're + // going to use BEFORE calling GetDynamicMesh. + virtual IMesh* GetDynamicMesh( + bool buffered = true, + IMesh* pVertexOverride = 0, + IMesh* pIndexOverride = 0, + IMaterial *pAutoBind = 0 ) = 0; + + // ------------ New Vertex/Index Buffer interface ---------------------------- + // Do we need support for bForceTempMesh and bSoftwareVertexShader? + // I don't think we use bSoftwareVertexShader anymore. .need to look into bForceTempMesh. + virtual IVertexBuffer *CreateStaticVertexBuffer( VertexFormat_t fmt, int nVertexCount, const char *pTextureBudgetGroup ) = 0; + virtual IIndexBuffer *CreateStaticIndexBuffer( MaterialIndexFormat_t fmt, int nIndexCount, const char *pTextureBudgetGroup ) = 0; + virtual void DestroyVertexBuffer( IVertexBuffer * ) = 0; + virtual void DestroyIndexBuffer( IIndexBuffer * ) = 0; + // Do we need to specify the stream here in the case of locking multiple dynamic VBs on different streams? + virtual IVertexBuffer *GetDynamicVertexBuffer( int streamID, VertexFormat_t vertexFormat, bool bBuffered = true ) = 0; + virtual IIndexBuffer *GetDynamicIndexBuffer( MaterialIndexFormat_t fmt, bool bBuffered = true ) = 0; + virtual void BindVertexBuffer( int streamID, IVertexBuffer *pVertexBuffer, int nOffsetInBytes, int nFirstVertex, int nVertexCount, VertexFormat_t fmt, int nRepetitions = 1 ) = 0; + virtual void BindIndexBuffer( IIndexBuffer *pIndexBuffer, int nOffsetInBytes ) = 0; + virtual void Draw( MaterialPrimitiveType_t primitiveType, int firstIndex, int numIndices ) = 0; + // ------------ End ---------------------------- + + // Selection mode methods + virtual int SelectionMode( bool selectionMode ) = 0; + virtual void SelectionBuffer( unsigned int* pBuffer, int size ) = 0; + virtual void ClearSelectionNames( ) = 0; + virtual void LoadSelectionName( int name ) = 0; + virtual void PushSelectionName( int name ) = 0; + virtual void PopSelectionName() = 0; + + // Sets the Clear Color for ClearBuffer.... + virtual void ClearColor3ub( unsigned char r, unsigned char g, unsigned char b ) = 0; + virtual void ClearColor4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) = 0; + + // Allows us to override the depth buffer setting of a material + virtual void OverrideDepthEnable( bool bEnable, bool bDepthEnable ) = 0; + + // FIXME: This is a hack required for NVidia/XBox, can they fix in drivers? + virtual void DrawScreenSpaceQuad( IMaterial* pMaterial ) = 0; + + // For debugging and building recording files. This will stuff a token into the recording file, + // then someone doing a playback can watch for the token. + virtual void SyncToken( const char *pToken ) = 0; + + // FIXME: REMOVE THIS FUNCTION! + // The only reason why it's not gone is because we're a week from ship when I found the bug in it + // and everything's tuned to use it. + // It's returning values which are 2x too big (it's returning sphere diameter x2) + // Use ComputePixelDiameterOfSphere below in all new code instead. + virtual float ComputePixelWidthOfSphere( const Vector& origin, float flRadius ) = 0; + + // + // Occlusion query support + // + + // Allocate and delete query objects. + virtual OcclusionQueryObjectHandle_t CreateOcclusionQueryObject( void ) = 0; + virtual void DestroyOcclusionQueryObject( OcclusionQueryObjectHandle_t ) = 0; + + // Bracket drawing with begin and end so that we can get counts next frame. + virtual void BeginOcclusionQueryDrawing( OcclusionQueryObjectHandle_t ) = 0; + virtual void EndOcclusionQueryDrawing( OcclusionQueryObjectHandle_t ) = 0; + + // Get the number of pixels rendered between begin and end on an earlier frame. + // Calling this in the same frame is a huge perf hit! + virtual int OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjectHandle_t ) = 0; + + virtual void SetFlashlightMode( bool bEnable ) = 0; + + virtual void SetFlashlightState( const FlashlightState_t &state, const VMatrix &worldToTexture ) = 0; + + // Gets the current height clip mode + virtual MaterialHeightClipMode_t GetHeightClipMode( ) = 0; + + // This returns the diameter of the sphere in pixels based on + // the current model, view, + projection matrices and viewport. + virtual float ComputePixelDiameterOfSphere( const Vector& vecAbsOrigin, float flRadius ) = 0; + + // By default, the material system applies the VIEW and PROJECTION matrices to the user clip + // planes (which are specified in world space) to generate projection-space user clip planes + // Occasionally (for the particle system in hl2, for example), we want to override that + // behavior and explictly specify a ViewProj transform for user clip planes + virtual void EnableUserClipTransformOverride( bool bEnable ) = 0; + virtual void UserClipTransform( const VMatrix &worldToView ) = 0; + + virtual bool GetFlashlightMode() const = 0; + + // Used to make the handle think it's never had a successful query before + virtual void ResetOcclusionQueryObject( OcclusionQueryObjectHandle_t ) = 0; + + // FIXME: Remove + virtual void Unused3() {} + + // Creates/destroys morph data associated w/ a particular material + virtual IMorph *CreateMorph( MorphFormat_t format, const char *pDebugName ) = 0; + virtual void DestroyMorph( IMorph *pMorph ) = 0; + + // Binds the morph data for use in rendering + virtual void BindMorph( IMorph *pMorph ) = 0; + + // Sets flexweights for rendering + virtual void SetFlexWeights( int nFirstWeight, int nCount, const MorphWeight_t* pWeights ) = 0; + + // FIXME: Remove + virtual void Unused4() {}; + virtual void Unused5() {}; + virtual void Unused6() {}; + virtual void Unused7() {}; + virtual void Unused8() {}; + + // Read w/ stretch to a host-memory buffer + virtual void ReadPixelsAndStretch( Rect_t *pSrcRect, Rect_t *pDstRect, unsigned char *pBuffer, ImageFormat dstFormat, int nDstStride ) = 0; + + // Gets the window size + virtual void GetWindowSize( int &width, int &height ) const = 0; + + // This function performs a texture map from one texture map to the render destination, doing + // all the necessary pixel/texel coordinate fix ups. fractional values can be used for the + // src_texture coordinates to get linear sampling - integer values should produce 1:1 mappings + // for non-scaled operations. + virtual void DrawScreenSpaceRectangle( + IMaterial *pMaterial, + int destx, int desty, + int width, int height, + float src_texture_x0, float src_texture_y0, // which texel you want to appear at + // destx/y + float src_texture_x1, float src_texture_y1, // which texel you want to appear at + // destx+width-1, desty+height-1 + int src_texture_width, int src_texture_height, // needed for fixup + void *pClientRenderable = NULL, + int nXDice = 1, + int nYDice = 1 )=0; + + virtual void LoadBoneMatrix( int boneIndex, const matrix3x4_t& matrix ) = 0; + + // This version will push the current rendertarget + current viewport onto the stack + virtual void PushRenderTargetAndViewport( ) = 0; + + // This version will push a new rendertarget + a maximal viewport for that rendertarget onto the stack + virtual void PushRenderTargetAndViewport( ITexture *pTexture ) = 0; + + // This version will push a new rendertarget + a specified viewport onto the stack + virtual void PushRenderTargetAndViewport( ITexture *pTexture, int nViewX, int nViewY, int nViewW, int nViewH ) = 0; + + // This version will push a new rendertarget + a specified viewport onto the stack + virtual void PushRenderTargetAndViewport( ITexture *pTexture, ITexture *pDepthTexture, int nViewX, int nViewY, int nViewW, int nViewH ) = 0; + + // This will pop a rendertarget + viewport + virtual void PopRenderTargetAndViewport( void ) = 0; + + // Binds a particular texture as the current lightmap + virtual void BindLightmapTexture( ITexture *pLightmapTexture ) = 0; + + // Blit a subrect of the current render target to another texture + virtual void CopyRenderTargetToTextureEx( ITexture *pTexture, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect = NULL ) = 0; + virtual void CopyTextureToRenderTargetEx( int nRenderTargetID, ITexture *pTexture, Rect_t *pSrcRect, Rect_t *pDstRect = NULL ) = 0; + + // Special off-center perspective matrix for DoF, MSAA jitter and poster rendering + virtual void PerspectiveOffCenterX( double fovx, double aspect, double zNear, double zFar, double bottom, double top, double left, double right ) = 0; + + // Rendering parameters control special drawing modes withing the material system, shader + // system, shaders, and engine. renderparm.h has their definitions. + virtual void SetFloatRenderingParameter(int parm_number, float value) = 0; + virtual void SetIntRenderingParameter(int parm_number, int value) = 0; + virtual void SetVectorRenderingParameter(int parm_number, Vector const &value) = 0; + + // stencil buffer operations. + virtual void SetStencilEnable(bool onoff) = 0; + virtual void SetStencilFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilZFailOperation(StencilOperation_t op) = 0; + virtual void SetStencilPassOperation(StencilOperation_t op) = 0; + virtual void SetStencilCompareFunction(StencilComparisonFunction_t cmpfn) = 0; + virtual void SetStencilReferenceValue(int ref) = 0; + virtual void SetStencilTestMask(uint32 msk) = 0; + virtual void SetStencilWriteMask(uint32 msk) = 0; + virtual void ClearStencilBufferRectangle(int xmin, int ymin, int xmax, int ymax,int value) =0; + + virtual void SetRenderTargetEx( int nRenderTargetID, ITexture *pTexture ) = 0; + + // rendering clip planes, beware that only the most recently pushed plane will actually be used in a sizeable chunk of hardware configurations + // and that changes to the clip planes mid-frame while UsingFastClipping() is true will result unresolvable depth inconsistencies + virtual void PushCustomClipPlane( const float *pPlane ) = 0; + virtual void PopCustomClipPlane( void ) = 0; + + // Returns the number of vertices + indices we can render using the dynamic mesh + // Passing true in the second parameter will return the max # of vertices + indices + // we can use before a flush is provoked and may return different values + // if called multiple times in succession. + // Passing false into the second parameter will return + // the maximum possible vertices + indices that can be rendered in a single batch + virtual void GetMaxToRender( IMesh *pMesh, bool bMaxUntilFlush, int *pMaxVerts, int *pMaxIndices ) = 0; + + // Returns the max possible vertices + indices to render in a single draw call + virtual int GetMaxVerticesToRender( IMaterial *pMaterial ) = 0; + virtual int GetMaxIndicesToRender( ) = 0; + virtual void DisableAllLocalLights() = 0; + virtual int CompareMaterialCombos( IMaterial *pMaterial1, IMaterial *pMaterial2, int lightMapID1, int lightMapID2 ) = 0; + + virtual IMesh *GetFlexMesh() = 0; + + virtual void SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture ) = 0; + + // Returns the currently bound local cubemap + virtual ITexture *GetLocalCubemap( ) = 0; + + // This is a version of clear buffers which will only clear the buffer at pixels which pass the stencil test + virtual void ClearBuffersObeyStencil( bool bClearColor, bool bClearDepth ) = 0; + + //enables/disables all entered clipping planes, returns the input from the last time it was called. + virtual bool EnableClipping( bool bEnable ) = 0; + + //get fog distances entered with FogStart(), FogEnd(), and SetFogZ() + virtual void GetFogDistances( float *fStart, float *fEnd, float *fFogZ ) = 0; + + // Hooks for firing PIX events from outside the Material System... + virtual void BeginPIXEvent( unsigned long color, const char *szName ) = 0; + virtual void EndPIXEvent() = 0; + virtual void SetPIXMarker( unsigned long color, const char *szName ) = 0; + + // Batch API + // from changelist 166623: + // - replaced obtuse material system batch usage with an explicit and easier to thread API + virtual void BeginBatch( IMesh* pIndices ) = 0; + virtual void BindBatch( IMesh* pVertices, IMaterial *pAutoBind = NULL ) = 0; + virtual void DrawBatch(int firstIndex, int numIndices ) = 0; + virtual void EndBatch() = 0; + + // Raw access to the call queue, which can be NULL if not in a queued mode + virtual ICallQueue *GetCallQueue() = 0; + + // Returns the world-space camera position + virtual void GetWorldSpaceCameraPosition( Vector *pCameraPos ) = 0; + virtual void GetWorldSpaceCameraVectors( Vector *pVecForward, Vector *pVecRight, Vector *pVecUp ) = 0; + + // Tone mapping + virtual void ResetToneMappingScale( float monoscale) = 0; // set scale to monoscale instantly with no chasing + virtual void SetGoalToneMappingScale( float monoscale) = 0; // set scale to monoscale instantly with no chasing + + // call TurnOnToneMapping before drawing the 3d scene to get the proper interpolated brightness + // value set. + virtual void TurnOnToneMapping() = 0; + + // Set a linear vector color scale for all 3D rendering. + // A value of [1.0f, 1.0f, 1.0f] should match non-tone-mapped rendering. + virtual void SetToneMappingScaleLinear( const Vector &scale ) = 0; + + virtual Vector GetToneMappingScaleLinear( void ) = 0; + virtual void SetShadowDepthBiasFactors( float fSlopeScaleDepthBias, float fDepthBias ) = 0; + + // Apply stencil operations to every pixel on the screen without disturbing depth or color buffers + virtual void PerformFullScreenStencilOperation( void ) = 0; + + // Sets lighting origin for the current model (needed to convert directional lights to points) + virtual void SetLightingOrigin( Vector vLightingOrigin ) = 0; + + // Set scissor rect for rendering + virtual void SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor ) = 0; + + // Methods used to build the morph accumulator that is read from when HW morph E* LockRenderDataTyped( int nCount, const E* pSrcData = NULL ); + + // Temp render data gets immediately freed after it's all unlocked in single core. + // This prevents it from being freed + virtual void AddRefRenderData() = 0; + virtual void ReleaseRenderData() = 0; + + // Returns whether a pointer is render data. NOTE: passing NULL returns true + virtual bool IsRenderData( const void *pData ) const = 0; + virtual void PrintfVA( char *fmt, va_list vargs ) = 0; + virtual void Printf( PRINTF_FORMAT_STRING char *fmt, ... ) = 0; + virtual float Knob( char *knobname, float *setvalue = NULL ) = 0; + // Allows us to override the alpha write setting of a material + virtual void OverrideAlphaWriteEnable( bool bEnable, bool bAlphaWriteEnable ) = 0; + virtual void OverrideColorWriteEnable( bool bOverrideEnable, bool bColorWriteEnable ) = 0; + + virtual void ClearBuffersObeyStencilEx( bool bClearColor, bool bClearAlpha, bool bClearDepth ) = 0; +}; + +template< class E > inline E* IMatRenderContext::LockRenderDataTyped( int nCount, const E* pSrcData ) +{ + int nSizeInBytes = nCount * sizeof(E); + E *pDstData = (E*)LockRenderData( nSizeInBytes ); + if ( pSrcData && pDstData ) + { + memcpy( pDstData, pSrcData, nSizeInBytes ); + } + return pDstData; +} + + +//----------------------------------------------------------------------------- +// Utility class for addreffing/releasing render data (prevents freeing on single core) +//----------------------------------------------------------------------------- +class CMatRenderDataReference +{ +public: + CMatRenderDataReference(); + CMatRenderDataReference( IMatRenderContext* pRenderContext ); + ~CMatRenderDataReference(); + void Lock( IMatRenderContext *pRenderContext ); + void Release(); + +private: + IMatRenderContext *m_pRenderContext; +}; + + +inline CMatRenderDataReference::CMatRenderDataReference() +{ + m_pRenderContext = NULL; +} + +inline CMatRenderDataReference::CMatRenderDataReference( IMatRenderContext* pRenderContext ) +{ + m_pRenderContext = NULL; + Lock( pRenderContext ); +} + +inline CMatRenderDataReference::~CMatRenderDataReference() +{ + Release(); +} + +inline void CMatRenderDataReference::Lock( IMatRenderContext* pRenderContext ) +{ + if ( !m_pRenderContext ) + { + m_pRenderContext = pRenderContext; + m_pRenderContext->AddRefRenderData( ); + } +} + +inline void CMatRenderDataReference::Release() +{ + if ( m_pRenderContext ) + { + m_pRenderContext->ReleaseRenderData( ); + m_pRenderContext = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Utility class for locking/unlocking render data +//----------------------------------------------------------------------------- +template< typename E > +class CMatRenderData +{ +public: + CMatRenderData( IMatRenderContext* pRenderContext ); + CMatRenderData( IMatRenderContext* pRenderContext, int nCount, const E *pSrcData = NULL ); + ~CMatRenderData(); + E* Lock( int nCount, const E* pSrcData = NULL ); + void Release(); + bool IsValid() const; + const E* Base() const; + E* Base(); + const E& operator[]( int i ) const; + E& operator[]( int i ); + +private: + IMatRenderContext* m_pRenderContext; + E *m_pRenderData; + int m_nCount; + bool m_bNeedsUnlock; +}; + +template< typename E > +inline CMatRenderData::CMatRenderData( IMatRenderContext* pRenderContext ) +{ + m_pRenderContext = pRenderContext; + m_nCount = 0; + m_pRenderData = 0; + m_bNeedsUnlock = false; +} + +template< typename E > +inline CMatRenderData::CMatRenderData( IMatRenderContext* pRenderContext, int nCount, const E* pSrcData ) +{ + m_pRenderContext = pRenderContext; + m_nCount = 0; + m_pRenderData = 0; + m_bNeedsUnlock = false; + Lock( nCount, pSrcData ); +} + +template< typename E > +inline CMatRenderData::~CMatRenderData() +{ + Release(); +} + +template< typename E > +inline bool CMatRenderData::IsValid() const +{ + return m_pRenderData != NULL; +} + +template< typename E > +inline E* CMatRenderData::Lock( int nCount, const E* pSrcData ) +{ + m_nCount = nCount; + if ( pSrcData && m_pRenderContext->IsRenderData( pSrcData ) ) + { + // Yes, we're const-casting away, but that should be ok since + // the src data is render data + m_pRenderData = const_cast( pSrcData ); + m_pRenderContext->AddRefRenderData(); + m_bNeedsUnlock = false; + return m_pRenderData; + } + m_pRenderData = m_pRenderContext->LockRenderDataTyped( nCount, pSrcData ); + m_bNeedsUnlock = true; + return m_pRenderData; +} + +template< typename E > +inline void CMatRenderData::Release() +{ + if ( m_pRenderContext && m_pRenderData ) + { + if ( m_bNeedsUnlock ) + { + m_pRenderContext->UnlockRenderData( m_pRenderData ); + } + else + { + m_pRenderContext->ReleaseRenderData(); + } + } + m_pRenderData = NULL; + m_nCount = 0; + m_bNeedsUnlock = false; +} + +template< typename E > +inline E* CMatRenderData::Base() +{ + return m_pRenderData; +} + +template< typename E > +inline const E* CMatRenderData::Base() const +{ + return m_pRenderData; +} + +template< typename E > +inline E& CMatRenderData::operator[]( int i ) +{ + Assert( ( i >= 0 ) && ( i < m_nCount ) ); + return m_pRenderData[i]; +} + +template< typename E > +inline const E& CMatRenderData::operator[]( int i ) const +{ + Assert( ( i >= 0 ) && ( i < m_nCount ) ); + return m_pRenderData[i]; +} + + +//----------------------------------------------------------------------------- + +class CMatRenderContextPtr : public CRefPtr +{ + typedef CRefPtr BaseClass; +public: + CMatRenderContextPtr() {} + CMatRenderContextPtr( IMatRenderContext *pInit ) : BaseClass( pInit ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->BeginRender(); } + CMatRenderContextPtr( IMaterialSystem *pFrom ) : BaseClass( pFrom->GetRenderContext() ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->BeginRender(); } + ~CMatRenderContextPtr() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->EndRender(); } + + IMatRenderContext *operator=( IMatRenderContext *p ) { if ( p ) p->BeginRender(); return BaseClass::operator=( p ); } + + void SafeRelease() { if ( BaseClass::m_pObject ) BaseClass::m_pObject->EndRender(); BaseClass::SafeRelease(); } + void AssignAddRef( IMatRenderContext *pFrom ) { if ( BaseClass::m_pObject ) BaseClass::m_pObject->EndRender(); BaseClass::AssignAddRef( pFrom ); BaseClass::m_pObject->BeginRender(); } + + void GetFrom( IMaterialSystem *pFrom ) { AssignAddRef( pFrom->GetRenderContext() ); } + + +private: + CMatRenderContextPtr( const CMatRenderContextPtr &from ); + void operator=( const CMatRenderContextPtr &from ); + +}; + +//----------------------------------------------------------------------------- +// Helper class for begin/end of pix event via constructor/destructor +//----------------------------------------------------------------------------- +#define PIX_VALVE_ORANGE 0xFFF5940F + +class PIXEvent +{ +public: + PIXEvent( IMatRenderContext *pRenderContext, const char *szName, unsigned long color = PIX_VALVE_ORANGE ) + { + m_pRenderContext = pRenderContext; + Assert( m_pRenderContext ); + Assert( szName ); + m_pRenderContext->BeginPIXEvent( color, szName ); + } + ~PIXEvent() + { + m_pRenderContext->EndPIXEvent(); + } +private: + IMatRenderContext *m_pRenderContext; +}; + + +// Also be sure to enable PIX_INSTRUMENTATION in shaderdevicedx8.h +//#define PIX_ENABLE 1 // set this to 1 and build engine/studiorender to enable pix events in the engine + +#if PIX_ENABLE +# define PIXEVENT PIXEvent _pixEvent +#else +# define PIXEVENT +#endif + +//----------------------------------------------------------------------------- + +#ifdef MATERIAL_SYSTEM_DEBUG_CALL_QUEUE +#include "tier1/callqueue.h" +#include "tier1/fmtstr.h" +static void DoMatSysQueueMark( IMaterialSystem *pMaterialSystem, const char *psz ) +{ + CMatRenderContextPtr pRenderContext( pMaterialSystem ); + if ( pRenderContext->GetCallQueue() ) + pRenderContext->GetCallQueue()->QueueCall( Plat_DebugString, CUtlEnvelope( psz ) ); +} + +#define MatSysQueueMark( pMaterialSystem, ...) DoMatSysQueueMark( pMaterialSystem, CFmtStr( __VA_ARGS__ ) ) +#else +#define MatSysQueueMark( msg, ...) ((void)0) +#endif + +//----------------------------------------------------------------------------- + +extern IMaterialSystem *materials; +extern IMaterialSystem *g_pMaterialSystem; + +#endif // IMATERIALSYSTEM_H diff --git a/mp/src/public/materialsystem/imaterialsystemhardwareconfig.h b/mp/src/public/materialsystem/imaterialsystemhardwareconfig.h new file mode 100644 index 00000000..4aef4228 --- /dev/null +++ b/mp/src/public/materialsystem/imaterialsystemhardwareconfig.h @@ -0,0 +1,212 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//===========================================================================// + +#ifndef IMATERIALSYSTEMHARDWARECONFIG_H +#define IMATERIALSYSTEMHARDWARECONFIG_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "tier1/interface.h" + +//----------------------------------------------------------------------------- +// GL helpers +//----------------------------------------------------------------------------- +FORCEINLINE bool IsEmulatingGL() +{ + static bool bIsEmulatingGL = ( Plat_GetCommandLineA() ) ? ( strstr( Plat_GetCommandLineA(), "-r_emulate_gl" ) != NULL ) : false; + return bIsEmulatingGL; +} + +FORCEINLINE bool IsOpenGL( void ) +{ + return IsPlatformOpenGL() || IsEmulatingGL(); +} + +//----------------------------------------------------------------------------- +// Material system interface version +//----------------------------------------------------------------------------- +#define MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION "MaterialSystemHardwareConfig012" + +// HDRFIXME NOTE: must match common_ps_fxc.h +enum HDRType_t +{ + HDR_TYPE_NONE, + HDR_TYPE_INTEGER, + HDR_TYPE_FLOAT, +}; + +// For now, vertex compression is simply "on or off" (for the sake of simplicity +// and MeshBuilder perf.), but later we may support multiple flavours. +enum VertexCompressionType_t +{ + // This indicates an uninitialized VertexCompressionType_t value + VERTEX_COMPRESSION_INVALID = 0xFFFFFFFF, + + // 'VERTEX_COMPRESSION_NONE' means that no elements of a vertex are compressed + VERTEX_COMPRESSION_NONE = 0, + + // Currently (more stuff may be added as needed), 'VERTEX_COMPRESSION_ON' means: + // - if a vertex contains VERTEX_ELEMENT_NORMAL, this is compressed + // (see CVertexBuilder::CompressedNormal3f) + // - if a vertex contains VERTEX_ELEMENT_USERDATA4 (and a normal - together defining a tangent + // frame, with the binormal reconstructed in the vertex shader), this is compressed + // (see CVertexBuilder::CompressedUserData) + // - if a vertex contains VERTEX_ELEMENT_BONEWEIGHTSx, this is compressed + // (see CVertexBuilder::CompressedBoneWeight3fv) + VERTEX_COMPRESSION_ON = 1 +}; + + +// use DEFCONFIGMETHOD to define time-critical methods that we want to make just return constants +// on the 360, so that the checks will happen at compile time. Not all methods are defined this way +// - just the ones that I perceive as being called often in the frame interval. +#ifdef _X360 +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) \ +FORCEINLINE ret_type method const \ +{ \ + return xbox_return_value; \ +} + + +#else +#define DEFCONFIGMETHOD( ret_type, method, xbox_return_value ) \ +virtual ret_type method const = 0; +#endif + + + +//----------------------------------------------------------------------------- +// Material system configuration +//----------------------------------------------------------------------------- +class IMaterialSystemHardwareConfig +{ +public: + // on xbox, some methods are inlined to return constants + + DEFCONFIGMETHOD( bool, HasDestAlphaBuffer(), true ); + DEFCONFIGMETHOD( bool, HasStencilBuffer(), true ); + virtual int GetFrameBufferColorDepth() const = 0; + virtual int GetSamplerCount() const = 0; + virtual bool HasSetDeviceGammaRamp() const = 0; + DEFCONFIGMETHOD( bool, SupportsCompressedTextures(), true ); + virtual VertexCompressionType_t SupportsCompressedVertices() const = 0; + DEFCONFIGMETHOD( bool, SupportsNormalMapCompression(), true ); + DEFCONFIGMETHOD( bool, SupportsVertexAndPixelShaders(), true ); + DEFCONFIGMETHOD( bool, SupportsPixelShaders_1_4(), true ); + DEFCONFIGMETHOD( bool, SupportsStaticControlFlow(), true ); + DEFCONFIGMETHOD( bool, SupportsPixelShaders_2_0(), true ); + DEFCONFIGMETHOD( bool, SupportsVertexShaders_2_0(), true ); + virtual int MaximumAnisotropicLevel() const = 0; // 0 means no anisotropic filtering + virtual int MaxTextureWidth() const = 0; + virtual int MaxTextureHeight() const = 0; + virtual int TextureMemorySize() const = 0; + virtual bool SupportsOverbright() const = 0; + virtual bool SupportsCubeMaps() const = 0; + virtual bool SupportsMipmappedCubemaps() const = 0; + virtual bool SupportsNonPow2Textures() const = 0; + + // The number of texture stages represents the number of computations + // we can do in the fixed-function pipeline, it is *not* related to the + // simultaneous number of textures we can use + virtual int GetTextureStageCount() const = 0; + virtual int NumVertexShaderConstants() const = 0; + virtual int NumPixelShaderConstants() const = 0; + virtual int MaxNumLights() const = 0; + virtual bool SupportsHardwareLighting() const = 0; + virtual int MaxBlendMatrices() const = 0; + virtual int MaxBlendMatrixIndices() const = 0; + virtual int MaxTextureAspectRatio() const = 0; + virtual int MaxVertexShaderBlendMatrices() const = 0; + virtual int MaxUserClipPlanes() const = 0; + virtual bool UseFastClipping() const = 0; + + // This here should be the major item looked at when checking for compat + // from anywhere other than the material system shaders + DEFCONFIGMETHOD( int, GetDXSupportLevel(), 98 ); + virtual const char *GetShaderDLLName() const = 0; + + virtual bool ReadPixelsFromFrontBuffer() const = 0; + + // Are dx dynamic textures preferred? + virtual bool PreferDynamicTextures() const = 0; + + DEFCONFIGMETHOD( bool, SupportsHDR(), true ); + + virtual bool HasProjectedBumpEnv() const = 0; + virtual bool SupportsSpheremapping() const = 0; + virtual bool NeedsAAClamp() const = 0; + virtual bool NeedsATICentroidHack() const = 0; + + virtual bool SupportsColorOnSecondStream() const = 0; + virtual bool SupportsStaticPlusDynamicLighting() const = 0; + + // Does our card have a hard time with fillrate + // relative to other cards w/ the same dx level? + virtual bool PreferReducedFillrate() const = 0; + + // This is the max dx support level supported by the card + virtual int GetMaxDXSupportLevel() const = 0; + + // Does the card specify fog color in linear space when sRGBWrites are enabled? + virtual bool SpecifiesFogColorInLinearSpace() const = 0; + + // Does the card support sRGB reads/writes? + DEFCONFIGMETHOD( bool, SupportsSRGB(), true ); + DEFCONFIGMETHOD( bool, FakeSRGBWrite(), false ); + DEFCONFIGMETHOD( bool, CanDoSRGBReadFromRTs(), true ); + + virtual bool SupportsGLMixedSizeTargets() const = 0; + + virtual bool IsAAEnabled() const = 0; // Is antialiasing being used? + + // NOTE: Anything after this was added after shipping HL2. + virtual int GetVertexTextureCount() const = 0; + virtual int GetMaxVertexTextureDimension() const = 0; + + virtual int MaxTextureDepth() const = 0; + + virtual HDRType_t GetHDRType() const = 0; + virtual HDRType_t GetHardwareHDRType() const = 0; + + DEFCONFIGMETHOD( bool, SupportsPixelShaders_2_b(), true ); + virtual bool SupportsStreamOffset() const = 0; + + virtual int StencilBufferBits() const = 0; + virtual int MaxViewports() const = 0; + + virtual void OverrideStreamOffsetSupport( bool bOverrideEnabled, bool bEnableSupport ) = 0; + + virtual int GetShadowFilterMode() const = 0; + + virtual int NeedsShaderSRGBConversion() const = 0; + + DEFCONFIGMETHOD( bool, UsesSRGBCorrectBlending(), true ); + + virtual bool SupportsShaderModel_3_0() const = 0; + virtual bool HasFastVertexTextures() const = 0; + virtual int MaxHWMorphBatchCount() const = 0; + + // Does the board actually support this? + DEFCONFIGMETHOD( bool, ActuallySupportsPixelShaders_2_b(), true ); + + virtual bool SupportsHDRMode( HDRType_t nHDRMode ) const = 0; + + virtual bool GetHDREnabled( void ) const = 0; + virtual void SetHDREnabled( bool bEnable ) = 0; + + virtual bool SupportsBorderColor( void ) const = 0; + virtual bool SupportsFetch4( void ) const = 0; + + inline bool ShouldAlwaysUseShaderModel2bShaders() const { return IsOpenGL(); } + inline bool PlatformRequiresNonNullPixelShaders() const { return IsOpenGL(); } +}; + +#endif // IMATERIALSYSTEMHARDWARECONFIG_H diff --git a/mp/src/public/materialsystem/imaterialsystemstub.h b/mp/src/public/materialsystem/imaterialsystemstub.h new file mode 100644 index 00000000..6ff48f35 --- /dev/null +++ b/mp/src/public/materialsystem/imaterialsystemstub.h @@ -0,0 +1,31 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef IMATERIALSYSTEMSTUB_H +#define IMATERIALSYSTEMSTUB_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "materialsystem/imaterialsystem.h" + + +// If you get this interface out of the material system, it'll return an IMaterialSystem +// with everything stubbed. This is used for running the client in text mode. +#define MATERIAL_SYSTEM_STUB_INTERFACE_VERSION "VMaterialSystemStub001" + + +class IMaterialSystemStub : public IMaterialSystem +{ +public: + // If this is called, then the stub will call through to the real material + // system in some functions. + virtual void SetRealMaterialSystem( IMaterialSystem *pSys ) = 0; +}; + + +#endif // IMATERIALSYSTEMSTUB_H diff --git a/mp/src/public/materialsystem/imaterialvar.h b/mp/src/public/materialsystem/imaterialvar.h new file mode 100644 index 00000000..69412e8f --- /dev/null +++ b/mp/src/public/materialsystem/imaterialvar.h @@ -0,0 +1,245 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef IMATERIALVAR_H +#define IMATERIALVAR_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier1/utlsymbol.h" +#include "mathlib/vector4d.h" +class IMaterial; +class VMatrix; +class ITexture; + +#define MAKE_MATERIALVAR_FOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned long)(ch0) | ((unsigned long)(ch1) << 8) | \ + ((unsigned long)(ch2) << 16) | ((unsigned long)(ch3) << 24 )) + +// This fourcc is reserved. +#define FOURCC_UNKNOWN MAKE_MATERIALVAR_FOURCC('U','N','K','N') + + +//----------------------------------------------------------------------------- +// Various material var types +//----------------------------------------------------------------------------- +enum MaterialVarType_t +{ + MATERIAL_VAR_TYPE_FLOAT = 0, + MATERIAL_VAR_TYPE_STRING, + MATERIAL_VAR_TYPE_VECTOR, + MATERIAL_VAR_TYPE_TEXTURE, + MATERIAL_VAR_TYPE_INT, + MATERIAL_VAR_TYPE_FOURCC, + MATERIAL_VAR_TYPE_UNDEFINED, + MATERIAL_VAR_TYPE_MATRIX, + MATERIAL_VAR_TYPE_MATERIAL, +}; + +typedef unsigned short MaterialVarSym_t; + +class IMaterialVar +{ +public: + typedef unsigned long FourCC; + +protected: + // base data and accessors + char* m_pStringVal; + int m_intVal; + Vector4D m_VecVal; + + // member data. total = 4 bytes + uint8 m_Type : 4; + uint8 m_nNumVectorComps : 3; + uint8 m_bFakeMaterialVar : 1; + uint8 m_nTempIndex; + CUtlSymbol m_Name; + +public: + // class factory methods + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, VMatrix const& matrix ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, char const* pVal ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, float* pVal, int numcomps ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, float val ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey, int val ); + static IMaterialVar* Create( IMaterial* pMaterial, char const* pKey ); + static void Destroy( IMaterialVar* pVar ); + static MaterialVarSym_t GetSymbol( char const* pName ); + static MaterialVarSym_t FindSymbol( char const* pName ); + static bool SymbolMatches( char const* pName, MaterialVarSym_t symbol ); + static void DeleteUnreferencedTextures( bool enable ); + + virtual ITexture *GetTextureValue( void ) = 0; + + virtual char const * GetName( void ) const = 0; + virtual MaterialVarSym_t GetNameAsSymbol() const = 0; + + virtual void SetFloatValue( float val ) = 0; + + virtual void SetIntValue( int val ) = 0; + + virtual void SetStringValue( char const *val ) = 0; + virtual char const * GetStringValue( void ) const = 0; + + // Use FourCC values to pass app-defined data structures between + // the proxy and the shader. The shader should ignore the data if + // its FourCC type not correct. + virtual void SetFourCCValue( FourCC type, void *pData ) = 0; + virtual void GetFourCCValue( FourCC *type, void **ppData ) = 0; + + // Vec (dim 2-4) + virtual void SetVecValue( float const* val, int numcomps ) = 0; + virtual void SetVecValue( float x, float y ) = 0; + virtual void SetVecValue( float x, float y, float z ) = 0; + virtual void SetVecValue( float x, float y, float z, float w ) = 0; + virtual void GetLinearVecValue( float *val, int numcomps ) const = 0; + + // revisit: is this a good interface for textures? + virtual void SetTextureValue( ITexture * ) = 0; + + virtual IMaterial * GetMaterialValue( void ) = 0; + virtual void SetMaterialValue( IMaterial * ) = 0; + + virtual bool IsDefined() const = 0; + virtual void SetUndefined() = 0; + + // Matrix + virtual void SetMatrixValue( VMatrix const& matrix ) = 0; + virtual const VMatrix &GetMatrixValue( ) = 0; + virtual bool MatrixIsIdentity() const = 0; + + // Copy.... + virtual void CopyFrom( IMaterialVar *pMaterialVar ) = 0; + + virtual void SetValueAutodetectType( char const *val ) = 0; + + virtual IMaterial * GetOwningMaterial() = 0; + + //set just 1 component + virtual void SetVecComponentValue( float fVal, int nComponent ) = 0; + +protected: + virtual int GetIntValueInternal( void ) const = 0; + virtual float GetFloatValueInternal( void ) const = 0; + virtual float const* GetVecValueInternal( ) const = 0; + virtual void GetVecValueInternal( float *val, int numcomps ) const = 0; + virtual int VectorSizeInternal() const = 0; + +public: + FORCEINLINE MaterialVarType_t GetType( void ) const + { + return ( MaterialVarType_t )m_Type; + } + + FORCEINLINE bool IsTexture() const + { + return m_Type == MATERIAL_VAR_TYPE_TEXTURE; + } + + FORCEINLINE operator ITexture*() + { + return GetTextureValue(); + } + + // NOTE: Fast methods should only be called in thread-safe situations + FORCEINLINE int GetIntValueFast( void ) const + { + // Set methods for float and vector update this + return m_intVal; + } + + FORCEINLINE float GetFloatValueFast( void ) const + { + return m_VecVal[0]; + } + + FORCEINLINE float const* GetVecValueFast( ) const + { + return m_VecVal.Base(); + } + + FORCEINLINE void GetVecValueFast( float *val, int numcomps ) const + { + Assert( ( numcomps >0 ) && ( numcomps <= 4 ) ); + for( int i=0 ; i < numcomps; i++ ) + { + val[i] = m_VecVal[ i ]; + } + } + + FORCEINLINE int VectorSizeFast() const + { + return m_nNumVectorComps; + } + +#ifdef FAST_MATERIALVAR_ACCESS + FORCEINLINE int GetIntValue( void ) const + { + return GetIntValueFast(); + } + + FORCEINLINE float GetFloatValue( void ) const + { + return GetFloatValueFast(); + } + + FORCEINLINE float const* GetVecValue( ) const + { + return GetVecValueFast(); + } + + FORCEINLINE void GetVecValue( float *val, int numcomps ) const + { + GetVecValueFast( val, numcomps ); + } + + FORCEINLINE int VectorSize() const + { + return VectorSizeFast(); + } +#else // !FAST_MATERIALVAR_ACCESS + FORCEINLINE int GetIntValue( void ) const + { + return GetIntValueInternal(); + } + + FORCEINLINE float GetFloatValue( void ) const + { + return GetFloatValueInternal(); + } + + FORCEINLINE float const* GetVecValue( ) const + { + return GetVecValueInternal(); + } + + FORCEINLINE void GetVecValue( float *val, int numcomps ) const + { + return GetVecValueInternal( val, numcomps ); + } + + FORCEINLINE int VectorSize() const + { + return VectorSizeInternal(); + } +#endif + +private: + FORCEINLINE void SetTempIndex( int nIndex ) + { + m_nTempIndex = nIndex; + } + + friend void EnableThreadedMaterialVarAccess( bool bEnable, IMaterialVar **ppParams, int nVarCount ); +}; + +#endif // IMATERIALVAR_H diff --git a/mp/src/public/materialsystem/imesh.h b/mp/src/public/materialsystem/imesh.h new file mode 100644 index 00000000..7ee35de9 --- /dev/null +++ b/mp/src/public/materialsystem/imesh.h @@ -0,0 +1,4047 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef IMESH_H +#define IMESH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/interface.h" +#include "materialsystem/imaterial.h" +#include +#include +#include "tier0/dbg.h" +#include "tier2/meshutils.h" +#include "mathlib/mathlib.h" + +#if defined( DX_TO_GL_ABSTRACTION ) +// Swap these so that we do color swapping on 10.6.2, which doesn't have EXT_vertex_array_bgra +#define OPENGL_SWAP_COLORS +#endif + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterial; +class CMeshBuilder; +class IMaterialVar; +typedef uint64 VertexFormat_t; + + +//----------------------------------------------------------------------------- +// Define this to find write-combine problems +//----------------------------------------------------------------------------- +#ifdef _DEBUG +//#ifndef DEBUG_WRITE_COMBINE +//#define DEBUG_WRITE_COMBINE 1 +//#endif +#endif + + +//----------------------------------------------------------------------------- +// The Vertex Buffer interface +//----------------------------------------------------------------------------- +enum +{ + VERTEX_MAX_TEXTURE_COORDINATES = 8, + BONE_MATRIX_INDEX_INVALID = 255 +}; + +// Internal maximums for sizes. Don't use directly, use IMaterialSystem::GetMaxToRender() +enum +{ + INDEX_BUFFER_SIZE = 32768, + DYNAMIC_VERTEX_BUFFER_MEMORY = ( 1024 + 512 ) * 1024, + DYNAMIC_VERTEX_BUFFER_MEMORY_SMALL = 384 * 1024, // Only allocate this much during map transitions +}; + +// Vertex fields must be written in well-defined order to achieve write combining, +// which is a perf booster +enum WriteCombineOrdering_t +{ + MB_FIELD_NONE = -1, + MB_FIELD_POSITION = 0, + MB_FIELD_BONE_WEIGHTS, + MB_FIELD_BONE_INDEX, + MB_FIELD_NORMAL, + MB_FIELD_COLOR, + MB_FIELD_SPECULAR, + MB_FIELD_TEXCOORD_FIRST, + MB_FIELD_TEXCOORD_LAST = MB_FIELD_TEXCOORD_FIRST + VERTEX_MAX_TEXTURE_COORDINATES - 1, + MB_FIELD_TANGENT_S, + MB_FIELD_TANGENT_T, + MB_FIELD_USERDATA, +}; + +#define MB_FIELD_TEXCOORD( nStage ) ( MB_FIELD_TEXCOORD_FIRST + ( nStage ) ) + +struct VertexDesc_t +{ + // These can be set to zero if there are pointers to dummy buffers, when the + // actual buffer format doesn't contain the data but it needs to be safe to + // use all the CMeshBuilder functions. + int m_VertexSize_Position; + int m_VertexSize_BoneWeight; + int m_VertexSize_BoneMatrixIndex; + int m_VertexSize_Normal; + int m_VertexSize_Color; + int m_VertexSize_Specular; + int m_VertexSize_TexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + int m_VertexSize_TangentS; + int m_VertexSize_TangentT; + int m_VertexSize_Wrinkle; + + int m_VertexSize_UserData; + + int m_ActualVertexSize; // Size of the vertices.. Some of the m_VertexSize_ elements above + // are set to this value and some are set to zero depending on which + // fields exist in a buffer's vertex format. + + // The type of compression applied to this vertex data + VertexCompressionType_t m_CompressionType; + + // Number of bone weights per vertex... + int m_NumBoneWeights; + + // Pointers to our current vertex data + float *m_pPosition; + + float *m_pBoneWeight; + +#ifndef NEW_SKINNING + unsigned char *m_pBoneMatrixIndex; +#else + float *m_pBoneMatrixIndex; +#endif + + float *m_pNormal; + + unsigned char *m_pColor; + unsigned char *m_pSpecular; + float *m_pTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + + // Tangent space *associated with one particular set of texcoords* + float *m_pTangentS; + float *m_pTangentT; + + float *m_pWrinkle; + + // user data + float *m_pUserData; + + // The first vertex index (used for buffered vertex buffers, or cards that don't support stream offset) + int m_nFirstVertex; + + // The offset in bytes of the memory we're writing into + // from the start of the D3D buffer (will be 0 for static meshes) + unsigned int m_nOffset; + +#ifdef DEBUG_WRITE_COMBINE + int m_nLastWrittenField; + unsigned char* m_pLastWrittenAddress; +#endif +}; + +struct IndexDesc_t +{ + // Pointers to the index data + unsigned short *m_pIndices; + + // The offset in bytes of the memory we're writing into + // from the start of the D3D buffer (will be 0 for static meshes) + unsigned int m_nOffset; + + // The first index (used for buffered index buffers, or cards that don't support stream offset) + unsigned int m_nFirstIndex; + + // 1 if the device is active, 0 if the device isn't active. + // Faster than doing if checks for null m_pIndices if someone is + // trying to write the m_pIndices while the device is inactive. + unsigned char m_nIndexSize; +}; + + +//----------------------------------------------------------------------------- +// The Mesh memory descriptor +//----------------------------------------------------------------------------- +struct MeshDesc_t : public VertexDesc_t, public IndexDesc_t +{ +}; + + +//----------------------------------------------------------------------------- +// Standard vertex formats for models +//----------------------------------------------------------------------------- +struct ModelVertexDX7_t +{ + Vector m_vecPosition; + Vector2D m_flBoneWeights; + unsigned int m_nBoneIndices; + Vector m_vecNormal; + unsigned int m_nColor; // ARGB + Vector2D m_vecTexCoord; +}; + +struct ModelVertexDX8_t : public ModelVertexDX7_t +{ + Vector4D m_vecUserData; +}; + + +//----------------------------------------------------------------------------- +// Utility methods for buffer builders +//----------------------------------------------------------------------------- +inline float *OffsetFloatPointer( float *pBufferPointer, int nVertexCount, int vertexSize ) +{ + return reinterpret_cast( + reinterpret_cast(pBufferPointer) + + nVertexCount * vertexSize); +} + +inline const float *OffsetFloatPointer( const float *pBufferPointer, int nVertexCount, int vertexSize ) +{ + return reinterpret_cast( + reinterpret_cast(pBufferPointer) + + nVertexCount * vertexSize); +} + +inline void IncrementFloatPointer( float* &pBufferPointer, int vertexSize ) +{ + pBufferPointer = reinterpret_cast( reinterpret_cast( pBufferPointer ) + vertexSize ); +} + + +//----------------------------------------------------------------------------- +// Used in lists of indexed primitives. +//----------------------------------------------------------------------------- +class CPrimList +{ +public: + CPrimList(); + CPrimList( int nFirstIndex, int nIndexCount ); + + int m_FirstIndex; + int m_NumIndices; +}; + +inline CPrimList::CPrimList() +{ +} + +inline CPrimList::CPrimList( int nFirstIndex, int nIndexCount ) +{ + m_FirstIndex = nFirstIndex; + m_NumIndices = nIndexCount; +} + +abstract_class IVertexBuffer +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IVertexBuffer() {} + + // NOTE: The following two methods are only valid for static vertex buffers + // Returns the number of vertices and the format of the vertex buffer + virtual int VertexCount() const = 0; + virtual VertexFormat_t GetVertexFormat() const = 0; + + // Is this vertex buffer dynamic? + virtual bool IsDynamic() const = 0; + + // NOTE: For dynamic vertex buffers only! + // Casts the memory of the dynamic vertex buffer to the appropriate type + virtual void BeginCastBuffer( VertexFormat_t format ) = 0; + virtual void EndCastBuffer() = 0; + + // Returns the number of vertices that can still be written into the buffer + virtual int GetRoomRemaining() const = 0; + + virtual bool Lock( int nVertexCount, bool bAppend, VertexDesc_t &desc ) = 0; + virtual void Unlock( int nVertexCount, VertexDesc_t &desc ) = 0; + + // Spews the mesh data + virtual void Spew( int nVertexCount, const VertexDesc_t &desc ) = 0; + + // Call this in debug mode to make sure our data is good. + virtual void ValidateData( int nVertexCount, const VertexDesc_t & desc ) = 0; +}; + +abstract_class IIndexBuffer +{ +public: + // Add a virtual destructor to silence the clang warning. + // This is harmless but not important since the only derived class + // doesn't have a destructor. + virtual ~IIndexBuffer() {} + + // NOTE: The following two methods are only valid for static index buffers + // Returns the number of indices and the format of the index buffer + virtual int IndexCount() const = 0; + virtual MaterialIndexFormat_t IndexFormat() const = 0; + + // Is this index buffer dynamic? + virtual bool IsDynamic() const = 0; + + // NOTE: For dynamic index buffers only! + // Casts the memory of the dynamic index buffer to the appropriate type + virtual void BeginCastBuffer( MaterialIndexFormat_t format ) = 0; + virtual void EndCastBuffer() = 0; + + // Returns the number of indices that can still be written into the buffer + virtual int GetRoomRemaining() const = 0; + + // Locks, unlocks the index buffer + virtual bool Lock( int nMaxIndexCount, bool bAppend, IndexDesc_t &desc ) = 0; + virtual void Unlock( int nWrittenIndexCount, IndexDesc_t &desc ) = 0; + + // FIXME: Remove this!! + // Locks, unlocks the index buffer for modify + virtual void ModifyBegin( bool bReadOnly, int nFirstIndex, int nIndexCount, IndexDesc_t& desc ) = 0; + virtual void ModifyEnd( IndexDesc_t& desc ) = 0; + + // Spews the mesh data + virtual void Spew( int nIndexCount, const IndexDesc_t &desc ) = 0; + + // Ensures the data in the index buffer is valid + virtual void ValidateData( int nIndexCount, const IndexDesc_t &desc ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Interface to the mesh - needs to contain an IVertexBuffer and an IIndexBuffer to emulate old mesh behavior +//----------------------------------------------------------------------------- +abstract_class IMesh : public IVertexBuffer, public IIndexBuffer +{ +public: + // ----------------------------------- + + // Sets/gets the primitive type + virtual void SetPrimitiveType( MaterialPrimitiveType_t type ) = 0; + + // Draws the mesh + virtual void Draw( int nFirstIndex = -1, int nIndexCount = 0 ) = 0; + + virtual void SetColorMesh( IMesh *pColorMesh, int nVertexOffset ) = 0; + + // Draw a list of (lists of) primitives. Batching your lists together that use + // the same lightmap, material, vertex and index buffers with multipass shaders + // can drastically reduce state-switching overhead. + // NOTE: this only works with STATIC meshes. + virtual void Draw( CPrimList *pLists, int nLists ) = 0; + + // Copy verts and/or indices to a mesh builder. This only works for temp meshes! + virtual void CopyToMeshBuilder( + int iStartVert, // Which vertices to copy. + int nVerts, + int iStartIndex, // Which indices to copy. + int nIndices, + int indexOffset, // This is added to each index. + CMeshBuilder &builder ) = 0; + + // Spews the mesh data + virtual void Spew( int nVertexCount, int nIndexCount, const MeshDesc_t &desc ) = 0; + + // Call this in debug mode to make sure our data is good. + virtual void ValidateData( int nVertexCount, int nIndexCount, const MeshDesc_t &desc ) = 0; + + // New version + // Locks/unlocks the mesh, providing space for nVertexCount and nIndexCount. + // nIndexCount of -1 means don't lock the index buffer... + virtual void LockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc ) = 0; + virtual void ModifyBegin( int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t& desc ) = 0; + virtual void ModifyEnd( MeshDesc_t& desc ) = 0; + virtual void UnlockMesh( int nVertexCount, int nIndexCount, MeshDesc_t &desc ) = 0; + + virtual void ModifyBeginEx( bool bReadOnly, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount, MeshDesc_t &desc ) = 0; + + virtual void SetFlexMesh( IMesh *pMesh, int nVertexOffset ) = 0; + + virtual void DisableFlexMesh() = 0; + + virtual void MarkAsDrawn() = 0; + + virtual unsigned ComputeMemoryUsed() = 0; +}; + + +#include "meshreader.h" + +#define INVALID_BUFFER_OFFSET 0xFFFFFFFFUL + +// flags for advancevertex optimization +#define VTX_HAVEPOS 1 +#define VTX_HAVENORMAL 2 +#define VTX_HAVECOLOR 4 +#define VTX_HAVEALL ( VTX_HAVEPOS | VTX_HAVENORMAL | VTX_HAVECOLOR ) + + +//----------------------------------------------------------------------------- +// +// Helper class used to define vertex buffers +// +//----------------------------------------------------------------------------- +class CVertexBuilder : private VertexDesc_t +{ +public: + CVertexBuilder(); + CVertexBuilder( IVertexBuffer *pVertexBuffer, VertexFormat_t fmt = 0 ); + ~CVertexBuilder(); + + // Begins, ends modification of the index buffer (returns true if the lock succeeded) + // A lock may not succeed if append is set to true and there isn't enough room + // NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers + bool Lock( int nMaxIndexCount, bool bAppend = false ); + void Unlock(); + + // Spews the current data + // NOTE: Can only be called during a lock/unlock block + void SpewData(); + + // Returns the number of indices we can fit into the buffer without needing to discard + int GetRoomRemaining() const; + + // Binds this vertex buffer + void Bind( IMatRenderContext *pContext, int nStreamID, VertexFormat_t usage = 0 ); + + // Returns the byte offset + int Offset() const; + + // This must be called before Begin, if a vertex buffer with a compressed format is to be used + void SetCompressionType( VertexCompressionType_t compressionType ); + void ValidateCompressionType(); + + void Begin( IVertexBuffer *pVertexBuffer, int nVertexCount, int *nFirstVertex ); + void Begin( IVertexBuffer *pVertexBuffer, int nVertexCount ); + + // Use this when you're done writing + // Set bDraw to true to call m_pMesh->Draw automatically. + void End( bool bSpewData = false ); + + // Locks the vertex buffer to modify existing data + // Passing nVertexCount == -1 says to lock all the vertices for modification. + void BeginModify( IVertexBuffer *pVertexBuffer, int nFirstVertex = 0, int nVertexCount = -1 ); + void EndModify( bool bSpewData = false ); + + // returns the number of vertices + int VertexCount() const; + + // Returns the total number of vertices across all Locks() + int TotalVertexCount() const; + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + // Returns the size of the vertex + int VertexSize() { return m_ActualVertexSize; } + + // returns the data size of a given texture coordinate + int TextureCoordinateSize( int nTexCoordNumber ) { return m_VertexSize_TexCoord[ nTexCoordNumber ]; } + + // Returns the base vertex memory pointer + void* BaseVertexData(); + + // Selects the nth Vertex and Index + void SelectVertex( int idx ); + + // Advances the current vertex and index by one + void AdvanceVertex( void ); + template void AdvanceVertexF( void ); + void AdvanceVertices( int nVerts ); + + int GetCurrentVertex() const; + int GetFirstVertex() const; + + // Data retrieval... + const float *Position() const; + + const float *Normal() const; + + unsigned int Color() const; + + unsigned char *Specular() const; + + const float *TexCoord( int stage ) const; + + const float *TangentS() const; + const float *TangentT() const; + + const float *BoneWeight() const; + float Wrinkle() const; + + int NumBoneWeights() const; +#ifndef NEW_SKINNING + unsigned char *BoneMatrix() const; +#else + float *BoneMatrix() const; +#endif + + // position setting + void Position3f( float x, float y, float z ); + void Position3fv( const float *v ); + + // normal setting + void Normal3f( float nx, float ny, float nz ); + void Normal3fv( const float *n ); + void NormalDelta3fv( const float *n ); + void NormalDelta3f( float nx, float ny, float nz ); + // normal setting (templatized for code which needs to support compressed vertices) + template void CompressedNormal3f( float nx, float ny, float nz ); + template void CompressedNormal3fv( const float *n ); + + // color setting + void Color3f( float r, float g, float b ); + void Color3fv( const float *rgb ); + void Color4f( float r, float g, float b, float a ); + void Color4fv( const float *rgba ); + + // Faster versions of color + void Color3ub( unsigned char r, unsigned char g, unsigned char b ); + void Color3ubv( unsigned char const* rgb ); + void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Color4ubv( unsigned char const* rgba ); + + // specular color setting + void Specular3f( float r, float g, float b ); + void Specular3fv( const float *rgb ); + void Specular4f( float r, float g, float b, float a ); + void Specular4fv( const float *rgba ); + + // Faster version of specular + void Specular3ub( unsigned char r, unsigned char g, unsigned char b ); + void Specular3ubv( unsigned char const *c ); + void Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Specular4ubv( unsigned char const *c ); + + // texture coordinate setting + void TexCoord1f( int stage, float s ); + void TexCoord2f( int stage, float s, float t ); + void TexCoord2fv( int stage, const float *st ); + void TexCoord3f( int stage, float s, float t, float u ); + void TexCoord3fv( int stage, const float *stu ); + void TexCoord4f( int stage, float s, float t, float u, float w ); + void TexCoord4fv( int stage, const float *stuv ); + + void TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ); + void TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale ); + + // tangent space + void TangentS3f( float sx, float sy, float sz ); + void TangentS3fv( const float* s ); + + void TangentT3f( float tx, float ty, float tz ); + void TangentT3fv( const float* t ); + + // Wrinkle + void Wrinkle1f( float flWrinkle ); + + // bone weights + void BoneWeight( int idx, float weight ); + // bone weights (templatized for code which needs to support compressed vertices) + template void CompressedBoneWeight3fv( const float * pWeights ); + + // bone matrix index + void BoneMatrix( int idx, int matrixIndex ); + + // Generic per-vertex data + void UserData( const float* pData ); + // Generic per-vertex data (templatized for code which needs to support compressed vertices) + template void CompressedUserData( const float* pData ); + + // Fast Vertex! No need to call advance vertex, and no random access allowed. + // WARNING - these are low level functions that are intended only for use + // in the software vertex skinner. + void FastVertex( const ModelVertexDX7_t &vertex ); + void FastVertexSSE( const ModelVertexDX7_t &vertex ); + + // store 4 dx7 vertices fast. for special sse dx7 pipeline + void Fast4VerticesSSE( + ModelVertexDX7_t const *vtx_a, + ModelVertexDX7_t const *vtx_b, + ModelVertexDX7_t const *vtx_c, + ModelVertexDX7_t const *vtx_d); + + void FastVertex( const ModelVertexDX8_t &vertex ); + void FastVertexSSE( const ModelVertexDX8_t &vertex ); + + // Add number of verts and current vert since FastVertex routines do not update. + void FastAdvanceNVertices( int n ); + +#if defined( _X360 ) + void VertexDX8ToX360( const ModelVertexDX8_t &vertex ); +#endif + + // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. + void AttachBegin( IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t &desc ); + void AttachEnd(); + void AttachBeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t &desc ); + void AttachEndModify(); + +private: + // The vertex buffer we're modifying + IVertexBuffer *m_pVertexBuffer; + + // Used to make sure Begin/End calls and BeginModify/EndModify calls match. + bool m_bModify; + + // Max number of indices and vertices + int m_nMaxVertexCount; + + // Number of indices and vertices + int m_nVertexCount; + + // The current vertex and index + mutable int m_nCurrentVertex; + + // Optimization: Pointer to the current pos, norm, texcoord, and color + mutable float *m_pCurrPosition; + mutable float *m_pCurrNormal; + mutable float *m_pCurrTexCoord[VERTEX_MAX_TEXTURE_COORDINATES]; + mutable unsigned char *m_pCurrColor; + + // Total number of vertices appended + int m_nTotalVertexCount; + + // First vertex buffer offset + index + unsigned int m_nBufferOffset; + unsigned int m_nBufferFirstVertex; + +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // Debug checks to make sure we write userdata4/tangents AFTER normals + bool m_bWrittenNormal : 1; + bool m_bWrittenUserData : 1; +#endif + + friend class CMeshBuilder; +}; + + +//----------------------------------------------------------------------------- +// +// Inline methods of CVertexBuilder +// +//----------------------------------------------------------------------------- +inline CVertexBuilder::CVertexBuilder() +{ + m_pVertexBuffer = NULL; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstVertex = 0; + m_nVertexCount = 0; + m_nCurrentVertex = 0; + m_nMaxVertexCount = 0; + m_nTotalVertexCount = 0; + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + m_bModify = false; +#endif +} + +inline CVertexBuilder::CVertexBuilder( IVertexBuffer *pVertexBuffer, VertexFormat_t fmt ) +{ + m_pVertexBuffer = pVertexBuffer; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstVertex = 0; + m_nVertexCount = 0; + m_nCurrentVertex = 0; + m_nMaxVertexCount = 0; + m_nTotalVertexCount = 0; + m_CompressionType = VERTEX_COMPRESSION_INVALID; + + if ( m_pVertexBuffer->IsDynamic() ) + { + m_pVertexBuffer->BeginCastBuffer( fmt ); + } + else + { + Assert( m_pVertexBuffer->GetVertexFormat() == fmt ); + } + +#ifdef _DEBUG + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + m_bModify = false; +#endif +} + +inline CVertexBuilder::~CVertexBuilder() +{ + if ( m_pVertexBuffer && m_pVertexBuffer->IsDynamic() ) + { + m_pVertexBuffer->EndCastBuffer(); + } +} + +//----------------------------------------------------------------------------- +// Begins, ends modification of the index buffer +//----------------------------------------------------------------------------- +inline bool CVertexBuilder::Lock( int nMaxVertexCount, bool bAppend ) +{ + Assert( m_pVertexBuffer ); + m_bModify = false; + m_nMaxVertexCount = nMaxVertexCount; + bool bFirstLock = ( m_nBufferOffset == INVALID_BUFFER_OFFSET ); + if ( bFirstLock ) + { + bAppend = false; + } + if ( !bAppend ) + { + m_nTotalVertexCount = 0; + } + + // Lock the vertex buffer + if ( !m_pVertexBuffer->Lock( m_nMaxVertexCount, bAppend, *this ) ) + { + m_nMaxVertexCount = 0; + return false; + } + + Reset(); + + if ( bFirstLock ) + { + m_nBufferOffset = m_nOffset; + m_nBufferFirstVertex = m_nFirstVertex; + } + + return true; +} + +inline void CVertexBuilder::Unlock() +{ + Assert( !m_bModify && m_pVertexBuffer ); + +#ifdef _DEBUG + m_pVertexBuffer->ValidateData( m_nVertexCount, *this ); +#endif + + m_pVertexBuffer->Unlock( m_nVertexCount, *this ); + m_nTotalVertexCount += m_nVertexCount; + + m_nMaxVertexCount = 0; + +#ifdef _DEBUG + // Null out our data... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + +inline void CVertexBuilder::SpewData() +{ + m_pVertexBuffer->Spew( m_nVertexCount, *this ); +} + + +//----------------------------------------------------------------------------- +// Binds this vertex buffer +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Bind( IMatRenderContext *pContext, int nStreamID, VertexFormat_t usage ) +{ + if ( m_pVertexBuffer && ( m_nBufferOffset != INVALID_BUFFER_OFFSET ) ) + { + pContext->BindVertexBuffer( nStreamID, m_pVertexBuffer, m_nBufferOffset, + m_nFirstVertex, m_nTotalVertexCount, usage ? usage : m_pVertexBuffer->GetVertexFormat() ); + } + else + { + pContext->BindVertexBuffer( nStreamID, NULL, 0, 0, 0, 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Returns the byte offset +//----------------------------------------------------------------------------- +inline int CVertexBuilder::Offset() const +{ + return m_nBufferOffset; +} + +inline int CVertexBuilder::GetFirstVertex() const +{ + return m_nBufferFirstVertex; +} + +//----------------------------------------------------------------------------- +// Specify the type of vertex compression that this CMeshBuilder will perform +//----------------------------------------------------------------------------- +inline void CVertexBuilder::SetCompressionType( VertexCompressionType_t compressionType ) +{ + // The real purpose of this method is to allow us to emit a Warning in Begin() + m_CompressionType = compressionType; +} + +inline void CVertexBuilder::ValidateCompressionType() +{ +#ifdef _DEBUG + VertexCompressionType_t vbCompressionType = CompressionType( m_pVertexBuffer->GetVertexFormat() ); + if ( vbCompressionType != VERTEX_COMPRESSION_NONE ) + { + Assert( m_CompressionType == vbCompressionType ); + if ( m_CompressionType != vbCompressionType ) + { + Warning( "ERROR: CVertexBuilder::SetCompressionType() must be called to specify the same vertex compression type (%s) as the vertex buffer being modified." + "Junk vertices will be rendered, or there will be a crash in CVertexBuilder!\n", + vbCompressionType == VERTEX_COMPRESSION_ON ? "VERTEX_COMPRESSION_ON" : "VERTEX_COMPRESSION_NONE" ); + } + // Never use vertex compression for dynamic VBs (the conversions can really hurt perf) + Assert( !m_pVertexBuffer->IsDynamic() ); + } +#endif +} + +inline void CVertexBuilder::Begin( IVertexBuffer *pVertexBuffer, int nVertexCount ) +{ + Assert( pVertexBuffer && (!m_pVertexBuffer) ); + + m_pVertexBuffer = pVertexBuffer; + m_bModify = false; + + m_nMaxVertexCount = nVertexCount; + m_nVertexCount = 0; + + // Make sure SetCompressionType was called correctly, if this VB is compressed + ValidateCompressionType(); + + // Lock the vertex and index buffer + m_pVertexBuffer->Lock( m_nMaxVertexCount, false, *this ); + + // Point to the start of the buffers.. + Reset(); +} + + +//----------------------------------------------------------------------------- +// Use this when you're done modifying the mesh +//----------------------------------------------------------------------------- +inline void CVertexBuilder::End( bool bSpewData ) +{ + // Make sure they called Begin() + Assert( !m_bModify ); + + if ( bSpewData ) + { + m_pVertexBuffer->Spew( m_nVertexCount, *this ); + } + +#ifdef _DEBUG + m_pVertexBuffer->ValidateData( m_nVertexCount, *this ); +#endif + + // Unlock our buffers + m_pVertexBuffer->Unlock( m_nVertexCount, *this ); + + m_pVertexBuffer = 0; + m_nMaxVertexCount = 0; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + // Null out our pointers... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast< VertexDesc_t* >( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. +//----------------------------------------------------------------------------- +inline void CVertexBuilder::AttachBegin( IMesh* pMesh, int nMaxVertexCount, const MeshDesc_t &desc ) +{ + VertexCompressionType_t compressionType = m_CompressionType; + + m_pVertexBuffer = pMesh; + memcpy( static_cast( this ), static_cast( &desc ), sizeof(VertexDesc_t) ); + m_nMaxVertexCount = nMaxVertexCount; + m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; // Two weights if any + m_nVertexCount = 0; + m_bModify = false; + + if ( compressionType != VERTEX_COMPRESSION_INVALID ) + m_CompressionType = compressionType; + + // Make sure SetCompressionType was called correctly, if this VB is compressed + ValidateCompressionType(); + + if ( m_nBufferOffset == INVALID_BUFFER_OFFSET ) + { + m_nTotalVertexCount = 0; + m_nBufferOffset = static_cast< const VertexDesc_t* >( &desc )->m_nOffset; + m_nBufferFirstVertex = desc.m_nFirstVertex; + } +} + +inline void CVertexBuilder::AttachEnd() +{ + // Make sure they called Begin() + Assert( !m_bModify ); + + m_nMaxVertexCount = 0; + m_pVertexBuffer = NULL; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + // Null out our pointers... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + +inline void CVertexBuilder::AttachBeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, const MeshDesc_t &desc ) +{ + Assert( pMesh && (!m_pVertexBuffer) ); + + m_pVertexBuffer = pMesh; + memcpy( static_cast( this ), static_cast( &desc ), sizeof(VertexDesc_t) ); + m_nMaxVertexCount = m_nVertexCount = nVertexCount; + m_NumBoneWeights = m_NumBoneWeights == 0 ? 0 : 2; // Two weights if any + m_bModify = true; + + // Make sure SetCompressionType was called correctly, if this VB is compressed + ValidateCompressionType(); +} + +inline void CVertexBuilder::AttachEndModify() +{ + Assert( m_pVertexBuffer ); + Assert( m_bModify ); // Make sure they called BeginModify. + + m_pVertexBuffer = 0; + m_nMaxVertexCount = 0; + + m_CompressionType = VERTEX_COMPRESSION_INVALID; + +#ifdef _DEBUG + // Null out our pointers... + m_pCurrPosition = NULL; + m_pCurrNormal = NULL; + m_pCurrColor = NULL; + memset( m_pCurrTexCoord, 0, sizeof( m_pCurrTexCoord ) ); + memset( static_cast( this ), 0, sizeof(VertexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Computes the first min non-null address +//----------------------------------------------------------------------------- +inline unsigned char* FindMinAddress( void *pAddress1, void *pAddress2, int nAddress2Size ) +{ + if ( nAddress2Size == 0 ) + return (unsigned char*)pAddress1; + if ( !pAddress1 ) + return (unsigned char*)pAddress2; + return ( pAddress1 < pAddress2 ) ? (unsigned char*)pAddress1 : (unsigned char*)pAddress2; +} + +//----------------------------------------------------------------------------- +// Resets the vertex buffer builder so it points to the start of everything again +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Reset() +{ + m_nCurrentVertex = 0; + + m_pCurrPosition = m_pPosition; + m_pCurrNormal = m_pNormal; + for ( int i = 0; i < NELEMS( m_pCurrTexCoord ); i++ ) + { + m_pCurrTexCoord[i] = m_pTexCoord[i]; + } + m_pCurrColor = m_pColor; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif + +#ifdef DEBUG_WRITE_COMBINE + // Logic for m_pLastWrittenAddress is tricky. It really wants the min of the + // non-null address pointers. + m_nLastWrittenField = MB_FIELD_NONE; + m_pLastWrittenAddress = NULL; + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pPosition, m_VertexSize_Position ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pBoneWeight, m_VertexSize_BoneWeight ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pBoneMatrixIndex, m_VertexSize_BoneMatrixIndex ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pNormal, m_VertexSize_Normal ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pColor, m_VertexSize_Color ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pSpecular, m_VertexSize_Specular ); + for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i ) + { + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTexCoord[i], m_VertexSize_TexCoord[i] ); + } + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTangentS, m_VertexSize_TangentS ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pTangentT, m_VertexSize_TangentT ); + m_pLastWrittenAddress = FindMinAddress( m_pLastWrittenAddress, m_pUserData, m_VertexSize_UserData ); +#endif +} + + +//----------------------------------------------------------------------------- +// returns the number of vertices +//----------------------------------------------------------------------------- +inline int CVertexBuilder::VertexCount() const +{ + return m_nVertexCount; +} + + +//----------------------------------------------------------------------------- +// Returns the total number of vertices across all Locks() +//----------------------------------------------------------------------------- +inline int CVertexBuilder::TotalVertexCount() const +{ + return m_nTotalVertexCount; +} + + +//----------------------------------------------------------------------------- +// Returns the base vertex memory pointer +//----------------------------------------------------------------------------- +inline void* CVertexBuilder::BaseVertexData() +{ + // FIXME: If there's no position specified, we need to find + // the base address + Assert( m_pPosition ); + return m_pPosition; +} + + +//----------------------------------------------------------------------------- +// Selects the current vertex +//----------------------------------------------------------------------------- +inline void CVertexBuilder::SelectVertex( int nIndex ) +{ + // NOTE: This index is expected to be relative + Assert( (nIndex >= 0) && (nIndex < m_nMaxVertexCount) ); + m_nCurrentVertex = nIndex; + + m_pCurrPosition = OffsetFloatPointer( m_pPosition, m_nCurrentVertex, m_VertexSize_Position ); + m_pCurrNormal = OffsetFloatPointer( m_pNormal, m_nCurrentVertex, m_VertexSize_Normal ); + + COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 ); + m_pCurrTexCoord[0] = OffsetFloatPointer( m_pTexCoord[0], m_nCurrentVertex, m_VertexSize_TexCoord[0] ); + m_pCurrTexCoord[1] = OffsetFloatPointer( m_pTexCoord[1], m_nCurrentVertex, m_VertexSize_TexCoord[1] ); + m_pCurrTexCoord[2] = OffsetFloatPointer( m_pTexCoord[2], m_nCurrentVertex, m_VertexSize_TexCoord[2] ); + m_pCurrTexCoord[3] = OffsetFloatPointer( m_pTexCoord[3], m_nCurrentVertex, m_VertexSize_TexCoord[3] ); + m_pCurrTexCoord[4] = OffsetFloatPointer( m_pTexCoord[4], m_nCurrentVertex, m_VertexSize_TexCoord[4] ); + m_pCurrTexCoord[5] = OffsetFloatPointer( m_pTexCoord[5], m_nCurrentVertex, m_VertexSize_TexCoord[5] ); + m_pCurrTexCoord[6] = OffsetFloatPointer( m_pTexCoord[6], m_nCurrentVertex, m_VertexSize_TexCoord[6] ); + m_pCurrTexCoord[7] = OffsetFloatPointer( m_pTexCoord[7], m_nCurrentVertex, m_VertexSize_TexCoord[7] ); + m_pCurrColor = m_pColor + m_nCurrentVertex * m_VertexSize_Color; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +//----------------------------------------------------------------------------- +// Advances vertex after you're done writing to it. +//----------------------------------------------------------------------------- + +template FORCEINLINE void CVertexBuilder::AdvanceVertexF() +{ + if ( ++m_nCurrentVertex > m_nVertexCount ) + { + m_nVertexCount = m_nCurrentVertex; + } + + if ( nFlags & VTX_HAVEPOS ) + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + if ( nFlags & VTX_HAVENORMAL ) + IncrementFloatPointer( m_pCurrNormal, m_VertexSize_Normal ); + if ( nFlags & VTX_HAVECOLOR ) + m_pCurrColor += m_VertexSize_Color; + + COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 ); + if ( nNumTexCoords > 0 ) + IncrementFloatPointer( m_pCurrTexCoord[0], m_VertexSize_TexCoord[0] ); + if ( nNumTexCoords > 1 ) + IncrementFloatPointer( m_pCurrTexCoord[1], m_VertexSize_TexCoord[1] ); + if ( nNumTexCoords > 2 ) + IncrementFloatPointer( m_pCurrTexCoord[2], m_VertexSize_TexCoord[2] ); + if ( nNumTexCoords > 3 ) + IncrementFloatPointer( m_pCurrTexCoord[3], m_VertexSize_TexCoord[3] ); + if ( nNumTexCoords > 4 ) + IncrementFloatPointer( m_pCurrTexCoord[4], m_VertexSize_TexCoord[4] ); + if ( nNumTexCoords > 5 ) + IncrementFloatPointer( m_pCurrTexCoord[5], m_VertexSize_TexCoord[5] ); + if ( nNumTexCoords > 6 ) + IncrementFloatPointer( m_pCurrTexCoord[6], m_VertexSize_TexCoord[6] ); + if ( nNumTexCoords > 7 ) + IncrementFloatPointer( m_pCurrTexCoord[7], m_VertexSize_TexCoord[7] ); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::AdvanceVertex() +{ + AdvanceVertexF(); +} + + +inline void CVertexBuilder::AdvanceVertices( int nVerts ) +{ + m_nCurrentVertex += nVerts; + if ( m_nCurrentVertex > m_nVertexCount ) + { + m_nVertexCount = m_nCurrentVertex; + } + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position*nVerts ); + IncrementFloatPointer( m_pCurrNormal, m_VertexSize_Normal*nVerts ); + + COMPILE_TIME_ASSERT( VERTEX_MAX_TEXTURE_COORDINATES == 8 ); + IncrementFloatPointer( m_pCurrTexCoord[0], m_VertexSize_TexCoord[0]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[1], m_VertexSize_TexCoord[1]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[2], m_VertexSize_TexCoord[2]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[3], m_VertexSize_TexCoord[3]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[4], m_VertexSize_TexCoord[4]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[5], m_VertexSize_TexCoord[5]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[6], m_VertexSize_TexCoord[6]*nVerts ); + IncrementFloatPointer( m_pCurrTexCoord[7], m_VertexSize_TexCoord[7]*nVerts ); + m_pCurrColor += m_VertexSize_Color*nVerts; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + + +//----------------------------------------------------------------------------- +// For use with the FastVertex methods, advances the current vertex by N +//----------------------------------------------------------------------------- +inline void CVertexBuilder::FastAdvanceNVertices( int n ) +{ + m_nCurrentVertex += n; + m_nVertexCount = m_nCurrentVertex; +} + + + +#ifndef COMPILER_MSVC64 +// Implement for 64-bit Windows if needed. +//----------------------------------------------------------------------------- +// Fast Vertex! No need to call advance vertex, and no random access allowed +//----------------------------------------------------------------------------- +inline void CVertexBuilder::FastVertex( const ModelVertexDX7_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movq mm0, [esi + 0] + movq mm1, [esi + 8] + movq mm2, [esi + 16] + movq mm3, [esi + 24] + movq mm4, [esi + 32] + movq mm5, [esi + 40] + + movntq [edi + 0], mm0 + movntq [edi + 8], mm1 + movntq [edi + 16], mm2 + movntq [edi + 24], mm3 + movntq [edi + 32], mm4 + movntq [edi + 40], mm5 + + emms + } +#elif defined(GNUC) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm__ __volatile__ ( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "emms\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error( "Implement CMeshBuilder::FastVertex(dx7) "); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + //m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX7_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + + movntps [edi + 0], xmm0 + movntps [edi + 16], xmm1 + movntps [edi + 32], xmm2 + } +#elif defined(GNUC) + const char *pRead = (char *)&vertex; + char *pCurrPos = (char *)m_pCurrPosition; + __m128 m1 = _mm_load_ps( (float *)pRead ); + __m128 m2 = _mm_load_ps( (float *)(pRead + 16) ); + __m128 m3 = _mm_load_ps( (float *)(pRead + 32) ); + _mm_stream_ps( (float *)pCurrPos, m1 ); + _mm_stream_ps( (float *)(pCurrPos + 16), m2 ); + _mm_stream_ps( (float *)(pCurrPos + 32), m3 ); +#else + Error( "Implement CMeshBuilder::FastVertexSSE(dx7)" ); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + //m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::Fast4VerticesSSE( + ModelVertexDX7_t const *vtx_a, + ModelVertexDX7_t const *vtx_b, + ModelVertexDX7_t const *vtx_c, + ModelVertexDX7_t const *vtx_d) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount-3 ); + +#if defined( _WIN32 ) && !defined( _X360 ) + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, vtx_a + mov ecx, vtx_b + + mov edi, pCurrPos + nop + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + movaps xmm3, [ecx + 0] + movaps xmm4, [ecx + 16] + movaps xmm5, [ecx + 32] + + mov esi, vtx_c + mov ecx, vtx_d + + movntps [edi + 0], xmm0 + movntps [edi + 16], xmm1 + movntps [edi + 32], xmm2 + movntps [edi + 48], xmm3 + movntps [edi + 64], xmm4 + movntps [edi + 80], xmm5 + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + movaps xmm3, [ecx + 0] + movaps xmm4, [ecx + 16] + movaps xmm5, [ecx + 32] + + movntps [edi + 0+96], xmm0 + movntps [edi + 16+96], xmm1 + movntps [edi + 32+96], xmm2 + movntps [edi + 48+96], xmm3 + movntps [edi + 64+96], xmm4 + movntps [edi + 80+96], xmm5 + + } +#else + Error( "Implement CMeshBuilder::Fast4VerticesSSE\n"); +#endif + IncrementFloatPointer( m_pCurrPosition, 4*m_VertexSize_Position ); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertex( const ModelVertexDX8_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movq mm0, [esi + 0] + movq mm1, [esi + 8] + movq mm2, [esi + 16] + movq mm3, [esi + 24] + movq mm4, [esi + 32] + movq mm5, [esi + 40] + movq mm6, [esi + 48] + movq mm7, [esi + 56] + + movntq [edi + 0], mm0 + movntq [edi + 8], mm1 + movntq [edi + 16], mm2 + movntq [edi + 24], mm3 + movntq [edi + 32], mm4 + movntq [edi + 40], mm5 + movntq [edi + 48], mm6 + movntq [edi + 56], mm7 + + emms + } +#elif defined(GNUC) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm__ __volatile__ ( + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "movq 16(%0), %%mm2\n" + "movq 24(%0), %%mm3\n" + "movq 32(%0), %%mm4\n" + "movq 40(%0), %%mm5\n" + "movq 48(%0), %%mm6\n" + "movq 56(%0), %%mm7\n" + "movntq %%mm0, (%1)\n" + "movntq %%mm1, 8(%1)\n" + "movntq %%mm2, 16(%1)\n" + "movntq %%mm3, 24(%1)\n" + "movntq %%mm4, 32(%1)\n" + "movntq %%mm5, 40(%1)\n" + "movntq %%mm6, 48(%1)\n" + "movntq %%mm7, 56(%1)\n" + "emms\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error( "Implement CMeshBuilder::FastVertex(dx8)" ); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + // m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} + +inline void CVertexBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + +#if defined( _WIN32 ) && !defined( _X360 ) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm + { + mov esi, pRead + mov edi, pCurrPos + + movaps xmm0, [esi + 0] + movaps xmm1, [esi + 16] + movaps xmm2, [esi + 32] + movaps xmm3, [esi + 48] + + movntps [edi + 0], xmm0 + movntps [edi + 16], xmm1 + movntps [edi + 32], xmm2 + movntps [edi + 48], xmm3 + } +#elif defined(GNUC) + const void *pRead = &vertex; + void *pCurrPos = m_pCurrPosition; + __asm__ __volatile__ ( + "movaps (%0), %%xmm0\n" + "movaps 16(%0), %%xmm1\n" + "movaps 32(%0), %%xmm2\n" + "movaps 48(%0), %%xmm3\n" + "movntps %%xmm0, (%1)\n" + "movntps %%xmm1, 16(%1)\n" + "movntps %%xmm2, 32(%1)\n" + "movntps %%xmm3, 48(%1)\n" + :: "r" (pRead), "r" (pCurrPos) : "memory"); +#else + Error( "Implement CMeshBuilder::FastVertexSSE((dx8)" ); +#endif + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + // m_nVertexCount = ++m_nCurrentVertex; + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} +#endif // COMPILER_MSVC64 + + +//----------------------------------------------------------------------------- +// Returns the current vertex +//----------------------------------------------------------------------------- +inline int CVertexBuilder::GetCurrentVertex() const +{ + return m_nCurrentVertex; +} + + +//----------------------------------------------------------------------------- +// Copies a vertex into the x360 format +//----------------------------------------------------------------------------- +#if defined( _X360 ) +inline void CVertexBuilder::VertexDX8ToX360( const ModelVertexDX8_t &vertex ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // FIXME: support compressed verts if needed + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + + // get the start of the data + unsigned char *pDst = (unsigned char*)m_pCurrPosition; + + Assert( m_VertexSize_Position > 0 ); // Assume position is always present + Assert( GetVertexElementSize( VERTEX_ELEMENT_POSITION, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecPosition ) ); + memcpy( pDst, vertex.m_vecPosition.Base(), sizeof( vertex.m_vecPosition ) ); + pDst += sizeof( vertex.m_vecPosition ); + + if ( m_VertexSize_BoneWeight ) + { + Assert( vertex.m_flBoneWeights[0] >= 0 && vertex.m_flBoneWeights[0] <= 1.0f ); + Assert( vertex.m_flBoneWeights[1] >= 0 && vertex.m_flBoneWeights[1] <= 1.0f ); + Assert( GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_flBoneWeights ) ); + memcpy( pDst, vertex.m_flBoneWeights.Base(), sizeof( vertex.m_flBoneWeights ) ); + pDst += sizeof( vertex.m_flBoneWeights ); + + if ( m_VertexSize_BoneMatrixIndex ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_nBoneIndices ) ); + *(unsigned int*)pDst = vertex.m_nBoneIndices; + pDst += sizeof( vertex.m_nBoneIndices ); + } + } + + if ( m_VertexSize_Normal ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecNormal ) ); + memcpy( pDst, vertex.m_vecNormal.Base(), sizeof( vertex.m_vecNormal ) ); + pDst += sizeof( vertex.m_vecNormal ); + } + + if ( m_VertexSize_Color ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_COLOR, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_nColor ) ); + *(unsigned int*)pDst = vertex.m_nColor; + pDst += sizeof( vertex.m_nColor ); + } + + if ( m_VertexSize_TexCoord[0] ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_TEXCOORD2D_0, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecTexCoord ) ); + memcpy( pDst, vertex.m_vecTexCoord.Base(), sizeof( vertex.m_vecTexCoord ) ); + pDst += sizeof( vertex.m_vecTexCoord ); + } + + if ( m_VertexSize_UserData ) + { + Assert( GetVertexElementSize( VERTEX_ELEMENT_USERDATA4, VERTEX_COMPRESSION_NONE ) == sizeof( vertex.m_vecUserData ) ); + memcpy( pDst, vertex.m_vecUserData.Base(), sizeof( vertex.m_vecUserData ) ); + pDst += sizeof( vertex.m_vecUserData ); + } + + // ensure code is synced with the mesh builder that established the offsets + Assert( pDst - (unsigned char*)m_pCurrPosition == m_VertexSize_Position ); + + IncrementFloatPointer( m_pCurrPosition, m_VertexSize_Position ); + +#if ( defined( _DEBUG ) && ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + m_bWrittenNormal = false; + m_bWrittenUserData = false; +#endif +} +#endif + + +//----------------------------------------------------------------------------- +// Data retrieval... +//----------------------------------------------------------------------------- +inline const float* CVertexBuilder::Position() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pCurrPosition; +} + +inline const float* CVertexBuilder::Normal() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pCurrNormal; +} + +inline unsigned int CVertexBuilder::Color() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + // Swizzle it so it returns the same format as accepted by Color4ubv - rgba + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + unsigned int color; + if ( IsPC() || !IsX360() ) + { + color = (m_pCurrColor[3] << 24) | (m_pCurrColor[0] << 16) | (m_pCurrColor[1] << 8) | (m_pCurrColor[2]); + } + else + { + // in memory as argb, back to rgba + color = (m_pCurrColor[1] << 24) | (m_pCurrColor[2] << 16) | (m_pCurrColor[3] << 8) | (m_pCurrColor[0]); + } + return color; +} + +inline unsigned char *CVertexBuilder::Specular() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pSpecular + m_nCurrentVertex * m_VertexSize_Specular; +} + +inline const float* CVertexBuilder::TexCoord( int stage ) const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pCurrTexCoord[stage]; +} + +inline const float* CVertexBuilder::TangentS() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS ); +} + +inline const float* CVertexBuilder::TangentT() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT ); +} + +inline float CVertexBuilder::Wrinkle() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return *OffsetFloatPointer( m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle ); +} + +inline const float* CVertexBuilder::BoneWeight() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight ); +} + +inline int CVertexBuilder::NumBoneWeights() const +{ + return m_NumBoneWeights; +} + +#ifndef NEW_SKINNING +inline unsigned char* CVertexBuilder::BoneMatrix() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; +} +#else +inline float* CVertexBuilder::BoneMatrix() const +{ + // FIXME: add a templatized accessor (return type varies to ensure calling code is updated appropriately) + // for code that needs to access compressed data (and/or a return-by-value templatized accessor) + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); + Assert( m_nCurrentVertex < m_nMaxVertexCount ); + return m_pBoneMatrixIndex + m_nCurrentVertex * m_VertexSize_BoneMatrixIndex; +} +#endif + + +//----------------------------------------------------------------------------- +// Position setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Position3f( float x, float y, float z ) +{ + Assert( m_pPosition && m_pCurrPosition ); + Assert( IsFinite(x) && IsFinite(y) && IsFinite(z) ); + float *pDst = m_pCurrPosition; + *pDst++ = x; + *pDst++ = y; + *pDst = z; +} + +inline void CVertexBuilder::Position3fv( const float *v ) +{ + Assert(v); + Assert( m_pPosition && m_pCurrPosition ); + + float *pDst = m_pCurrPosition; + *pDst++ = *v++; + *pDst++ = *v++; + *pDst = *v; +} + + +//----------------------------------------------------------------------------- +// Normal setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Normal3f( float nx, float ny, float nz ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( m_pNormal ); + Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) ); + Assert( nx >= -1.05f && nx <= 1.05f ); + Assert( ny >= -1.05f && ny <= 1.05f ); + Assert( nz >= -1.05f && nz <= 1.05f ); + + float *pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; +} + +inline void CVertexBuilder::Normal3fv( const float *n ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( n ); + Assert( m_pNormal && m_pCurrNormal ); + Assert( IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2]) ); + Assert( n[0] >= -1.05f && n[0] <= 1.05f ); + Assert( n[1] >= -1.05f && n[1] <= 1.05f ); + Assert( n[2] >= -1.05f && n[2] <= 1.05f ); + + float *pDst = m_pCurrNormal; + *pDst++ = *n++; + *pDst++ = *n++; + *pDst = *n; +} + +inline void CVertexBuilder::NormalDelta3f( float nx, float ny, float nz ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( m_pNormal ); + Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) ); + + float *pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; +} + +inline void CVertexBuilder::NormalDelta3fv( const float *n ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( n ); + Assert( m_pNormal && m_pCurrNormal ); + Assert( IsFinite(n[0]) && IsFinite(n[1]) && IsFinite(n[2]) ); + + float *pDst = m_pCurrNormal; + *pDst++ = *n++; + *pDst++ = *n++; + *pDst = *n; +} + +//----------------------------------------------------------------------------- +// Templatized normal setting methods which support compressed vertices +//----------------------------------------------------------------------------- +template inline void CVertexBuilder::CompressedNormal3f( float nx, float ny, float nz ) +{ + Assert( T == m_CompressionType ); + Assert( m_pNormal && m_pCurrNormal ); + Assert( IsFinite(nx) && IsFinite(ny) && IsFinite(nz) ); + Assert( nx >= -1.05f && nx <= 1.05f ); + Assert( ny >= -1.05f && ny <= 1.05f ); + Assert( nz >= -1.05f && nz <= 1.05f ); + // FIXME: studiorender is passing in non-unit normals + //float lengthSqd = nx*nx + ny*ny + nz*nz; + //Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f ); + + if ( T == VERTEX_COMPRESSION_ON ) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + PackNormal_SHORT2( nx, ny, nz, (unsigned int *)m_pCurrNormal ); + +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // NOTE: write the normal into the lower 16 bits of a word, clearing the top 16 bits - a userdata4 + // tangent must be written into the upper 16 bits by CompressedUserData() *AFTER* this. +#ifdef _DEBUG + Assert( m_bWrittenUserData == false ); + m_bWrittenNormal = true; +#endif + PackNormal_UBYTE4( nx, ny, nz, (unsigned int *)m_pCurrNormal ); +#endif + } + else + { + float *pDst = m_pCurrNormal; + *pDst++ = nx; + *pDst++ = ny; + *pDst = nz; + } +} + +template inline void CVertexBuilder::CompressedNormal3fv( const float *n ) +{ + Assert( n ); + CompressedNormal3f( n[0], n[1], n[2] ); +} + + +//----------------------------------------------------------------------------- +// Color setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Color3f( float r, float g, float b ) +{ + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | 0xFF000000; +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; +#endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color3fv( const float *rgb ) +{ + Assert(rgb); + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) ); + Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) ); + Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | 0xFF000000; +#else + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; +#endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4f( float r, float g, float b, float a ) +{ + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | (FastFToC(a) << 24); +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); +#endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4fv( const float *rgba ) +{ + Assert(rgba); + Assert( m_pColor && m_pCurrColor ); + Assert( IsFinite(rgba[0]) && IsFinite(rgba[1]) && IsFinite(rgba[2]) && IsFinite(rgba[3]) ); + Assert( (rgba[0] >= 0.0) && (rgba[1] >= 0.0) && (rgba[2] >= 0.0) && (rgba[3] >= 0.0) ); + Assert( (rgba[0] <= 1.0) && (rgba[1] <= 1.0) && (rgba[2] <= 1.0) && (rgba[3] <= 1.0) ); + +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgba[0])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[2]) << 16) | (FastFToC(rgba[3]) << 24); +#else + int col = (FastFToC(rgba[2])) | (FastFToC(rgba[1]) << 8) | (FastFToC(rgba[0]) << 16) | (FastFToC(rgba[3]) << 24); +#endif + *(int*)m_pCurrColor = col; +} + + +//----------------------------------------------------------------------------- +// Faster versions of color +//----------------------------------------------------------------------------- + +// note that on the OSX target (OpenGL) whenever there is vertex data being written as bytes - they need to be written in R,G,B,A memory order + +inline void CVertexBuilder::Color3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | 0xFF000000; + #endif + + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color3ubv( unsigned char const* rgb ) +{ + Assert(rgb); + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = rgb[0] | (rgb[1] << 8) | (rgb[2] << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16) | 0xFF000000; + #endif + + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | (a << 24); + #endif + + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Color4ubv( unsigned char const* rgba ) +{ + Assert( rgba ); + Assert( m_pColor && m_pCurrColor ); + #ifdef OPENGL_SWAP_COLORS + int col = rgba[0] | (rgba[1] << 8) | (rgba[2] << 16) | (rgba[3] << 24); // r, g, b, a in memory + #else + int col = rgba[2] | (rgba[1] << 8) | (rgba[0] << 16) | (rgba[3] << 24); + #endif + *(int*)m_pCurrColor = col; +} + +inline void CVertexBuilder::Specular3f( float r, float g, float b ) +{ + Assert( m_pSpecular ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | 0xFF000000; +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | 0xFF000000; +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3fv( const float *rgb ) +{ + Assert(rgb); + Assert( m_pSpecular ); + Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) ); + Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) ); + Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | 0xFF000000; +#else + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | 0xFF000000; +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4f( float r, float g, float b, float a ) +{ + Assert( m_pSpecular ); + Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) && IsFinite(a) ); + Assert( (r >= 0.0) && (g >= 0.0) && (b >= 0.0) && (a >= 0.0) ); + Assert( (r <= 1.0) && (g <= 1.0) && (b <= 1.0) && (a <= 1.0f) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(r)) | (FastFToC(g) << 8) | (FastFToC(b) << 16) | (FastFToC(a) << 24); +#else + int col = (FastFToC(b)) | (FastFToC(g) << 8) | (FastFToC(r) << 16) | (FastFToC(a) << 24); +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4fv( const float *rgb ) +{ + Assert(rgb); + Assert( m_pSpecular ); + Assert( IsFinite(rgb[0]) && IsFinite(rgb[1]) && IsFinite(rgb[2]) && IsFinite(rgb[3]) ); + Assert( (rgb[0] >= 0.0) && (rgb[1] >= 0.0) && (rgb[2] >= 0.0) && (rgb[3] >= 0.0) ); + Assert( (rgb[0] <= 1.0) && (rgb[1] <= 1.0) && (rgb[2] <= 1.0) && (rgb[3] <= 1.0) ); + + unsigned char* pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; +#ifdef OPENGL_SWAP_COLORS + int col = (FastFToC(rgb[0])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[2]) << 16) | (FastFToC(rgb[3]) << 24); +#else + int col = (FastFToC(rgb[2])) | (FastFToC(rgb[1]) << 8) | (FastFToC(rgb[0]) << 16) | (FastFToC(rgb[3]) << 24); +#endif + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | 0xFF000000; + #endif + + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular3ubv( unsigned char const *c ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = c[0] | (c[1] << 8) | (c[2] << 16) | 0xFF000000; // r, g, b, a in memory + #else + int col = c[2] | (c[1] << 8) | (c[0] << 16) | 0xFF000000; + #endif + + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = r | (g << 8) | (b << 16) | (a << 24); // r, g, b, a in memory + #else + int col = b | (g << 8) | (r << 16) | (a << 24); + #endif + + *(int*)pSpecular = col; +} + +inline void CVertexBuilder::Specular4ubv( unsigned char const *c ) +{ + Assert( m_pSpecular ); + unsigned char *pSpecular = &m_pSpecular[m_nCurrentVertex * m_VertexSize_Specular]; + + #ifdef OPENGL_SWAP_COLORS + int col = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); + #else + int col = c[2] | (c[1] << 8) | (c[0] << 16) | (c[3] << 24); + #endif + + *(int*)pSpecular = col; +} + + +//----------------------------------------------------------------------------- +// Texture coordinate setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::TexCoord1f( int nStage, float s ) +{ + Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] ); + Assert( IsFinite(s) ); + + float *pDst = m_pCurrTexCoord[nStage]; + *pDst = s; +} + +inline void CVertexBuilder::TexCoord2f( int nStage, float s, float t ) +{ + Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] ); + Assert( IsFinite(s) && IsFinite(t) ); + + float *pDst = m_pCurrTexCoord[nStage]; + *pDst++ = s; + *pDst = t; +} + +inline void CVertexBuilder::TexCoord2fv( int nStage, const float *st ) +{ + Assert(st); + Assert( m_pTexCoord[nStage] && m_pCurrTexCoord[nStage] ); + Assert( IsFinite(st[0]) && IsFinite(st[1]) ); + + float *pDst = m_pCurrTexCoord[nStage]; + *pDst++ = *st++; + *pDst = *st; +} + +inline void CVertexBuilder::TexCoord3f( int stage, float s, float t, float u ) +{ + // Tried to add too much! + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) ); + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = s; + *pDst++ = t; + *pDst = u; +} + +inline void CVertexBuilder::TexCoord3fv( int stage, const float *stu ) +{ + Assert(stu); + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(stu[0]) && IsFinite(stu[1]) && IsFinite(stu[2]) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = *stu++; + *pDst++ = *stu++; + *pDst = *stu; +} + +inline void CVertexBuilder::TexCoord4f( int stage, float s, float t, float u, float v ) +{ + // Tried to add too much! + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(s) && IsFinite(t) && IsFinite(u) ); + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = s; + *pDst++ = t; + *pDst++ = u; + *pDst = v; +} + +inline void CVertexBuilder::TexCoord4fv( int stage, const float *stuv ) +{ + Assert(stuv); + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(stuv[0]) && IsFinite(stuv[1]) && IsFinite(stuv[2]) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = *stuv++; + *pDst++ = *stuv++; + *pDst++ = *stuv++; + *pDst = *stuv; +} + + +inline void CVertexBuilder::TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ) +{ + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(s) && IsFinite(t) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = ( s * scaleS ) + offsetS; + *pDst = ( t * scaleT ) + offsetT; +} + +inline void CVertexBuilder::TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale ) +{ + Assert(st); + Assert( m_pTexCoord[stage] && m_pCurrTexCoord[stage] ); + Assert( IsFinite(st[0]) && IsFinite(st[1]) ); + + float *pDst = m_pCurrTexCoord[stage]; + *pDst++ = ( *st++ * *scale++ ) + *offset++; + *pDst = ( *st * *scale ) + *offset; +} + + +//----------------------------------------------------------------------------- +// Tangent space setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::TangentS3f( float sx, float sy, float sz ) +{ + Assert( m_pTangentS ); + Assert( IsFinite(sx) && IsFinite(sy) && IsFinite(sz) ); + + float* pTangentS = OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS ); + *pTangentS++ = sx; + *pTangentS++ = sy; + *pTangentS = sz; +} + +inline void CVertexBuilder::TangentS3fv( const float* s ) +{ + Assert( s ); + Assert( m_pTangentS ); + Assert( IsFinite(s[0]) && IsFinite(s[1]) && IsFinite(s[2]) ); + + float* pTangentS = OffsetFloatPointer( m_pTangentS, m_nCurrentVertex, m_VertexSize_TangentS ); + *pTangentS++ = *s++; + *pTangentS++ = *s++; + *pTangentS = *s; +} + +inline void CVertexBuilder::TangentT3f( float tx, float ty, float tz ) +{ + Assert( m_pTangentT ); + Assert( IsFinite(tx) && IsFinite(ty) && IsFinite(tz) ); + + float* pTangentT = OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT ); + *pTangentT++ = tx; + *pTangentT++ = ty; + *pTangentT = tz; +} + +inline void CVertexBuilder::TangentT3fv( const float* t ) +{ + Assert( t ); + Assert( m_pTangentT ); + Assert( IsFinite(t[0]) && IsFinite(t[1]) && IsFinite(t[2]) ); + + float* pTangentT = OffsetFloatPointer( m_pTangentT, m_nCurrentVertex, m_VertexSize_TangentT ); + *pTangentT++ = *t++; + *pTangentT++ = *t++; + *pTangentT = *t; +} + + +//----------------------------------------------------------------------------- +// Wrinkle setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::Wrinkle1f( float flWrinkle ) +{ + Assert( m_pWrinkle ); + Assert( IsFinite(flWrinkle) ); + + float *pWrinkle = OffsetFloatPointer( m_pWrinkle, m_nCurrentVertex, m_VertexSize_Wrinkle ); + *pWrinkle = flWrinkle; +} + + +//----------------------------------------------------------------------------- +// Bone weight setting methods +//----------------------------------------------------------------------------- +inline void CVertexBuilder::BoneWeight( int idx, float weight ) +{ + Assert( m_pBoneWeight ); + Assert( IsFinite( weight ) ); + Assert( idx >= 0 ); + AssertOnce( m_NumBoneWeights == 2 ); + + // This test is here because we store N-1 bone weights (the Nth is computed in + // the vertex shader as "1 - C", where C is the sum of the (N-1) other weights) + if ( idx < m_NumBoneWeights ) + { + float* pBoneWeight = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight ); + pBoneWeight[idx] = weight; + } +} + +static int sg_IndexSwap[4] = { 2, 1, 0, 3 }; + +inline void CVertexBuilder::BoneMatrix( int idx, int matrixIdx ) +{ + Assert( m_pBoneMatrixIndex ); + Assert( idx >= 0 ); + Assert( idx < 4 ); + + // garymcthack + if ( matrixIdx == BONE_MATRIX_INDEX_INVALID ) + { + matrixIdx = 0; + } + Assert( (matrixIdx >= 0) && (matrixIdx < 53) ); + +#ifdef OPENGL_SWAP_COLORS + idx = sg_IndexSwap[idx]; +#endif + +#ifndef NEW_SKINNING + unsigned char* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + if ( IsX360() ) + { + // store sequentially as wzyx order, gpu delivers as xyzw + idx = 3-idx; + } + pBoneMatrix[idx] = (unsigned char)matrixIdx; +#else + float* pBoneMatrix = &m_pBoneMatrixIndex[m_nCurrentVertex * m_VertexSize_BoneMatrixIndex]; + pBoneMatrix[idx] = matrixIdx; +#endif +} + +//----------------------------------------------------------------------------- +// Templatized bone weight setting methods which support compressed vertices +//----------------------------------------------------------------------------- +template inline void CVertexBuilder::CompressedBoneWeight3fv( const float * pWeights ) +{ + Assert( T == m_CompressionType ); + Assert( m_pBoneWeight ); + Assert( pWeights ); + + float *pDestWeights = OffsetFloatPointer( m_pBoneWeight, m_nCurrentVertex, m_VertexSize_BoneWeight ); + + if ( T == VERTEX_COMPRESSION_ON ) + { + // Quantize to 15 bits per weight (we use D3DDECLTYPE_SHORT2) + // NOTE: we perform careful normalization (weights sum to 1.0f in the vertex shader), so + // as to avoid cracking at boundaries between meshes with different numbers of weights + // per vertex. For example, (1) needs to yield the same normalized weights as (1,0), + // and (0.5,0.49) needs to normalize the same normalized weights as (0.5,0.49,0). + // The key is that values which are *computed* in the shader (e.g. the second weight + // in a 2-weight mesh) must exactly equal values which are *read* from the vertex + // stream (e.g. the second weight in a 3-weight mesh). + + // Only 1 or 2 weights (SHORT2N) supported for compressed verts so far + Assert( m_NumBoneWeights <= 2 ); + + const int WEIGHT0_SHIFT = IsX360() ? 16 : 0; + const int WEIGHT1_SHIFT = IsX360() ? 0 : 16; + unsigned int *weights = (unsigned int *)pDestWeights; + + // We scale our weights so that they sum to 32768, then subtract 1 (which gets added + // back in the shader), because dividing by 32767 introduces nasty rounding issues. + Assert( IsFinite( pWeights[0] ) && ( pWeights[0] >= 0.0f ) && ( pWeights[0] <= 1.0f ) ); + unsigned int weight0 = Float2Int( pWeights[0] * 32768.0f ); + *weights = ( 0x0000FFFF & (weight0 - 1) ) << WEIGHT0_SHIFT; + +#ifdef DEBUG + if ( m_NumBoneWeights == 1 ) + { + // Double-check the validity of the values that were passed in + Assert( IsFinite( pWeights[1] ) && ( pWeights[1] >= 0.0f ) && ( pWeights[1] <= 1.0f ) ); + unsigned int weight1 = Float2Int( pWeights[1] * 32768.0f ); + Assert( ( weight0 + weight1 ) <= 32768 ); + } +#endif + + if ( m_NumBoneWeights > 1 ) + { + // This path for 3 weights per vert (2 are stored and the 3rd is computed + // in the shader - we do post-quantization normalization here in such a + // way as to avoid mesh-boundary cracking) + Assert( m_NumBoneWeights == 2 ); + Assert( IsFinite( pWeights[1] ) && ( pWeights[1] >= 0.0f ) && ( pWeights[1] <= 1.0f ) ); + Assert( IsFinite( pWeights[2] ) && ( pWeights[2] >= 0.0f ) && ( pWeights[2] <= 1.0f ) ); + unsigned int weight1 = Float2Int( pWeights[1] * 32768.0f ); + unsigned int weight2 = Float2Int( pWeights[2] * 32768.0f ); + Assert( ( weight0 + weight1 + weight2 ) <= 32768 ); + unsigned int residual = 32768 - ( weight0 + weight1 + weight2 ); + weight1 += residual; // Normalize + *weights |= ( 0x0000FFFF & ( weight1 - 1 ) ) << WEIGHT1_SHIFT; + } + } + else // Uncompressed path + { + pDestWeights[0] = pWeights[0]; + pDestWeights[1] = pWeights[1]; + } +} + +//----------------------------------------------------------------------------- +// Generic per-vertex data setting method +//----------------------------------------------------------------------------- +inline void CVertexBuilder::UserData( const float* pData ) +{ + Assert( m_CompressionType == VERTEX_COMPRESSION_NONE ); // Use the templatized version if you want to support compression + Assert( pData ); + + int userDataSize = 4; // garymcthack + float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData ); + memcpy( pUserData, pData, sizeof( float ) * userDataSize ); +} + +//----------------------------------------------------------------------------- +// Templatized generic per-vertex data setting method which supports compressed vertices +//----------------------------------------------------------------------------- +template inline void CVertexBuilder::CompressedUserData( const float* pData ) +{ + Assert( T == m_CompressionType ); + Assert( pData ); + // This is always in fact a tangent vector, not generic 'userdata' + Assert( IsFinite(pData[0]) && IsFinite(pData[1]) && IsFinite(pData[2]) ); + Assert( pData[0] >= -1.05f && pData[0] <= 1.05f ); + Assert( pData[1] >= -1.05f && pData[1] <= 1.05f ); + Assert( pData[2] >= -1.05f && pData[2] <= 1.05f ); + Assert( pData[3] == +1.0f || pData[3] == -1.0f ); + // FIXME: studiorender is passing in non-unit normals + //float lengthSqd = pData[0]*pData[0] + pData[1]*pData[1] + pData[2]*pData[2]; + //Assert( lengthSqd >= 0.95f && lengthSqd <= 1.05f ); + + if ( T == VERTEX_COMPRESSION_ON ) + { + float binormalSign = pData[3]; + +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData ); + PackNormal_SHORT2( pData, (unsigned int *)pUserData, binormalSign ); +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + // FIXME: add a combined CompressedNormalAndTangent() accessor, to avoid reading back from write-combined memory here + // The normal should have already been written into the lower 16 + // bits - here, we OR in the tangent into the upper 16 bits + unsigned int existingNormalData = *(unsigned int *)m_pCurrNormal; + Assert( ( existingNormalData & 0xFFFF0000 ) == 0 ); +#ifdef _DEBUG + Assert( m_bWrittenNormal == true ); + m_bWrittenUserData = true; +#endif + bool bIsTangent = true; + unsigned int tangentData = 0; + PackNormal_UBYTE4( pData, &tangentData, bIsTangent, binormalSign ); + *(unsigned int *)m_pCurrNormal = existingNormalData | tangentData; +#endif + } + else + { + int userDataSize = 4; // garymcthack + float *pUserData = OffsetFloatPointer( m_pUserData, m_nCurrentVertex, m_VertexSize_UserData ); + memcpy( pUserData, pData, sizeof( float ) * userDataSize ); + } +} + + +//----------------------------------------------------------------------------- +// +// Helper class used to define index buffers +// +//----------------------------------------------------------------------------- +class CIndexBuilder : private IndexDesc_t +{ +public: + CIndexBuilder(); + CIndexBuilder( IIndexBuffer *pIndexBuffer, MaterialIndexFormat_t fmt = MATERIAL_INDEX_FORMAT_UNKNOWN ); + ~CIndexBuilder(); + + // Begins, ends modification of the index buffer (returns true if the lock succeeded) + // A lock may not succeed if append is set to true and there isn't enough room + // NOTE: Append is only used with dynamic index buffers; it's ignored for static buffers + bool Lock( int nMaxIndexCount, int nIndexOffset, bool bAppend = false ); + void Unlock(); + + // Spews the current data + // NOTE: Can only be called during a lock/unlock block + void SpewData(); + + // Returns the number of indices we can fit into the buffer without needing to discard + int GetRoomRemaining() const; + + // Binds this index buffer + void Bind( IMatRenderContext *pContext ); + + // Returns the byte offset + int Offset() const; + + // Begins, ends modification of the index buffer + // NOTE: IndexOffset is the number to add to all indices written into the buffer; + // useful when using dynamic vertex buffers. + void Begin( IIndexBuffer *pIndexBuffer, int nMaxIndexCount, int nIndexOffset = 0 ); + void End( bool bSpewData = false ); + + // Locks the index buffer to modify existing data + // Passing nVertexCount == -1 says to lock all the vertices for modification. + // Pass 0 for nIndexCount to not lock the index buffer. + void BeginModify( IIndexBuffer *pIndexBuffer, int nFirstIndex = 0, int nIndexCount = 0, int nIndexOffset = 0 ); + void EndModify( bool bSpewData = false ); + + // returns the number of indices + int IndexCount() const; + + // Returns the total number of indices across all Locks() + int TotalIndexCount() const; + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + // Selects the nth Index + void SelectIndex( int nBufferIndex ); + + // Advances the current index by one + void AdvanceIndex(); + void AdvanceIndices( int nIndexCount ); + + int GetCurrentIndex(); + int GetFirstIndex() const; + + unsigned short const* Index() const; + + // Used to define the indices (only used if you aren't using primitives) + void Index( unsigned short nIndex ); + + // Fast Index! No need to call advance index, and no random access allowed + void FastIndex( unsigned short nIndex ); + + // NOTE: This version is the one you really want to achieve write-combining; + // Write combining only works if you write in 4 bytes chunks. + void FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ); + + // Generates indices for a particular primitive type + void GenerateIndices( MaterialPrimitiveType_t primitiveType, int nIndexCount ); + + // FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. + void AttachBegin( IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t &desc ); + void AttachEnd(); + void AttachBeginModify( IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t &desc ); + void AttachEndModify(); + + void FastTriangle( int startVert ); + void FastQuad( int startVert ); + void FastPolygon( int startVert, int numTriangles ); + void FastPolygonList( int startVert, int *pVertexCount, int polygonCount ); + void FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount ); + +private: + // The mesh we're modifying + IIndexBuffer *m_pIndexBuffer; + + // Max number of indices + int m_nMaxIndexCount; + + // Number of indices + int m_nIndexCount; + + // Offset to add to each index as it's written into the buffer + int m_nIndexOffset; + + // The current index + mutable int m_nCurrentIndex; + + // Total number of indices appended + int m_nTotalIndexCount; + + // First index buffer offset + first index + unsigned int m_nBufferOffset; + unsigned int m_nBufferFirstIndex; + + // Used to make sure Begin/End calls and BeginModify/EndModify calls match. + bool m_bModify; +}; + + +//----------------------------------------------------------------------------- +// +// Inline methods related to CIndexBuilder +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +inline CIndexBuilder::CIndexBuilder() : m_pIndexBuffer(0), m_nIndexCount(0), + m_nCurrentIndex(0), m_nMaxIndexCount(0) +{ + m_nTotalIndexCount = 0; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstIndex = 0; +#ifdef _DEBUG + m_bModify = false; +#endif +} + +inline CIndexBuilder::CIndexBuilder( IIndexBuffer *pIndexBuffer, MaterialIndexFormat_t fmt ) +{ + m_pIndexBuffer = pIndexBuffer; + m_nBufferOffset = INVALID_BUFFER_OFFSET; + m_nBufferFirstIndex = 0; + m_nIndexCount = 0; + m_nCurrentIndex = 0; + m_nMaxIndexCount = 0; + m_nTotalIndexCount = 0; + if ( m_pIndexBuffer->IsDynamic() ) + { + m_pIndexBuffer->BeginCastBuffer( fmt ); + } + else + { + Assert( m_pIndexBuffer->IndexFormat() == fmt ); + } +#ifdef _DEBUG + m_bModify = false; +#endif +} + +inline CIndexBuilder::~CIndexBuilder() +{ + if ( m_pIndexBuffer && m_pIndexBuffer->IsDynamic() ) + { + m_pIndexBuffer->EndCastBuffer(); + } +} + + +//----------------------------------------------------------------------------- +// Begins, ends modification of the index buffer +//----------------------------------------------------------------------------- +inline bool CIndexBuilder::Lock( int nMaxIndexCount, int nIndexOffset, bool bAppend ) +{ + Assert( m_pIndexBuffer ); + m_bModify = false; + m_nIndexOffset = nIndexOffset; + m_nMaxIndexCount = nMaxIndexCount; + bool bFirstLock = ( m_nBufferOffset == INVALID_BUFFER_OFFSET ); + if ( bFirstLock ) + { + bAppend = false; + } + if ( !bAppend ) + { + m_nTotalIndexCount = 0; + } + Reset(); + + // Lock the index buffer + if ( !m_pIndexBuffer->Lock( m_nMaxIndexCount, bAppend, *this ) ) + { + m_nMaxIndexCount = 0; + return false; + } + + if ( bFirstLock ) + { + m_nBufferOffset = m_nOffset; + m_nBufferFirstIndex = m_nFirstIndex; + } + + return true; +} + +inline void CIndexBuilder::Unlock() +{ + Assert( !m_bModify && m_pIndexBuffer ); + + m_pIndexBuffer->Unlock( m_nIndexCount, *this ); + m_nTotalIndexCount += m_nIndexCount; + + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + +inline void CIndexBuilder::SpewData() +{ + m_pIndexBuffer->Spew( m_nIndexCount, *this ); +} + + +//----------------------------------------------------------------------------- +// Binds this index buffer +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Bind( IMatRenderContext *pContext ) +{ + if ( m_pIndexBuffer && ( m_nBufferOffset != INVALID_BUFFER_OFFSET ) ) + { + pContext->BindIndexBuffer( m_pIndexBuffer, m_nBufferOffset ); + } + else + { + pContext->BindIndexBuffer( NULL, 0 ); + } +} + + +//----------------------------------------------------------------------------- +// Returns the byte offset +//----------------------------------------------------------------------------- +inline int CIndexBuilder::Offset() const +{ + return m_nBufferOffset; +} + +inline int CIndexBuilder::GetFirstIndex() const +{ + return m_nBufferFirstIndex; +} + + +//----------------------------------------------------------------------------- +// Begins, ends modification of the index buffer +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Begin( IIndexBuffer *pIndexBuffer, int nMaxIndexCount, int nIndexOffset ) +{ + Assert( pIndexBuffer && (!m_pIndexBuffer) ); + + m_pIndexBuffer = pIndexBuffer; + m_nIndexCount = 0; + m_nMaxIndexCount = nMaxIndexCount; + m_nIndexOffset = nIndexOffset; + + m_bModify = false; + + // Lock the index buffer + m_pIndexBuffer->Lock( m_nMaxIndexCount, false, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::End( bool bSpewData ) +{ + // Make sure they called Begin() + Assert( !m_bModify ); + + if ( bSpewData ) + { + m_pIndexBuffer->Spew( m_nIndexCount, *this ); + } + + // Unlock our buffers + m_pIndexBuffer->Unlock( m_nIndexCount, *this ); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Begins, ends modification of an existing index buffer which has already been filled out +//----------------------------------------------------------------------------- +inline void CIndexBuilder::BeginModify( IIndexBuffer* pIndexBuffer, int nFirstIndex, int nIndexCount, int nIndexOffset ) +{ + m_pIndexBuffer = pIndexBuffer; + m_nIndexCount = nIndexCount; + m_nMaxIndexCount = nIndexCount; + m_nIndexOffset = nIndexOffset; + m_bModify = true; + + // Lock the vertex and index buffer + m_pIndexBuffer->ModifyBegin( false, nFirstIndex, nIndexCount, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::EndModify( bool bSpewData ) +{ + Assert( m_pIndexBuffer ); + Assert( m_bModify ); // Make sure they called BeginModify. + + if ( bSpewData ) + { + m_pIndexBuffer->Spew( m_nIndexCount, *this ); + } + + // Unlock our buffers + m_pIndexBuffer->ModifyEnd( *this ); + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// FIXME: Remove! Backward compat so we can use this from a CMeshBuilder. +//----------------------------------------------------------------------------- +inline void CIndexBuilder::AttachBegin( IMesh* pMesh, int nMaxIndexCount, const MeshDesc_t &desc ) +{ + m_pIndexBuffer = pMesh; + m_nIndexCount = 0; + m_nMaxIndexCount = nMaxIndexCount; + + m_bModify = false; + + // Copy relevant data from the mesh desc + m_nIndexOffset = desc.m_nFirstVertex; + m_pIndices = desc.m_pIndices; + m_nIndexSize = desc.m_nIndexSize; + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::AttachEnd() +{ + Assert( m_pIndexBuffer ); + Assert( !m_bModify ); // Make sure they called AttachBegin. + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + +inline void CIndexBuilder::AttachBeginModify( IMesh* pMesh, int nFirstIndex, int nIndexCount, const MeshDesc_t &desc ) +{ + m_pIndexBuffer = pMesh; + m_nIndexCount = nIndexCount; + m_nMaxIndexCount = nIndexCount; + m_bModify = true; + + // Copy relevant data from the mesh desc + m_nIndexOffset = desc.m_nFirstVertex; + m_pIndices = desc.m_pIndices; + m_nIndexSize = desc.m_nIndexSize; + + // Point to the start of the buffers.. + Reset(); +} + +inline void CIndexBuilder::AttachEndModify() +{ + Assert( m_pIndexBuffer ); + Assert( m_bModify ); // Make sure they called AttachBeginModify. + + m_pIndexBuffer = 0; + m_nMaxIndexCount = 0; + +#ifdef _DEBUG + // Null out our data... + memset( (IndexDesc_t*)this, 0, sizeof(IndexDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Resets the index buffer builder so it points to the start of everything again +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Reset() +{ + m_nCurrentIndex = 0; +} + + +//----------------------------------------------------------------------------- +// returns the number of indices +//----------------------------------------------------------------------------- +inline int CIndexBuilder::IndexCount() const +{ + return m_nIndexCount; +} + + +//----------------------------------------------------------------------------- +// Returns the total number of indices across all Locks() +//----------------------------------------------------------------------------- +inline int CIndexBuilder::TotalIndexCount() const +{ + return m_nTotalIndexCount; +} + + +//----------------------------------------------------------------------------- +// Advances the current index +//----------------------------------------------------------------------------- +inline void CIndexBuilder::AdvanceIndex() +{ + m_nCurrentIndex += m_nIndexSize; + if ( m_nCurrentIndex > m_nIndexCount ) + { + m_nIndexCount = m_nCurrentIndex; + } +} + +inline void CIndexBuilder::AdvanceIndices( int nIndices ) +{ + m_nCurrentIndex += nIndices * m_nIndexSize; + if ( m_nCurrentIndex > m_nIndexCount ) + { + m_nIndexCount = m_nCurrentIndex; + } +} + + +//----------------------------------------------------------------------------- +// Returns the current index +//----------------------------------------------------------------------------- +inline int CIndexBuilder::GetCurrentIndex() +{ + return m_nCurrentIndex; +} + +inline unsigned short const* CIndexBuilder::Index() const +{ + Assert( m_nCurrentIndex < m_nMaxIndexCount ); + return &m_pIndices[m_nCurrentIndex]; +} + +inline void CIndexBuilder::SelectIndex( int nIndex ) +{ + Assert( ( nIndex >= 0 ) && ( nIndex < m_nIndexCount ) ); + m_nCurrentIndex = nIndex * m_nIndexSize; +} + + +//----------------------------------------------------------------------------- +// Used to write data into the index buffer +//----------------------------------------------------------------------------- +inline void CIndexBuilder::Index( unsigned short nIndex ) +{ + Assert( m_pIndices ); + Assert( m_nCurrentIndex < m_nMaxIndexCount ); + m_pIndices[ m_nCurrentIndex ] = (unsigned short)( m_nIndexOffset + nIndex ); +} + +// Fast Index! No need to call advance index +inline void CIndexBuilder::FastIndex( unsigned short nIndex ) +{ + Assert( m_pIndices ); + Assert( m_nCurrentIndex < m_nMaxIndexCount ); + m_pIndices[m_nCurrentIndex] = (unsigned short)( m_nIndexOffset + nIndex ); + m_nCurrentIndex += m_nIndexSize; + m_nIndexCount = m_nCurrentIndex; +} + +inline void CIndexBuilder::FastTriangle( int startVert ) +{ + startVert += m_nIndexOffset; + m_pIndices[m_nCurrentIndex+0] = startVert; + m_pIndices[m_nCurrentIndex+1] = startVert + 1; + m_pIndices[m_nCurrentIndex+2] = startVert + 2; + + AdvanceIndices(3); +} + +inline void CIndexBuilder::FastQuad( int startVert ) +{ + startVert += m_nIndexOffset; + m_pIndices[m_nCurrentIndex+0] = startVert; + m_pIndices[m_nCurrentIndex+1] = startVert + 1; + m_pIndices[m_nCurrentIndex+2] = startVert + 2; + m_pIndices[m_nCurrentIndex+3] = startVert; + m_pIndices[m_nCurrentIndex+4] = startVert + 2; + m_pIndices[m_nCurrentIndex+5] = startVert + 3; + AdvanceIndices(6); +} + +inline void CIndexBuilder::FastPolygon( int startVert, int triangleCount ) +{ + unsigned short *pIndex = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + if ( !IsX360() ) + { + // NOTE: IndexSize is 1 or 0 (0 for alt-tab) + // This prevents us from writing into bogus memory + Assert( m_nIndexSize == 0 || m_nIndexSize == 1 ); + triangleCount *= m_nIndexSize; + } + for ( int v = 0; v < triangleCount; ++v ) + { + *pIndex++ = startVert; + *pIndex++ = startVert + v + 1; + *pIndex++ = startVert + v + 2; + } + AdvanceIndices(triangleCount*3); +} + +inline void CIndexBuilder::FastPolygonList( int startVert, int *pVertexCount, int polygonCount ) +{ + unsigned short *pIndex = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + int indexOut = 0; + + if ( !IsX360() ) + { + // NOTE: IndexSize is 1 or 0 (0 for alt-tab) + // This prevents us from writing into bogus memory + Assert( m_nIndexSize == 0 || m_nIndexSize == 1 ); + polygonCount *= m_nIndexSize; + } + + for ( int i = 0; i < polygonCount; i++ ) + { + int vertexCount = pVertexCount[i]; + int triangleCount = vertexCount-2; + for ( int v = 0; v < triangleCount; ++v ) + { + *pIndex++ = startVert; + *pIndex++ = startVert + v + 1; + *pIndex++ = startVert + v + 2; + } + startVert += vertexCount; + indexOut += triangleCount * 3; + } + AdvanceIndices(indexOut); +} + +inline void CIndexBuilder::FastIndexList( const unsigned short *pIndexList, int startVert, int indexCount ) +{ + unsigned short *pIndexOut = &m_pIndices[m_nCurrentIndex]; + startVert += m_nIndexOffset; + if ( !IsX360() ) + { + // NOTE: IndexSize is 1 or 0 (0 for alt-tab) + // This prevents us from writing into bogus memory + Assert( m_nIndexSize == 0 || m_nIndexSize == 1 ); + indexCount *= m_nIndexSize; + } + for ( int i = 0; i < indexCount; ++i ) + { + pIndexOut[i] = startVert + pIndexList[i]; + } + AdvanceIndices(indexCount); +} + + +//----------------------------------------------------------------------------- +// NOTE: This version is the one you really want to achieve write-combining; +// Write combining only works if you write in 4 bytes chunks. +//----------------------------------------------------------------------------- +inline void CIndexBuilder::FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ) +{ + Assert( m_pIndices ); + Assert( m_nCurrentIndex < m_nMaxIndexCount - 1 ); +// Assert( ( (int)( &m_pIndices[m_nCurrentIndex] ) & 0x3 ) == 0 ); + +#ifndef _X360 + unsigned int nIndices = ( (unsigned int)nIndex1 + m_nIndexOffset ) | ( ( (unsigned int)nIndex2 + m_nIndexOffset ) << 16 ); +#else + unsigned int nIndices = ( (unsigned int)nIndex2 + m_nIndexOffset ) | ( ( (unsigned int)nIndex1 + m_nIndexOffset ) << 16 ); +#endif + + *(int*)( &m_pIndices[m_nCurrentIndex] ) = nIndices; + m_nCurrentIndex += m_nIndexSize + m_nIndexSize; + m_nIndexCount = m_nCurrentIndex; +} + + +//----------------------------------------------------------------------------- +// Generates indices for a particular primitive type +//----------------------------------------------------------------------------- +inline void CIndexBuilder::GenerateIndices( MaterialPrimitiveType_t primitiveType, int nIndexCount ) +{ + // FIXME: How to make this work with short vs int sized indices? + // Don't generate indices if we've got an empty buffer + if ( m_nIndexSize == 0 ) + return; + + int nMaxIndices = m_nMaxIndexCount - m_nCurrentIndex; + nIndexCount = Min( nMaxIndices, nIndexCount ); + if ( nIndexCount == 0 ) + return; + + unsigned short *pIndices = &m_pIndices[m_nCurrentIndex]; + + switch( primitiveType ) + { + case MATERIAL_INSTANCED_QUADS: + Assert(0); // Shouldn't get here (this primtype is unindexed) + break; + case MATERIAL_QUADS: + GenerateQuadIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_POLYGON: + GeneratePolygonIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_LINE_STRIP: + GenerateLineStripIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_LINE_LOOP: + GenerateLineLoopIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + case MATERIAL_POINTS: + Assert(0); // Shouldn't get here (this primtype is unindexed) + break; + default: + GenerateSequentialIndexBuffer( pIndices, nIndexCount, m_nIndexOffset ); + break; + } + + AdvanceIndices( nIndexCount ); +} + + +//----------------------------------------------------------------------------- +// +// Helper class used to define meshes +// +//----------------------------------------------------------------------------- +//class CMeshBuilder : private MeshDesc_t +// hack fixme +class CMeshBuilder : public MeshDesc_t +{ +public: + CMeshBuilder(); + ~CMeshBuilder() { Assert(!m_pMesh); } // if this fires you did a Begin() without an End() + + operator CIndexBuilder&() { return m_IndexBuilder; } + + // This must be called before Begin, if a vertex buffer with a compressed format is to be used + void SetCompressionType( VertexCompressionType_t compressionType ); + + // Locks the vertex buffer + // (*cannot* use the Index() call below) + void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int numPrimitives ); + + // Locks the vertex buffer, can specify arbitrary index lists + // (must use the Index() call below) + void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ); + void Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ); + + // forward compat + void Begin( IVertexBuffer *pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives ); + void Begin( IVertexBuffer *pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ); + void Begin( IVertexBuffer *pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ); + + // Use this when you're done writing + // Set bDraw to true to call m_pMesh->Draw automatically. + void End( bool bSpewData = false, bool bDraw = false ); + + // Locks the vertex buffer to modify existing data + // Passing nVertexCount == -1 says to lock all the vertices for modification. + // Pass 0 for nIndexCount to not lock the index buffer. + void BeginModify( IMesh *pMesh, int nFirstVertex = 0, int nVertexCount = -1, int nFirstIndex = 0, int nIndexCount = 0 ); + void EndModify( bool bSpewData = false ); + + // A helper method since this seems to be done a whole bunch. + void DrawQuad( IMesh* pMesh, const float *v1, const float *v2, + const float *v3, const float *v4, unsigned char const *pColor, bool wireframe = false ); + + // returns the number of indices and vertices + int VertexCount() const; + int IndexCount() const; + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + // Returns the size of the vertex + int VertexSize() { return m_ActualVertexSize; } + + // returns the data size of a given texture coordinate + int TextureCoordinateSize( int nTexCoordNumber ) { return m_VertexSize_TexCoord[ nTexCoordNumber ]; } + + // Returns the base vertex memory pointer + void* BaseVertexData(); + + // Selects the nth Vertex and Index + void SelectVertex( int idx ); + void SelectIndex( int idx ); + + // Given an index, point to the associated vertex + void SelectVertexFromIndex( int idx ); + + // Advances the current vertex and index by one + void AdvanceVertex(); + template void AdvanceVertexF(); + void AdvanceVertices( int nVerts ); + void AdvanceIndex(); + void AdvanceIndices( int nIndices ); + + int GetCurrentVertex(); + int GetCurrentIndex(); + + // Data retrieval... + const float *Position() const; + + const float *Normal() const; + + unsigned int Color() const; + + unsigned char *Specular() const; + + const float *TexCoord( int stage ) const; + + const float *TangentS() const; + const float *TangentT() const; + + const float *BoneWeight() const; + float Wrinkle() const; + + int NumBoneWeights() const; +#ifndef NEW_SKINNING + unsigned char *BoneMatrix() const; +#else + float *BoneMatrix() const; +#endif + unsigned short const *Index() const; + + // position setting + void Position3f( float x, float y, float z ); + void Position3fv( const float *v ); + + // normal setting + void Normal3f( float nx, float ny, float nz ); + void Normal3fv( const float *n ); + void NormalDelta3fv( const float *n ); + void NormalDelta3f( float nx, float ny, float nz ); + + // normal setting (templatized for code which needs to support compressed vertices) + template void CompressedNormal3f( float nx, float ny, float nz ); + template void CompressedNormal3fv( const float *n ); + + // color setting + void Color3f( float r, float g, float b ); + void Color3fv( const float *rgb ); + void Color4f( float r, float g, float b, float a ); + void Color4fv( const float *rgba ); + + // Faster versions of color + void Color3ub( unsigned char r, unsigned char g, unsigned char b ); + void Color3ubv( unsigned char const* rgb ); + void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Color4ubv( unsigned char const* rgba ); + + // specular color setting + void Specular3f( float r, float g, float b ); + void Specular3fv( const float *rgb ); + void Specular4f( float r, float g, float b, float a ); + void Specular4fv( const float *rgba ); + + // Faster version of specular + void Specular3ub( unsigned char r, unsigned char g, unsigned char b ); + void Specular3ubv( unsigned char const *c ); + void Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void Specular4ubv( unsigned char const *c ); + + // texture coordinate setting + void TexCoord1f( int stage, float s ); + void TexCoord2f( int stage, float s, float t ); + void TexCoord2fv( int stage, const float *st ); + void TexCoord3f( int stage, float s, float t, float u ); + void TexCoord3fv( int stage, const float *stu ); + void TexCoord4f( int stage, float s, float t, float u, float w ); + void TexCoord4fv( int stage, const float *stuv ); + + void TexCoordSubRect2f( int stage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ); + void TexCoordSubRect2fv( int stage, const float *st, const float *offset, const float *scale ); + + // tangent space + void TangentS3f( float sx, float sy, float sz ); + void TangentS3fv( const float *s ); + + void TangentT3f( float tx, float ty, float tz ); + void TangentT3fv( const float *t ); + + // Wrinkle + void Wrinkle1f( float flWrinkle ); + + // bone weights + void BoneWeight( int idx, float weight ); + // bone weights (templatized for code which needs to support compressed vertices) + template void CompressedBoneWeight3fv( const float * pWeights ); + + // bone matrix index + void BoneMatrix( int idx, int matrixIndex ); + + // Generic per-vertex data + void UserData( const float *pData ); + // Generic per-vertex data (templatized for code which needs to support compressed vertices) + template void CompressedUserData( const float* pData ); + + // Used to define the indices (only used if you aren't using primitives) + void Index( unsigned short index ); + + // NOTE: Use this one to get write combining! Much faster than the other version of FastIndex + // Fast Index! No need to call advance index, and no random access allowed + void FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ); + + // Fast Index! No need to call advance index, and no random access allowed + void FastIndex( unsigned short index ); + + // Fast Vertex! No need to call advance vertex, and no random access allowed. + // WARNING - these are low level functions that are intended only for use + // in the software vertex skinner. + void FastVertex( const ModelVertexDX7_t &vertex ); + void FastVertexSSE( const ModelVertexDX7_t &vertex ); + + // store 4 dx7 vertices fast. for special sse dx7 pipeline + void Fast4VerticesSSE( + ModelVertexDX7_t const *vtx_a, + ModelVertexDX7_t const *vtx_b, + ModelVertexDX7_t const *vtx_c, + ModelVertexDX7_t const *vtx_d); + + void FastVertex( const ModelVertexDX8_t &vertex ); + void FastVertexSSE( const ModelVertexDX8_t &vertex ); + + // Add number of verts and current vert since FastVertexxx routines do not update. + void FastAdvanceNVertices(int n); + +#if defined( _X360 ) + void VertexDX8ToX360( const ModelVertexDX8_t &vertex ); +#endif + +private: + // Computes number of verts and indices + void ComputeNumVertsAndIndices( int *pMaxVertices, int *pMaxIndices, + MaterialPrimitiveType_t type, int nPrimitiveCount ); + int IndicesFromVertices( MaterialPrimitiveType_t type, int nVertexCount ); + + // The mesh we're modifying + IMesh *m_pMesh; + + MaterialPrimitiveType_t m_Type; + + // Generate indices? + bool m_bGenerateIndices; + + CIndexBuilder m_IndexBuilder; + CVertexBuilder m_VertexBuilder; +}; + + +//----------------------------------------------------------------------------- +// Forward compat +//----------------------------------------------------------------------------- +inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, MaterialPrimitiveType_t type, int numPrimitives ) +{ + Assert( 0 ); + // Begin( pVertexBuffer->GetMesh(), type, numPrimitives ); +} + +inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ) +{ + Assert( 0 ); + // Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount, nFirstVertex ); +} + +inline void CMeshBuilder::Begin( IVertexBuffer* pVertexBuffer, IIndexBuffer *pIndexBuffer, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ) +{ + Assert( 0 ); + // Begin( pVertexBuffer->GetMesh(), type, nVertexCount, nIndexCount ); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +inline CMeshBuilder::CMeshBuilder() : m_pMesh(0), m_bGenerateIndices(false) +{ +} + + +//----------------------------------------------------------------------------- +// Computes the number of verts and indices based on primitive type and count +//----------------------------------------------------------------------------- +inline void CMeshBuilder::ComputeNumVertsAndIndices( int *pMaxVertices, int *pMaxIndices, + MaterialPrimitiveType_t type, int nPrimitiveCount ) +{ + switch(type) + { + case MATERIAL_POINTS: + *pMaxVertices = *pMaxIndices = nPrimitiveCount; + break; + + case MATERIAL_LINES: + *pMaxVertices = *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_LINE_STRIP: + *pMaxVertices = nPrimitiveCount + 1; + *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_LINE_LOOP: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = nPrimitiveCount * 2; + break; + + case MATERIAL_TRIANGLES: + *pMaxVertices = *pMaxIndices = nPrimitiveCount * 3; + break; + + case MATERIAL_TRIANGLE_STRIP: + *pMaxVertices = *pMaxIndices = nPrimitiveCount + 2; + break; + + case MATERIAL_QUADS: + *pMaxVertices = nPrimitiveCount * 4; + *pMaxIndices = nPrimitiveCount * 6; + break; + + case MATERIAL_INSTANCED_QUADS: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = 0; // This primtype is unindexed + break; + + case MATERIAL_POLYGON: + *pMaxVertices = nPrimitiveCount; + *pMaxIndices = (nPrimitiveCount - 2) * 3; + break; + + default: + Assert(0); + } + + // FIXME: need to get this from meshdx8.cpp, or move it to somewhere common + Assert( *pMaxVertices <= 32768 ); + Assert( *pMaxIndices <= 32768 ); +} + + +inline int CMeshBuilder::IndicesFromVertices( MaterialPrimitiveType_t type, int nVertexCount ) +{ + switch( type ) + { + case MATERIAL_QUADS: + Assert( (nVertexCount & 0x3) == 0 ); + return (nVertexCount * 6) / 4; + + case MATERIAL_INSTANCED_QUADS: + // This primtype is unindexed + return 0; + + case MATERIAL_POLYGON: + Assert( nVertexCount >= 3 ); + return (nVertexCount - 2) * 3; + + case MATERIAL_LINE_STRIP: + Assert( nVertexCount >= 2 ); + return (nVertexCount - 1) * 2; + + case MATERIAL_LINE_LOOP: + Assert( nVertexCount >= 3 ); + return nVertexCount * 2; + + default: + return nVertexCount; + } +} + +//----------------------------------------------------------------------------- +// Specify the type of vertex compression that this CMeshBuilder will perform +//----------------------------------------------------------------------------- +inline void CMeshBuilder::SetCompressionType( VertexCompressionType_t vertexCompressionType ) +{ + m_VertexBuilder.SetCompressionType( vertexCompressionType ); +} + +//----------------------------------------------------------------------------- +// Begins modifying the mesh +//----------------------------------------------------------------------------- +inline void CMeshBuilder::Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int numPrimitives ) +{ + Assert( pMesh && (!m_pMesh) ); + Assert( type != MATERIAL_HETEROGENOUS ); + + m_pMesh = pMesh; + m_bGenerateIndices = true; + m_Type = type; + + int nMaxVertexCount, nMaxIndexCount; + ComputeNumVertsAndIndices( &nMaxVertexCount, &nMaxIndexCount, type, numPrimitives ); + + switch( type ) + { + case MATERIAL_INSTANCED_QUADS: + m_pMesh->SetPrimitiveType( MATERIAL_INSTANCED_QUADS ); + break; + + case MATERIAL_QUADS: + case MATERIAL_POLYGON: + m_pMesh->SetPrimitiveType( MATERIAL_TRIANGLES ); + break; + + case MATERIAL_LINE_STRIP: + case MATERIAL_LINE_LOOP: + m_pMesh->SetPrimitiveType( MATERIAL_LINES ); + break; + + default: + m_pMesh->SetPrimitiveType( type ); + } + + // Lock the mesh + m_pMesh->LockMesh( nMaxVertexCount, nMaxIndexCount, *this ); + + m_IndexBuilder.AttachBegin( pMesh, nMaxIndexCount, *this ); + m_VertexBuilder.AttachBegin( pMesh, nMaxVertexCount, *this ); + + // Point to the start of the index and vertex buffers + Reset(); +} + +inline void CMeshBuilder::Begin( IMesh *pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount, int *nFirstVertex ) +{ + Begin( pMesh, type, nVertexCount, nIndexCount ); + + *nFirstVertex = m_VertexBuilder.m_nFirstVertex * m_VertexBuilder.VertexSize(); +} + +inline void CMeshBuilder::Begin( IMesh* pMesh, MaterialPrimitiveType_t type, int nVertexCount, int nIndexCount ) +{ + Assert( pMesh && (!m_pMesh) ); + + // NOTE: We can't specify the indices when we use quads, polygons, or + // linestrips; they aren't actually directly supported by + // the material system + Assert( (type != MATERIAL_QUADS) && (type != MATERIAL_INSTANCED_QUADS) && (type != MATERIAL_POLYGON) && + (type != MATERIAL_LINE_STRIP) && (type != MATERIAL_LINE_LOOP)); + + // Dx8 doesn't support indexed points... + Assert( type != MATERIAL_POINTS ); + + m_pMesh = pMesh; + m_bGenerateIndices = false; + m_Type = type; + + // Set the primitive type + m_pMesh->SetPrimitiveType( type ); + + // Lock the vertex and index buffer + m_pMesh->LockMesh( nVertexCount, nIndexCount, *this ); + + m_IndexBuilder.AttachBegin( pMesh, nIndexCount, *this ); + m_VertexBuilder.AttachBegin( pMesh, nVertexCount, *this ); + + // Point to the start of the buffers.. + Reset(); +} + + +//----------------------------------------------------------------------------- +// Use this when you're done modifying the mesh +//----------------------------------------------------------------------------- +inline void CMeshBuilder::End( bool bSpewData, bool bDraw ) +{ + if ( m_bGenerateIndices ) + { + int nIndexCount = IndicesFromVertices( m_Type, m_VertexBuilder.VertexCount() ); + m_IndexBuilder.GenerateIndices( m_Type, nIndexCount ); + } + + if ( bSpewData ) + { + m_pMesh->Spew( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); + } + +#ifdef _DEBUG + m_pMesh->ValidateData( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); +#endif + + // Unlock our buffers + m_pMesh->UnlockMesh( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); + + m_IndexBuilder.AttachEnd(); + m_VertexBuilder.AttachEnd(); + + if ( bDraw ) + { + m_pMesh->Draw(); + } + + m_pMesh = 0; + +#ifdef _DEBUG + memset( (MeshDesc_t*)this, 0, sizeof(MeshDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Locks the vertex buffer to modify existing data +//----------------------------------------------------------------------------- +inline void CMeshBuilder::BeginModify( IMesh* pMesh, int nFirstVertex, int nVertexCount, int nFirstIndex, int nIndexCount ) +{ + Assert( pMesh && (!m_pMesh) ); + + if (nVertexCount < 0) + { + nVertexCount = pMesh->VertexCount(); + } + + m_pMesh = pMesh; + m_bGenerateIndices = false; + + // Locks mesh for modifying + pMesh->ModifyBeginEx( false, nFirstVertex, nVertexCount, nFirstIndex, nIndexCount, *this ); + + m_IndexBuilder.AttachBeginModify( pMesh, nFirstIndex, nIndexCount, *this ); + m_VertexBuilder.AttachBeginModify( pMesh, nFirstVertex, nVertexCount, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CMeshBuilder::EndModify( bool bSpewData ) +{ + Assert( m_pMesh ); + + if (bSpewData) + { + m_pMesh->Spew( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); + } +#ifdef _DEBUG + m_pMesh->ValidateData( m_VertexBuilder.VertexCount(), m_IndexBuilder.IndexCount(), *this ); +#endif + + // Unlocks mesh + m_pMesh->ModifyEnd( *this ); + m_pMesh = 0; + + m_IndexBuilder.AttachEndModify(); + m_VertexBuilder.AttachEndModify(); + +#ifdef _DEBUG + // Null out our pointers... + memset( (MeshDesc_t*)this, 0, sizeof(MeshDesc_t) ); +#endif +} + + +//----------------------------------------------------------------------------- +// Resets the mesh builder so it points to the start of everything again +//----------------------------------------------------------------------------- +inline void CMeshBuilder::Reset() +{ + m_IndexBuilder.Reset(); + m_VertexBuilder.Reset(); +} + + +//----------------------------------------------------------------------------- +// Selects the current Vertex and Index +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::SelectVertex( int nIndex ) +{ + m_VertexBuilder.SelectVertex( nIndex ); +} + +inline void CMeshBuilder::SelectVertexFromIndex( int idx ) +{ + // NOTE: This index is expected to be relative + int vertIdx = idx - m_nFirstVertex; + SelectVertex( vertIdx ); +} + +FORCEINLINE void CMeshBuilder::SelectIndex( int idx ) +{ + m_IndexBuilder.SelectIndex( idx ); +} + + +//----------------------------------------------------------------------------- +// Advances the current vertex and index by one +//----------------------------------------------------------------------------- +template FORCEINLINE void CMeshBuilder::AdvanceVertexF() +{ + m_VertexBuilder.AdvanceVertexF(); +} +FORCEINLINE void CMeshBuilder::AdvanceVertex() +{ + m_VertexBuilder.AdvanceVertex(); +} + +FORCEINLINE void CMeshBuilder::AdvanceVertices( int nVertexCount ) +{ + m_VertexBuilder.AdvanceVertices( nVertexCount ); +} + +FORCEINLINE void CMeshBuilder::AdvanceIndex() +{ + m_IndexBuilder.AdvanceIndex(); +} + +FORCEINLINE void CMeshBuilder::AdvanceIndices( int nIndices ) +{ + m_IndexBuilder.AdvanceIndices( nIndices ); +} + +FORCEINLINE int CMeshBuilder::GetCurrentVertex() +{ + return m_VertexBuilder.GetCurrentVertex(); +} + +FORCEINLINE int CMeshBuilder::GetCurrentIndex() +{ + return m_IndexBuilder.GetCurrentIndex(); +} + + +//----------------------------------------------------------------------------- +// A helper method since this seems to be done a whole bunch. +//----------------------------------------------------------------------------- +inline void CMeshBuilder::DrawQuad( IMesh* pMesh, const float* v1, const float* v2, + const float* v3, const float* v4, unsigned char const* pColor, bool wireframe ) +{ + if (!wireframe) + { + Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 ); + + Position3fv (v1); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v2); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v4); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v3); + Color4ubv( pColor ); + AdvanceVertexF(); + } + else + { + Begin( pMesh, MATERIAL_LINE_LOOP, 4 ); + Position3fv (v1); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v2); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v3); + Color4ubv( pColor ); + AdvanceVertexF(); + + Position3fv (v4); + Color4ubv( pColor ); + AdvanceVertexF(); + } + + End(); + pMesh->Draw(); +} + + +//----------------------------------------------------------------------------- +// returns the number of indices and vertices +//----------------------------------------------------------------------------- +FORCEINLINE int CMeshBuilder::VertexCount() const +{ + return m_VertexBuilder.VertexCount(); +} + +FORCEINLINE int CMeshBuilder::IndexCount() const +{ + return m_IndexBuilder.IndexCount(); +} + + +//----------------------------------------------------------------------------- +// Returns the base vertex memory pointer +//----------------------------------------------------------------------------- +FORCEINLINE void* CMeshBuilder::BaseVertexData() +{ + return m_VertexBuilder.BaseVertexData(); +} + +//----------------------------------------------------------------------------- +// Data retrieval... +//----------------------------------------------------------------------------- +FORCEINLINE const float* CMeshBuilder::Position() const +{ + return m_VertexBuilder.Position(); +} + +FORCEINLINE const float* CMeshBuilder::Normal() const +{ + return m_VertexBuilder.Normal(); +} + +FORCEINLINE unsigned int CMeshBuilder::Color() const +{ + return m_VertexBuilder.Color(); +} + +FORCEINLINE unsigned char *CMeshBuilder::Specular() const +{ + return m_VertexBuilder.Specular(); +} + +FORCEINLINE const float* CMeshBuilder::TexCoord( int nStage ) const +{ + return m_VertexBuilder.TexCoord( nStage ); +} + +FORCEINLINE const float* CMeshBuilder::TangentS() const +{ + return m_VertexBuilder.TangentS(); +} + +FORCEINLINE const float* CMeshBuilder::TangentT() const +{ + return m_VertexBuilder.TangentT(); +} + +FORCEINLINE float CMeshBuilder::Wrinkle() const +{ + return m_VertexBuilder.Wrinkle(); +} + +FORCEINLINE const float* CMeshBuilder::BoneWeight() const +{ + return m_VertexBuilder.BoneWeight(); +} + +FORCEINLINE int CMeshBuilder::NumBoneWeights() const +{ + return m_VertexBuilder.NumBoneWeights(); +} + +FORCEINLINE unsigned short const* CMeshBuilder::Index() const +{ + return m_IndexBuilder.Index(); +} + + +//----------------------------------------------------------------------------- +// Index +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::Index( unsigned short idx ) +{ + m_IndexBuilder.Index( idx ); +} + + +//----------------------------------------------------------------------------- +// Fast Index! No need to call advance index +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::FastIndex( unsigned short idx ) +{ + m_IndexBuilder.FastIndex( idx ); +} + +// NOTE: Use this one to get write combining! Much faster than the other version of FastIndex +// Fast Index! No need to call advance index, and no random access allowed +FORCEINLINE void CMeshBuilder::FastIndex2( unsigned short nIndex1, unsigned short nIndex2 ) +{ + m_IndexBuilder.FastIndex2( nIndex1, nIndex2 ); +} + +//----------------------------------------------------------------------------- +// For use with the FastVertex methods, advances the current vertex by N +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::FastAdvanceNVertices( int nVertexCount ) +{ + m_VertexBuilder.FastAdvanceNVertices( nVertexCount ); +} + + +//----------------------------------------------------------------------------- +// Fast Vertex! No need to call advance vertex, and no random access allowed +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::FastVertex( const ModelVertexDX7_t &vertex ) +{ + m_VertexBuilder.FastVertex( vertex ); +} + +FORCEINLINE void CMeshBuilder::FastVertexSSE( const ModelVertexDX7_t &vertex ) +{ + m_VertexBuilder.FastVertexSSE( vertex ); +} + +FORCEINLINE void CMeshBuilder::Fast4VerticesSSE( + const ModelVertexDX7_t *vtx_a, const ModelVertexDX7_t *vtx_b, + const ModelVertexDX7_t *vtx_c, const ModelVertexDX7_t *vtx_d ) +{ + m_VertexBuilder.Fast4VerticesSSE( vtx_a, vtx_b, vtx_c, vtx_d ); +} + +FORCEINLINE void CMeshBuilder::FastVertex( const ModelVertexDX8_t &vertex ) +{ + m_VertexBuilder.FastVertex( vertex ); +} + +FORCEINLINE void CMeshBuilder::FastVertexSSE( const ModelVertexDX8_t &vertex ) +{ + m_VertexBuilder.FastVertexSSE( vertex ); +} + +//----------------------------------------------------------------------------- +// Copies a vertex into the x360 format +//----------------------------------------------------------------------------- +#if defined( _X360 ) +inline void CMeshBuilder::VertexDX8ToX360( const ModelVertexDX8_t &vertex ) +{ + m_VertexBuilder.VertexDX8ToX360( vertex ); +} +#endif + +//----------------------------------------------------------------------------- +// Vertex field setting methods +//----------------------------------------------------------------------------- +FORCEINLINE void CMeshBuilder::Position3f( float x, float y, float z ) +{ + m_VertexBuilder.Position3f( x, y, z ); +} + +FORCEINLINE void CMeshBuilder::Position3fv( const float *v ) +{ + m_VertexBuilder.Position3fv( v ); +} + +FORCEINLINE void CMeshBuilder::Normal3f( float nx, float ny, float nz ) +{ + m_VertexBuilder.Normal3f( nx, ny, nz ); +} + +FORCEINLINE void CMeshBuilder::Normal3fv( const float *n ) +{ + m_VertexBuilder.Normal3fv( n ); +} + +FORCEINLINE void CMeshBuilder::NormalDelta3f( float nx, float ny, float nz ) +{ + m_VertexBuilder.NormalDelta3f( nx, ny, nz ); +} + +FORCEINLINE void CMeshBuilder::NormalDelta3fv( const float *n ) +{ + m_VertexBuilder.NormalDelta3fv( n ); +} + +FORCEINLINE void CMeshBuilder::Color3f( float r, float g, float b ) +{ + m_VertexBuilder.Color3f( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Color3fv( const float *rgb ) +{ + m_VertexBuilder.Color3fv( rgb ); +} + +FORCEINLINE void CMeshBuilder::Color4f( float r, float g, float b, float a ) +{ + m_VertexBuilder.Color4f( r, g ,b, a ); +} + +FORCEINLINE void CMeshBuilder::Color4fv( const float *rgba ) +{ + m_VertexBuilder.Color4fv( rgba ); +} + +FORCEINLINE void CMeshBuilder::Color3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + m_VertexBuilder.Color3ub( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Color3ubv( unsigned char const* rgb ) +{ + m_VertexBuilder.Color3ubv( rgb ); +} + +FORCEINLINE void CMeshBuilder::Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + m_VertexBuilder.Color4ub( r, g, b, a ); +} + +FORCEINLINE void CMeshBuilder::Color4ubv( unsigned char const* rgba ) +{ + m_VertexBuilder.Color4ubv( rgba ); +} + +FORCEINLINE void CMeshBuilder::Specular3f( float r, float g, float b ) +{ + m_VertexBuilder.Specular3f( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Specular3fv( const float *rgb ) +{ + m_VertexBuilder.Specular3fv( rgb ); +} + +FORCEINLINE void CMeshBuilder::Specular4f( float r, float g, float b, float a ) +{ + m_VertexBuilder.Specular4f( r, g, b, a ); +} + +FORCEINLINE void CMeshBuilder::Specular4fv( const float *rgba ) +{ + m_VertexBuilder.Specular4fv( rgba ); +} + +FORCEINLINE void CMeshBuilder::Specular3ub( unsigned char r, unsigned char g, unsigned char b ) +{ + m_VertexBuilder.Specular3ub( r, g, b ); +} + +FORCEINLINE void CMeshBuilder::Specular3ubv( unsigned char const *c ) +{ + m_VertexBuilder.Specular3ubv( c ); +} + +FORCEINLINE void CMeshBuilder::Specular4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a ) +{ + m_VertexBuilder.Specular4ub( r, g, b, a ); +} + +FORCEINLINE void CMeshBuilder::Specular4ubv( unsigned char const *c ) +{ + m_VertexBuilder.Specular4ubv( c ); +} + +FORCEINLINE void CMeshBuilder::TexCoord1f( int nStage, float s ) +{ + m_VertexBuilder.TexCoord1f( nStage, s ); +} + +FORCEINLINE void CMeshBuilder::TexCoord2f( int nStage, float s, float t ) +{ + m_VertexBuilder.TexCoord2f( nStage, s, t ); +} + +FORCEINLINE void CMeshBuilder::TexCoord2fv( int nStage, const float *st ) +{ + m_VertexBuilder.TexCoord2fv( nStage, st ); +} + +FORCEINLINE void CMeshBuilder::TexCoord3f( int nStage, float s, float t, float u ) +{ + m_VertexBuilder.TexCoord3f( nStage, s, t, u ); +} + +FORCEINLINE void CMeshBuilder::TexCoord3fv( int nStage, const float *stu ) +{ + m_VertexBuilder.TexCoord3fv( nStage, stu ); +} + +FORCEINLINE void CMeshBuilder::TexCoord4f( int nStage, float s, float t, float u, float v ) +{ + m_VertexBuilder.TexCoord4f( nStage, s, t, u, v ); +} + +FORCEINLINE void CMeshBuilder::TexCoord4fv( int nStage, const float *stuv ) +{ + m_VertexBuilder.TexCoord4fv( nStage, stuv ); +} + +FORCEINLINE void CMeshBuilder::TexCoordSubRect2f( int nStage, float s, float t, float offsetS, float offsetT, float scaleS, float scaleT ) +{ + m_VertexBuilder.TexCoordSubRect2f( nStage, s, t, offsetS, offsetT, scaleS, scaleT ); +} + +FORCEINLINE void CMeshBuilder::TexCoordSubRect2fv( int nStage, const float *st, const float *offset, const float *scale ) +{ + m_VertexBuilder.TexCoordSubRect2fv( nStage, st, offset, scale ); +} + +FORCEINLINE void CMeshBuilder::TangentS3f( float sx, float sy, float sz ) +{ + m_VertexBuilder.TangentS3f( sx, sy, sz ); +} + +FORCEINLINE void CMeshBuilder::TangentS3fv( const float* s ) +{ + m_VertexBuilder.TangentS3fv( s ); +} + +FORCEINLINE void CMeshBuilder::TangentT3f( float tx, float ty, float tz ) +{ + m_VertexBuilder.TangentT3f( tx, ty, tz ); +} + +FORCEINLINE void CMeshBuilder::TangentT3fv( const float* t ) +{ + m_VertexBuilder.TangentT3fv( t ); +} + +FORCEINLINE void CMeshBuilder::Wrinkle1f( float flWrinkle ) +{ + m_VertexBuilder.Wrinkle1f( flWrinkle ); +} + +FORCEINLINE void CMeshBuilder::BoneWeight( int nIndex, float flWeight ) +{ + m_VertexBuilder.BoneWeight( nIndex, flWeight ); +} + +template FORCEINLINE void CMeshBuilder::CompressedBoneWeight3fv( const float * pWeights ) +{ + m_VertexBuilder.CompressedBoneWeight3fv( pWeights ); +} + +FORCEINLINE void CMeshBuilder::BoneMatrix( int nIndex, int nMatrixIdx ) +{ + m_VertexBuilder.BoneMatrix( nIndex, nMatrixIdx ); +} + +FORCEINLINE void CMeshBuilder::UserData( const float* pData ) +{ + m_VertexBuilder.UserData( pData ); +} + +template FORCEINLINE void CMeshBuilder::CompressedUserData( const float* pData ) +{ + m_VertexBuilder.CompressedUserData( pData ); +} + +//----------------------------------------------------------------------------- +// Templatized vertex field setting methods which support compression +//----------------------------------------------------------------------------- + +template FORCEINLINE void CMeshBuilder::CompressedNormal3f( float nx, float ny, float nz ) +{ + m_VertexBuilder.CompressedNormal3f( nx, ny, nz ); +} + +template FORCEINLINE void CMeshBuilder::CompressedNormal3fv( const float *n ) +{ + m_VertexBuilder.CompressedNormal3fv( n ); +} + +#endif // IMESH_H diff --git a/mp/src/public/materialsystem/imorph.h b/mp/src/public/materialsystem/imorph.h new file mode 100644 index 00000000..45af7ee7 --- /dev/null +++ b/mp/src/public/materialsystem/imorph.h @@ -0,0 +1,251 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Interface used to construct morph buffers +//============================================================================= + +#ifndef IMORPH_H +#define IMORPH_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "mathlib/vector.h" +#include +#include "tier0/dbg.h" +#include "materialsystem/imaterial.h" + + +//----------------------------------------------------------------------------- +// Single morph data +//----------------------------------------------------------------------------- +struct MorphVertexInfo_t +{ + int m_nVertexId; // What vertex is this going to affect? + int m_nMorphTargetId; // What morph did it come from? + Vector m_PositionDelta; // Positional morph delta + Vector m_NormalDelta; // Normal morph delta + float m_flWrinkleDelta; // Wrinkle morph delta + float m_flSpeed; + float m_flSide; +}; + + +//----------------------------------------------------------------------------- +// Morph weight data +//----------------------------------------------------------------------------- +enum MorphWeightType_t +{ + MORPH_WEIGHT = 0, + MORPH_WEIGHT_LAGGED, + MORPH_WEIGHT_STEREO, + MORPH_WEIGHT_STEREO_LAGGED, + + MORPH_WEIGHT_COUNT, +}; + +struct MorphWeight_t +{ + float m_pWeight[MORPH_WEIGHT_COUNT]; +}; + + +//----------------------------------------------------------------------------- +// Interface to the morph +//----------------------------------------------------------------------------- +abstract_class IMorph +{ +public: + // Locks the morph, destroys any existing contents + virtual void Lock( float flFloatToFixedScale = 1.0f ) = 0; + + // Adds a morph + virtual void AddMorph( const MorphVertexInfo_t &info ) = 0; + + // Unlocks the morph + virtual void Unlock( ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Morph builders +//----------------------------------------------------------------------------- +class CMorphBuilder +{ +public: + CMorphBuilder(); + ~CMorphBuilder(); + + // Start building the morph + void Begin( IMorph *pMorph, float flFloatToFixedScale = 1.0f ); + + // End building the morph + void End(); + + void PositionDelta3fv( const float *pDelta ); + void PositionDelta3f( float dx, float dy, float dz ); + void PositionDelta3( const Vector &vec ); + + void NormalDelta3fv( const float *pDelta ); + void NormalDelta3f( float dx, float dy, float dz ); + void NormalDelta3( const Vector &vec ); + + void WrinkleDelta1f( float flWrinkle ); + + // Both are 0-1 values indicating which morph target to use (for stereo morph targets) + // and how much to blend between using lagged weights vs actual weights + // Speed: 0 - use lagged, 1 - use actual + void Speed1f( float flSpeed ); + void Side1f( float flSide ); + + void AdvanceMorph( int nSourceVertex, int nMorphTargetId ); + +private: + MorphVertexInfo_t m_Info; + IMorph *m_pMorph; +}; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +inline CMorphBuilder::CMorphBuilder() +{ + m_pMorph = NULL; +} + +inline CMorphBuilder::~CMorphBuilder() +{ + // You forgot to call End()! + Assert( !m_pMorph ); +} + + +//----------------------------------------------------------------------------- +// Start building the morph +//----------------------------------------------------------------------------- +inline void CMorphBuilder::Begin( IMorph *pMorph, float flFloatToFixedScale ) +{ + Assert( pMorph && !m_pMorph ); + m_pMorph = pMorph; + m_pMorph->Lock( flFloatToFixedScale ); + +#ifdef _DEBUG + m_Info.m_PositionDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_NormalDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_flWrinkleDelta = VEC_T_NAN; + m_Info.m_flSpeed = VEC_T_NAN; + m_Info.m_flSide = VEC_T_NAN; +#endif +} + +// End building the morph +inline void CMorphBuilder::End() +{ + Assert( m_pMorph ); + m_pMorph->Unlock(); + m_pMorph = NULL; +} + + +//----------------------------------------------------------------------------- +// Set position delta +//----------------------------------------------------------------------------- +inline void CMorphBuilder::PositionDelta3fv( const float *pDelta ) +{ + Assert( m_pMorph ); + m_Info.m_PositionDelta.Init( pDelta[0], pDelta[1], pDelta[2] ); +} + +inline void CMorphBuilder::PositionDelta3f( float dx, float dy, float dz ) +{ + Assert( m_pMorph ); + m_Info.m_PositionDelta.Init( dx, dy, dz ); +} + +inline void CMorphBuilder::PositionDelta3( const Vector &vec ) +{ + Assert( m_pMorph ); + m_Info.m_PositionDelta = vec; +} + + +//----------------------------------------------------------------------------- +// Set normal delta +//----------------------------------------------------------------------------- +inline void CMorphBuilder::NormalDelta3fv( const float *pDelta ) +{ + Assert( m_pMorph ); + m_Info.m_NormalDelta.Init( pDelta[0], pDelta[1], pDelta[2] ); +} + +inline void CMorphBuilder::NormalDelta3f( float dx, float dy, float dz ) +{ + Assert( m_pMorph ); + m_Info.m_NormalDelta.Init( dx, dy, dz ); +} + +inline void CMorphBuilder::NormalDelta3( const Vector &vec ) +{ + Assert( m_pMorph ); + m_Info.m_NormalDelta = vec; +} + + +//----------------------------------------------------------------------------- +// Set wrinkle delta +//----------------------------------------------------------------------------- +inline void CMorphBuilder::WrinkleDelta1f( float flWrinkle ) +{ + Assert( m_pMorph ); + m_Info.m_flWrinkleDelta = flWrinkle; +} + + +//----------------------------------------------------------------------------- +// Set speed,side data +//----------------------------------------------------------------------------- +inline void CMorphBuilder::Speed1f( float flSpeed ) +{ + Assert( m_pMorph ); + m_Info.m_flSpeed = flSpeed; +} + +inline void CMorphBuilder::Side1f( float flSide ) +{ + Assert( m_pMorph ); + m_Info.m_flSide = flSide; +} + + +//----------------------------------------------------------------------------- +// Advance morph +//----------------------------------------------------------------------------- +inline void CMorphBuilder::AdvanceMorph( int nSourceVertex, int nMorphTargetId ) +{ + Assert( m_pMorph ); + + m_Info.m_nVertexId = nSourceVertex; + m_Info.m_nMorphTargetId = nMorphTargetId; + + m_pMorph->AddMorph( m_Info ); + +#ifdef _DEBUG + m_Info.m_PositionDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_NormalDelta.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); + m_Info.m_flWrinkleDelta = VEC_T_NAN; + m_Info.m_flSpeed = VEC_T_NAN; + m_Info.m_flSide = VEC_T_NAN; +#endif +} + + +#endif // IMORPH_H diff --git a/mp/src/public/materialsystem/ishaderapi.h b/mp/src/public/materialsystem/ishaderapi.h new file mode 100644 index 00000000..5db40666 --- /dev/null +++ b/mp/src/public/materialsystem/ishaderapi.h @@ -0,0 +1,43 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: NOTE: This file is for backward compat! +// We'll get rid of it soon. Most of the contents of this file were moved +// into shaderpi/ishadershadow.h, shaderapi/ishaderdynamic.h, or +// shaderapi/shareddefs.h +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ISHADERAPI_MS_H +#define ISHADERAPI_MS_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + + +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- +class IMaterialVar; + + +//----------------------------------------------------------------------------- +// Methods that can be called from the SHADER_INIT blocks of shaders +//----------------------------------------------------------------------------- +abstract_class IShaderInit +{ +public: + // Loads up a texture + virtual void LoadTexture( IMaterialVar *pTextureVar, const char *pTextureGroupName, int nAdditionalCreationFlags = 0 ) = 0; + virtual void LoadBumpMap( IMaterialVar *pTextureVar, const char *pTextureGroupName ) = 0; + virtual void LoadCubeMap( IMaterialVar **ppParams, IMaterialVar *pTextureVar, int nAdditionalCreationFlags = 0 ) = 0; +}; + + +#endif // ISHADERAPI_MS_H diff --git a/mp/src/public/materialsystem/itexture.h b/mp/src/public/materialsystem/itexture.h new file mode 100644 index 00000000..35da645b --- /dev/null +++ b/mp/src/public/materialsystem/itexture.h @@ -0,0 +1,132 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef ITEXTURE_H +#define ITEXTURE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "bitmap/imageformat.h" // ImageFormat defn. + +class IVTFTexture; +class ITexture; +struct Rect_t; + +//----------------------------------------------------------------------------- +// This will get called on procedural textures to re-fill the textures +// with the appropriate bit pattern. Calling Download() will also +// cause this interface to be called. It will also be called upon +// mode switch, or on other occasions where the bits are discarded. +//----------------------------------------------------------------------------- +abstract_class ITextureRegenerator +{ +public: + // This will be called when the texture bits need to be regenerated. + // Use the VTFTexture interface, which has been set up with the + // appropriate texture size + format + // The rect specifies which part of the texture needs to be updated + // You can choose to update all of the bits if you prefer + virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect ) = 0; + + // This will be called when the regenerator needs to be deleted + // which will happen when the texture is destroyed + virtual void Release() = 0; +}; + +abstract_class ITexture +{ +public: + // Various texture polling methods + virtual const char *GetName( void ) const = 0; + virtual int GetMappingWidth() const = 0; + virtual int GetMappingHeight() const = 0; + virtual int GetActualWidth() const = 0; + virtual int GetActualHeight() const = 0; + virtual int GetNumAnimationFrames() const = 0; + virtual bool IsTranslucent() const = 0; + virtual bool IsMipmapped() const = 0; + + virtual void GetLowResColorSample( float s, float t, float *color ) const = 0; + + // Gets texture resource data of the specified type. + // Params: + // eDataType type of resource to retrieve. + // pnumBytes on return is the number of bytes available in the read-only data buffer or is undefined + // Returns: + // pointer to the resource data, or NULL + virtual void *GetResourceData( uint32 eDataType, size_t *pNumBytes ) const = 0; + + // Methods associated with reference count + virtual void IncrementReferenceCount( void ) = 0; + virtual void DecrementReferenceCount( void ) = 0; + + inline void AddRef() { IncrementReferenceCount(); } + inline void Release() { DecrementReferenceCount(); } + + // Used to modify the texture bits (procedural textures only) + virtual void SetTextureRegenerator( ITextureRegenerator *pTextureRegen ) = 0; + + // Reconstruct the texture bits in HW memory + + // If rect is not specified, reconstruct all bits, otherwise just + // reconstruct a subrect. + virtual void Download( Rect_t *pRect = 0, int nAdditionalCreationFlags = 0 ) = 0; + + // Uses for stats. . .get the approximate size of the texture in it's current format. + virtual int GetApproximateVidMemBytes( void ) const = 0; + + // Returns true if the texture data couldn't be loaded. + virtual bool IsError() const = 0; + + // NOTE: Stuff after this is added after shipping HL2. + + // For volume textures + virtual bool IsVolumeTexture() const = 0; + virtual int GetMappingDepth() const = 0; + virtual int GetActualDepth() const = 0; + + virtual ImageFormat GetImageFormat() const = 0; + virtual NormalDecodeMode_t GetNormalDecodeMode() const = 0; + + // Various information about the texture + virtual bool IsRenderTarget() const = 0; + virtual bool IsCubeMap() const = 0; + virtual bool IsNormalMap() const = 0; + virtual bool IsProcedural() const = 0; + + virtual void DeleteIfUnreferenced() = 0; + +#if defined( _X360 ) + virtual bool ClearTexture( int r, int g, int b, int a ) = 0; + virtual bool CreateRenderTargetSurface( int width, int height, ImageFormat format, bool bSameAsTexture ) = 0; +#endif + + // swap everything except the name with another texture + virtual void SwapContents( ITexture *pOther ) = 0; + + // Retrieve the vtf flags mask + virtual unsigned int GetFlags( void ) const = 0; + + // Force LOD override (automatically downloads the texture) + virtual void ForceLODOverride( int iNumLodsOverrideUpOrDown ) = 0; + + // Save texture to a file. + virtual bool SaveToFile( const char *fileName ) = 0; +}; + + +inline bool IsErrorTexture( ITexture *pTex ) +{ + return !pTex || pTex->IsError(); +} + + +#endif // ITEXTURE_H diff --git a/mp/src/public/materialsystem/ivballoctracker.h b/mp/src/public/materialsystem/ivballoctracker.h new file mode 100644 index 00000000..dfd723c9 --- /dev/null +++ b/mp/src/public/materialsystem/ivballoctracker.h @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: tracks VB allocations (and compressed/uncompressed vertex memory usage) +// +//===========================================================================// + +#ifndef IVBALLOCTRACKER_H +#define IVBALLOCTRACKER_H + +#include "materialsystem/imaterialsystem.h" + +// By default, only enable this alloc tracking for a debug shaderapidx*.dll +// (it uses about 0.25MB to track ~7000 allocations) +#if defined(_DEBUG) +#define ENABLE_VB_ALLOC_TRACKER 1 +#else +#define ENABLE_VB_ALLOC_TRACKER 0 +#endif + +// This interface is actually exported by the shader API DLL. +#define VB_ALLOC_TRACKER_INTERFACE_VERSION "VBAllocTracker001" + +// Interface to the VB mem alloc tracker +abstract_class IVBAllocTracker +{ +public: + // This should be called wherever VertexBuffers are allocated + virtual void CountVB( void * buffer, bool isDynamic, int bufferSize, int vertexSize, VertexFormat_t fmt ) = 0; + // This should be called wherever VertexBuffers are freed + virtual void UnCountVB( void * buffer ) = 0; + // Track mesh allocations (set this before an allocation, clear it after) + virtual bool TrackMeshAllocations( const char * allocatorName ) = 0; +}; + +#endif // IVBALLOCTRACKER_H diff --git a/mp/src/public/materialsystem/materialsystem_config.h b/mp/src/public/materialsystem/materialsystem_config.h new file mode 100644 index 00000000..1cdca782 --- /dev/null +++ b/mp/src/public/materialsystem/materialsystem_config.h @@ -0,0 +1,219 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef MATERIALSYSTEM_CONFIG_H +#define MATERIALSYSTEM_CONFIG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "materialsystem/imaterialsystem.h" + +#define MATERIALSYSTEM_CONFIG_VERSION "VMaterialSystemConfig002" + +enum MaterialSystem_Config_Flags_t +{ + MATSYS_VIDCFG_FLAGS_WINDOWED = ( 1 << 0 ), + MATSYS_VIDCFG_FLAGS_RESIZING = ( 1 << 1 ), + MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC = ( 1 << 3 ), + MATSYS_VIDCFG_FLAGS_STENCIL = ( 1 << 4 ), + MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR = ( 1 << 5 ), + MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC = ( 1 << 6 ), + MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR = ( 1 << 7 ), + MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP = ( 1 << 8 ), + MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING = ( 1 << 9 ), + MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL = ( 1 << 10 ), + MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE = ( 1 << 11 ), + MATSYS_VIDCFG_FLAGS_ENABLE_HDR = ( 1 << 12 ), + MATSYS_VIDCFG_FLAGS_LIMIT_WINDOWED_SIZE = ( 1 << 13 ), + MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION = ( 1 << 14 ), + MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS = ( 1 << 15 ), +}; + +struct MaterialSystemHardwareIdentifier_t +{ + char *m_pCardName; + unsigned int m_nVendorID; + unsigned int m_nDeviceID; +}; + +struct MaterialSystem_Config_t +{ + bool Windowed() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_WINDOWED ) != 0; } + bool Resizing() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_RESIZING ) != 0; } +#ifdef CSS_PERF_TEST + bool WaitForVSync() const { return false; }//( m_Flags & MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC ) == 0; } +#else + bool WaitForVSync() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC ) == 0; } +#endif + bool Stencil() const { return (m_Flags & MATSYS_VIDCFG_FLAGS_STENCIL ) != 0; } + bool ForceTrilinear() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR ) != 0; } + bool ForceHWSync() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC ) != 0; } + bool UseSpecular() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR ) == 0; } + bool UseBumpmapping() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP ) == 0; } + bool UseParallaxMapping() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING ) != 0; } + bool UseZPrefill() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL ) != 0; } + bool ReduceFillrate() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE ) != 0; } + bool HDREnabled() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_ENABLE_HDR ) != 0; } + bool LimitWindowedSize() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_LIMIT_WINDOWED_SIZE ) != 0; } + bool ScaleToOutputResolution() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION ) != 0; } + bool UsingMultipleWindows() const { return ( m_Flags & MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS ) != 0; } + bool ShadowDepthTexture() const { return m_bShadowDepthTexture; } + bool MotionBlur() const { return m_bMotionBlur; } + bool SupportFlashlight() const { return m_bSupportFlashlight; } + + void SetFlag( unsigned int flag, bool val ) + { + if( val ) + { + m_Flags |= flag; + } + else + { + m_Flags &= ~flag; + } + } + + // control panel stuff + MaterialVideoMode_t m_VideoMode; + float m_fMonitorGamma; + float m_fGammaTVRangeMin; + float m_fGammaTVRangeMax; + float m_fGammaTVExponent; + bool m_bGammaTVEnabled; + + int m_nAASamples; + int m_nForceAnisotropicLevel; + int skipMipLevels; + int dxSupportLevel; + unsigned int m_Flags; + bool bEditMode; // true if in Hammer. + unsigned char proxiesTestMode; // 0 = normal, 1 = no proxies, 2 = alpha test all, 3 = color mod all + bool bCompressedTextures; + bool bFilterLightmaps; + bool bFilterTextures; + bool bReverseDepth; + bool bBufferPrimitives; + bool bDrawFlat; + bool bMeasureFillRate; + bool bVisualizeFillRate; + bool bNoTransparency; + bool bSoftwareLighting; + bool bAllowCheats; + char nShowMipLevels; + bool bShowLowResImage; + bool bShowNormalMap; + bool bMipMapTextures; + unsigned char nFullbright; + bool m_bFastNoBump; + bool m_bSuppressRendering; + + // debug modes + bool bShowSpecular; // This is the fast version that doesn't require reloading materials + bool bShowDiffuse; // This is the fast version that doesn't require reloading materials + + // misc + int m_nReserved; // Currently unused + + // No depth bias + float m_SlopeScaleDepthBias_Normal; + float m_DepthBias_Normal; + + // Depth bias for rendering decals closer to the camera + float m_SlopeScaleDepthBias_Decal; + float m_DepthBias_Decal; + + // Depth bias for biasing shadow depth map rendering away from the camera + float m_SlopeScaleDepthBias_ShadowMap; + float m_DepthBias_ShadowMap; + + uint m_WindowedSizeLimitWidth; + uint m_WindowedSizeLimitHeight; + int m_nAAQuality; + bool m_bShadowDepthTexture; + bool m_bMotionBlur; + bool m_bSupportFlashlight; + + MaterialSystem_Config_t() + { + memset( this, 0, sizeof( *this ) ); + + // video config defaults + SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_NO_WAIT_FOR_VSYNC, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_STENCIL, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_FORCE_TRILINEAR, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_FORCE_HWSYNC, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_SPECULAR, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_ENABLE_PARALLAX_MAPPING, true ); + SetFlag( MATSYS_VIDCFG_FLAGS_USE_Z_PREFILL, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_REDUCE_FILLRATE, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_LIMIT_WINDOWED_SIZE, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_SCALE_TO_OUTPUT_RESOLUTION, false ); + SetFlag( MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS, false ); + + m_VideoMode.m_Width = 640; + m_VideoMode.m_Height = 480; + m_VideoMode.m_RefreshRate = 60; + dxSupportLevel = 0; + bCompressedTextures = true; + bFilterTextures = true; + bFilterLightmaps = true; + bMipMapTextures = true; + bBufferPrimitives = true; + + m_fMonitorGamma = 2.2f; + m_fGammaTVRangeMin = 16.0f; + m_fGammaTVRangeMax = 255.0f; + m_fGammaTVExponent = 2.5; + m_bGammaTVEnabled = IsX360(); + + m_nAASamples = 1; + m_bShadowDepthTexture = false; + m_bMotionBlur = false; + m_bSupportFlashlight = true; + + // misc defaults + bAllowCheats = false; + bCompressedTextures = true; + bEditMode = false; + + // debug modes + bShowSpecular = true; + bShowDiffuse = true; + nFullbright = 0; + bShowNormalMap = false; + bFilterLightmaps = true; + bFilterTextures = true; + bMipMapTextures = true; + nShowMipLevels = 0; + bShowLowResImage = false; + bReverseDepth = false; + bBufferPrimitives = true; + bDrawFlat = false; + bMeasureFillRate = false; + bVisualizeFillRate = false; + bSoftwareLighting = false; + bNoTransparency = false; + proxiesTestMode = 0; + m_bFastNoBump = false; + m_bSuppressRendering = false; + m_SlopeScaleDepthBias_Decal = -0.5f; + m_SlopeScaleDepthBias_Normal = 0.0f; + m_SlopeScaleDepthBias_ShadowMap = 0.5f; + m_DepthBias_Decal = -262144; + m_DepthBias_Normal = 0.0f; + m_DepthBias_ShadowMap = 262144; + m_WindowedSizeLimitWidth = 1280; + m_WindowedSizeLimitHeight = 1024; + } +}; + + +#endif // MATERIALSYSTEM_CONFIG_H diff --git a/mp/src/public/materialsystem/meshreader.h b/mp/src/public/materialsystem/meshreader.h new file mode 100644 index 00000000..7bfd80e2 --- /dev/null +++ b/mp/src/public/materialsystem/meshreader.h @@ -0,0 +1,268 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#ifndef MESHREADER_H +#define MESHREADER_H + +#ifdef _WIN32 +#pragma once +#endif + + +//----------------------------------------------------------------------------- +// This is used to read vertex and index data out of already-created meshes. +// xbox uses this a lot so it doesn't have to store sysmem backups of the +// vertex data. +//----------------------------------------------------------------------------- +class CBaseMeshReader : protected MeshDesc_t +{ +// Initialization. +public: + + CBaseMeshReader(); + ~CBaseMeshReader(); + + // Use BeginRead/EndRead to initialize the mesh reader. + void BeginRead( + IMesh* pMesh, + int firstVertex = 0, + int numVertices = 0, + int firstIndex = 0, + int numIndices = 0 ); + + void EndRead(); + + // PC can use this if it stores its own copy of meshes around, in case + // locking static buffers is too costly. + void BeginRead_Direct( const MeshDesc_t &desc, int numVertices, int nIndices ); + + // Resets the mesh builder so it points to the start of everything again + void Reset(); + + +protected: + IMesh *m_pMesh; + int m_MaxVertices; + int m_MaxIndices; +}; + + +// A bunch of accessors for the data that CBaseMeshReader sets up. +class CMeshReader : public CBaseMeshReader +{ +public: +// Access to vertex data. +public: + int NumIndices() const; + unsigned short Index( int index ) const; + + const Vector& Position( int iVertex ) const; + + unsigned int Color( int iVertex ) const; + + const float *TexCoord( int iVertex, int stage ) const; + void TexCoord2f( int iVertex, int stage, float &s, float &t ) const; + const Vector2D& TexCoordVector2D( int iVertex, int stage ) const; + + int NumBoneWeights() const; + float Wrinkle( int iVertex ) const; + + const Vector &Normal( int iVertex ) const; + void Normal( int iVertex, Vector &vNormal ) const; + + const Vector &TangentS( int iVertex ) const; + const Vector &TangentT( int iVertex ) const; + float BoneWeight( int iVertex ) const; + +#ifdef NEW_SKINNING + float* BoneMatrix( int iVertex ) const; +#else + unsigned char* BoneMatrix( int iVertex ) const; +#endif +}; + + +//----------------------------------------------------------------------------- +// CBaseMeshReader implementation. +//----------------------------------------------------------------------------- + +inline CBaseMeshReader::CBaseMeshReader() +{ + m_pMesh = NULL; +} + +inline CBaseMeshReader::~CBaseMeshReader() +{ + Assert( !m_pMesh ); +} + +inline void CBaseMeshReader::BeginRead( + IMesh* pMesh, + int firstVertex, + int numVertices, + int firstIndex, + int numIndices ) +{ + Assert( pMesh && (!m_pMesh) ); + + if ( numVertices < 0 ) + { + numVertices = pMesh->VertexCount(); + } + + if ( numIndices < 0 ) + { + numIndices = pMesh->IndexCount(); + } + + m_pMesh = pMesh; + m_MaxVertices = numVertices; + m_MaxIndices = numIndices; + + // UNDONE: support reading from compressed VBs if needed + VertexCompressionType_t compressionType = CompressionType( pMesh->GetVertexFormat() ); + Assert( compressionType == VERTEX_COMPRESSION_NONE ); + if ( compressionType != VERTEX_COMPRESSION_NONE ) + { + Warning( "Cannot use CBaseMeshReader with compressed vertices! Will get junk data or a crash.\n" ); + } + + // Locks mesh for modifying + pMesh->ModifyBeginEx( true, firstVertex, numVertices, firstIndex, numIndices, *this ); + + // Point to the start of the buffers.. + Reset(); +} + +inline void CBaseMeshReader::EndRead() +{ + Assert( m_pMesh ); + m_pMesh->ModifyEnd( *this ); + m_pMesh = NULL; +} + +inline void CBaseMeshReader::BeginRead_Direct( const MeshDesc_t &desc, int nVertices, int nIndices ) +{ + MeshDesc_t *pThis = this; + *pThis = desc; + m_MaxVertices = nVertices; + m_MaxIndices = nIndices; + + // UNDONE: support reading from compressed verts if necessary + Assert( desc.m_CompressionType == VERTEX_COMPRESSION_NONE ); + if ( desc.m_CompressionType != VERTEX_COMPRESSION_NONE ) + { + Warning( "Cannot use CBaseMeshReader with compressed vertices!\n" ); + } +} + +inline void CBaseMeshReader::Reset() +{ +} + + + + +// -------------------------------------------------------------------------------------- // +// CMeshReader implementation. +// -------------------------------------------------------------------------------------- // + +inline int CMeshReader::NumIndices() const +{ + return m_MaxIndices; +} + +inline unsigned short CMeshReader::Index( int index ) const +{ + Assert( (index >= 0) && (index < m_MaxIndices) ); + return m_pIndices[index * m_nIndexSize]; +} + +inline const Vector& CMeshReader::Position( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(Vector*)((char*)m_pPosition + iVertex * m_VertexSize_Position); +} + +inline unsigned int CMeshReader::Color( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + unsigned char *pColor = m_pColor + iVertex * m_VertexSize_Color; + return (pColor[0] << 16) | (pColor[1] << 8) | (pColor[2]) | (pColor[3] << 24); +} + +inline const float *CMeshReader::TexCoord( int iVertex, int iStage ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return (float*)( (char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage] ); +} + +inline void CMeshReader::TexCoord2f( int iVertex, int iStage, float &s, float &t ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + float *p = (float*)( (char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage] ); + s = p[0]; + t = p[1]; +} + +inline const Vector2D& CMeshReader::TexCoordVector2D( int iVertex, int iStage ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + Vector2D *p = (Vector2D*)( (char*)m_pTexCoord[iStage] + iVertex * m_VertexSize_TexCoord[iStage] ); + return *p; +} + +inline float CMeshReader::Wrinkle( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(float*)( (char*)m_pWrinkle + iVertex * m_VertexSize_Wrinkle ); +} + +inline int CMeshReader::NumBoneWeights() const +{ + return m_NumBoneWeights; +} + +inline const Vector &CMeshReader::Normal( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(const Vector *)(const float*)( (char*)m_pNormal + iVertex * m_VertexSize_Normal ); +} + +inline void CMeshReader::Normal( int iVertex, Vector &vNormal ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + const float *p = (const float*)( (char*)m_pNormal + iVertex * m_VertexSize_Normal ); + vNormal.Init( p[0], p[1], p[2] ); +} + +inline const Vector &CMeshReader::TangentS( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(const Vector*)( (char*)m_pTangentS + iVertex * m_VertexSize_TangentS ); +} + +inline const Vector &CMeshReader::TangentT( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + return *(const Vector*)( (char*)m_pTangentT + iVertex * m_VertexSize_TangentT ); +} + +inline float CMeshReader::BoneWeight( int iVertex ) const +{ + Assert( iVertex >= 0 && iVertex < m_MaxVertices ); + float *p = (float*)( (char*)m_pBoneWeight + iVertex * m_VertexSize_BoneWeight ); + return *p; +} + +#endif // MESHREADER_H + + + + + + + diff --git a/mp/src/public/materialsystem/shader_vcs_version.h b/mp/src/public/materialsystem/shader_vcs_version.h new file mode 100644 index 00000000..ed2c8c71 --- /dev/null +++ b/mp/src/public/materialsystem/shader_vcs_version.h @@ -0,0 +1,75 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SHADER_VCS_VERSION_H +#define SHADER_VCS_VERSION_H +#ifdef _WIN32 +#pragma once +#endif + +// 1 = hl2 shipped +// 2 = compressed with diffs version (lostcoast) +// 3 = compressed with bzip +// 4 = v2 + crc32 +// 5 = v3 + crc32 +// 6 = v5 + duplicate static combo records +#define SHADER_VCS_VERSION_NUMBER 6 + +#define MAX_SHADER_UNPACKED_BLOCK_SIZE (1<<17) +#define MAX_SHADER_PACKED_SIZE (1+MAX_SHADER_UNPACKED_BLOCK_SIZE) + +#pragma pack(1) +struct ShaderHeader_t +{ + int32 m_nVersion; + int32 m_nTotalCombos; + int32 m_nDynamicCombos; + uint32 m_nFlags; + uint32 m_nCentroidMask; + uint32 m_nNumStaticCombos; // includes sentinal key + uint32 m_nSourceCRC32; // NOTE: If you move this, update copyshaders.pl, *_prep.pl, updateshaders.pl +}; +#pragma pack() + +#pragma pack(1) +struct ShaderHeader_t_v4 // still used for assembly shaders +{ + int32 m_nVersion; + int32 m_nTotalCombos; + int32 m_nDynamicCombos; + uint32 m_nFlags; + uint32 m_nCentroidMask; + uint32 m_nDiffReferenceSize; + uint32 m_nSourceCRC32; // NOTE: If you move this, update copyshaders.pl, *_prep.pl, updateshaders.pl +}; +#pragma pack() + +// for old format files +struct ShaderDictionaryEntry_t +{ + int m_Offset; + int m_Size; +}; + +// record for one static combo +struct StaticComboRecord_t +{ + uint32 m_nStaticComboID; + uint32 m_nFileOffset; +}; + + +struct StaticComboAliasRecord_t // for duplicate static combos +{ + uint32 m_nStaticComboID; // this combo + uint32 m_nSourceStaticCombo; // the combo it is the same as +}; + + + + +#endif // SHADER_VCS_VERSION_H + -- cgit v1.2.3