void UVWChannel::SetWithMesh(MNMesh *mesh,int channel) { MNMap *mnmap = mesh->M(channel); if(mnmap&&mnmap->numv>0&&mnmap->numf>0) { int i; mNumVerts = mnmap->numv; mVerts = new UVVert[mNumVerts]; for(i=0;i<mNumVerts;++i) { mVerts[i] = mnmap->v[i]; } mNumFaces = mnmap->numf; mFaces = new UVWChannel::Face[mNumFaces]; for(i=0;i<mNumFaces;++i) { MNMapFace *face = mnmap->F(i); mFaces[i].AllocateVerts(face->deg); for(int j=0;j<mFaces[i].mNumVerts;++j) { mFaces[i].mTVVerts[j] = face->tv[j]; } } } }
///////////////////////////////////////////////////////////////////// // Note: // The vertex color data that is used by the ModifyPolyObject // method was created based on this PolyObject's displayed // TriMesh (Mesh). This data is mapped back to the original // PolyMesh (MNMesh). The mapping relies on the same process // that was used by the method MNMesh::OutToTri() to generate // the Mesh. // Warning: // The mapping used in this method will need to be updated if // anything changes in the way MNMesh generates its displayed Mesh. // Author: // Wayne Catalfano // Date: // August 30, 2000 // /////////////////////////////////////////////////////////////////////// void ApplyVCMod::ModifyPolyObject(PolyObject* pPolyObj, TimeValue t) { static int calls = 0; iValid = FOREVER; Interval valid = GetValidity(t); MNMesh& mesh = pPolyObj->GetMesh(); if (mesh.MNum() < 1) mesh.SetMapNum (1); // get the vertex color map MNMap* pVCMap = mesh.M(0); // initialize to an all white map if necessary if (pVCMap->GetFlag(MN_DEAD)) mesh.InitMap(0); if (mixedVertexColors.Count() > 0) { pVCMap->setNumVerts (mesh.VNum()); pVCMap->setNumFaces (mesh.FNum()); // MNMesh keeps the vertices in the same order when it creates // the Mesh. The Mesh vertices Map directly back to the MNMesh // vertices in the same order. for (int i=0; i<mesh.VNum(); i++) { pVCMap->v[i] = i<mixedVertexColors.Count() ? Point3(mixedVertexColors[i]->r, mixedVertexColors[i]->g, mixedVertexColors[i]->b) : Point3(1.0f, 1.0f, 1.0f); } for (int i=0; i<mesh.FNum(); i++) { if (mesh.F(i)->GetFlag (MN_DEAD)) continue; pVCMap->F(i)->SetSize(mesh.F(i)->deg); for (int j=0; j<mesh.F(i)->deg;++j) { pVCMap->F(i)->tv[j] = mesh.F(i)->vtx[j]; } } } else if (faceColors.Count() > 0) { int numVCVerts = 0; for (int i=0; i<mesh.FNum(); i++) { if (mesh.F(i)->GetFlag (MN_DEAD)) continue; numVCVerts += mesh.F(i)->deg; } pVCMap->setNumVerts (numVCVerts); pVCMap->setNumFaces (mesh.FNum()); // This mapping process mimicks the process used to generate // the Mesh in the method MNMesh::OutToTri(). int faceVert = 0; int triFaceIndx = 0; BitArray faceVertSet; for (int i=0; i<mesh.FNum(); i++) { if (mesh.F(i)->GetFlag (MN_DEAD)) continue; pVCMap->F(i)->SetSize(mesh.F(i)->deg); faceVertSet.SetSize(mesh.F(i)->deg); faceVertSet.ClearAll(); int tnum = mesh.F(i)->TriNum()*3; Tab<int> triVerts; // The method MNFace::GetTriangles is at the heart of the // process used to map Mesh triangles back to MNMesh faces. mesh.F(i)->GetTriangles (triVerts); for (int j=0; j<tnum; j+=3) { for (int k=0; k<3; ++k) { int vertIndex = triVerts[j+k]; // check if we already added a vert for this index if (!faceVertSet[vertIndex]) { pVCMap->v[faceVert] = triFaceIndx<faceColors.Count() ? Point3(faceColors[triFaceIndx]->colors[k].r, faceColors[triFaceIndx]->colors[k].g, faceColors[triFaceIndx]->colors[k].b) : Point3(1.0f, 1.0f, 1.0f); pVCMap->F(i)->tv[vertIndex] = faceVert; faceVertSet.Set(vertIndex); faceVert++; } } ++triFaceIndx; } } } NotifyDependents(Interval(t,t), PART_VERTCOLOR & PART_EXCLUDE_RADIOSITY, REFMSG_CHANGE); NotifyDependents(Interval(t,t), PART_TOPO & PART_EXCLUDE_RADIOSITY, REFMSG_CHANGE); pPolyObj->UpdateValidity(VERT_COLOR_CHAN_NUM, valid); }
IGeometryChecker::ReturnVal MissingUVCoordinatesChecker::GeometryCheck(TimeValue t,INode *nodeToCheck, IGeometryChecker::OutputVal &val) { val.mIndex.ZeroCount(); if(IsSupported(nodeToCheck)) { LARGE_INTEGER ups,startTime; QueryPerformanceFrequency(&ups); QueryPerformanceCounter(&startTime); //used to see if we need to pop up a dialog bool compute = true; bool checkTime = GetIGeometryCheckerManager()->GetAutoUpdate();//only check time for the dialog if auto update is active! UVWChannel uvmesh; ObjectState os = nodeToCheck->EvalWorldState(t); Object *obj = os.obj; if(os.obj->IsSubClassOf(triObjectClassID)) { TriObject *tri = dynamic_cast<TriObject *>(os.obj); if(tri) { BitArray arrayOfVertices; arrayOfVertices.SetSize(tri->mesh.numVerts); arrayOfVertices.ClearAll(); IGeometryChecker::ReturnVal returnval=IGeometryChecker::eFail; int numChannels = tri->mesh.getNumMaps(); int index; for(int i=0;i<numChannels;++i) { if(tri->mesh.mapSupport(i)) { MeshMap *map = &tri->mesh.Map(i); if(map->getNumVerts()>0 &&map->getNumFaces()>0) { returnval= TypeReturned(); int numFaces = map->getNumFaces(); TVFace * tvFaces = map->tf; UVVert * uvVerts= map->tv; #pragma omp parallel for for(int faceIndex =0;faceIndex<numFaces;++faceIndex) { if(compute) { TVFace& tvFace = tvFaces[faceIndex]; Point3 tv = uvVerts[tvFace.t[0]]; if(_isnan(tv.x) || !_finite(tv.x)||_isnan(tv.y) || !_finite(tv.y)||_isnan(tv.z) || !_finite(tv.z)) { index = tri->mesh.faces[faceIndex].v[0]; if(index>=0&&index<tri->mesh.numVerts) { #pragma omp critical { arrayOfVertices.Set(index); } } } tv = uvVerts[tvFace.t[1]]; if(_isnan(tv.x) || !_finite(tv.x)||_isnan(tv.y) || !_finite(tv.y)||_isnan(tv.z) || !_finite(tv.z)) { index = tri->mesh.faces[faceIndex].v[1]; if(index>=0&&index<tri->mesh.numVerts) { #pragma omp critical { arrayOfVertices.Set(index); } } } tv = uvVerts[tvFace.t[2]]; if(_isnan(tv.x) || !_finite(tv.x)||_isnan(tv.y) || !_finite(tv.y)||_isnan(tv.z) || !_finite(tv.z)) { index = tri->mesh.faces[faceIndex].v[2]; if(index>=0&&index<tri->mesh.numVerts) { #pragma omp critical { arrayOfVertices.Set(index); } } } if(checkTime==true) { #pragma omp critical { DialogChecker::Check(checkTime,compute,numFaces,startTime,ups); } } } } } } } if(arrayOfVertices.IsEmpty()==false) //we have overlapping faces { int localsize= arrayOfVertices.GetSize(); for(int i=0;i<localsize;++i) { if(arrayOfVertices[i]) val.mIndex.Append(1,&i); } } return returnval; } else return IGeometryChecker::eFail; } else if(os.obj->IsSubClassOf(polyObjectClassID)) { PolyObject *poly = dynamic_cast<PolyObject *>(os.obj); if(poly) { BitArray arrayOfVertices; arrayOfVertices.SetSize(poly->GetMesh().numv); arrayOfVertices.ClearAll(); IGeometryChecker::ReturnVal returnval=IGeometryChecker::eFail; int numChannels= poly->GetMesh().MNum(); int index; for(int i=0;i<numChannels;++i) { if(poly->GetMesh().M(i)) { MNMesh *mesh = &(poly->GetMesh()); MNMap *mnmap = mesh->M(i); if(mnmap&&mnmap->numv>0&&mnmap->numf>0) { returnval= TypeReturned(); int numFaces = mnmap->numf; #pragma omp parallel for for(int faceIndex =0;faceIndex<numFaces;++faceIndex) { if(compute) { Point3 tv; int a,b,c; MNMapFace *face = mnmap->F(faceIndex); UVVert * uvVerts= mnmap->v; for(int j=0;j<(face->deg);++j) { if(j==(face->deg-2)) { a = j; b = j+1; c = 0; } else if(j==(face->deg-1)) { a = j; b = 0; c = 1; } else { a = j; b = j+1; c = j+2; } tv = uvVerts[face->tv[a]]; if(_isnan(tv.x) || !_finite(tv.x)||_isnan(tv.y) || !_finite(tv.y)||_isnan(tv.z) || !_finite(tv.z)) { index = mesh->f->vtx[a]; if(index>=0&&index<mesh->numv) { #pragma omp critical { arrayOfVertices.Set(index); } } } tv = uvVerts[face->tv[b]]; if(_isnan(tv.x) || !_finite(tv.x)||_isnan(tv.y) || !_finite(tv.y)||_isnan(tv.z) || !_finite(tv.z)) { index = mesh->f->vtx[b]; if(index>=0&&index<mesh->numv) { #pragma omp critical { arrayOfVertices.Set(index); } } } tv = uvVerts[face->tv[c]]; if(_isnan(tv.x) || !_finite(tv.x)||_isnan(tv.y) || !_finite(tv.y)||_isnan(tv.z) || !_finite(tv.z)) { index = mesh->f->vtx[c]; if(index>=0&&index<mesh->numv) { #pragma omp critical { arrayOfVertices.Set(index); } } } if(checkTime==true) { #pragma omp critical { DialogChecker::Check(checkTime,compute,numFaces,startTime,ups); } } } } } } } } if(arrayOfVertices.IsEmpty()==false) //we have overlapping faces { int localsize= arrayOfVertices.GetSize(); for(int i=0;i<localsize;++i) { if(arrayOfVertices[i]) val.mIndex.Append(1,&i); } } return returnval; } else return IGeometryChecker::eFail; } } return IGeometryChecker::eFail; }