bool CEditableMesh::Convert( INode *node ) { // prepares & checks BOOL bDeleteObj; bool bResult = true; TriObject *obj = ExtractTriObject( node, bDeleteObj ); if( !obj ){ ELog.Msg(mtError,"%s -> Can't convert to TriObject", node->GetName() ); return false; } if( obj->mesh.getNumFaces() <=0 ){ ELog.Msg(mtError,"%s -> There are no faces ?", node->GetName() ); if (bDeleteObj) delete (obj); return false; } Mtl *pMtlMain = node->GetMtl(); DWORD cSubMaterials=0; if (pMtlMain){ // There is at least one material. We're in case 1) or 2) cSubMaterials = pMtlMain->NumSubMtls(); if (cSubMaterials < 1){ // Count the material itself as a submaterial. cSubMaterials = 1; } } // build normals obj->mesh.buildRenderNormals(); // vertices m_VertCount = obj->mesh.getNumVerts(); m_Vertices = xr_alloc<Fvector>(m_VertCount); for (int v_i=0; v_i<m_VertCount; v_i++){ Point3* p = obj->mesh.verts+v_i; m_Vertices[v_i].set(p->x,p->y,p->z); } // set smooth group MAX type m_Flags.set(flSGMask,TRUE); // faces m_FaceCount = obj->mesh.getNumFaces(); m_Faces = xr_alloc<st_Face> (m_FaceCount); m_SmoothGroups = xr_alloc<u32> (m_FaceCount); m_VMRefs.reserve(m_FaceCount*3); if (0==obj->mesh.mapFaces(1)) { bResult = false; ELog.Msg(mtError,"'%s' hasn't UV mapping!", node->GetName()); } if (bResult) { CSurface* surf=0; for (int f_i=0; f_i<m_FaceCount; ++f_i) { Face* vf = obj->mesh.faces+f_i; TVFace* tf = obj->mesh.mapFaces(1) + f_i; if (!tf) { bResult = false; ELog.Msg(mtError,"'%s' hasn't UV mapping!", node->GetName()); break; } m_SmoothGroups[f_i] = vf->getSmGroup(); for (int k=0; k<3; ++k) { m_Faces[f_i].pv[k].pindex = vf->v[k]; m_VMRefs.push_back(st_VMapPtLst()); st_VMapPtLst& vm_lst = m_VMRefs.back(); vm_lst.count = 1; vm_lst.pts = xr_alloc<st_VMapPt>(vm_lst.count); for (DWORD vm_i=0; vm_i<vm_lst.count; ++vm_i) { vm_lst.pts[vm_i].vmap_index = 0; vm_lst.pts[vm_i].index = tf->t[k]; } m_Faces[f_i].pv[k].vmref = m_VMRefs.size()-1; if (!bResult) break; } if (pMtlMain) { int m_id = obj->mesh.getFaceMtlIndex(f_i); if (cSubMaterials == 1) { m_id = 0; }else { // SDK recommends mod'ing the material ID by the valid # of materials, // as sometimes a material number that's too high is returned. m_id %= cSubMaterials; } surf = m_Parent->CreateSurface(pMtlMain,m_id); if (!surf) bResult = false; } if (!bResult) break; m_SurfFaces[surf].push_back(f_i); } } // vmaps if( bResult ){ int vm_cnt = obj->mesh.getNumTVerts(); m_VMaps.resize(1); st_VMap*& VM = m_VMaps.back(); VM = xr_new<st_VMap>("Texture",vmtUV,false); for (int tx_i=0; tx_i<vm_cnt; tx_i++){ UVVert* tv = obj->mesh.tVerts + tx_i; VM->appendUV(tv->x,1-tv->y); } } if ((GetVertexCount()<4)||(GetFaceCount()<2)) { ELog.Msg(mtError,"Invalid mesh: '%s'. Faces<2 or Verts<4"); bResult = false; } if (bResult ){ ELog.Msg(mtInformation,"Model '%s' contains: %d points, %d faces", node->GetName(), m_VertCount, m_FaceCount); } if (bResult) { RecomputeBBox (); OptimizeMesh (false); RebuildVMaps (); ELog.Msg(mtInformation,"Model '%s' converted: %d points, %d faces", node->GetName(), GetVertexCount(), GetFaceCount()); } if (bDeleteObj) delete (obj); return bResult; }
bool CEditableMesh::Convert(CExporter* E) { bool bResult = true; m_Name = E->m_MeshNode->GetName(); // maps // Weight maps m_VMaps.resize(E->m_Bones.size()+1); for (DWORD b_i=0; b_i<E->m_Bones.size(); b_i++) m_VMaps[b_i] = xr_new<st_VMap>(E->m_Bones[b_i]->name.c_str(),vmtWeight,false);; // UV map int VM_UV_idx = m_VMaps.size()-1; st_VMap*& VM_UV = m_VMaps[VM_UV_idx]; VM_UV = xr_new<st_VMap>("texture",vmtUV,false); // points { m_VertCount = E->m_ExpVertices.size(); m_Vertices = xr_alloc<Fvector>(m_VertCount); Fvector* p_it = m_Vertices; for (ExpVertIt ev_it=E->m_ExpVertices.begin(); ev_it!=E->m_ExpVertices.end(); ev_it++,p_it++){ p_it->set ((*ev_it)->P); VM_UV->appendUV ((*ev_it)->uv.x,(*ev_it)->uv.y); } } // faces { // set smooth group MAX type m_Flags.set(flSGMask,TRUE); // reserve space for faces and references m_FaceCount = E->m_ExpFaces.size(); m_Faces = xr_alloc<st_Face> (m_FaceCount); m_SmoothGroups = xr_alloc<u32> (m_FaceCount); m_VMRefs.resize (m_VertCount); int f_id=0; for (ExpFaceIt ef_it=E->m_ExpFaces.begin(); ef_it!=E->m_ExpFaces.end(); ef_it++,f_id++){ // FACES m_SmoothGroups[f_id] = (*ef_it)->sm_group; st_Face& F = m_Faces[f_id]; for (int k=0; k<3; ++k) { int v_idx = (*ef_it)->v[k]; st_FaceVert& vt = F.pv[k]; st_VERT* V = E->m_ExpVertices[v_idx]; vt.pindex = v_idx; st_VMapPtLst& vm_lst= m_VMRefs[vt.pindex]; vm_lst.count = V->data.size()+1; vm_lst.pts = xr_alloc<st_VMapPt>(vm_lst.count); vm_lst.pts[0].vmap_index= VM_UV_idx; vm_lst.pts[0].index = vt.pindex; for (VDIt vd_it=V->data.begin(); vd_it!=V->data.end(); vd_it++){ DWORD idx = vd_it-V->data.begin()+1; st_VMap* vm = m_VMaps[vd_it->bone]; vm->appendW (vd_it->weight); vm_lst.pts[idx].vmap_index = vd_it->bone; vm_lst.pts[idx].index = vm->size()-1; } vt.vmref = vt.pindex; } CSurface* surf = m_Parent->CreateSurface(E->m_MtlMain,(*ef_it)->m_id); if (!surf){ bResult = FALSE; break; } m_SurfFaces[surf].push_back(f_id); } } if ((GetVertexCount()<4)||(GetFaceCount()<2)) { Log("!Invalid mesh: '%s'. Faces<2 or Verts<4",*Name()); bResult = false; } if (bResult) { RecomputeBBox (); OptimizeMesh (true);//false); RebuildVMaps (); } return bResult; }
std::shared_ptr<Mesh> MeshUtil::CreateCylinder(const std::string &name, float topR, float bottomR, float height, int segH, int segV) { if (segH < 2 || segV < 3) { LOGW << "SegH or SegV tooooo small!"; return nullptr; } Mesh::Ptr mesh = Mesh::Create(name); // allocate some space. mesh->Positions.Data.reserve((segV * segH + 2) * 3); mesh->Indices.Data.reserve((segV * segH * 2) * 3); float avgRadian = Angle::PI * 2.0f / segV; /*if (inclusive) { topR = topR / std::cos(avgRadian * 0.5f); bottomR = bottomR / std::cos(avgRadian * 0.5f); }*/ float currentHeight = height / 2.0f; float currentRadius = topR; float heightStep = height / (segH - 1); float radiusSetp = (topR - bottomR) / (segH - 1); std::vector<unsigned int> previousRing; previousRing.reserve(segV * 3); std::vector<unsigned int> currentRing; currentRing.reserve(segV * 3); unsigned int index = 0; auto AddVertex = [¤tRing, &mesh, &index](float x, float y, float z) -> unsigned int { mesh->Positions.Data.insert(mesh->Positions.Data.end(), { x, y, z }); return index++; }; for (int h = 0; h < segH; h++) { // fill current ring for (int v = 0; v < segV; v++) { float radian = avgRadian * v; currentRing.push_back(AddVertex( cos(radian) * currentRadius, currentHeight, sin(radian) * currentRadius)); } if (previousRing.size() > 0) { // has previous ring, we connect them to triangles. for (unsigned int i = 0; i < currentRing.size() - 1; i++) { mesh->Indices.Data.insert(mesh->Indices.Data.end(), { previousRing[i], previousRing[i + 1], currentRing[i + 1], currentRing[i + 1], currentRing[i], previousRing[i] }); } mesh->Indices.Data.insert(mesh->Indices.Data.end(), { previousRing.back(), previousRing.front(), currentRing.front(), currentRing.front(), currentRing.back(), previousRing.back() }); } else { // don't have previous ring, then we're on top. // close this ring. unsigned int center = AddVertex(0, currentHeight, 0); for (unsigned int i = 0; i < currentRing.size() - 1; i++) { mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing[i + 1], currentRing[i] }); } mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing.front(), currentRing.back() }); } previousRing = currentRing; currentRing.erase(currentRing.begin(), currentRing.end()); currentHeight -= heightStep; currentRadius -= radiusSetp; } // close bottom ring unsigned int center = AddVertex(0, -height / 2.0f, 0); for (unsigned int i = 0; i < previousRing.size() - 1; i++) { mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing[i], previousRing[i + 1] }); } mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing.back(), previousRing.front() }); LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]"; if (topR == 0 || bottomR == 0) OptimizeMesh(mesh); mesh->CalculateAABB(); return mesh; }
bool CEditableMesh::LoadMesh(IReader& F){ u32 version=0; R_ASSERT(F.r_chunk(EMESH_CHUNK_VERSION,&version)); if (version!=EMESH_CURRENT_VERSION){ ELog.DlgMsg( mtError, "CEditableMesh: unsuported file version. Mesh can't load."); return false; } R_ASSERT(F.find_chunk(EMESH_CHUNK_MESHNAME)); F.r_stringZ (m_Name); R_ASSERT(F.r_chunk(EMESH_CHUNK_BBOX,&m_Box)); R_ASSERT(F.r_chunk(EMESH_CHUNK_FLAGS,&m_Flags)); F.r_chunk(EMESH_CHUNK_BOP,&m_Ops); R_ASSERT(F.find_chunk(EMESH_CHUNK_VERTS)); m_VertCount = F.r_u32(); if (m_VertCount<3){ Log ("! CEditableMesh: Vertices<3."); return false; } m_Vertices = xr_alloc<Fvector>(m_VertCount); F.r (m_Vertices, m_VertCount*sizeof(Fvector)); R_ASSERT(F.find_chunk(EMESH_CHUNK_FACES)); m_FaceCount = F.r_u32(); m_Faces = xr_alloc<st_Face>(m_FaceCount); if (m_FaceCount==0){ Log ("! CEditableMesh: Faces==0."); return false; } F.r (m_Faces, m_FaceCount*sizeof(st_Face)); m_SmoothGroups = xr_alloc<u32>(m_FaceCount); Memory.mem_fill32 (m_SmoothGroups,m_Flags.is(flSGMask)?0:u32(-1),m_FaceCount); u32 sg_chunk_size = F.find_chunk(EMESH_CHUNK_SG); if (sg_chunk_size){ VERIFY (m_FaceCount*sizeof(u32)==sg_chunk_size); F.r (m_SmoothGroups, m_FaceCount*sizeof(u32)); } R_ASSERT(F.find_chunk(EMESH_CHUNK_VMREFS)); m_VMRefs.resize (F.r_u32()); int sz_vmpt = sizeof(st_VMapPt); for (VMRefsIt r_it=m_VMRefs.begin(); r_it!=m_VMRefs.end(); r_it++){ r_it->count = F.r_u8(); r_it->pts = xr_alloc<st_VMapPt>(r_it->count); F.r (r_it->pts, sz_vmpt*r_it->count); } R_ASSERT(F.find_chunk(EMESH_CHUNK_SFACE)); string128 surf_name; u32 sface_cnt = F.r_u16(); // surface-face count for (u32 sp_i=0; sp_i<sface_cnt; sp_i++){ F.r_stringZ (surf_name,sizeof(surf_name)); int surf_id; CSurface* surf = m_Parent->FindSurfaceByName(surf_name, &surf_id); VERIFY(surf); IntVec& face_lst = m_SurfFaces[surf]; face_lst.resize (F.r_u32()); if (face_lst.empty()){ Log ("! Empty surface found: %s",surf->_Name()); return false; } F.r (&*face_lst.begin(), face_lst.size()*sizeof(int)); std::sort (face_lst.begin(),face_lst.end()); } if(F.find_chunk(EMESH_CHUNK_VMAPS_2)){ m_VMaps.resize (F.r_u32()); for (VMapIt vm_it=m_VMaps.begin(); vm_it!=m_VMaps.end(); vm_it++){ *vm_it = new st_VMap(); F.r_stringZ ((*vm_it)->name); (*vm_it)->dim = F.r_u8(); (*vm_it)->polymap=F.r_u8(); (*vm_it)->type = F.r_u8(); (*vm_it)->resize(F.r_u32()); F.r ((*vm_it)->getVMdata(), (*vm_it)->VMdatasize()); F.r ((*vm_it)->getVIdata(), (*vm_it)->VIdatasize()); if ((*vm_it)->polymap) F.r ((*vm_it)->getPIdata(), (*vm_it)->PIdatasize()); } }else{ if(F.find_chunk(EMESH_CHUNK_VMAPS_1)){ m_VMaps.resize (F.r_u32()); for (VMapIt vm_it=m_VMaps.begin(); vm_it!=m_VMaps.end(); vm_it++){ *vm_it = new st_VMap(); F.r_stringZ ((*vm_it)->name); (*vm_it)->dim = F.r_u8(); (*vm_it)->type = F.r_u8(); (*vm_it)->resize(F.r_u32()); F.r ((*vm_it)->getVMdata(), (*vm_it)->VMdatasize() ); } }else{ R_ASSERT(F.find_chunk(EMESH_CHUNK_VMAPS_0)); m_VMaps.resize (F.r_u32()); for (VMapIt vm_it=m_VMaps.begin(); vm_it!=m_VMaps.end(); vm_it++){ *vm_it = new st_VMap(); F.r_stringZ ((*vm_it)->name); (*vm_it)->dim = 2; (*vm_it)->type = vmtUV; (*vm_it)->resize(F.r_u32()); F.r ((*vm_it)->getVMdata(), (*vm_it)->VMdatasize() ); } } // update vmaps RebuildVMaps(); } #ifdef _EDITOR if (!EPrefs->object_flags.is(epoDeffLoadRB)){ GenerateFNormals (); GenerateAdjacency (); GenerateVNormals (0); GenerateRenderBuffers(); UnloadFNormals (); UnloadAdjacency (); UnloadVNormals (); } if (!EPrefs->object_flags.is(epoDeffLoadCF)) GenerateCFModel(); #endif OptimizeMesh(false); RebuildVMaps(); return true; }
std::shared_ptr<Mesh> MeshUtil::CreateSphere(const std::string &name, float radius, int segH, int segV) { if (segH < 2 || segV < 3) { LOGW << "SegH or SegV tooooo small!"; return nullptr; } Mesh::Ptr mesh = Mesh::Create(name); float avgRadianH = Angle::PI / (segH - 1); float avgRadianV = Angle::PI * 2.0f / segV; float currentHeight = radius; float currentRadius = 0.0f; std::vector<unsigned int> previousRing; previousRing.reserve(segV * 3); std::vector<unsigned int> currentRing; currentRing.reserve(segV * 3); /*if (inclusive) radius = radius / std::cos(avgRadianH * 0.5f);*/ unsigned int index = 0; auto AddVertex = [¤tRing, &mesh, &index](float x, float y, float z) -> unsigned int { mesh->Positions.Data.insert(mesh->Positions.Data.end(), { x, y, z }); return index++; }; for (int h = 0; h < segH; h++) { currentRadius = std::sin(h * avgRadianH) * radius; currentHeight = std::cos(h * avgRadianH) * radius; // fill current ring for (int v = 0; v < segV; v++) { float radian = avgRadianV * v; currentRing.push_back(AddVertex( cos(radian) * currentRadius, currentHeight, sin(radian) * currentRadius)); } if (previousRing.size() > 0) { // has previous ring, we connect them to triangles. for (unsigned int i = 0; i < currentRing.size() - 1; i++) { mesh->Indices.Data.insert(mesh->Indices.Data.end(), { previousRing[i], previousRing[i + 1], currentRing[i + 1], currentRing[i + 1], currentRing[i], previousRing[i] }); } mesh->Indices.Data.insert(mesh->Indices.Data.end(), { previousRing.back(), previousRing.front(), currentRing.front(), currentRing.front(), currentRing.back(), previousRing.back() }); } else { // don't have previous ring, then we're on top. // close this ring. unsigned int center = AddVertex(0, currentHeight, 0); for (unsigned int i = 0; i < currentRing.size() - 1; i++) { mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing[i + 1], currentRing[i] }); } mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, currentRing.front(), currentRing.back() }); } previousRing = currentRing; currentRing.erase(currentRing.begin(), currentRing.end()); } // close bottom ring unsigned int center = AddVertex(0, -radius, 0); for (unsigned int i = 0; i < previousRing.size() - 1; i++) { mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing[i], previousRing[i + 1] }); } mesh->Indices.Data.insert(mesh->Indices.Data.end(), { center, previousRing.back(), previousRing.front() }); LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]"; OptimizeMesh(mesh); mesh->CalculateAABB(); return mesh; }