Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

1193 lines
29 KiB
C++

#include "MAXProxyHeaders.hpp"
//
//############################################################################
//########################### MAXPolygonMesh ############################
//############################################################################
//
MemoryBlock*
MAXPolygonMesh::AllocatedMemory = NULL;
MAXPolygonMesh::ClassData*
MAXPolygonMesh::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::InitializeClass()
{
Verify(!AllocatedMemory);
AllocatedMemory =
new MemoryBlock(
sizeof(MAXPolygonMesh),
10,
10,
"MAXPolygonMesh"
);
Register_Object(AllocatedMemory);
Verify(!DefaultData);
DefaultData =
new ClassData(
MAXPolygonMeshClassID,
"MAXPolygonMesh",
PolygonMeshProxy::DefaultData
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
Unregister_Object(AllocatedMemory);
delete AllocatedMemory;
AllocatedMemory = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::Destroy()
{
Check_Object(this);
Verify(referenceCount == 1);
Verify(activePolygonProxies.IsEmpty());
Check_Pointer(proxiedMesh);
if (needToDelete)
{
delete meshData;
needToDelete = false;
}
if (newMesh)
{
Unregister_Pointer(newMesh);
delete newMesh;
newMesh = NULL;
}
DetachReference();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MAXPolygonMesh::MAXPolygonMesh(
MAXScene *scene,
MAXGroup *parent,
INode *mesh,
TimeValue t,
int index,
bool children
):
Proxies::PolygonMeshProxy(DefaultData, scene, parent),
proxiedMesh(mesh),
time(t),
childIndex(index),
pseudoChild(children)
{
newMesh = NULL;
bmeshInitialized = false;
Check_Pointer(this);
Check_Pointer(proxiedMesh);
//
// we get the data for the mesh by making it a tri object
//
needToDelete = FALSE;
Object *obj = proxiedMesh->EvalWorldState(time).obj;
Verify(obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)));
meshData = (TriObject *) obj->ConvertToType(time,Class_ID(TRIOBJ_CLASS_ID, 0));
//meshData->mesh.buildNormals();
//
// now that we have the local in max space let
// get the offset in max space and make them
// our space
//
Point3 offset_trans = proxiedMesh->GetObjOffsetPos();
Quat offset_rot = proxiedMesh->GetObjOffsetRot();
Point3D offset_translation;
offset_translation=ConvertMaxToMW(offset_trans);
UnitQuaternion offset_rotation;
offset_rotation=ConvertMaxToMW(offset_rot);
meshToPivot.BuildRotation(offset_rotation);
meshToPivot.BuildTranslation(offset_translation);
// Note that the TriObject should only be deleted
// if the pointer to it is not equal to the object
// pointer that called ConvertToType()
if (obj != meshData) needToDelete = TRUE;
if (pseudoChild)
{
childIndex = 0;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MAXPolygonMesh::~MAXPolygonMesh()
{
Check_Object(this);
if (needToDelete)
{
delete meshData;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
Check_Pointer(proxiedMesh);
MAXScene *scene_proxy = Cast_Pointer(MAXScene*, sceneProxy);
Check_Object(scene_proxy);
const INode *scene = scene_proxy->GetProxiedScene();
Check_Pointer(scene);
Object *obj = proxiedMesh->EvalWorldState(time).obj;
Verify(obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::Copy(Proxies::PolygonMeshProxy *mesh)
{
Check_Object(this);
Check_Object(mesh);
STOP(("Not implemented"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::TransferAndAppendToParentGroup(Proxies::GroupProxy *parent)
{
Check_Object(this);
Check_Pointer(proxiedMesh);
//
// detach the node but do not allow the position
// to be move ie. 1 as the second arg
//
proxiedMesh->Detach(time,1);
MAXGroup *old_parent = GetParentGroupProxy();
if (old_parent)
{
Check_Object(old_parent);
old_parent->DetachChildProxy(this);
}
else
{
Check_Object(GetSceneProxy());
GetSceneProxy()->DetachChildProxy(this);
}
INode *parent_rec = NULL;
if (parent)
{
MAXGroup *max_parent = Cast_Object(MAXGroup*, parent);
parent_rec = max_parent->GetProxiedGroup();
parent->AttachChildProxy(this);
}
else
{
MAXScene *max_scene = GetSceneProxy();
Check_Object(max_scene);
parent_rec = max_scene->GetProxiedScene();
max_scene->AttachChildProxy(this);
}
Check_Pointer(parent_rec);
proxiedMesh->AttachChild(parent_rec,1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
MAXPolygonMesh::UseNextSiblingProxy()
{
Check_Object(this);
Check_Pointer(proxiedMesh);
INode *parent = proxiedMesh->GetParentNode();
Check_Pointer(parent);
unsigned children = parent->NumberOfChildren();
Verify(children>0);
INode *next = NULL;
unsigned index;
if (pseudoChild)
{
children = proxiedMesh->NumberOfChildren();
Verify(children>0);
index = 0;
next = proxiedMesh->GetChildNode(index);
}
else
{
if (childIndex+1 < children)
{
index = childIndex+1;
next = parent->GetChildNode(index);
}
}
if (next)
{
return
GetSceneProxy()->InterpretRecord(GetParentGroupProxy(), next, index, true);
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Proxies::ChildProxy*
MAXPolygonMesh::UsePreviousSiblingProxy()
{
Check_Object(this);
Check_Pointer(proxiedMesh);
INode *parent = proxiedMesh->GetParentNode();
Check_Pointer(parent);
unsigned children = parent->NumberOfChildren();;
INode *prev = NULL;
if (!children)
{
return NULL;
}
if (childIndex-1 >= 0)
{
prev = parent->GetChildNode(childIndex-1);
}
if (prev)
{
return
GetSceneProxy()->InterpretRecord(GetParentGroupProxy(), prev, childIndex-1,true);
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MAXPolygonMesh::GetName(MString *name)
{
Check_Object(this);
Check_Object(name);
TCHAR *string = proxiedMesh->GetName();
int len = strlen(string);
if (len != 0)
{
*name = string;
return true;
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::SetName(const char* name)
{
Check_Object(this);
Check_Pointer(name);
TCHAR *string = (TCHAR *)name;
proxiedMesh->SetName(string);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MAXPolygonMesh::GetLocalToParent(LinearMatrix4D *matrix)
{
Check_Object(this);
Check_Pointer(matrix);
Check_Pointer(proxiedMesh);
Matrix3 LocalToWorld = proxiedMesh->GetNodeTM(time,NULL);
Matrix3 ParentToWorld = proxiedMesh->GetParentTM(time);
Matrix3 LocalToParent = LocalToWorld * Inverse(ParentToWorld);
//
// now decompose the max matrix and make our linear matrix
//
if (pseudoChild)
{
*matrix = LinearMatrix4D::Identity;
}
else
{
AffineParts parts;
decomp_affine(LocalToParent, &parts);
Point3D translation;
translation=ConvertMaxToMW(parts.t);
UnitQuaternion rotation;
rotation=ConvertMaxToMW(parts.q);
matrix->BuildRotation(rotation);
matrix->BuildTranslation(translation);
}
return *matrix != LinearMatrix4D::Identity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::SetLocalToParent(const LinearMatrix4D &matrix)
{
Check_Object(this);
Check_Object(&matrix);
// Matrix3 *mat3 = matrix;
// SetNodeTM(time, mat3);
STOP(("Not implemented"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MAXPolygonMesh::GetOBB(OBB *obb)
{
Check_Object(this);
Check_Pointer(obb);
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::SetOBB(const OBB &obb)
{
Check_Object(this);
Check_Object(&obb);
STOP(("Not implemented"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::SetBoundingSphere(const Sphere &sphere)
{
Check_Object(this);
Check_Object(&sphere);
STOP(("Not implemented"));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
MAXPolygonMesh::UsePolygonArray(DynamicArrayOf<Proxies::PolygonProxy*> *polygons)
{
Check_Object(this);
Check_Object(polygons);
Check_Pointer(meshData);
InitMesh();
unsigned face_count = face_array.GetLength();
polygons->SetLength(face_count);
for (unsigned i=0; i<face_count; ++i)
{
(*polygons)[i] = MAXPolygon::MakeProxy(this,&(face_array[i]),i);
Register_Object((*polygons)[i]);
}
return face_count;
}
Quat ConvertMWToMax(UnitQuaternion &quat)
{
Quat rotation;
rotation.x = quat.x;
rotation.y = -quat.z;
rotation.z = quat.y;
rotation.w = -quat.w;
return rotation;
}
Point3 ConvertMWToMax(Point3D &pnt)
{
Point3 translation;
translation.x = pnt.x;
translation.y = -pnt.z;
translation.z = pnt.y;
return translation;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::AddPolygons(Proxies::Process *process, DynamicArrayOf<Proxies::PolygonProxy*> &source_polygons)
{
Check_Object(this);
Check_Object(process);
Check_Object(&source_polygons);
Check_Pointer(meshData);
//
//------------------------------------------------------------------
// Make an array out of both the source polys and the existing polys
//------------------------------------------------------------------
//
DynamicArrayOf<Proxies::PolygonProxy*> existing_polygons;
unsigned existing_polys = UsePolygonArray(&existing_polygons);
unsigned source_polys = source_polygons.GetLength();
unsigned total_polys = existing_polys + source_polys;
DynamicArrayOf<Proxies::PolygonProxy*> new_polys(total_polys);
unsigned i;
for (i=0; i<existing_polys; ++i)
new_polys[i] = existing_polygons[i];
for (i=0; i<source_polys; ++i)
new_polys[i+existing_polys] = source_polygons[i];
//
//-------------------------------------------------
// Make the vertex index array
//-------------------------------------------------
DynamicArrayOf<Face> faces(total_polys);
DynamicArrayOf< DynamicArrayOf<TVFace> > tfaces(total_polys);
//tfaces[face_number][mutlitexture_number]
DynamicArrayOf<Point3> vertices;
DynamicArrayOf<Point3> normals;
DynamicArrayOf<Point3> tvertices;
DynamicArrayOf<VertColor> colors;
DynamicArrayOf<int> indices; // non optimized, the number of indices is the total number of vertices and normals - many duplicates
int current_index = 0;
int total_index = 0;
int current_tindex = 0;
int total_tindex = 0;
DynamicArrayOf<StdMat *>material_array;
int new_statecount = 0;
material_array.SetLength(0);
Proxies::StateLibrary *state_library = GetSceneProxy()->GetStateLibrary();
// TODO: Get the ProxiedMesh's material - should be a multi-material. Append these materials to it.
for (i=0;i<total_polys;++i)
{
int j;
// Get the material state
int matid = 0;
Proxies::MultiState multistate;
int state_count = new_polys[i]->UseMultiState(&multistate);
for (j=0;j<state_count;++j)
{
Proxies::StateProxy *state = state_library->UseMatchingStateProxy(multistate[j]);
matid = ((MAXProxies::MAXState *)state)->matID;
state->DetachReference();
}
multistate.DetachReferences();
// Get the geometry stuff
DynamicArrayOf<Proxies::IndexProxy *> poly_indices;
int index_count = new_polys[i]->UseIndexArray(&poly_indices);
Verify(3 == index_count);
total_index += index_count;
indices.SetLength(total_index);
vertices.SetLength(total_index);
normals.SetLength(total_index);
colors.SetLength(total_index);
for (j=0;j<index_count;++j)
{
Proxies::VertexProxy *vertex = poly_indices[j]->GetVertexProxy();
Stuff::Point3D position;
vertex->GetPosition(&position);
Stuff::Normal3D normal;
vertex->GetNormal(&normal);
Stuff::RGBAColor color;
vertex->GetColor(&color);
// Get the UV - Texture information
Stuff::DynamicArrayOf<Stuff::Vector2DOf<Stuff::Scalar> > tvector;
vertex->GetUVs(&tvector); // this is an array for the multitexture support
int tvector_count = tvector.GetLength();
total_tindex += tvector_count;
tvertices.SetLength(total_tindex);
tfaces[i].SetLength(tvector_count);
for (int k=0;k<tvector_count;++k)
{
tvertices[current_tindex].x = tvector[k].x;
tvertices[current_tindex].y = 1.0f - tvector[k].y;
tvertices[current_tindex].z = 0.0;
tfaces[i][k].t[j] = current_tindex;
current_tindex++;
}
faces[i].v[j] = current_index;
faces[i].flags = EDGE_ALL | HAS_TVERTS;
faces[i].setMatID(matid);
// Convert position and normal from MW to MAX
vertices[current_index] = ConvertMWToMax(position);
normals[current_index] = ConvertMWToMax((Stuff::Point3D)normal);
colors[current_index].x = color.red;
colors[current_index].y = color.green;
colors[current_index].z = color.blue;
indices[current_index] = current_index;
//faces[i].smGroup = smGroup
current_index++;
}
new_polys[i]->DetachArrayReferences(&poly_indices);
}
// Optimize the data
// TODO: reduce face vertex sharing
// Create the MAX materials
MAXScene *scene_proxy = Cast_Pointer(MAXScene*, sceneProxy);
Check_Object(scene_proxy);
scene_proxy->GetInterface()->GetMaterialLibrary().RemoveDuplicates();
// Copy the data into the mesh
meshData->mesh.setNumFaces(total_polys);
meshData->mesh.setNumTVFaces(total_polys);
for (i=0;i<total_polys;++i)
{
meshData->mesh.faces[i] = faces[i];
int total_uvs = tfaces[i].GetLength();
// Should be either 1 or 2
for (int j=0;j<total_uvs;++j)
{
switch (j)
{
case 0:
{
meshData->mesh.tvFace[i] = tfaces[i][0];
break;
}
case 1:
default:
{
}
}
}
}
int total_vertices = vertices.GetLength();
meshData->mesh.setNumVerts(total_vertices);
for (i=0;i<total_vertices;++i)
{
meshData->mesh.setVert(i,vertices[i]);
meshData->mesh.setNormal(i,normals[i]);
}
int total_tvertices = tvertices.GetLength();
meshData->mesh.setNumTVerts(total_tvertices);
for (i=0;i<total_tvertices;++i)
{
meshData->mesh.setTVert(i,tvertices[i]);
}
int total_colors = colors.GetLength();
meshData->mesh.setNumVertCol(total_colors);
for (i=0;i<total_colors;++i)
{
meshData->mesh.vertCol[i] = colors[i];
}
/*int total_uv_faces = uvs.GetLength();
meshData->mesh.setNumTVerts(total_uvs);
for (i=0;i<total_uvs;++i)
{
int total_TVerts = uvs[i].GetLength();
for (int j=0;j<total_TVerts;++j)
{
switch (j)
{
case 0:meshData->mesh.setTVert(i,uvs[i][0].x,uvs[i][0].y,0.0);break;
case 1:
default:
{
// too many textures (for multitexture support)
}
}
}
}
*/
DetachArrayReferences(&existing_polygons);
//
//-------------------------------------------------
// Now do the state analysis of the new polygon set
//-------------------------------------------------
//
/* DynamicArrayOf<unsigned> match;
DynamicArrayOf<unsigned> count;
DynamicArrayOf<Proxies::MultiState*> multi_states;
unsigned unique_combinations =
UseMultiStateArray(&multi_states, &match, &count, new_polys);
Verify(unique_combinations>0);
//
//----------------------------------------------------------------
// We need to create one MLRPolyMesh object per unique combination
//----------------------------------------------------------------
//
/* gos_PushCurrentHeap(MidLevelRenderer::Heap);
MLRShape *new_shape = new MLRShape(unique_combinations);
Register_Object(new_shape);
DynamicArrayOf<MLRPrimitiveBase*> meshes(unique_combinations);
ElementSceneProxy *scene = GetSceneProxy();
Check_Object(scene);
StateLibrary *state_library = scene->GetStateLibrary();
Check_Object(state_library);
int primitive;
for (primitive=0; primitive<unique_combinations; ++primitive)
{
Verify( multi_states[primitive]->GetLength() >= 0 &&
multi_states[primitive]->GetLength() <= 2);
if(multi_states[primitive]->GetLength() < 2)
{
meshes[primitive] = new MLR_I_L_PMesh;
}
else
{
meshes[primitive] = new MLR_I_L_DT_PMesh;
}
Register_Object(meshes[primitive]);
new_shape->Add(meshes[primitive]);
//
//--------------------------------------------------------------------
// For each unique combination, we need to create the mesh data
// structures, so we need to first identify the polygons to be grouped
// together
//--------------------------------------------------------------------
//
Verify(count[primitive]>0);
DynamicArrayOf<PolygonProxy*> polygons(count[primitive]);
unsigned i;
unsigned poly_count = 0;
for (i=0; i<total_polys && poly_count<count[primitive]; ++i)
{
PolygonProxy *polygon = new_polys[i];
Check_Object(polygon);
if (match[i] == primitive)
{
if (!poly_count)
{
Check_Object(multi_states[primitive]);
if(multi_states[primitive]->GetLength() > 0)
{
MLRStateProxy *state =
Cast_Object(
MLRStateProxy*,
state_library->UseMatchingStateProxy((*multi_states[primitive])[0])
);
Check_Object(state);
MLRState mlr_state;
meshes[primitive]->SetReferenceState(state->GetMLRState());
state->DetachReference();
}
if(multi_states[primitive]->GetLength() > 1)
{
MLRStateProxy *state =
Cast_Object(
MLRStateProxy*,
state_library->UseMatchingStateProxy((*multi_states[primitive])[1])
);
Check_Object(state);
MLRState mlr_state;
if(multi_states[primitive]->isInverted == false)
{
meshes[primitive]->SetReferenceState(state->GetMLRState(), 1);
}
else
{
meshes[primitive]->SetReferenceState(meshes[primitive]->GetReferenceState(), 1);
meshes[primitive]->SetReferenceState(state->GetMLRState(), 0);
}
state->DetachReference();
}
}
polygons[poly_count++] = polygon;
}
}
Verify(poly_count == count[primitive]);
if(multi_states[primitive]->GetLength() < 2)
{
SetPolyMeshArrays(
mlrShape,
Cast_Pointer(MLR_I_L_PMesh*, meshes[primitive]),
polygons,
process
);
}
else
{
SetPolyMeshArrays(
mlrShape,
Cast_Pointer(MLR_I_L_DT_PMesh*, meshes[primitive]),
polygons,
process,
multi_states[primitive]->isInverted
);
}
multi_states[primitive]->DetachReferences();
meshes[primitive]->DetachReference();
}
//
//-----------------------------------------------------------------------
// Now we need to clean out the shape and stick the new primitives inside
// it
//-----------------------------------------------------------------------
//
DetachArrayReferences(&existing_polygons);
mlrShape->DetachReference();
Check_Object(proxiedShape);
proxiedShape->SetMLRShape(new_shape);
mlrShape = new_shape;
mlrShape->AttachReference();
gos_PopCurrentHeap();
*/
//
//----------------------------------------------------------
// Clean up the proxy arrays, then load up the useful arrays
//----------------------------------------------------------
//
// LoadArrays();
}
void
MAXPolygonMesh::SetToMatchMultiState(Proxies::MultiState* multi_state)
{
STOP(("Not implemented"));
}
#if 0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MAXPolygonMesh::SetToMatchStateProxy(Proxies::StateProxy* state)
{
STOP(("Not implemented"));
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
unsigned
MAXPolygonMesh::UseVertexArray(DynamicArrayOf<Proxies::VertexProxy*> *vertices)
{
Check_Object(this);
Check_Object(vertices);
Check_Pointer(meshData);
InitMesh();
unsigned vertex_count = vertex_array.GetLength();
vertices->SetLength(vertex_count);
for (unsigned i=0; i<vertex_count; ++i)
{
(*vertices)[i] = MAXVertex::MakeProxy(this,
i,
0,
&(vertex_array[i]),-1);
Register_Object((*vertices)[i]);
}
return vertex_count;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
INode
*MAXPolygonMesh::GetNextChild()
{
Check_Pointer(proxiedMesh);
INode *parent = proxiedMesh->GetParentNode();
Check_Pointer(parent);
unsigned children = parent->NumberOfChildren();;
if (!children)
{
return NULL;
}
if (childIndex+1 < children)
{
INode *child = parent->GetChildNode(childIndex);
childIndex++;
return child;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
INode
*MAXPolygonMesh::GetPreviousChild()
{
Check_Pointer(proxiedMesh);
INode *parent = proxiedMesh->GetParentNode();
Check_Pointer(parent);
unsigned children = parent->NumberOfChildren();;
if (!children)
{
return NULL;
}
if (childIndex > -1)
{
INode *child = parent->GetChildNode(childIndex);
childIndex--;
return child;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MAXPolygonMesh::GetNumberTextureMaps(int face_index)
{
Check_Pointer(proxiedMesh);
Mtl* m = proxiedMesh->GetMtl();
int index = 0;
if (face_index >= 0)
{
Face face = meshData->mesh.faces[face_index];
index = face.getMatID();
}
int num_sub = 0;
Mtl* mat = NULL;
if (m)
{
num_sub = m->NumSubMtls();
if (index < num_sub)
{
mat = m->GetSubMtl(index);
}
else
{
mat = m;
}
}
if (mat == NULL) return -1;
Check_Pointer(mat);
int texture_count = 0;
for (int i=0;i<NTEXMAPS;i++)
{
if (i==ID_OP) continue; // skip over the opacity map cause we use it
Texmap* texmap = NULL;
texmap = m->GetSubTexmap(i);
if (texmap!=NULL)
{
texture_count++;
}
}
return texture_count;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MAXPolygonMesh::GetUVTypeOfMap(int texture_index, int face_index)
{
Check_Pointer(proxiedMesh);
Mtl* m = proxiedMesh->GetMtl();
Check_Pointer(m);
int index = 0;
if (face_index >= 0)
{
Face face = meshData->mesh.faces[face_index];
index = face.getMatID();
}
int num_sub = 0;
Mtl* mat = NULL;
if (m)
{
num_sub = m->NumSubMtls();
if (index < num_sub)
{
mat = m->GetSubMtl(index);
}
else
{
mat = m;
}
}
Check_Pointer(mat);
int texture_count = 0;
int uv_type = UVWSRC_EXPLICIT;
for (int i=0;i<NTEXMAPS;i++)
{
if (i==ID_OP) continue; // skip over the opacity map cause we use it
Texmap* texmap = NULL;
texmap = mat->GetSubTexmap(i);
if (texmap!=NULL)
{
uv_type = texmap->GetUVWSource();
texture_count++;
if (texture_index == texture_count) break;
}
}
return uv_type;
}
int MAXPolygonMesh::InitMesh()
{
if (!bmeshInitialized)
{
//JKYLE - defer this work until it is needed
meshData->mesh.buildNormals();
//Split the mesh by smoothing group
// Create a mesh for each smoothing group
int face_count = meshData->mesh.numFaces;
int vertex_count = meshData->mesh.numVerts;
// Create a hash table of mappings from the original vertex index to the multiple copies of the new vertex index
// each copy of the vertex belongs to a unique smoothing group
DynamicArrayOf< DynamicArrayOf<DWORD> > hash_table;
hash_table.SetLength(vertex_count);
vertex_array.SetLength(vertex_count);
vertex_ref_array.SetLength(vertex_count);
face_array.SetLength(face_count);
vertex_revmap.SetLength(vertex_count);
for (int iVertex = 0;iVertex < vertex_count;iVertex++)
{
vertex_array[iVertex] = meshData->mesh.verts[iVertex];
vertex_ref_array[iVertex] = -1;
vertex_revmap[iVertex] = iVertex;
hash_table[iVertex].SetLength(1);
hash_table[iVertex][0] = iVertex;
}
for (int iFace = 0;iFace < face_count;iFace++)
{
face_array[iFace] = meshData->mesh.faces[iFace];
Face *pFace = &face_array[iFace];
DWORD group = meshData->mesh.faces[iFace].smGroup;
// We are done with the meshData for this iteration, use pFace and group
// find or create the group index
int group_count = group_array.GetLength();
for (int iGroup = 0;iGroup < group_count;iGroup++)
{
if (group_array[iGroup] == group)
break; // Found group
}
if (iGroup == group_count)
{
// did not find group, add one
group_count++;
group_array.SetLength(group_count);
group_array[iGroup] = group;
}
// iGroup is now the index in group_array that equals group
// Set the vertices in the face to the matching vertex in vertex_array that matches the smoothing group
for (int i = 0;i<3;i++)
{
DWORD iVertex = pFace->v[i];
Verify(iVertex < vertex_count);
// Find the vertex index in the hash table such that the vertex is in the same smoothing group
int hash_count = hash_table[iVertex].GetLength();
for (int iHash = 0;iHash < hash_count;iHash++)
{
DWORD hash_vert = hash_table[iVertex][iHash];
if (-1 == vertex_ref_array[hash_vert])
{
//This is the first time this vertex is used, so it has no reference to a group
vertex_ref_array[hash_vert] = iGroup;
break;
}
else
{
DWORD group_ref = vertex_ref_array[hash_vert];
if (iGroup == vertex_ref_array[hash_vert])
{
// we found the vertex
break;
}
}
}
//
if (iHash == hash_count)
{
// we did not find the same vertex in the right smoothing group, so add it
// first make a new vertex, copy of the old vertex
DWORD new_vertex = vertex_count;
vertex_count++;
vertex_array.SetLength(vertex_count);
vertex_ref_array.SetLength(vertex_count);
vertex_array[new_vertex] = vertex_array[iVertex];
vertex_ref_array[new_vertex] = iGroup;
vertex_revmap.SetLength(vertex_count);
vertex_revmap[new_vertex] = iVertex;
// add the new entry to the hash table
hash_count++;
hash_table[iVertex].SetLength(hash_count);
hash_table[iVertex][iHash] = new_vertex;
}
pFace->v[i] = hash_table[iVertex][iHash];
}
}
bmeshInitialized = true;
}
return 1;
}
Point3 *MAXPolygonMesh::GetVertex(DWORD index)
{
InitMesh();
Verify(index < vertex_array.GetLength());
return &(vertex_array[index]);
}
DWORD MAXPolygonMesh::GetVertexGroup(DWORD index)
{
InitMesh();
// If returns 0 then this is flat shaded
return group_array[vertex_ref_array[index]];
}
int MAXPolygonMesh::GetNumVertices()
{
InitMesh();
return vertex_array.GetLength();
}
TVFace *MAXPolygonMesh::GetTVFace(int index)
{
Verify(index < meshData->mesh.numFaces);
return &meshData->mesh.tvFace[index];
}
int MAXPolygonMesh::GetnumTVerts()
{
return meshData->mesh.numTVerts;
}
UVVert MAXPolygonMesh::GetTVert(DWORD index)
{
Verify(index < meshData->mesh.numTVerts);
return meshData->mesh.tVerts[index];
}
void MAXPolygonMesh::SetTVert(DWORD index, UVVert tvert)
{
meshData->mesh.setTVert(index,tvert);
}
int MAXPolygonMesh::GetnumCVerts()
{
return meshData->mesh.numCVerts;
}
VertColor *MAXPolygonMesh::GetvertColor(DWORD index)
{
return &meshData->mesh.vertCol[index];
}
Point3 MAXPolygonMesh::GetFaceNormal(DWORD index)
{
InitMesh();
// These are flat shaded vertex normals
// Index is the face index
Point3 p0 = vertex_array[face_array[index].v[0]];
Point3 p1 = vertex_array[face_array[index].v[1]];
Point3 p2 = vertex_array[face_array[index].v[2]];
Point3 norm = CrossProd(p1-p0,p2-p1);
return norm;
}
Point3 MAXPolygonMesh::GetVertexNormal(DWORD index)
{
InitMesh();
// These are gourand shaded vertex normals
// Which index is this & how is it calculated?
//DWORD dwIndex = vertex_revmap[index];
//Verify(-1 != dwIndex);
if (!newMesh)
{
newMesh = new Mesh();
Register_Pointer(newMesh);
newMesh->setNumVerts(vertex_array.GetLength());
for (int x=0;x<vertex_array.GetLength();x++)
{
newMesh->setVert(x,vertex_array[x]);
}
newMesh->setNumFaces(face_array.GetLength());
for (x=0;x<face_array.GetLength();x++)
{
newMesh->faces[x] = face_array[x];
}
newMesh->buildNormals();
}
return newMesh->getNormal(index);
}
void MAXPolygonMesh::SetNormal(DWORD index,Point3 norm)
{
meshData->mesh.setNormal(index,norm);
}
int MAXPolygonMesh::GetNumVertCol()
{
return meshData->mesh.getNumVertCol();
}