/* ** Command & Conquer Generals Zero Hour(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/Tools/max2w3d/meshbuild.h $* * * * Author:: Greg_h * * * * $Modtime:: 5/22/00 3:17p $* * * * $Revision:: 12 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #if defined(_MSC_VER) #pragma once #endif #ifndef MESHBUILD_H #define MESHBUILD_H #include "always.h" #include "vector2.h" #include "vector3.h" #include "bittype.h" #include /* ** WorldInfoClass ** Abstract base class that defines an interface for 'world information'. ** This class provides the mesh builder with information about the world ** outside of its mesh. */ class WorldInfoClass { public: WorldInfoClass(void) { } virtual ~WorldInfoClass(void) { } // Public methods virtual Vector3 Get_Shared_Vertex_Normal (Vector3 pos, int smgroup) = 0; virtual bool Are_Meshes_Smoothed (void) const { return true; } }; /* ** MeshBuilderClass ** This class will process meshes for you, splitting all vertices which do not ** share all parameters (such as texture coordinates), sort the polygons by ** material, and put them into strip order. ** ** To "build" a mesh: ** 1. Reset the builder with the number of polys you're going to sumbit ** 2. Enable the vertex channels that you want ** 3. Submit each face in the form of a FaceClass ** 4. Call Build_Mesh ** ** To use the results: ** 1. Call Get_Vertex_Count and Get_Face_Count to get the counts ** 2. Loop through the verts, looking at each one using Get_Vertex ** 3. Loop through the faces, looking at each one using Get_Face ** ** *NOTE* This class is meant to be relatively self-sufficient. It is used in a ** variety of different applications which are built on completely different ** code-bases. Do not introduce dependencies into this module lightly! :-) */ class MeshBuilderClass { public: enum { STATE_ACCEPTING_INPUT = 0, // mesh builder is accepting input triangles STATE_MESH_PROCESSED, // mesh builder has processed the mesh MAX_PASSES = 4, // maximum number of material passes supported MAX_STAGES = 2, // maximum number of texture stages supported in a single pass }; /* ** Constructor, Destructor */ MeshBuilderClass(int pass_count=1,int face_count_guess=255,int face_count_growth_rate=64); ~MeshBuilderClass(void); /* ** VertClass. The MeshBuilder deals with vertices in this format. */ class VertClass { public: VertClass(void) { Reset(); } void Reset(void); public: Vector3 Position; // position of the vertex Vector3 Normal; // vertex normal (can be calculated by mesh builder) int SmGroup; // smoothing group of the face this vertex was submitted with int Id; // id of the vertex, must match for vert to be welded, ok at zero if you don't care int BoneIndex; // bone influence if the mesh is a skin int MaxVertColIndex; // Index into the Max mesh.vertCol array of this vertex. Vector2 TexCoord[MAX_PASSES][MAX_STAGES]; Vector3 DiffuseColor[MAX_PASSES]; // diffuse color Vector3 SpecularColor[MAX_PASSES]; // specular color Vector3 DiffuseIllumination[MAX_PASSES]; // pre-calced diffuse illum float Alpha[MAX_PASSES]; // alpha int VertexMaterialIndex[MAX_PASSES]; // vertex material index int Attribute0; // user-set attributes (passed on through...) int Attribute1; // user-set attributes // These values are set up by the mesh builder: int SharedSmGroup; // smooth bits that were on in all faces that contributed to this final vertex int UniqueIndex; // used internally! int ShadeIndex; // used internally! VertClass * NextHash; // used internally! }; /* ** FaceClass. The MeshBuilder deals faces in this format. When inputing faces, set the ** top half of the struct and the builder will fill in the bottom (vertex indices, normal, ** and distance). */ class FaceClass { public: FaceClass(void) { Reset(); } void Reset(void); // reset this face public: VertClass Verts[3]; // array of 3 verts int SmGroup; // smoothing group int Index; // user-set index of the face int Attributes; // user-set attributes int TextureIndex[MAX_PASSES][MAX_STAGES]; // texture to use for each pass int ShaderIndex[MAX_PASSES]; // shader for each pass uint32 SurfaceType; // surface type identifier int AddIndex; // set by builder: index of addition int VertIdx[3]; // set by builder: "optimized" vertex indices Vector3 Normal; // set by builder: Face normal float32 Dist; // set by builder: Plane distance void Compute_Plane(void); bool operator != (const FaceClass & that) { return !(*this == that); } bool operator == (const FaceClass & /*that*/) { return false; } bool Is_Degenerate(void); friend class MeshBuilderClass; }; /* ** To "build" a mesh: ** 1. Reset the builder with the approximate number of polys you're going to sumbit, etc. ** 3. Submit each face in the form of a FaceClass, set only the fields you need (leave others at default) ** 4. Call Build_Mesh */ void Reset(int pass_count,int face_count_guess,int face_count_growth_rate); int Add_Face(const FaceClass & face); void Build_Mesh(bool compute_normals); /* ** Optional controls: ** If one of your passes has more textures than another, you may wish to do the ** stripping and sorting based on that channel. By default, everything will ** be stripped and sorted based on pass 0, stage 0 ** Sort_Vertices can be used to order the vertices arbitrarily. I use it to ** sort them according to the bone they are attached for skin meshes. */ void Set_Polygon_Ordering_Channel(int pass,int texstage); /* ** To use the results: ** 1. Call Get_Vertex_Count and Get_Face_Count to get the counts ** 2. Loop through the verts, looking at each one using Get_Vertex ** 3. Loop through the faces, looking at each one using Get_Face */ int Get_Pass_Count(void) const; int Get_Vertex_Count(void) const; int Get_Face_Count(void) const; const VertClass & Get_Vertex(int index) const; const FaceClass & Get_Face(int index) const; /* ** Access to the Vertices and Faces for modifications. This is used by ** the max plugin when generating a skin mesh for example. Be careful ** what you do to them. (I haven't thought through all of the ** possible things you might do to mess up my nice clean mesh...). */ VertClass & Get_Vertex(int index); FaceClass & Get_Face(int index); /* ** Bounding volume information about the mesh. These functions can compute ** various types of bounding volumes for the mesh you just processed... */ void Compute_Bounding_Box(Vector3 * set_min,Vector3 * set_max); void Compute_Bounding_Sphere(Vector3 * set_center,float * set_radius); /* ** World information managment. Used to give the mesh builder information ** about the world outside of its mesh. */ WorldInfoClass * Peek_World_Info(void) const { return WorldInfo; } void Set_World_Info(WorldInfoClass *world_info) { WorldInfo = world_info; } /* ** Mesh Stats, mainly lots of flags for whether this mesh has various ** channels of information. */ struct MeshStatsStruct { void Reset(void); bool HasTexture[MAX_PASSES][MAX_STAGES]; // has at least one texture in given pass/stage bool HasShader[MAX_PASSES]; // has at least one shader in given pass bool HasVertexMaterial[MAX_PASSES]; // has at least one vert material in given pass bool HasPerPolyTexture[MAX_PASSES][MAX_STAGES]; // has 2+ textures in given pass/stage bool HasPerPolyShader[MAX_PASSES]; // has 2+ shaders in given pass bool HasPerVertexMaterial[MAX_PASSES]; // has 2+ vertex materials in given pass bool HasDiffuseColor[MAX_PASSES]; // has diffuse colors in given pass bool HasSpecularColor[MAX_PASSES]; // has specular colors in given pass bool HasDiffuseIllumination[MAX_PASSES]; // has diffuse illum in given pass bool HasTexCoords[MAX_PASSES][MAX_STAGES]; // has texture coords in given pass int UVSplitCount; // how many vertices were split due solely to UV discontinuities int StripCount; // number of strips that were created int MaxStripLength; // longest strip created float AvgStripLength; // average strip length }; const MeshStatsStruct & Get_Mesh_Stats(void) const; private: void Free(void); void Compute_Mesh_Stats(void); void Optimize_Mesh(bool compute_normals); void Strip_Optimize_Mesh(void); void Remove_Degenerate_Faces(void); void Compute_Face_Normals(void); bool Verify_Face_Normals(void); void Compute_Vertex_Normals(void); void Grow_Face_Array(void); void Sort_Vertices(void); /* ** Winged edge stuff is used by the strip optimize function */ struct WingedEdgeStruct { int MaterialIdx; WingedEdgeStruct * Next; int Vertex[2]; int Poly[2]; }; struct WingedEdgePolyStruct { WingedEdgeStruct * Edge[3]; }; int State; // is the builder accepting input or already processed the mesh. int PassCount; // number of render passes for this mesh int FaceCount; // number of faces FaceClass * Faces; // array of faces int InputVertCount; // number of input verts; int VertCount; // number of verts; VertClass * Verts; // array of verts; int CurFace; // current face being added WorldInfoClass * WorldInfo; // obj containing info about other meshes in the world MeshStatsStruct Stats; // internally useful junk about the mesh being processed. int PolyOrderPass; // order the polys using the texture indices in this pass int PolyOrderStage; // order the polys using the texture indices in this stage int AllocFaceCount; // number of faces allocated int AllocFaceGrowth; // growth rate of face array }; inline void MeshBuilderClass::Set_Polygon_Ordering_Channel(int pass,int texstage) { assert(pass >= 0); assert(pass < MAX_PASSES); assert(texstage >= 0); assert(texstage < MAX_STAGES); PolyOrderPass = pass; PolyOrderStage = texstage; } inline int MeshBuilderClass::Get_Pass_Count(void) const { return PassCount; } inline int MeshBuilderClass::Get_Vertex_Count(void) const { assert(State == STATE_MESH_PROCESSED); return VertCount; } inline int MeshBuilderClass::Get_Face_Count(void) const { assert(State == STATE_MESH_PROCESSED); return FaceCount; } inline const MeshBuilderClass::VertClass & MeshBuilderClass::Get_Vertex(int index) const { assert(State == STATE_MESH_PROCESSED); assert(index >= 0); assert(index < VertCount); return Verts[index]; } inline const MeshBuilderClass::FaceClass & MeshBuilderClass::Get_Face(int index) const { assert(State == STATE_MESH_PROCESSED); assert(index >= 0); assert(index < FaceCount); return Faces[index]; } inline MeshBuilderClass::VertClass & MeshBuilderClass::Get_Vertex(int index) { assert(State == STATE_MESH_PROCESSED); assert(index >= 0); assert(index < VertCount); return Verts[index]; } inline MeshBuilderClass::FaceClass & MeshBuilderClass::Get_Face(int index) { assert(State == STATE_MESH_PROCESSED); assert(index >= 0); assert(index < FaceCount); return Faces[index]; } inline const MeshBuilderClass::MeshStatsStruct & MeshBuilderClass::Get_Mesh_Stats(void) const { assert(State == STATE_MESH_PROCESSED); return Stats; } #endif