Beispiel #1
0
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
   }
Beispiel #2
0
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
   }
Beispiel #3
0
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);     
   }
}
Beispiel #4
0
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;
	}
}
Beispiel #5
0
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;
		}
	}