#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 *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 &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 existing_polygons; unsigned existing_polys = UsePolygonArray(&existing_polygons); unsigned source_polys = source_polygons.GetLength(); unsigned total_polys = existing_polys + source_polys; DynamicArrayOf new_polys(total_polys); unsigned i; for (i=0; i faces(total_polys); DynamicArrayOf< DynamicArrayOf > tfaces(total_polys); //tfaces[face_number][mutlitexture_number] DynamicArrayOf vertices; DynamicArrayOf normals; DynamicArrayOf tvertices; DynamicArrayOf colors; DynamicArrayOf 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; DynamicArrayOfmaterial_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;iUseMultiState(&multistate); for (j=0;jUseMatchingStateProxy(multistate[j]); matid = ((MAXProxies::MAXState *)state)->matID; state->DetachReference(); } multistate.DetachReferences(); // Get the geometry stuff DynamicArrayOf 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;jGetVertexProxy(); 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 > 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;kDetachArrayReferences(&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;imesh.faces[i] = faces[i]; int total_uvs = tfaces[i].GetLength(); // Should be either 1 or 2 for (int j=0;jmesh.tvFace[i] = tfaces[i][0]; break; } case 1: default: { } } } } int total_vertices = vertices.GetLength(); meshData->mesh.setNumVerts(total_vertices); for (i=0;imesh.setVert(i,vertices[i]); meshData->mesh.setNormal(i,normals[i]); } int total_tvertices = tvertices.GetLength(); meshData->mesh.setNumTVerts(total_tvertices); for (i=0;imesh.setTVert(i,tvertices[i]); } int total_colors = colors.GetLength(); meshData->mesh.setNumVertCol(total_colors); for (i=0;imesh.vertCol[i] = colors[i]; } /*int total_uv_faces = uvs.GetLength(); meshData->mesh.setNumTVerts(total_uvs); for (i=0;imesh.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 match; DynamicArrayOf count; DynamicArrayOf 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 meshes(unique_combinations); ElementSceneProxy *scene = GetSceneProxy(); Check_Object(scene); StateLibrary *state_library = scene->GetStateLibrary(); Check_Object(state_library); int primitive; for (primitive=0; primitiveGetLength() >= 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 polygons(count[primitive]); unsigned i; unsigned poly_count = 0; for (i=0; iGetLength() > 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 *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; iGetParentNode(); 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;iGetSubTexmap(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;iGetSubTexmap(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 > 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;xsetVert(x,vertex_array[x]); } newMesh->setNumFaces(face_array.GetLength()); for (x=0;xfaces[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(); }