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 (); } } }
// 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; }
///////////////////////////////////////////////////////////////////// // 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); }
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 ); }