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]; } } } }
void EditPolyData::ApplyAllOperations (MNMesh & mesh) { #ifdef __DEBUG_PRINT_EDIT_POLY DebugPrint (_T("EditPolyData::ApplyAllOperations\n")); #endif if (mpOpList) { // Preallocate if possible. (Upon first application, this will do nothing.) PolyOperationRecord* pOpRec = NULL; int newFaces(0), newVertices(0), newEdges(0); Tab<int> newMapVertices; newMapVertices.SetCount (mesh.numm + NUM_HIDDENMAPS); for (int mp=-NUM_HIDDENMAPS; mp<mesh.numm; mp++) newMapVertices[mp+NUM_HIDDENMAPS] = 0; for (pOpRec=mpOpList; pOpRec != NULL; pOpRec=pOpRec->Next()) { newFaces += pOpRec->Operation()->NewFaceCount(); newVertices += pOpRec->Operation()->NewVertexCount(); newEdges += pOpRec->Operation()->NewEdgeCount (); for (int mp=-NUM_HIDDENMAPS; mp<mesh.numm; mp++) { if (mesh.M(mp)->GetFlag (MN_DEAD)) continue; newMapVertices[mp+NUM_HIDDENMAPS] += pOpRec->Operation()->NewMapVertexCount(mp); } } mesh.VAlloc (mesh.numv + newVertices); mesh.EAlloc (mesh.nume + newEdges); mesh.FAlloc (mesh.numf + newFaces); for (int mp=-NUM_HIDDENMAPS; mp<mesh.numm; mp++) { MNMap *map = mesh.M(mp); if (map->GetFlag (MN_DEAD)) continue; map->VAlloc (map->numv + newMapVertices[mp+NUM_HIDDENMAPS]); map->FAlloc (map->numf + newFaces); } for (pOpRec=mpOpList; pOpRec != NULL; pOpRec=pOpRec->Next()) { #ifdef __DEBUG_PRINT_EDIT_POLY DebugPrint (_T("EditPolyData::Applying %s\n"), pOpRec->Operation()->Name()); #endif pOpRec->Operation()->SetUserFlags (mesh); bool ret = pOpRec->Operation()->Apply (mesh, pOpRec->LocalData()); if (ret && pOpRec->Operation()->CanDelete()) mesh.CollapseDeadStructs (); } } }
///////////////////////////////////////////////////////////////////// // 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; }
// This method needs to be moved to class MNMesh when the SDK opens up again. // Note that it's an exact copy of some code in the EditablePoly source. bool MNMeshCollapseEdges (MNMesh & mm, DWORD edgeFlag) { // Collect average locations ourselves // We do this by collecting information about which vertex // or map vertex each eliminated point was welded to - its destination. // Then we average things out at the end. Tab<int> pointDest; pointDest.SetCount (mm.numv); for (int i=0; i<mm.numv; i++) pointDest[i] = -1; Tab<Tab<int> *> mapPointDest; mapPointDest.SetCount (mm.numm + NUM_HIDDENMAPS); for (int mapChannel=-NUM_HIDDENMAPS; mapChannel<mm.numm; mapChannel++) { int nhm = mapChannel + NUM_HIDDENMAPS; if (mm.M(mapChannel)->GetFlag (MN_DEAD)) mapPointDest[nhm] = NULL; else { int nv = mm.M(mapChannel)->numv; if (!nv) mapPointDest[nhm] = NULL; else { mapPointDest[nhm] = new Tab<int>; mapPointDest[nhm]->SetCount (nv); int *md = mapPointDest[nhm]->Addr(0); for (i=0; i<nv; i++) md[i] = -1; } } } // Perform topological welding, edge by edge bool ret=false; for (i=0; i<mm.nume; i++) { if (mm.e[i].GetFlag (MN_DEAD)) continue; if (!mm.e[i].GetFlag (MN_USER)) continue; int v1 = mm.e[i].v1; int v2 = mm.e[i].v2; int f1 = mm.e[i].f1; int f2 = mm.e[i].f2; int eid1 = mm.f[f1].EdgeIndex (i); int eid2 = (f2>-1) ? mm.f[f2].EdgeIndex (i) : -1; Tab<int> mv1, mv2; mv1.SetCount ((mm.numm+NUM_HIDDENMAPS)*2); mv2.SetCount ((mm.numm+NUM_HIDDENMAPS)*2); for (int mapChannel = -NUM_HIDDENMAPS; mapChannel<mm.numm; mapChannel++) { MNMap *map = mm.M(mapChannel); int nhm = (NUM_HIDDENMAPS + mapChannel)*2; if (map->GetFlag (MN_DEAD)) { mv1[nhm] = -1; continue; } mv1[nhm] = map->f[f1].tv[eid1]; mv1[nhm+1] = (f2>-1) ? map->f[f2].tv[(eid2+1)%mm.f[f2].deg] : mv1[nhm]; mv2[nhm] = map->f[f1].tv[(eid1+1)%mm.f[f1].deg]; mv2[nhm+1] = (f2>-1) ? map->f[f2].tv[eid2] : mv2[nhm]; } if (mm.WeldEdge (i)) { pointDest[v2] = v1; for (int nhm=0; nhm<mapPointDest.Count(); nhm++) { if (mapPointDest[nhm] == NULL) continue; if (!mapPointDest[nhm]->Count()) continue; if (mv1[nhm*2]<0) continue; int *mpd = mapPointDest[nhm]->Addr(0); mpd[mv2[nhm*2]] = mv1[nhm*2]; if (mv2[nhm*2+1] != mv2[nhm*2]) mpd[mv2[nhm*2+1]] = mv1[nhm*2+1]; } ret = true; } } // Then set all the welded vertices to the correct averaged locations if (ret) { for (mapChannel = -NUM_HIDDENMAPS-1; mapChannel<mm.numm; mapChannel++) { // note - -NUM_HIDDENMAPS-1 is not a valid map channel, // We're using it for a convenient extra loop for the actual geometry. int nhm = mapChannel+NUM_HIDDENMAPS; if ((nhm>-1) && mapPointDest[nhm] == NULL) continue; Tab<int> & destinations = (nhm<0) ? pointDest : *(mapPointDest[nhm]); for (i=0; i<destinations.Count(); i++) { if (destinations[i] < 0) continue; if (destinations[destinations[i]] > -1) { // We have nested destinations - straighten them out. // Form a stack of all the intermediate destinations: Tab<int> intermediate; for (int last=i; destinations[last]>-1; last=destinations[last]) { intermediate.Append (1, &last, 2); } // Now destinations[current] = -1, which means it's the final destination of all of these. // Correct whole chain. for (int k=0; k<intermediate.Count()-1; k++) destinations[intermediate[k]] = last; } if (nhm<0) mm.v[destinations[i]].p += mm.v[i].p; else mm.M(mapChannel)->v[destinations[i]] += mm.M(mapChannel)->v[i]; destinations[destinations[i]]--; } for (i=0; i<destinations.Count(); i++) { if (destinations[i] > -2) continue; if (nhm<0) mm.v[i].p /= float(-destinations[i]); else mm.M(mapChannel)->v[i] /= float(-destinations[i]); } // Free memory if (nhm>-1) { delete mapPointDest[nhm]; mapPointDest[nhm] = NULL; } } } return ret; }
void ModifierPtex::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int uvw_channel = 0; if ( m_pblock->GetInt( UVW_TYPE ) == 0 ) { uvw_channel = m_pblock->GetInt( UVW_CHANNEL ); } if ( os->obj->IsSubClassOf( polyObjectClassID ) ) { PolyObject *polyObj = (PolyObject*)os->obj; MNMesh &mnMesh = polyObj->GetMesh(); bool has_map; if ( uvw_channel >= mnMesh.MNum() ) { mnMesh.SetMapNum( uvw_channel + 1 ); has_map = false; } else { has_map = mnMesh.M( uvw_channel )->GetFlag( MN_DEAD ) == false; } MNMap *mc = mnMesh.M( uvw_channel ); if ( has_map == false ) { mc->setNumFaces( mnMesh.numf ); for ( int i_f = 0; i_f < mnMesh.numf; i_f++ ) { mc->f[ i_f ].SetSize( mnMesh.f[ i_f ].deg ); } } if ( mc->GetFlag( MN_DEAD ) ) mc->ClearFlag( MN_DEAD ); unsigned int num_tverts = 0; for ( int i_f = 0; i_f < mnMesh.numf; i_f++ ) { num_tverts += mc->f[ i_f ].deg; } mc->setNumVerts( num_tverts ); unsigned int tvert_id = 0; for ( int i_f = 0; i_f < mnMesh.numf; i_f++ ) { unsigned int deg = mc->f[ i_f ].deg; for ( unsigned int i_v = 0; i_v < deg; i_v++ ) { mc->f[ i_f ].tv[ i_v ] = tvert_id; Point3 tv; if ( i_v == 0 ) tv = Point3( (float)i_f, 0.0f, 0.0f ); else if ( i_v == 1 ) tv = Point3( (float)i_f + 1.0f, 0.0f, 0.0f ); else if ( i_v == 2 ) tv = Point3( (float)i_f + 1.0f, 1.0f, 0.0f ); else tv = Point3( (float)i_f, 1.0f, 0.0f ); tv.z = 0.0f; mc->v[ tvert_id ] = tv; tvert_id++; } } } // Update all the caches etc Interval iv = LocalValidity(t); iv = iv & os->obj->ChannelValidity( t, GEOM_CHAN_NUM ); iv = iv & os->obj->ChannelValidity( t, TOPO_CHAN_NUM ); os->obj->UpdateValidity( TEXMAP_CHAN_NUM, iv ); }