/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : WW3D * * * * $Archive:: /Commando/Code/ww3d2/meshmatdesc.h $* * * * Original Author:: Greg Hjelstrom * * * * $Author:: Greg_h $* * * * $Modtime:: 1/18/02 3:08p $* * * * $Revision:: 14 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #ifndef MESHMATDESC_H #define MESHMATDESC_H #include "always.h" #include "vector2.h" #include "vector3.h" #include "vector3i.h" #include "vector4.h" #include "sharebuf.h" #include "shader.h" #include "vertmaterial.h" class MatBufferClass; class TexBufferClass; class UVBufferClass; class TextureClass; class MeshModelClass; /** ** MeshMatDescClass - This class encapsulates all of the material description data for a mesh. ** WARNING: The vertex count and polygon count *MUST* be kept in sync with the mesh */ class MeshMatDescClass { public: enum { MAX_PASSES = 4, MAX_TEX_STAGES = 2, MAX_COLOR_ARRAYS = 2, MAX_UV_ARRAYS = MAX_PASSES * MAX_TEX_STAGES }; MeshMatDescClass(void); MeshMatDescClass(const MeshMatDescClass & that); ~MeshMatDescClass(void); void Reset(int polycount,int vertcount,int passcount); MeshMatDescClass & operator = (const MeshMatDescClass & that); /* ** Initialize the alternate material description by copying the default materials ** and overriding the entries that exist in the alternate_desc */ void Init_Alternate(MeshMatDescClass & def_mat_desc,MeshMatDescClass & alternate_desc); bool Is_Empty(void); /* ** Counts, make sure the vertex and polygon counts match the parent mesh. */ void Set_Pass_Count(int passes) { PassCount = passes; } int Get_Pass_Count(void) const { return PassCount; } void Set_Vertex_Count(int vertcount) { VertexCount = vertcount; } int Get_Vertex_Count(void) const { return VertexCount; } void Set_Polygon_Count(int polycount) { PolyCount = polycount; } int Get_Polygon_Count(void) const { return PolyCount; } /* ** Material Interface */ Vector2 * Get_UV_Array(int pass,int stage); void Install_UV_Array(int pass,int stage,Vector2 * uvs,int count); void Set_UV_Source(int pass,int stage,int sourceindex); int Get_UV_Source(int pass,int stage); int Get_UV_Array_Count(void); Vector2 * Get_UV_Array_By_Index(int index, bool create = true); unsigned* Get_DCG_Array(int pass); unsigned* Get_DIG_Array(int pass); void Set_DCG_Source(int pass,VertexMaterialClass::ColorSourceType source); void Set_DIG_Source(int pass,VertexMaterialClass::ColorSourceType source); VertexMaterialClass::ColorSourceType Get_DCG_Source(int pass); VertexMaterialClass::ColorSourceType Get_DIG_Source(int pass); unsigned * Get_Color_Array(int array,bool create = true); void Set_Single_Material(VertexMaterialClass * vmat,int pass=0); void Set_Single_Texture(TextureClass * tex,int pass=0,int stage=0); void Set_Single_Shader(ShaderClass shader,int pass=0); /* ** the "Get" functions add a reference before returning the pointer (if appropriate) */ VertexMaterialClass * Get_Single_Material(int pass=0) const; TextureClass * Get_Single_Texture(int pass=0,int stage=0) const; ShaderClass Get_Single_Shader(int pass=0) const; /* ** the "Peek" functions just return the pointer and it's the caller's responsibility to ** maintain a reference to an object with a reference to the data */ VertexMaterialClass * Peek_Single_Material(int pass=0) const; TextureClass * Peek_Single_Texture(int pass=0,int stage=0) const; void Set_Material(int vidx,VertexMaterialClass * vmat,int pass=0); void Set_Shader(int pidx,ShaderClass shader,int pass=0); void Set_Texture(int pidx,TextureClass * tex,int pass=0,int stage=0); /* ** Queries for determining whether this model has per-polygon arrays of Materials, Shaders, or Textures */ bool Has_Material_Array(int pass) const; bool Has_Shader_Array(int pass) const; bool Has_Texture_Array(int pass,int stage) const; /* ** Determine whether this material description contains data for the specified category */ bool Has_UV(int pass,int stage) { return UVSource[pass][stage] != -1; } bool Has_Color_Array(int array) { return ColorArray[array] != NULL; } bool Has_Texture_Data(int pass,int stage) { return (Texture[pass][stage] != NULL) || (TextureArray[pass][stage] != NULL); } bool Has_Shader_Data(int pass) { return (Shader[pass] != NullShader) || (ShaderArray[pass] != NULL); } bool Has_Material_Data(int pass) { return (Material[pass] != NULL) || (MaterialArray[pass] != NULL); } /* ** "Get" functions for Materials, Textures, and Shaders when there are more than one (per-polygon or per-vertex) */ VertexMaterialClass * Get_Material(int vidx,int pass=0) const; TextureClass * Get_Texture(int pidx,int pass=0,int stage=0) const; ShaderClass Get_Shader(int pidx,int pass=0) const; /* ** "Peek" functions for Materials and Textures when there are more than one (per-polygon or per-vertex) */ VertexMaterialClass * Peek_Material(int vidx,int pass=0) const; TextureClass * Peek_Texture(int pidx,int pass=0,int stage=0) const; /* ** Access to the arrays */ TexBufferClass * Get_Texture_Array(int pass,int stage,bool create = true); MatBufferClass * Get_Material_Array(int pass,bool create = true); ShaderClass * Get_Shader_Array(int pass,bool create = true); void Make_UV_Array_Unique(int pass,int stage); void Make_Color_Array_Unique(int index); /* ** Post-Load processing, configures all materials to use the correct passes and ** material color sources, etc. */ void Post_Load_Process(bool enable_lighting = true,MeshModelClass * parent = NULL); void Disable_Lighting(void); /* ** Do any of the vertex materials require vertex normals? */ bool Do_Mappers_Need_Normals(void); static ShaderClass NullShader; // Used to mark no shader data protected: void Configure_Material(VertexMaterialClass * mtl,int pass,bool lighting_enabled); void Disable_Backface_Culling(void); void Delete_Pass(int pass); int PassCount; int VertexCount; int PolyCount; // u-v coordinates UVBufferClass * UV[MAX_UV_ARRAYS]; int UVSource[MAX_PASSES][MAX_TEX_STAGES]; // vertex color arrays, we support two arrays: each can only be used on the // first pass. ShareBufferClass * ColorArray[2]; VertexMaterialClass::ColorSourceType DCGSource[MAX_PASSES]; VertexMaterialClass::ColorSourceType DIGSource[MAX_PASSES]; // default textures, shader, vmat TextureClass * Texture[MAX_PASSES][MAX_TEX_STAGES]; ShaderClass Shader[MAX_PASSES]; VertexMaterialClass * Material[MAX_PASSES]; // array textures, shaders, vmats TexBufferClass * TextureArray[MAX_PASSES][MAX_TEX_STAGES]; MatBufferClass * MaterialArray[MAX_PASSES]; ShareBufferClass * ShaderArray[MAX_PASSES]; friend class MeshModelClass; }; /** ** MatBufferClass ** This is a ShareBufferClass of pointers to vertex materials. Should be written as a template... ** Get and Peek work like normal, and all non-NULL pointers will be released when the buffer ** is destroyed. */ class MatBufferClass : public ShareBufferClass < VertexMaterialClass * > { public: MatBufferClass(int count) : ShareBufferClass(count) { Clear(); } MatBufferClass(const MatBufferClass & that); ~MatBufferClass(void); void Set_Element(int index,VertexMaterialClass * mat); VertexMaterialClass * Get_Element(int index); VertexMaterialClass * Peek_Element(int index); private: // not implemented MatBufferClass & operator = (const MatBufferClass & that); }; /** ** TexBufferClass ** This is a ShareBufferClass of pointers to textures. Works just like MatBufferClass but with ** TextureClass's... */ class TexBufferClass : public ShareBufferClass < TextureClass * > { public: TexBufferClass(int count) : ShareBufferClass(count) { Clear(); } TexBufferClass(const TexBufferClass & that); ~TexBufferClass(void); void Set_Element(int index,TextureClass * mat); TextureClass * Get_Element(int index); TextureClass * Peek_Element(int index); private: // not implemented TexBufferClass & operator = (const TexBufferClass & that); }; /** ** UVBufferClass ** This is a ShareBufferClass of uv coordinates. At load time, we are detecting redundant UV arrays ** so this class stores a CRC for quick checking. */ class UVBufferClass : public ShareBufferClass < Vector2 > { public: UVBufferClass(int count) : ShareBufferClass(count), CRC(0xFFFFFFFF) { } UVBufferClass(const UVBufferClass & that); bool operator == (const UVBufferClass & that); bool Is_Equal_To(const UVBufferClass & that); void Update_CRC(void); unsigned int Get_CRC(void) { return CRC; } private: unsigned int CRC; // not implemented UVBufferClass & operator = (const UVBufferClass & that); }; /********************************************************************************************************* ** ** MeshMatDescClass Inline Functions ** These functions manage the data associated with the material description for the mesh. Since there ** can be an alternate material description, these functions are encapsulated into MatDescClass. ** *********************************************************************************************************/ inline Vector2 * MeshMatDescClass::Get_UV_Array(int pass,int stage) { if (UVSource[pass][stage] == -1) { return NULL; } if (UV[UVSource[pass][stage]] != NULL) { return UV[UVSource[pass][stage]]->Get_Array(); } return NULL; } inline void MeshMatDescClass::Set_UV_Source(int pass,int stage,int sourceindex) { WWASSERT(pass >= 0); WWASSERT(pass < MAX_PASSES); WWASSERT(stage >= 0); WWASSERT(stage < MAX_TEX_STAGES); UVSource[pass][stage] = sourceindex; } inline int MeshMatDescClass::Get_UV_Source(int pass,int stage) { WWASSERT(pass >= 0); WWASSERT(pass < MAX_PASSES); WWASSERT(stage >= 0); WWASSERT(stage < MAX_TEX_STAGES); return UVSource[pass][stage]; } inline int MeshMatDescClass::Get_UV_Array_Count(void) { int count = 0; while ((UV[count] != NULL) && (count < MAX_UV_ARRAYS)) { count++; } return count; } inline Vector2 * MeshMatDescClass::Get_UV_Array_By_Index(int index, bool create) { WWASSERT((index >= 0)&&(index < MAX_UV_ARRAYS)); if (create && !UV[index]) { UV[index] = NEW_REF(UVBufferClass,(VertexCount)); } if (UV[index] != NULL) { return UV[index]->Get_Array(); } return NULL; } inline unsigned* MeshMatDescClass::Get_DCG_Array(int pass) { WWASSERT(pass >= 0); WWASSERT(pass < MAX_PASSES); switch (DCGSource[pass]) { case VertexMaterialClass::MATERIAL: return NULL; break; case VertexMaterialClass::COLOR1: if (ColorArray[0]) { return ColorArray[0]->Get_Array(); } else { return NULL; } break; case VertexMaterialClass::COLOR2: if (ColorArray[1]) { return ColorArray[1]->Get_Array(); } else { return NULL; } break; default: WWASSERT(0); return(NULL); break; }; } inline unsigned * MeshMatDescClass::Get_DIG_Array(int pass) { WWASSERT(pass >= 0); WWASSERT(pass < MAX_PASSES); switch (DIGSource[pass]) { case VertexMaterialClass::MATERIAL: return NULL; break; case VertexMaterialClass::COLOR1: if (ColorArray[0]) { return ColorArray[0]->Get_Array(); } else { return NULL; } break; case VertexMaterialClass::COLOR2: if (ColorArray[1]) { return ColorArray[1]->Get_Array(); } else { return NULL; } break; default: WWASSERT(0); return(NULL); break; }; } inline void MeshMatDescClass::Set_DCG_Source(int pass,VertexMaterialClass::ColorSourceType source) { DCGSource[pass] = source; } inline void MeshMatDescClass::Set_DIG_Source(int pass,VertexMaterialClass::ColorSourceType source) { DIGSource[pass] = source; } inline VertexMaterialClass::ColorSourceType MeshMatDescClass::Get_DCG_Source(int pass) { return DCGSource[pass]; } inline VertexMaterialClass::ColorSourceType MeshMatDescClass::Get_DIG_Source(int pass) { return DIGSource[pass]; } inline unsigned * MeshMatDescClass::Get_Color_Array(int index,bool create) { if (create && !ColorArray[index]) { ColorArray[index] = NEW_REF(ShareBufferClass,(VertexCount)); } if (ColorArray[index]) { return ColorArray[index]->Get_Array(); } return NULL; } inline VertexMaterialClass * MeshMatDescClass::Get_Single_Material(int pass) const { if (Material[pass]) { Material[pass]->Add_Ref(); } return Material[pass]; } inline VertexMaterialClass * MeshMatDescClass::Peek_Single_Material(int pass) const { return Material[pass]; } inline TextureClass * MeshMatDescClass::Peek_Single_Texture(int pass,int stage) const { return Texture[pass][stage]; } inline ShaderClass MeshMatDescClass::Get_Single_Shader(int pass) const { return Shader[pass]; } inline bool MeshMatDescClass::Has_Material_Array(int pass) const { return (MaterialArray[pass] != NULL); } inline bool MeshMatDescClass::Has_Shader_Array(int pass) const { return (ShaderArray[pass] != NULL); } inline bool MeshMatDescClass::Has_Texture_Array(int pass,int stage) const { return (TextureArray[pass][stage] != NULL); } inline void MeshMatDescClass::Disable_Backface_Culling(void) { for (int pass = 0; pass < PassCount; pass++) { Shader[pass].Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); if (ShaderArray[pass]) { for (int tri = 0; tri < ShaderArray[pass]->Get_Count(); tri++) { ShaderArray[pass]->Get_Element(tri).Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); } } } } #endif //MESHMATDESC_H