void MatMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int id; pblock->GetValue(PB_MATID,t,id,valid); id--; if (id<0) id = 0; if (id>0xffff) id = 0xffff; // For version 4 and later, we process patch meshes as they are and pass them on. Earlier // versions converted to TriMeshes (done below). For adding other new types of objects, add // them here! #ifndef NO_PATCHES if(version >= MATMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *patchOb = (PatchObject *)os->obj; PatchMesh &pmesh = patchOb->GetPatchMesh(t); BOOL useSel = pmesh.selLevel >= PO_PATCH; for (int i=0; i<pmesh.getNumPatches(); i++) { if (!useSel || pmesh.patchSel[i]) { pmesh.setPatchMtlIndex(i,(MtlID)id); } } pmesh.InvalidateGeomCache(); // Do this because there isn't a topo cache in PatchMesh patchOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else #endif // NO_PATCHES // Process PolyObjects if(os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject *polyOb = (PolyObject *)os->obj; MNMesh &mesh = polyOb->GetMesh(); BOOL useSel = mesh.selLevel == MNM_SL_FACE; for (int i=0; i<mesh.numf; i++) { if (!useSel || mesh.f[i].GetFlag(MN_SEL)) { mesh.f[i].material = (MtlID)id; } } polyOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // If it's a TriObject, process it if(os->obj->IsSubClassOf(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj; DoMaterialSet(triOb, id); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // Fallback position: If it can convert to a TriObject, do it! if(os->obj->CanConvertToType(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); // Now stuff this into the pipeline! os->obj = triOb; DoMaterialSet(triOb, id); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else return; // Do nothing if it can't convert to triObject }
void NormalMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int flip, unify; pblock->GetValue(PB_FLIP,t,flip,valid); pblock->GetValue(PB_UNIFY,t,unify,valid); // For version 4 and later, we process patch meshes as they are and pass them on. Earlier // versions converted to TriMeshes (done below). For adding other new types of objects, add // them here! #ifndef NO_PATCHES if(version >= MATMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *patchOb = (PatchObject *)os->obj; PatchMesh &pmesh = patchOb->GetPatchMesh(t); BOOL useSel = pmesh.selLevel >= PO_PATCH; if (unify) pmesh.UnifyNormals(useSel); if (flip) pmesh.FlipPatchNormal(useSel ? -1 : -2); patchOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // If it's a TriObject, process it #endif // NO_PATCHES if(os->obj->IsSubClassOf(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj; DoNormalSet(triOb, unify, flip); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } // Process PolyObjects // note: Since PolyObjects must always have the normals alligned they do not // need to support unify and they do not allow normal flips on selected faces else if(os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject *pPolyOb = (PolyObject *)os->obj; MNMesh& mesh = pPolyOb->GetMesh(); if (flip) { // flip selected faces only if entire elements are selected if (mesh.selLevel == MNM_SL_FACE) { // sca 12/8/2000: Use MNMesh flipping code instead of the code that was here. mesh.FlipElementNormals (MN_SEL); } else { // Flip the entire object if selected elements were not flipped for (int i=0; i<mesh.FNum(); i++) { mesh.f[i].SetFlag (MN_WHATEVER, !mesh.f[i].GetFlag(MN_DEAD)); } mesh.FlipElementNormals (MN_WHATEVER); } // Luna task 747: // We cannot support specified normals here at this time. // NOTE this assumes that both the topo and geo channels are to be freed // this means that the modifier needs to also set the channels changed to // geo and topo otherwise we will be deleting a channel we dont own. mesh.ClearSpecifiedNormals (); } pPolyOb->UpdateValidity(GEOM_CHAN_NUM,valid); pPolyOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // Fallback position: If it can convert to a TriObject, do it! if(os->obj->CanConvertToType(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); // Now stuff this into the pipeline! os->obj = triOb; DoNormalSet(triOb, unify, flip); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else return; // Do nothing if it can't convert to triObject }
void SmoothMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int autoSmooth, bits = 0, prevent = 0; float thresh = 0.0f; pblock->GetValue(sm_autosmooth, t, autoSmooth, valid); if (autoSmooth) { pblock->GetValue(sm_threshold, t, thresh, valid); pblock->GetValue(sm_prevent_indirect, t, prevent, valid); } else { pblock->GetValue(sm_smoothbits, t, bits, valid); } // For version 4 and later, we process patch meshes as they are and pass them on. Earlier // versions converted to TriMeshes (done below). For adding other new types of objects, add // them here! bool done = false; #ifndef NO_PATCHES if(version >= MATMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *patchOb = (PatchObject *)os->obj; PatchMesh &pmesh = patchOb->GetPatchMesh(t); BOOL useSel = pmesh.selLevel >= PO_PATCH; if (autoSmooth) pmesh.AutoSmooth (thresh, useSel, prevent); else { for (int i=0; i<pmesh.getNumPatches(); i++) { if (!useSel || pmesh.patchSel[i]) pmesh.patches[i].smGroup = (DWORD)bits; } } pmesh.InvalidateGeomCache(); // Do this because there isn't a topo cache in PatchMesh patchOb->UpdateValidity(TOPO_CHAN_NUM,valid); done = true; } #endif // NO_PATCHES if (!done && os->obj->IsSubClassOf (polyObjectClassID)) { PolyObject *pPolyOb = (PolyObject *)os->obj; MNMesh &mesh = pPolyOb->GetMesh(); BOOL useSel = (mesh.selLevel == MNM_SL_FACE); if (autoSmooth) mesh.AutoSmooth (thresh, useSel, prevent); else { for (int faceIndex=0; faceIndex<mesh.FNum(); faceIndex++) { if (!useSel || mesh.F(faceIndex)->GetFlag(MN_SEL)) { mesh.F(faceIndex)->smGroup = (DWORD)bits; } } } // Luna task 747 // We need to rebuild the smoothing-group-based normals in the normalspec, if any: if (mesh.GetSpecifiedNormals()) { mesh.GetSpecifiedNormals()->SetParent (&mesh); mesh.GetSpecifiedNormals()->BuildNormals (); mesh.GetSpecifiedNormals()->ComputeNormals (); } pPolyOb->UpdateValidity(TOPO_CHAN_NUM,valid); done = true; } TriObject *triOb = NULL; if (!done) { if (os->obj->IsSubClassOf(triObjectClassID)) triOb = (TriObject *)os->obj; else { // Convert to triobject if we can. if(os->obj->CanConvertToType(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); // We'll need to stuff this back into the pipeline: os->obj = triOb; // Convert validities: Interval objValid = os->obj->ChannelValidity (t, TOPO_CHAN_NUM); triOb->SetChannelValidity (TOPO_CHAN_NUM, objValid); triOb->SetChannelValidity (GEOM_CHAN_NUM, objValid & os->obj->ChannelValidity (t, GEOM_CHAN_NUM)); triOb->SetChannelValidity (TEXMAP_CHAN_NUM, objValid & os->obj->ChannelValidity (t, TEXMAP_CHAN_NUM)); triOb->SetChannelValidity (VERT_COLOR_CHAN_NUM, objValid & os->obj->ChannelValidity (t, VERT_COLOR_CHAN_NUM)); triOb->SetChannelValidity (DISP_ATTRIB_CHAN_NUM, objValid & os->obj->ChannelValidity (t, DISP_ATTRIB_CHAN_NUM)); } } } if (triOb) { // one way or another, there's a triobject to smooth. Mesh & mesh = triOb->GetMesh(); BOOL useSel = mesh.selLevel == MESH_FACE; if (autoSmooth) mesh.AutoSmooth (thresh, useSel, prevent); else { for (int i=0; i<mesh.getNumFaces(); i++) { if (!useSel || mesh.faceSel[i]) mesh.faces[i].smGroup = (DWORD)bits; } } triOb->GetMesh().InvalidateTopologyCache(); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } }
void RelaxMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *node) { // Get our personal validity interval... Interval valid = GetValidity(t); // and intersect it with the channels we use as input (see ChannelsUsed) valid &= os->obj->ChannelValidity (t, GEOM_CHAN_NUM); valid &= os->obj->ChannelValidity (t, TOPO_CHAN_NUM); valid &= os->obj->ChannelValidity (t, SUBSEL_TYPE_CHAN_NUM); valid &= os->obj->ChannelValidity (t, SELECT_CHAN_NUM); Matrix3 modmat,minv; if (mc.localData == NULL) mc.localData = new RelaxModData; RelaxModData *rd = (RelaxModData *) mc.localData; TriObject *triObj = NULL; PatchObject *patchObj = NULL; PolyObject *polyObj = NULL; BOOL converted = FALSE; // For version 4 and later, we process patch or poly meshes as they are and pass them on. // Earlier versions converted to TriMeshes (done below). // For adding other new types of objects, add them here! #ifndef NO_PATCHES if(version >= RELAXMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { patchObj = (PatchObject *)os->obj; } else // If it's a TriObject, process it #endif // NO_PATCHES if(os->obj->IsSubClassOf(triObjectClassID)) { triObj = (TriObject *)os->obj; } else if (os->obj->IsSubClassOf (polyObjectClassID)) { polyObj = (PolyObject *) os->obj; } else // If it can convert to a TriObject, do it if(os->obj->CanConvertToType(triObjectClassID)) { triObj = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); converted = TRUE; } else return; // We can't deal with it! Mesh *mesh = triObj ? &(triObj->GetMesh()) : NULL; #ifndef NO_PATCHES PatchMesh &pmesh = patchObj ? patchObj->GetPatchMesh(t) : *((PatchMesh *)NULL); #else PatchMesh &pmesh = *((PatchMesh *)NULL); #endif // NO_PATCHES float relax, wtdRelax; // mjm - 4.8.99 int iter; BOOL boundary, saddle; pblock->GetValue (PB_RELAX, t, relax, FOREVER); pblock->GetValue (PB_ITER, t, iter, FOREVER); pblock->GetValue (PB_BOUNDARY, t, boundary, FOREVER); pblock->GetValue (PB_SADDLE, t, saddle, FOREVER); LimitValue (relax, MIN_RELAX, MAX_RELAX); LimitValue (iter, MIN_ITER, MAX_ITER); if(triObj) { int i, j, max; DWORD selLevel = mesh->selLevel; // mjm - 4.8.99 - add support for soft selection // sca - 4.29.99 - extended soft selection support to cover EDGE and FACE selection levels. float *vsw = (selLevel!=MESH_OBJECT) ? mesh->getVSelectionWeights() : NULL; if (rd->ivalid.InInterval(t) && (mesh->numVerts != rd->vnum)) { // Shouldn't happen, but does with Loft bug and may with other bugs. rd->ivalid.SetEmpty (); } if (!rd->ivalid.InInterval(t)) { rd->SetVNum (mesh->numVerts); for (i=0; i<rd->vnum; i++) { rd->fnum[i]=0; rd->nbor[i].ZeroCount(); } rd->sel.ClearAll (); DWORD *v; int k1, k2, origmax; for (i=0; i<mesh->numFaces; i++) { v = mesh->faces[i].v; for (j=0; j<3; j++) { if ((selLevel==MESH_FACE) && mesh->faceSel[i]) rd->sel.Set(v[j]); if ((selLevel==MESH_EDGE) && mesh->edgeSel[i*3+j]) rd->sel.Set(v[j]); if ((selLevel==MESH_EDGE) && mesh->edgeSel[i*3+(j+2)%3]) rd->sel.Set(v[j]); origmax = max = rd->nbor[v[j]].Count(); rd->fnum[v[j]]++; for (k1=0; k1<max; k1++) if (rd->nbor[v[j]][k1] == v[(j+1)%3]) break; if (k1==max) { rd->nbor[v[j]].Append (1, v+(j+1)%3, 1); max++; } for (k2=0; k2<max; k2++) if (rd->nbor[v[j]][k2] == v[(j+2)%3]) break; if (k2==max) { rd->nbor[v[j]].Append (1, v+(j+2)%3, 1); max++; } if (max>origmax) rd->vis[v[j]].SetSize (max, TRUE); if (mesh->faces[i].getEdgeVis (j)) rd->vis[v[j]].Set (k1); else if (k1>=origmax) rd->vis[v[j]].Clear (k1); if (mesh->faces[i].getEdgeVis ((j+2)%3)) rd->vis[v[j]].Set (k2); else if (k2>= origmax) rd->vis[v[j]].Clear (k2); } } // mjm - begin - 4.8.99 // if (selLevel==MESH_VERTEX) rd->sel = mesh->vertSel; if (selLevel==MESH_VERTEX) rd->sel = mesh->vertSel; else if (selLevel==MESH_OBJECT) rd->sel.SetAll (); // mjm - end rd->ivalid = os->obj->ChannelValidity (t, TOPO_CHAN_NUM); rd->ivalid &= os->obj->ChannelValidity (t, SUBSEL_TYPE_CHAN_NUM); rd->ivalid &= os->obj->ChannelValidity (t, SELECT_CHAN_NUM); } Tab<float> vangles; if (saddle) vangles.SetCount (rd->vnum); Point3 *hold = new Point3[rd->vnum]; int act; for (int k=0; k<iter; k++) { for (i=0; i<rd->vnum; i++) hold[i] = triObj->GetPoint(i); if (saddle) mesh->FindVertexAngles (vangles.Addr(0)); for (i=0; i<rd->vnum; i++) { // mjm - begin - 4.8.99 // if ((selLevel!=MESH_OBJECT) && (!rd->sel[i])) continue; if ( (!rd->sel[i] ) && (!vsw || vsw[i] == 0) ) continue; // mjm - end if (saddle && (vangles[i] <= 2*PI*.99999f)) continue; max = rd->nbor[i].Count(); if (boundary && (rd->fnum[i] < max)) continue; if (max<1) continue; Point3 avg(0.0f, 0.0f, 0.0f); for (j=0,act=0; j<max; j++) { if (!rd->vis[i][j]) continue; act++; avg += hold[rd->nbor[i][j]]; } if (act<1) continue; // mjm - begin - 4.8.99 wtdRelax = (!rd->sel[i]) ? relax * vsw[i] : relax; triObj->SetPoint (i, hold[i]*(1-wtdRelax) + avg*wtdRelax/((float)act)); // triObj->SetPoint (i, hold[i]*(1-relax) + avg*relax/((float)act)); // mjm - end } } delete [] hold; } if (polyObj) { int i, j, max; MNMesh & mm = polyObj->mm; float *vsw = (mm.selLevel!=MNM_SL_OBJECT) ? mm.getVSelectionWeights() : NULL; if (rd->ivalid.InInterval(t) && (mm.numv != rd->vnum)) { // Shouldn't happen, but does with Loft bug and may with other bugs. rd->ivalid.SetEmpty (); } if (!rd->ivalid.InInterval(t)) { rd->SetVNum (mm.numv); for (i=0; i<rd->vnum; i++) { rd->fnum[i]=0; rd->nbor[i].ZeroCount(); } rd->sel = mm.VertexTempSel (); int k1, k2, origmax; for (i=0; i<mm.numf; i++) { int deg = mm.f[i].deg; int *vtx = mm.f[i].vtx; for (j=0; j<deg; j++) { Tab<DWORD> & nbor = rd->nbor[vtx[j]]; origmax = max = nbor.Count(); rd->fnum[vtx[j]]++; DWORD va = vtx[(j+1)%deg]; DWORD vb = vtx[(j+deg-1)%deg]; for (k1=0; k1<max; k1++) if (nbor[k1] == va) break; if (k1==max) { nbor.Append (1, &va, 1); max++; } for (k2=0; k2<max; k2++) if (nbor[k2] == vb) break; if (k2==max) { nbor.Append (1, &vb, 1); max++; } } } rd->ivalid = os->obj->ChannelValidity (t, TOPO_CHAN_NUM); rd->ivalid &= os->obj->ChannelValidity (t, SUBSEL_TYPE_CHAN_NUM); rd->ivalid &= os->obj->ChannelValidity (t, SELECT_CHAN_NUM); } Tab<float> vangles; if (saddle) vangles.SetCount (rd->vnum); Tab<Point3> hold; hold.SetCount (rd->vnum); int act; for (int k=0; k<iter; k++) { for (i=0; i<rd->vnum; i++) hold[i] = mm.P(i); if (saddle) FindVertexAngles (mm, vangles.Addr(0)); for (i=0; i<rd->vnum; i++) { if ((!rd->sel[i]) && (!vsw || vsw[i] == 0) ) continue; if (saddle && (vangles[i] <= 2*PI*.99999f)) continue; max = rd->nbor[i].Count(); if (boundary && (rd->fnum[i] < max)) continue; if (max<1) continue; Point3 avg(0.0f, 0.0f, 0.0f); for (j=0,act=0; j<max; j++) { act++; avg += hold[rd->nbor[i][j]]; } if (act<1) continue; wtdRelax = (!rd->sel[i]) ? relax * vsw[i] : relax; polyObj->SetPoint (i, hold[i]*(1-wtdRelax) + avg*wtdRelax/((float)act)); } } } #ifndef NO_PATCHES else if(patchObj) { int i, j, max; DWORD selLevel = pmesh.selLevel; // mjm - 4.8.99 - add support for soft selection // sca - 4.29.99 - extended soft selection support to cover EDGE and FACE selection levels. float *vsw = (selLevel!=PATCH_OBJECT) ? pmesh.GetVSelectionWeights() : NULL; if (rd->ivalid.InInterval(t) && (pmesh.numVerts != rd->vnum)) { // Shouldn't happen, but does with Loft bug and may with other bugs. rd->ivalid.SetEmpty (); } if (!rd->ivalid.InInterval(t)) { int vecBase = pmesh.numVerts; rd->SetVNum (pmesh.numVerts + pmesh.numVecs); for (i=0; i<rd->vnum; i++) { rd->fnum[i]=1; // For patches, this means it's not a boundary rd->nbor[i].ZeroCount(); } rd->sel.ClearAll (); for (i=0; i<pmesh.numPatches; i++) { Patch &p = pmesh.patches[i]; int vecLimit = p.type * 2; for (j=0; j<p.type; j++) { PatchEdge &e = pmesh.edges[p.edge[j]]; BOOL isBoundary = (e.patches.Count() < 2) ? TRUE : FALSE; int theVert = p.v[j]; int nextVert = p.v[(j+1)%p.type]; int nextVec = p.vec[j*2] + vecBase; int nextVec2 = p.vec[j*2+1] + vecBase; int prevEdge = (j+p.type-1)%p.type; int prevVec = p.vec[prevEdge*2+1] + vecBase; int prevVec2 = p.vec[prevEdge*2] + vecBase; int theInterior = p.interior[j] + vecBase; // Establish selection bits if ((selLevel==PATCH_PATCH) && pmesh.patchSel[i]) { rd->sel.Set(theVert); rd->sel.Set(nextVec); rd->sel.Set(prevVec); rd->sel.Set(theInterior); } else if ((selLevel==PATCH_EDGE) && pmesh.edgeSel[p.edge[j]]) { rd->sel.Set(e.v1); rd->sel.Set(e.vec12 + vecBase); rd->sel.Set(e.vec21 + vecBase); rd->sel.Set(e.v2); } else if ((selLevel==PATCH_VERTEX) && pmesh.vertSel[theVert]) { rd->sel.Set(theVert); rd->sel.Set(nextVec); rd->sel.Set(prevVec); rd->sel.Set(theInterior); } // Set boundary flags if necessary if(isBoundary) { rd->fnum[theVert] = 0; rd->fnum[nextVec] = 0; rd->fnum[nextVec2] = 0; rd->fnum[nextVert] = 0; } // First process the verts int work = theVert; max = rd->nbor[work].Count(); // Append the neighboring vectors rd->MaybeAppendNeighbor(work, nextVec, max); rd->MaybeAppendNeighbor(work, prevVec, max); rd->MaybeAppendNeighbor(work, theInterior, max); // Now process the edge vectors work = nextVec; max = rd->nbor[work].Count(); // Append the neighboring points rd->MaybeAppendNeighbor(work, theVert, max); rd->MaybeAppendNeighbor(work, theInterior, max); rd->MaybeAppendNeighbor(work, prevVec, max); rd->MaybeAppendNeighbor(work, nextVec2, max); rd->MaybeAppendNeighbor(work, p.interior[(j+1)%p.type] + vecBase, max); work = prevVec; max = rd->nbor[work].Count(); // Append the neighboring points rd->MaybeAppendNeighbor(work, theVert, max); rd->MaybeAppendNeighbor(work, theInterior, max); rd->MaybeAppendNeighbor(work, nextVec, max); rd->MaybeAppendNeighbor(work, prevVec2, max); rd->MaybeAppendNeighbor(work, p.interior[(j+p.type-1)%p.type] + vecBase, max); // Now append the interior, if not auto if(!p.IsAuto()) { work = theInterior; max = rd->nbor[work].Count(); // Append the neighboring points rd->MaybeAppendNeighbor(work, p.v[j], max); rd->MaybeAppendNeighbor(work, nextVec, max); rd->MaybeAppendNeighbor(work, nextVec2, max); rd->MaybeAppendNeighbor(work, prevVec, max); rd->MaybeAppendNeighbor(work, prevVec2, max); for(int k = 1; k < p.type; ++k) rd->MaybeAppendNeighbor(work, p.interior[(j+k)%p.type] + vecBase, max); } } } // mjm - begin - 4.8.99 if (selLevel==PATCH_VERTEX) { for (int i=0; i<pmesh.numVerts; ++i) { if (pmesh.vertSel[i]) rd->sel.Set(i); } } else if (selLevel==PATCH_OBJECT) rd->sel.SetAll(); // mjm - end rd->ivalid = os->obj->ChannelValidity (t, TOPO_CHAN_NUM); rd->ivalid &= os->obj->ChannelValidity (t, SUBSEL_TYPE_CHAN_NUM); rd->ivalid &= os->obj->ChannelValidity (t, SELECT_CHAN_NUM); } Tab<float> vangles; if (saddle) vangles.SetCount (rd->vnum); Point3 *hold = new Point3[rd->vnum]; int act; for (int k=0; k<iter; k++) { for (i=0; i<rd->vnum; i++) hold[i] = patchObj->GetPoint(i); if (saddle) FindVertexAngles(pmesh, vangles.Addr(0)); for (i=0; i<rd->vnum; i++) { // mjm - begin - 4.8.99 // if ((selLevel!=MESH_OBJECT) && (!rd->sel[i])) continue; if ( (!rd->sel[i] ) && (!vsw || vsw[i] == 0) ) continue; // mjm - end if (saddle && (i < pmesh.numVerts) && (vangles[i] <= 2*PI*.99999f)) continue; max = rd->nbor[i].Count(); if (boundary && !rd->fnum[i]) continue; if (max<1) continue; Point3 avg(0.0f, 0.0f, 0.0f); for (j=0,act=0; j<max; j++) { act++; avg += hold[rd->nbor[i][j]]; } if (act<1) continue; // mjm - begin - 4.8.99 wtdRelax = (!rd->sel[i]) ? relax * vsw[i] : relax; patchObj->SetPoint (i, hold[i]*(1-wtdRelax) + avg*wtdRelax/((float)act)); // patchObj->SetPoint (i, hold[i]*(1-relax) + avg*relax/((float)act)); // mjm - end } } delete [] hold; patchObj->patch.computeInteriors(); patchObj->patch.ApplyConstraints(); } #endif // NO_PATCHES if(!converted) { os->obj->SetChannelValidity(GEOM_CHAN_NUM, valid); } else { // Stuff converted object into the pipeline! triObj->SetChannelValidity(TOPO_CHAN_NUM, valid); triObj->SetChannelValidity(GEOM_CHAN_NUM, valid); triObj->SetChannelValidity(TEXMAP_CHAN_NUM, valid); triObj->SetChannelValidity(MTL_CHAN_NUM, valid); triObj->SetChannelValidity(SELECT_CHAN_NUM, valid); triObj->SetChannelValidity(SUBSEL_TYPE_CHAN_NUM, valid); triObj->SetChannelValidity(DISP_ATTRIB_CHAN_NUM, valid); os->obj = triObj; } }
void MirrorMod::ModifyObject( TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Matrix3 itm = CompMatrix(t,NULL,&mc); Matrix3 tm = Inverse(itm); Interval iv = FOREVER; int axis, copy; float offset; pblock->GetValue(PB_AXIS,t,axis,iv); pblock->GetValue(PB_COPY,t,copy,iv); pblock->GetValue(PB_OFFSET,t,offset,iv); DWORD oldLevel; BOOL convertedShape = FALSE; BitArray oldFaceSelections; // support for TriObjects if (os->obj->IsSubClassOf(triObjectClassID)) { TriObject *tobj = (TriObject*)os->obj; Mesh &mesh = tobj->GetMesh(); switch (mesh.selLevel) { case MESH_OBJECT: mesh.faceSel.SetAll(); break; case MESH_VERTEX: { for (int i=0; i<mesh.getNumFaces(); i++) { for (int j=0; j<3; j++) { if (mesh.vertSel[mesh.faces[i].v[j]]) { mesh.faceSel.Set(i); } } } break; } case MESH_EDGE: { for (int i=0; i<mesh.getNumFaces(); i++) { for (int j=0; j<3; j++) { if (mesh.edgeSel[i*3+j]) { mesh.faceSel.Set(i); } } } break; } } oldLevel = mesh.selLevel; mesh.selLevel = MESH_FACE; if (copy) { mesh.CloneFaces(mesh.faceSel); mesh.ClearVSelectionWeights (); } if (axis<3) { for (int i=0; i<mesh.getNumFaces(); i++) { if (mesh.faceSel[i]) mesh.FlipNormal(i); } } } #ifndef NO_PATCHES // support for PatchObjects if (os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *pobj = (PatchObject*)os->obj; PatchMesh &pmesh = pobj->GetPatchMesh(t); switch (pmesh.selLevel) { case PATCH_OBJECT: pmesh.patchSel.SetAll(); break; case PATCH_VERTEX: { for (int i=0; i<pmesh.getNumPatches(); i++) { Patch &p = pmesh.patches[i]; for (int j=0; j<p.type; j++) { if (pmesh.vertSel[p.v[j]]) { pmesh.patchSel.Set(i); break; } } } break; } case PATCH_EDGE: { for (int i=0; i<pmesh.getNumPatches(); i++) { Patch &p = pmesh.patches[i]; for (int j=0; j<p.type; j++) { if (pmesh.edgeSel[p.edge[j]]) { pmesh.patchSel.Set(i); break; } } } break; } } oldLevel = pmesh.selLevel; pmesh.selLevel = PATCH_PATCH; if (copy) pmesh.ClonePatchParts(); // Copy the selected patches if (axis<3) pmesh.FlipPatchNormal(-1); // Flip selected normals } #endif // NO_PATCHES // support for PolyObjects else if (os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject * pPolyOb = (PolyObject*)os->obj; MNMesh &mesh = pPolyOb->GetMesh(); // Luna task 747 // We don't support specified normals here because it would take special code mesh.ClearSpecifiedNormals (); BitArray faceSelections; mesh.getFaceSel (faceSelections); switch (mesh.selLevel) { case MNM_SL_OBJECT: faceSelections.SetAll(); break; case MNM_SL_VERTEX: { faceSelections.ClearAll (); for (int i=0; i<mesh.FNum(); i++) { for (int j=0; j<mesh.F(i)->deg; j++) { int vertIndex = mesh.F(i)->vtx[j]; if (mesh.V(vertIndex)->GetFlag(MN_SEL)) { faceSelections.Set(i); break; } } } break; } case MNM_SL_EDGE: { faceSelections.ClearAll (); for (int i=0; i<mesh.FNum(); i++) { for (int j=0; j<mesh.F(i)->deg; j++) { int edgeIndex = mesh.F(i)->edg[j]; if (mesh.E(edgeIndex)->GetFlag(MN_SEL)) { faceSelections.Set(i); break; } } } break; } } // preserve the existing selection settings oldLevel = mesh.selLevel; mesh.getFaceSel (oldFaceSelections); // set the face selections mesh.ClearFFlags (MN_SEL); mesh.FaceSelect(faceSelections); mesh.selLevel = MNM_SL_FACE; // copy the selected faces and flip Normal direction as needed if (copy) { mesh.CloneFaces(); mesh.freeVSelectionWeights (); } // Now, note that by PolyMesh rules, we can only flip entire selected elements. // So we broaden our selection to include entire elements that are only partially selected: for (int i=0; i<mesh.numf; i++) { if (mesh.f[i].GetFlag (MN_DEAD)) continue; if (!mesh.f[i].GetFlag (MN_SEL)) continue; mesh.PaintFaceFlag (i, MN_SEL); } if (axis<3) { for (i=0; i<mesh.FNum(); i++) { if (mesh.F(i)->GetFlag(MN_SEL)) mesh.FlipNormal(i); } if (mesh.GetFlag (MN_MESH_FILLED_IN)) { // We also need to flip edge normals: for (i=0; i<mesh.ENum(); i++) { if (mesh.f[mesh.e[i].f1].GetFlag (MN_SEL)) { int hold = mesh.e[i].v1; mesh.e[i].v1 = mesh.e[i].v2; mesh.e[i].v2 = hold; } } } } } // support for shape objects else if (os->obj->IsSubClassOf(splineShapeClassID)) { SplineShape *ss = (SplineShape*)os->obj; BezierShape &shape = ss->shape; oldLevel = shape.selLevel; switch (shape.selLevel) { case SHAPE_OBJECT: case SHAPE_VERTEX: shape.selLevel = SHAPE_SPLINE; shape.polySel.SetAll(); break; case SHAPE_SPLINE: case SHAPE_SEGMENT: break; } if (copy) shape.CloneSelectedParts((axis < 3 && splineMethod == SPLINE_REVERSE) ? TRUE : FALSE); } else if(os->obj->SuperClassID() == SHAPE_CLASS_ID) { ShapeObject *so = (ShapeObject *)os->obj; if(so->CanMakeBezier()) { SplineShape *ss = new SplineShape(); so->MakeBezier(t, ss->shape); ss->SetChannelValidity(GEOM_CHAN_NUM, GetValidity(t) & so->ObjectValidity(t)); os->obj = ss; os->obj->UnlockObject(); convertedShape = TRUE; BezierShape &shape = ss->shape; oldLevel = shape.selLevel; switch (shape.selLevel) { case SHAPE_OBJECT: case SHAPE_VERTEX: shape.selLevel = SHAPE_SPLINE; shape.polySel.SetAll(); break; case SHAPE_SPLINE: case SHAPE_SEGMENT: break; } if (copy) shape.CloneSelectedParts((axis < 3 && splineMethod == SPLINE_REVERSE) ? TRUE : FALSE); } } MirrorDeformer deformer(axis,offset,tm,itm); os->obj->Deform(&deformer, TRUE); // if (axis < 3 && splineMethod == SPLINE_REVERSE) { if (os->obj->IsSubClassOf(splineShapeClassID)) { SplineShape *ss = (SplineShape*)os->obj; BezierShape &shape = ss->shape; for (int i = 0; i < shape.bindList.Count(); i++) { int index = 0; int spindex = shape.bindList[i].pointSplineIndex; // Point3 p=shape.splines[spindex]->GetKnot(index).Knot(); if (shape.bindList[i].isEnd) index = shape.splines[spindex]->KnotCount()-1; shape.bindList[i].bindPoint = shape.splines[spindex]->GetKnotPoint(index); shape.bindList[i].segPoint = shape.splines[spindex]->GetKnotPoint(index); } shape.UpdateBindList(TRUE); } else if(os->obj->SuperClassID() == SHAPE_CLASS_ID) { ShapeObject *so = (ShapeObject *)os->obj; if(so->CanMakeBezier()) { SplineShape *ss = new SplineShape(); so->MakeBezier(t, ss->shape); ss->SetChannelValidity(GEOM_CHAN_NUM, GetValidity(t) & so->ObjectValidity(t)); os->obj = ss; os->obj->UnlockObject(); convertedShape = TRUE; BezierShape &shape = ss->shape; for (int i = 0; i < shape.bindList.Count(); i++) { int index = 0; int spindex = shape.bindList[i].pointSplineIndex; // Point3 p; if (shape.bindList[i].isEnd) index = shape.splines[spindex]->KnotCount()-1; shape.bindList[i].bindPoint = shape.splines[spindex]->GetKnotPoint(index); shape.bindList[i].segPoint = shape.splines[spindex]->GetKnotPoint(index); } shape.UpdateBindList(TRUE); } } } os->obj->UpdateValidity(GEOM_CHAN_NUM,GetValidity(t)); // restore the original selections if (os->obj->IsSubClassOf(triObjectClassID)) { TriObject *tobj = (TriObject*)os->obj; tobj->GetMesh().selLevel = oldLevel; } #ifndef NO_PATCHES else if (os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *pobj = (PatchObject*)os->obj; pobj->GetPatchMesh(t).selLevel = oldLevel; } #endif // NO_PATCHES else if (os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject *pPolyOb = (PolyObject*)os->obj; pPolyOb->GetMesh().selLevel = oldLevel; pPolyOb->GetMesh().dispFlags = 0; switch (oldLevel) { case MNM_SL_VERTEX: pPolyOb->GetMesh().dispFlags = MNDISP_SELVERTS | MNDISP_VERTTICKS; break; case MNM_SL_EDGE: pPolyOb->GetMesh().dispFlags = MNDISP_SELEDGES; break; case MNM_SL_FACE: pPolyOb->GetMesh().dispFlags = MNDISP_SELFACES; break; } pPolyOb->GetMesh().FaceSelect(oldFaceSelections); } else if(os->obj->IsSubClassOf(splineShapeClassID) || convertedShape) { SplineShape *ss = (SplineShape*)os->obj; ss->shape.selLevel = oldLevel; } }