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.
1193 lines
29 KiB
C++
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();
|
|
}
|
|
|