830 lines
25 KiB
C++
830 lines
25 KiB
C++
/*
|
|
** 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 <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 : Commando *
|
|
* *
|
|
* $Archive:: /Commando/Code/ww3d2/dynamesh.cpp $*
|
|
* *
|
|
* $Author:: Greg_h $*
|
|
* *
|
|
* $Modtime:: 12/03/01 4:50p $*
|
|
* *
|
|
* $Revision:: 25 $*
|
|
* *
|
|
*-------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "dynamesh.h"
|
|
#include "dx8vertexbuffer.h"
|
|
#include "dx8indexbuffer.h"
|
|
#include "dx8wrapper.h"
|
|
#include "sortingrenderer.h"
|
|
#include "rinfo.h"
|
|
#include "camera.h"
|
|
#include "dx8fvf.h"
|
|
|
|
|
|
|
|
/*
|
|
** DynamicMeshModel implementation
|
|
*/
|
|
|
|
DynamicMeshModel::DynamicMeshModel(unsigned int max_polys, unsigned int max_verts) :
|
|
MeshGeometryClass(),
|
|
DynamicMeshPNum(0),
|
|
DynamicMeshVNum(0),
|
|
MatDesc(NULL),
|
|
MatInfo(NULL)
|
|
{
|
|
MatInfo = NEW_REF(MaterialInfoClass, ());
|
|
|
|
MatDesc = new MeshMatDescClass;
|
|
MatDesc->Set_Polygon_Count(max_polys);
|
|
MatDesc->Set_Vertex_Count(max_verts);
|
|
|
|
Reset_Geometry(max_polys, max_verts);
|
|
}
|
|
|
|
DynamicMeshModel::DynamicMeshModel(unsigned int max_polys, unsigned int max_verts, MaterialInfoClass *mat_info) :
|
|
MeshGeometryClass(),
|
|
DynamicMeshPNum(0),
|
|
DynamicMeshVNum(0),
|
|
MatDesc(NULL),
|
|
MatInfo(NULL)
|
|
{
|
|
MatInfo = mat_info;
|
|
MatInfo->Add_Ref();
|
|
|
|
MatDesc = new MeshMatDescClass;
|
|
MatDesc->Set_Polygon_Count(max_polys);
|
|
MatDesc->Set_Vertex_Count(max_verts);
|
|
|
|
Reset_Geometry(max_polys, max_verts);
|
|
}
|
|
|
|
DynamicMeshModel::DynamicMeshModel(const DynamicMeshModel &src) :
|
|
MeshGeometryClass(src),
|
|
DynamicMeshPNum(src.DynamicMeshPNum),
|
|
DynamicMeshVNum(src.DynamicMeshVNum),
|
|
MatDesc(NULL),
|
|
MatInfo(NULL)
|
|
{
|
|
// Copy the material info structure.
|
|
MatInfo = NEW_REF(MaterialInfoClass, (*(src.MatInfo)));
|
|
|
|
// remap!
|
|
MaterialRemapperClass remapper(src.MatInfo, MatInfo);
|
|
remapper.Remap_Mesh(src.MatDesc, MatDesc);
|
|
|
|
MatDesc = new MeshMatDescClass;
|
|
}
|
|
|
|
DynamicMeshModel::~DynamicMeshModel(void)
|
|
{
|
|
if (MatDesc) {
|
|
delete MatDesc;
|
|
MatDesc = NULL;
|
|
}
|
|
REF_PTR_RELEASE(MatInfo);
|
|
}
|
|
|
|
void DynamicMeshModel::Compute_Plane_Equations(void)
|
|
{
|
|
// Make sure the arrays are allocated before we do this
|
|
get_vert_normals();
|
|
Vector4 * planes = get_planes(true);
|
|
|
|
// Set the poly and vertex counts to the dynamic counts, call the base class function, then
|
|
// set them back.
|
|
int old_poly_count = PolyCount;
|
|
int old_vert_count = VertexCount;
|
|
PolyCount = DynamicMeshPNum;
|
|
VertexCount = DynamicMeshVNum;
|
|
|
|
MeshGeometryClass::Compute_Plane_Equations(planes);
|
|
|
|
PolyCount = old_poly_count;
|
|
VertexCount = old_vert_count;
|
|
}
|
|
|
|
void DynamicMeshModel::Compute_Vertex_Normals(void)
|
|
{
|
|
// Make sure the arrays are allocated before we do this
|
|
Vector3 * vnorms = get_vert_normals();
|
|
get_planes(true);
|
|
|
|
// Set the poly and vertex counts to the dynamic counts, call the base class function, then
|
|
// set them back.
|
|
int old_poly_count = PolyCount;
|
|
int old_vert_count = VertexCount;
|
|
PolyCount = DynamicMeshPNum;
|
|
VertexCount = DynamicMeshVNum;
|
|
|
|
MeshGeometryClass::Compute_Vertex_Normals(vnorms);
|
|
|
|
PolyCount = old_poly_count;
|
|
VertexCount = old_vert_count;
|
|
}
|
|
|
|
void DynamicMeshModel::Compute_Bounds(Vector3 * verts)
|
|
{
|
|
// Set the poly and vertex counts to the dynamic counts, call the base class function, then
|
|
// set them back.
|
|
int old_poly_count = PolyCount;
|
|
int old_vert_count = VertexCount;
|
|
PolyCount = DynamicMeshPNum;
|
|
VertexCount = DynamicMeshVNum;
|
|
|
|
MeshGeometryClass::Compute_Bounds(verts);
|
|
|
|
PolyCount = old_poly_count;
|
|
VertexCount = old_vert_count;
|
|
}
|
|
|
|
void DynamicMeshModel::Reset(void)
|
|
{
|
|
Set_Counts(0, 0);
|
|
int polycount = Get_Polygon_Count();
|
|
int vertcount = Get_Vertex_Count();
|
|
Reset_Geometry(polycount, vertcount);
|
|
MatDesc->Reset(polycount, vertcount, 1);
|
|
REF_PTR_RELEASE(MatInfo);
|
|
MatInfo = NEW_REF(MaterialInfoClass, ());
|
|
}
|
|
|
|
void DynamicMeshModel::Render(RenderInfoClass & rinfo)
|
|
{
|
|
// Process texture reductions:
|
|
// MatInfo->Process_Texture_Reduction();
|
|
|
|
unsigned buffer_type=(Get_Flag(MeshGeometryClass::SORT)&& WW3D::Is_Sorting_Enabled()) ? BUFFER_TYPE_DYNAMIC_SORTING : BUFFER_TYPE_DYNAMIC_DX8;
|
|
|
|
/*
|
|
** Write the vertex data to the vertex buffer. We assume the FVF contains positions, normals,
|
|
** one texture channel, and the diffuse color channel (color0). If it does not contain all
|
|
** these components, the code will fail.
|
|
*/
|
|
DynamicVBAccessClass dynamic_vb(buffer_type,dynamic_fvf_type,DynamicMeshVNum);
|
|
const FVFInfoClass &fvf_info = dynamic_vb.FVF_Info();
|
|
|
|
{ // scope for lock
|
|
|
|
DynamicVBAccessClass::WriteLockClass lock(&dynamic_vb);
|
|
unsigned char *vertices = (unsigned char*)lock.Get_Formatted_Vertex_Array();
|
|
const Vector3 *locs = Get_Vertex_Array();
|
|
const Vector3 *normals = Get_Vertex_Normal_Array();
|
|
const Vector2 *uvs = MatDesc->Get_UV_Array_By_Index(0, false);
|
|
const Vector2 *uv1s = MatDesc->Get_UV_Array_By_Index(1, false);
|
|
const unsigned *colors = MatDesc->Get_Color_Array(0, false);
|
|
const static Vector3 default_normal(0.0f, 0.0f, 0.0f);
|
|
const static Vector2 default_uv(0.0f, 0.0f);
|
|
const unsigned int default_color = 0xFFFFFFFF;
|
|
for (int i=0; i < DynamicMeshVNum; i++)
|
|
{
|
|
*(Vector3 *)(vertices + fvf_info.Get_Location_Offset()) = locs[i];
|
|
*(Vector3 *)(vertices + fvf_info.Get_Normal_Offset()) = normals[i];
|
|
if (uvs) {
|
|
*(Vector2 *)(vertices + fvf_info.Get_Tex_Offset(0)) = uvs[i];
|
|
} else {
|
|
*(Vector2 *)(vertices + fvf_info.Get_Tex_Offset(0)) = default_uv;
|
|
}
|
|
if (uv1s) {
|
|
*(Vector2 *)(vertices + fvf_info.Get_Tex_Offset(1)) = uv1s[i];
|
|
} else {
|
|
*(Vector2 *)(vertices + fvf_info.Get_Tex_Offset(1)) = default_uv;
|
|
}
|
|
|
|
if (colors) {
|
|
*(unsigned int *)(vertices + fvf_info.Get_Diffuse_Offset()) = colors[i];
|
|
} else {
|
|
*(unsigned int *)(vertices + fvf_info.Get_Diffuse_Offset()) = default_color;
|
|
}
|
|
vertices += fvf_info.Get_FVF_Size();
|
|
}
|
|
|
|
} // end scope for lock
|
|
|
|
/*
|
|
** Write index data to index buffers
|
|
*/
|
|
DynamicIBAccessClass dynamic_ib(buffer_type,DynamicMeshPNum * 3);
|
|
const TriIndex *tris = Get_Polygon_Array();
|
|
|
|
{ // scope for lock
|
|
|
|
DynamicIBAccessClass::WriteLockClass lock(&dynamic_ib);
|
|
unsigned short * indices = lock.Get_Index_Array();
|
|
for (int i=0; i < DynamicMeshPNum; i++)
|
|
{
|
|
indices[i*3 + 0] = (unsigned short)tris[i][0];
|
|
indices[i*3 + 1] = (unsigned short)tris[i][1];
|
|
indices[i*3 + 2] = (unsigned short)tris[i][2];
|
|
}
|
|
|
|
} // end scope for lock
|
|
|
|
/*
|
|
** Set vertex and index buffers
|
|
*/
|
|
DX8Wrapper::Set_Vertex_Buffer(dynamic_vb);
|
|
DX8Wrapper::Set_Index_Buffer(dynamic_ib,0);
|
|
|
|
/*
|
|
** Draw dynamesh, one pass at a time
|
|
*/
|
|
unsigned int pass_count = Get_Pass_Count();
|
|
for (unsigned int pass = 0; pass < pass_count; pass++) {
|
|
|
|
/*
|
|
** Set current render states (texture, vertex material, shader). Scan triangles until one
|
|
** of these changes, and then draw.
|
|
*/
|
|
|
|
// The vertex index range used
|
|
unsigned short min_vert_idx = DynamicMeshVNum - 1;
|
|
unsigned short max_vert_idx = 0;
|
|
unsigned short start_tri_idx = 0;
|
|
unsigned short cur_tri_idx = 0;
|
|
|
|
bool done = false;
|
|
bool texture_changed = false;
|
|
bool texture1_changed = false;
|
|
bool material_changed = false;
|
|
bool shader_changed = false;
|
|
|
|
TextureClass **texture_array0 = NULL;
|
|
TexBufferClass * tex_buf = MatDesc->Get_Texture_Array(pass, 0, false);
|
|
if (tex_buf) {
|
|
texture_array0 = tex_buf->Get_Array();
|
|
} else {
|
|
texture_array0 = NULL;
|
|
}
|
|
|
|
TextureClass **texture_array1 = NULL;
|
|
TexBufferClass * tex_buf1 = MatDesc->Get_Texture_Array(pass, 1, false);
|
|
if (tex_buf1) {
|
|
texture_array1 = tex_buf1->Get_Array();
|
|
} else {
|
|
texture_array1 = NULL;
|
|
}
|
|
|
|
VertexMaterialClass **material_array = NULL;
|
|
MatBufferClass * mat_buf = MatDesc->Get_Material_Array(pass, false);
|
|
if (mat_buf) {
|
|
material_array = mat_buf->Get_Array();
|
|
} else {
|
|
material_array = NULL;
|
|
}
|
|
ShaderClass *shader_array = MatDesc->Get_Shader_Array(pass, false);
|
|
|
|
// Set the DX8 state to the first triangle's state
|
|
if (texture_array0) {
|
|
DX8Wrapper::Set_Texture(0,texture_array0[0]);
|
|
} else {
|
|
DX8Wrapper::Set_Texture(0,MatDesc->Peek_Single_Texture(pass, 0));
|
|
}
|
|
|
|
if (texture_array1) {
|
|
DX8Wrapper::Set_Texture(1,texture_array1[0]);
|
|
} else {
|
|
DX8Wrapper::Set_Texture(1,MatDesc->Peek_Single_Texture(pass, 1));
|
|
}
|
|
|
|
if (material_array) {
|
|
DX8Wrapper::Set_Material(material_array[tris[0].I]);
|
|
} else {
|
|
DX8Wrapper::Set_Material(MatDesc->Peek_Single_Material(pass));
|
|
}
|
|
if (shader_array) {
|
|
DX8Wrapper::Set_Shader(shader_array[0]);
|
|
} else {
|
|
DX8Wrapper::Set_Shader(MatDesc->Get_Single_Shader(pass));
|
|
}
|
|
|
|
SphereClass sphere(Vector3(0.0f,0.0f,0.0f),0.0f);
|
|
Get_Bounding_Sphere(&sphere);
|
|
|
|
// If no texture, shader or material arrays for this pass just draw and go to next pass
|
|
if (!texture_array0 && !texture_array1 && !material_array && !shader_array) {
|
|
if (buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) {
|
|
SortingRendererClass::Insert_Triangles(sphere,0, DynamicMeshPNum, 0, DynamicMeshVNum);
|
|
}
|
|
else {
|
|
DX8Wrapper::Draw_Triangles(0, DynamicMeshPNum, 0, DynamicMeshVNum);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
while (!done) {
|
|
|
|
// Add vertex indices of tri[cur_tri_idx] to min_vert_idx, max_vert_idx
|
|
const TriIndex &tri = tris[cur_tri_idx];
|
|
unsigned short min_idx = (unsigned short)MIN(MIN(tri.I, tri.J), tri.K);
|
|
unsigned short max_idx = (unsigned short)MAX(MAX(tri.I, tri.J), tri.K);
|
|
min_vert_idx = MIN(min_vert_idx, min_idx);
|
|
max_vert_idx = MAX(max_vert_idx, max_idx);
|
|
|
|
// Check the next triangle to see if the current run has ended.
|
|
unsigned short next_tri_idx = cur_tri_idx + 1;
|
|
done = next_tri_idx >= DynamicMeshPNum;
|
|
if (done) {
|
|
texture_changed = false;
|
|
texture1_changed = false;
|
|
material_changed = false;
|
|
shader_changed = false;
|
|
} else {
|
|
texture_changed = texture_array0 && texture_array0[cur_tri_idx] != texture_array0[next_tri_idx];
|
|
texture1_changed = texture_array1 && texture_array1[cur_tri_idx] != texture_array1[next_tri_idx];
|
|
material_changed = material_array && material_array[tris[cur_tri_idx].I] != material_array[tris[next_tri_idx].I];
|
|
shader_changed = shader_array && shader_array[cur_tri_idx] != shader_array[next_tri_idx];
|
|
}
|
|
|
|
// If run ends (mesh ends or state changes) draw, reset indices, set state for next run.
|
|
if (done || texture_changed || material_changed || shader_changed) {
|
|
if (buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) {
|
|
SortingRendererClass::Insert_Triangles(
|
|
sphere,
|
|
(start_tri_idx * 3),
|
|
(1 + cur_tri_idx - start_tri_idx),
|
|
min_vert_idx,
|
|
1 + max_vert_idx - min_vert_idx);
|
|
}
|
|
else {
|
|
DX8Wrapper::Draw_Triangles(
|
|
(start_tri_idx * 3),
|
|
(1 + cur_tri_idx - start_tri_idx),
|
|
min_vert_idx,
|
|
1 + max_vert_idx - min_vert_idx);
|
|
}
|
|
start_tri_idx = next_tri_idx;
|
|
min_vert_idx = DynamicMeshVNum - 1;
|
|
max_vert_idx = 0;
|
|
if (texture_changed) DX8Wrapper::Set_Texture(0,texture_array0[next_tri_idx]);
|
|
if (texture1_changed) DX8Wrapper::Set_Texture(1,texture_array1[next_tri_idx]);
|
|
if (material_changed) DX8Wrapper::Set_Material(material_array[tris[next_tri_idx].I]);
|
|
if (shader_changed) DX8Wrapper::Set_Shader(shader_array[next_tri_idx]);
|
|
}
|
|
|
|
cur_tri_idx = next_tri_idx;
|
|
|
|
} // while (!done)
|
|
|
|
} // for (pass)
|
|
|
|
}
|
|
|
|
void DynamicMeshModel::Initialize_Texture_Array(int pass, int stage, TextureClass *texture)
|
|
{
|
|
TexBufferClass * texlist = MatDesc->Get_Texture_Array(pass, 0, true);
|
|
for (int lp = 0; lp < PolyCount; lp++) {
|
|
texlist->Set_Element(lp, texture);
|
|
}
|
|
}
|
|
|
|
void DynamicMeshModel::Initialize_Material_Array(int pass, VertexMaterialClass *vmat)
|
|
{
|
|
MatBufferClass * vertmatlist = MatDesc->Get_Material_Array(pass, true);
|
|
for (int lp = 0; lp < VertexCount; lp++) {
|
|
vertmatlist->Set_Element(lp, vmat);
|
|
}
|
|
}
|
|
|
|
void DynamicMeshClass::Render(RenderInfoClass & rinfo)
|
|
{
|
|
if (Is_Not_Hidden_At_All() == false) return;
|
|
|
|
// test for an empty mesh..
|
|
if (PolyCount == 0 ) return;
|
|
|
|
// If static sort lists are enabled and this mesh has a sort level, put it on the list instead
|
|
// of rendering it.
|
|
|
|
if (WW3D::Are_Static_Sort_Lists_Enabled() && SortLevel != SORT_LEVEL_NONE) {
|
|
|
|
WW3D::Add_To_Static_Sort_List(this, SortLevel);
|
|
|
|
} else {
|
|
|
|
const FrustumClass & frustum = rinfo.Camera.Get_Frustum();
|
|
|
|
if (CollisionMath::Overlap_Test(frustum, Get_Bounding_Box()) != CollisionMath::OUTSIDE) {
|
|
DX8Wrapper::Set_Transform(D3DTS_WORLD, Transform);
|
|
Model->Render(rinfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DynamicMeshClass::End_Vertex()
|
|
{
|
|
// check that we have room for a new vertex
|
|
WWASSERT(VertCount < Model->Get_Vertex_Count());
|
|
|
|
// if we are a multi-material object record the material
|
|
int pass = Get_Pass_Count();
|
|
while (pass--) {
|
|
if (MultiVertexMaterial[pass]) {
|
|
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(VertexMaterialIdx[pass]);
|
|
Model->Set_Material(VertCount, mat, pass);
|
|
REF_PTR_RELEASE(mat);
|
|
}
|
|
|
|
}
|
|
|
|
// if we are multi colored, record the color
|
|
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
|
if (MultiVertexColor[color_array_index]) {
|
|
// Vector4 * color = &((Model->Get_Color_Array(color_array_index))[VertCount]);
|
|
// color->X = CurVertexColor[color_array_index].X;
|
|
// color->Y = CurVertexColor[color_array_index].Y;
|
|
// color->Z = CurVertexColor[color_array_index].Z;
|
|
// color->W = CurVertexColor[color_array_index].W;
|
|
unsigned * color = &((Model->Get_Color_Array(color_array_index))[VertCount]);
|
|
*color=DX8Wrapper::Convert_Color_Clamp(CurVertexColor[color_array_index]);
|
|
}
|
|
}
|
|
|
|
// mark this vertex as being complete
|
|
VertCount++;
|
|
TriVertexCount++;
|
|
|
|
// if we have 3 or more vertices, add a new poly
|
|
if (TriVertexCount >= 3) {
|
|
|
|
// check that we have room for a new poly
|
|
WWASSERT(PolyCount < Model->Get_Polygon_Count());
|
|
|
|
// set vertex indices
|
|
TriIndex *poly = &(Model->Get_Non_Const_Polygon_Array())[PolyCount];
|
|
if (TriMode == TRI_MODE_STRIPS) {
|
|
(*poly)[0] = VertCount-3;
|
|
(*poly)[1] = VertCount-2;
|
|
(*poly)[2] = VertCount-1;
|
|
|
|
// for every other tri, reverse vertex order
|
|
if (Flip_Face()) {
|
|
(*poly)[1] = VertCount-1;
|
|
(*poly)[2] = VertCount-2;
|
|
}
|
|
} else {
|
|
(*poly)[0] = FanVertex;
|
|
(*poly)[1] = VertCount-2;
|
|
(*poly)[2] = VertCount-1;
|
|
}
|
|
|
|
// check each pass
|
|
int pass = Get_Pass_Count();
|
|
while (pass--) {
|
|
|
|
// If we are multi texture
|
|
if (MultiTexture[pass]) {
|
|
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
|
Model->Set_Texture(PolyCount, tex, pass);
|
|
REF_PTR_RELEASE(tex);
|
|
}
|
|
}
|
|
|
|
// increase the count and record that we have a new material
|
|
PolyCount++;
|
|
Model->Set_Counts(PolyCount, VertCount);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/******************************************************************
|
|
**
|
|
** DynamicMeshClass
|
|
**
|
|
*******************************************************************/
|
|
DynamicMeshClass::DynamicMeshClass(int max_poly, int max_vert) :
|
|
Model(NULL),
|
|
PolyCount(0),
|
|
VertCount(0),
|
|
TriVertexCount(0),
|
|
FanVertex(0),
|
|
TriMode(TRI_MODE_STRIPS),
|
|
SortLevel(SORT_LEVEL_NONE)
|
|
{
|
|
int pass = MAX_PASSES;
|
|
while (pass--) {
|
|
MultiTexture[pass] = false;
|
|
TextureIdx[pass] = -1;
|
|
|
|
MultiVertexMaterial[pass] = false;
|
|
VertexMaterialIdx[pass] = -1;
|
|
}
|
|
|
|
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
|
MultiVertexColor[color_array_index] = false;
|
|
CurVertexColor[color_array_index].Set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
}
|
|
|
|
Model = NEW_REF(DynamicMeshModel, (max_poly, max_vert));
|
|
}
|
|
|
|
DynamicMeshClass::DynamicMeshClass(int max_poly, int max_vert, MaterialInfoClass *mat_info) :
|
|
Model(NULL),
|
|
PolyCount(0),
|
|
VertCount(0),
|
|
TriVertexCount(0),
|
|
FanVertex(0),
|
|
TriMode(TRI_MODE_STRIPS),
|
|
SortLevel(SORT_LEVEL_NONE)
|
|
{
|
|
int pass = MAX_PASSES;
|
|
while (pass--) {
|
|
MultiTexture[pass] = false;
|
|
TextureIdx[pass] = -1;
|
|
|
|
MultiVertexMaterial[pass] = false;
|
|
VertexMaterialIdx[pass] = -1;
|
|
}
|
|
|
|
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
|
MultiVertexColor[color_array_index] = false;
|
|
CurVertexColor[color_array_index].Set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
}
|
|
|
|
Model = NEW_REF(DynamicMeshModel, (max_poly, max_vert, mat_info));
|
|
}
|
|
|
|
DynamicMeshClass::DynamicMeshClass(const DynamicMeshClass & src) :
|
|
RenderObjClass(src),
|
|
Model(NULL),
|
|
PolyCount(src.PolyCount),
|
|
VertCount(src.VertCount),
|
|
TriVertexCount(src.TriVertexCount),
|
|
FanVertex(src.FanVertex),
|
|
TriMode(src.TriMode),
|
|
SortLevel(src.SortLevel)
|
|
{
|
|
int pass = MAX_PASSES;
|
|
while (pass--) {
|
|
MultiTexture[pass] = src.MultiTexture[pass];
|
|
TextureIdx[pass] = src.TextureIdx[pass];
|
|
|
|
MultiVertexMaterial[pass] = src.MultiVertexMaterial[pass];
|
|
VertexMaterialIdx[pass] = src.VertexMaterialIdx[pass];
|
|
|
|
MultiVertexColor[pass] = src.MultiVertexColor[pass];
|
|
CurVertexColor[pass] = src.CurVertexColor[pass];
|
|
}
|
|
|
|
for (int color_array_index = 0; color_array_index < MAX_COLOR_ARRAYS; color_array_index++) {
|
|
MultiVertexColor[color_array_index] = src.MultiVertexColor[color_array_index];
|
|
CurVertexColor[color_array_index] = src.CurVertexColor[color_array_index];
|
|
}
|
|
|
|
Model = NEW_REF(DynamicMeshModel, (*(src.Model)));
|
|
}
|
|
|
|
void DynamicMeshClass::Resize(int max_polys, int max_verts)
|
|
{
|
|
Reset();
|
|
|
|
REF_PTR_RELEASE(Model);
|
|
Model = NEW_REF(DynamicMeshModel, (max_polys, max_verts));
|
|
|
|
// reset all the texture & vertex material indices
|
|
int pass = MAX_PASSES;
|
|
while (pass--) {
|
|
TextureIdx[pass] = -1;
|
|
VertexMaterialIdx[pass] = -1;
|
|
MultiVertexMaterial[pass] = false;
|
|
}
|
|
}
|
|
|
|
DynamicMeshClass::~DynamicMeshClass()
|
|
{
|
|
REF_PTR_RELEASE(Model);
|
|
}
|
|
|
|
RenderObjClass * DynamicMeshClass::Clone(void) const
|
|
{
|
|
return NEW_REF(DynamicMeshClass, (*this));
|
|
}
|
|
|
|
void DynamicMeshClass::Location(float x, float y, float z)
|
|
{
|
|
Vector3 * loc = Model->Get_Vertex_Array();
|
|
assert(loc);
|
|
|
|
loc[VertCount].X = x;
|
|
loc[VertCount].Y = y;
|
|
loc[VertCount].Z = z;
|
|
}
|
|
|
|
/*
|
|
** For moving a vertex after the DynaMesh has already been created.
|
|
*/
|
|
void DynamicMeshClass::Move_Vertex(int index, float x, float y, float z)
|
|
{
|
|
Vector3 * loc = Model->Get_Vertex_Array();
|
|
assert(loc);
|
|
loc[index][0] = x;
|
|
loc[index][1] = y;
|
|
loc[index][2] = z;
|
|
}
|
|
|
|
/*
|
|
** Get a vertex value.
|
|
*/
|
|
void DynamicMeshClass::Get_Vertex(int index, float &x, float &y, float &z)
|
|
{
|
|
Vector3 * loc = Model->Get_Vertex_Array();
|
|
assert(loc);
|
|
x = loc[index][0];
|
|
y = loc[index][1];
|
|
z = loc[index][2];
|
|
}
|
|
|
|
|
|
/*
|
|
** Offset the entire mesh
|
|
*/
|
|
void DynamicMeshClass::Translate_Vertices(const Vector3 & offset)
|
|
{
|
|
Vector3 * loc = Model->Get_Vertex_Array();
|
|
assert(loc);
|
|
for (int i=0; i < Get_Num_Vertices(); i++) {
|
|
loc[i].X += offset.X;
|
|
loc[i].Y += offset.Y;
|
|
loc[i].Z += offset.Z;
|
|
}
|
|
|
|
Set_Dirty_Bounds();
|
|
Set_Dirty_Planes();
|
|
}
|
|
|
|
int DynamicMeshClass::Set_Vertex_Material(int idx, int pass)
|
|
{
|
|
assert(idx < Peek_Material_Info()->Vertex_Material_Count());
|
|
VertexMaterialIdx[pass] = idx;
|
|
if (!MultiVertexMaterial[pass]) {
|
|
// WWASSERT( VertexMaterialIdx[pass] == 0);
|
|
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(VertexMaterialIdx[pass]);
|
|
Model->Set_Single_Material(mat, pass);
|
|
mat->Release_Ref();
|
|
}
|
|
return VertexMaterialIdx[pass];
|
|
}
|
|
|
|
int DynamicMeshClass::Set_Vertex_Material(VertexMaterialClass *material, bool dont_search, int pass)
|
|
{
|
|
// Check if same as the last vertex material
|
|
if (Peek_Material_Info()->Vertex_Material_Count() && (VertexMaterialIdx[pass] != -1) && Peek_Material_Info()->Peek_Vertex_Material(VertexMaterialIdx[pass]) == material) {
|
|
return VertexMaterialIdx[pass];
|
|
}
|
|
|
|
// if there are vertex materials in the list then we may have just jumped
|
|
// to becoming a multi-vertex-material object. Take care of that here.
|
|
if ((!MultiVertexMaterial[pass]) && Peek_Material_Info()->Vertex_Material_Count() && (VertexMaterialIdx[pass] != -1) && Peek_Material_Info()->Peek_Vertex_Material(VertexMaterialIdx[pass]) != material) {
|
|
|
|
// allocate the array of per-vertex vertex material overrides
|
|
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(VertexMaterialIdx[pass]);
|
|
Model->Initialize_Material_Array(pass, mat);
|
|
mat->Release_Ref();
|
|
|
|
// flag that we need to write the per -vertex vertex material override array
|
|
MultiVertexMaterial[pass] = true;
|
|
}
|
|
|
|
// add the material to the material info class if we cant find it in the
|
|
// list. if we are not supposed to search the list for it then just add
|
|
// it.
|
|
if (!dont_search) {
|
|
for (int lp = 0, found = 0; lp < Peek_Material_Info()->Vertex_Material_Count(); lp ++) {
|
|
VertexMaterialClass *mat = Peek_Material_Info()->Get_Vertex_Material(lp);
|
|
if (material == mat) {
|
|
VertexMaterialIdx[pass] = lp;
|
|
found = true;
|
|
mat->Release_Ref();
|
|
break;
|
|
}
|
|
mat->Release_Ref();
|
|
}
|
|
if (!found) {
|
|
Peek_Material_Info()->Add_Vertex_Material(material);
|
|
VertexMaterialIdx[pass] = Peek_Material_Info()->Vertex_Material_Count() - 1;
|
|
}
|
|
} else {
|
|
Peek_Material_Info()->Add_Vertex_Material(material);
|
|
VertexMaterialIdx[pass] = Peek_Material_Info()->Vertex_Material_Count() - 1;
|
|
}
|
|
|
|
if (!MultiVertexMaterial[pass]) {
|
|
Model->Set_Single_Material(Peek_Material_Info()->Peek_Vertex_Material(VertexMaterialIdx[pass]), pass);
|
|
}
|
|
return(VertexMaterialIdx[pass]);
|
|
}
|
|
|
|
int DynamicMeshClass::Set_Texture(int idx, int pass)
|
|
{
|
|
WWASSERT(idx < Peek_Material_Info()->Texture_Count());
|
|
TextureIdx[pass] = idx;
|
|
if (!MultiTexture[pass]) {
|
|
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
|
Model->Set_Single_Texture(tex, pass);
|
|
tex->Release_Ref();
|
|
}
|
|
return TextureIdx[pass];
|
|
}
|
|
|
|
int DynamicMeshClass::Set_Texture(TextureClass *texture, bool dont_search, int pass)
|
|
{
|
|
// Check if same as the last texture
|
|
if (Peek_Material_Info()->Texture_Count() && (TextureIdx[pass] != -1) && Peek_Material_Info()->Peek_Texture(TextureIdx[pass]) == texture) {
|
|
return TextureIdx[pass];
|
|
}
|
|
|
|
// if there are textures in the list then we may have just jumped
|
|
// to becoming a multi-texture object. Take care of that here.
|
|
if ((!MultiTexture[pass]) && Peek_Material_Info()->Texture_Count() && (TextureIdx[pass] != -1) && Peek_Material_Info()->Peek_Texture(TextureIdx[pass]) != texture) {
|
|
|
|
// allocate the array of per polygon material over-rides
|
|
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
|
Model->Initialize_Texture_Array(pass, 0, tex);
|
|
tex->Release_Ref();
|
|
|
|
// flag that we need to write the per polygon material overide array
|
|
MultiTexture[pass] = true;
|
|
}
|
|
|
|
// add the material to the material info class if we cant find it in the
|
|
// list. if we are not supposed to search the list for it then just add
|
|
// it.
|
|
if (!dont_search) {
|
|
for (int lp = 0, found = 0; lp < Peek_Material_Info()->Texture_Count(); lp ++) {
|
|
TextureClass *tex = Peek_Material_Info()->Get_Texture(lp);
|
|
if (texture == tex) {
|
|
TextureIdx[pass] = lp;
|
|
found = true;
|
|
tex->Release_Ref();
|
|
break;
|
|
}
|
|
tex->Release_Ref();
|
|
}
|
|
if (!found) {
|
|
Peek_Material_Info()->Add_Texture(texture);
|
|
TextureIdx[pass] = Peek_Material_Info()->Texture_Count() - 1;
|
|
}
|
|
} else {
|
|
Peek_Material_Info()->Add_Texture(texture);
|
|
TextureIdx[pass] = Peek_Material_Info()->Texture_Count() - 1;
|
|
}
|
|
|
|
if (!MultiTexture[pass]) {
|
|
TextureClass *tex = Peek_Material_Info()->Get_Texture(TextureIdx[pass]);
|
|
Model->Set_Single_Texture(tex, pass);
|
|
tex->Release_Ref();
|
|
}
|
|
return(TextureIdx[pass]);
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
// Remap locations to match a screen
|
|
void DynamicScreenMeshClass::Location( float x, float y, float z)
|
|
{
|
|
DynamicMeshClass::Location( (x * 2) - 1, Aspect - (y * 2 * Aspect), 0);
|
|
}
|
|
|
|
// For moving a vertex after the DynaMesh has already been created.
|
|
void DynamicScreenMeshClass::Move_Vertex(int index, float x, float y, float z)
|
|
{
|
|
DynamicMeshClass::Move_Vertex( index, (x * 2) - 1, Aspect - (y * 2 * Aspect), 0);
|
|
}
|
|
|
|
// Set position
|
|
void DynamicScreenMeshClass::Set_Position(const Vector3 &v)
|
|
{
|
|
DynamicMeshClass::Set_Position(Vector3(v.X * 2, -(v.Y * 2 * Aspect), 0));
|
|
}
|
|
|
|
void DynamicScreenMeshClass::Reset( void )
|
|
{
|
|
Reset_Flags();
|
|
Reset_Mesh_Counters();
|
|
}
|
|
|
|
|