380 lines
14 KiB
C
380 lines
14 KiB
C
![]() |
/*
|
||
|
** 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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** 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 <assert.h>
|
||
|
|
||
|
/*
|
||
|
** 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
|