void Unreal3DExport::WriteModel()
{
    // Progress
        pInt->ProgressUpdate(Progress, FALSE, GetString(IDS_INFO_WRITE));

        // Open data file
        fMesh = _tfopen(ModelFileName,_T("wb"));
        if( !fMesh ) 
        {
            ProgressMsg.printf(GetString(IDS_ERR_FMODEL),ModelFileName);
            throw MAXException(ProgressMsg.data());
        }

        // Open anim file
        fAnim = _tfopen(AnimFileName,_T("wb"));
        if( !fAnim )
        {
            ProgressMsg.printf(GetString(IDS_ERR_FANIM),AnimFileName);
            throw MAXException(ProgressMsg.data());
        }
        
        // data headers
        hData.NumPolys = Tris.Count();
        hData.NumVertices = VertsPerFrame;

        // anim headers
        hAnim.FrameSize = VertsPerFrame * sizeof(FMeshVert); 
        hAnim.NumFrames = FrameCount;


        // Progress
        CheckCancel();
        pInt->ProgressUpdate(Progress, FALSE, GetString(IDS_INFO_WMESH));
        

        // Write data
        fwrite(&hData,sizeof(FJSDataHeader),1,fMesh);
        if( Tris.Count() > 0 )
        {
            fwrite(Tris.Addr(0),sizeof(FJSMeshTri),Tris.Count(),fMesh);
        }
        Progress += U3D_PROGRESS_WMESH;

        // Progress
        CheckCancel();
        pInt->ProgressUpdate(Progress, FALSE, GetString(IDS_INFO_WANIM));

        // Write anim
        fwrite(&hAnim,sizeof(FJSAnivHeader),1,fAnim);
        if( Verts.Count() > 0 )
        {
            fwrite(Verts.Addr(0),sizeof(FMeshVert),Verts.Count(),fAnim);
        }
        Progress += U3D_PROGRESS_WANIM;
}
Beispiel #2
0
void AFRMod::ModifyObject (TimeValue t, ModContext &mc, ObjectState *os, INode *node) {
	Interval iv = FOREVER;
	float f, p, b;
	int backface;
	Point3 pt1, pt2;
	pblock->GetValue(PB_FALLOFF,t,f,iv);
	pblock->GetValue(PB_PINCH,t,p,iv);
	pblock->GetValue(PB_BUBBLE,t,b,iv);
	pblock->GetValue(PB_BACKFACE,t,backface,iv);
	p1->GetValue(t,&pt1,iv,CTRL_ABSOLUTE);
	p2->GetValue(t,&pt2,iv,CTRL_ABSOLUTE);
	if (f==0.0) {
		os->obj->UpdateValidity(GEOM_CHAN_NUM,iv);	
		return;
	}
	Tab<Point3> normals;
	if (backface) {
		// Need to get vertex normals.
		if (os->obj->IsSubClassOf(triObjectClassID)) {
			TriObject *tobj = (TriObject*)os->obj;
			AverageVertexNormals (tobj->GetMesh(), normals);
		} else if (os->obj->IsSubClassOf (polyObjectClassID)) {
			PolyObject *pobj = (PolyObject *) os->obj;
			MNMesh &mesh = pobj->GetMesh();
			normals.SetCount (mesh.numv);
			Point3 *vn = normals.Addr(0);
			for (int i=0; i<mesh.numv; i++) {
				if (mesh.v[i].GetFlag (MN_DEAD)) vn[i]=Point3(0,0,0);
				else vn[i] = mesh.GetVertexNormal (i);
			}
#ifndef NO_PATCHES
		} else if (os->obj->IsSubClassOf (patchObjectClassID)) {
			PatchObject *pobj = (PatchObject *) os->obj;
			normals.SetCount (pobj->NumPoints ());
			Point3 *vn = normals.Addr(0);
			for (int i=0; i<pobj->NumPoints(); i++) vn[i] = pobj->VertexNormal (i);
#endif
		}
	}
	if (normals.Count()) {
		AFRDeformer deformer(mc,f,p,b,pt1,pt2,&normals);
		os->obj->Deform(&deformer, TRUE);
	} else {
		AFRDeformer deformer(mc,f,p,b,pt1,pt2);
		os->obj->Deform(&deformer, TRUE);
	}	
	os->obj->UpdateValidity(GEOM_CHAN_NUM,iv);	
	}
Beispiel #3
0
void BonesDefMod::RebuildPaintNodes()
	{
	//this sends all our dependant nodes to the painter
	MyEnumProc dep;              
	EnumDependents(&dep);
	Tab<INode *> nodes;
	for (int i = 0; i < nodes.Count(); i++)
		{

		ObjectState os = nodes[i]->EvalWorldState(GetCOREInterface()->GetTime());
						
		if ( (os.obj->NumPoints() != painterData[i].bmd->VertexData.Count()) ||
			  (painterData[i].bmd->isPatch) || (painterData[i].bmd->inputObjectIsNURBS) )
			{
			int ct = painterData[i].bmd->VertexData.Count();
			Tab<Point3> pointList;
			pointList.SetCount(ct);
			Matrix3 tm = nodes[i]->GetObjectTM(GetCOREInterface()->GetTime());
			for (int j =0; j < ct; j++)
				{
				pointList[j] = painterData[i].bmd->VertexData[j]->LocalPosPostDeform*tm;
				}
			pPainterInterface->LoadCustomPointGather(ct, pointList.Addr(0), nodes[i]);
			}
		}
	pPainterInterface->UpdateMeshes(TRUE);
	}
void MNMeshLoop::Build(MNMeshLoopAdvancer &adv, int startid, BitArray &finalsel)
{
  // prepare Loopitems
  m_items.SetCount(MESHLOOP_ALLOC_ITEMCOUNT);
  int allocated = MESHLOOP_ALLOC_ITEMCOUNT;

  // add ourself
  int itemcnt = 0;
  int wave = 1;

  MNMeshLoopItem *item = m_items.Addr(0);
  item->wave = 0;
  item->distance = 0.0f;
  item->id = startid;
  item->pos = adv.GetPos(startid);
  item->prev = NULL;
  finalsel.Set(startid);
  item++;
  itemcnt++;

  Tab<MNMeshLoopFront> fronts;
  int outcount = adv.SetupFront(startid,fronts);

  // then advance each direction
  int added = TRUE;
  while(added){
    added = FALSE;
    for (int o = 0; o < outcount; o++){
      MNMeshLoopFront *front = fronts.Addr(o);

      // loop ended
      if (adv.Advance(front,item,itemcnt,wave,finalsel))
        continue;

      item++;
      itemcnt++;

      // expand memory (we could use append but well no clue how it resizes)
      if (itemcnt%MESHLOOP_ALLOC_ITEMCOUNT == 0){
        m_items.SetCount(itemcnt+MESHLOOP_ALLOC_ITEMCOUNT);
        item = m_items.Addr(itemcnt);
      }
      added = TRUE;
    }
    wave += 1;
  }

  m_numitems = itemcnt;
}
int MNMeshLoopAdvancerVertex::SetupFront(int startid, Tab<MNMeshLoopFront> &fronts)
{
  // first previous is root
  // set initial connectors
  Tab<int> &connected = m_mesh->vedg[startid];
  int outcount = connected.Count();
  // for each direction
  fronts.SetCount(outcount);
  for (int o = 0; o < outcount; o++){
    MNMeshLoopFront *advance = fronts.Addr(o);

    int nextid = m_mesh->E(connected[o])->OtherVert(startid);
    advance->previndex = 0;
    advance->nextid = nextid;
    advance->connector = connected[o];
    advance->crossed = FALSE;
  }

  return outcount;
}
Beispiel #6
0
void PolyOpBevelFace::Do (MNMesh & mesh)
{
	// Topological extrusion first:
	MNChamferData chamData;
	if (mType<2) {
		MNFaceClusters fclust(mesh, MN_USER);
		if (!mesh.ExtrudeFaceClusters (fclust)) return;
		if (mType == 0) {
			// Get fresh face clusters:
			MNFaceClusters fclustAfter(mesh, MN_USER);
			Tab<Point3> clusterNormals, clusterCenters;
			fclustAfter.GetNormalsCenters (mesh, clusterNormals, clusterCenters);
			mesh.GetExtrudeDirection (&chamData, &fclustAfter, clusterNormals.Addr(0));
		} else {
			mesh.GetExtrudeDirection (&chamData, MN_USER);
		}
	} else {
		// Polygon-by-polygon extrusion.
		if (!mesh.ExtrudeFaces (MN_USER)) return;
		MNFaceClusters fclustAfter(mesh, MN_USER);
		Tab<Point3> clusterNormals, clusterCenters;
		fclustAfter.GetNormalsCenters (mesh, clusterNormals, clusterCenters);
		mesh.GetExtrudeDirection (&chamData, &fclustAfter, clusterNormals.Addr(0));
	}

	int i;
	if (mHeight) {
		for (i=0; i<mesh.numv; i++) mesh.v[i].p += chamData.vdir[i]*mHeight;
	}

	if (mOutline) {
		MNTempData temp(&mesh);
		Tab<Point3> *outDir;
		if (mType == 0) outDir = temp.OutlineDir (MESH_EXTRUDE_CLUSTER, MN_USER);
		else outDir = temp.OutlineDir (MESH_EXTRUDE_LOCAL, MN_USER);
		if (outDir && outDir->Count()) {
			Point3 *od = outDir->Addr(0);
			for (i=0; i<mesh.numv; i++) mesh.v[i].p += od[i]*mOutline;
		}
	}
}
//////////////////////////////////////////////////////////////////////////
// MNMeshLoopAdvancerFace
int MNMeshLoopAdvancerFace::SetupFront(int startid, Tab<MNMeshLoopFront> &fronts)
{
  // first previous is root
  // set initial connectors
  MNFace *face = m_mesh->F(startid);

  int outcount = face->deg;
  // for each direction
  fronts.SetCount(outcount);
  for (int o = 0; o < outcount; o++){
    MNMeshLoopFront *advance = fronts.Addr(o);

    int nextid = m_mesh->E(face->edg[o])->OtherFace(startid);
    advance->previndex = 0;
    advance->nextid = nextid;
    advance->connector = face->edg[o];
    advance->crossed = FALSE;
  }

  return outcount;
}
Beispiel #8
0
void UVW_ChannelClass::LoadOlderVersions(ILoad *iload)
{
	int ct = 0;
	ULONG nb = 0;
	
	switch(iload->CurChunkID())  
	{
		case VERTCOUNT_CHUNK:
			iload->Read(&ct, sizeof(ct), &nb);
			v.SetCount(ct);
			break;
		case FACECOUNT_CHUNK:
			iload->Read(&ct, sizeof(ct), &nb);
			SetCountFaces(ct);
			break;
/*
		case GEOMPOINTSCOUNT_CHUNK:
			iload->Read(&ct, sizeof(ct), &nb);
			geomPoints.SetCount(ct);
			break;
*/
			//old way here for legacy reason only
		case FACE_CHUNK:
			{
//				version = 1;
//				oldDataPresent = TRUE;
				Tab<TVFace> tf;
				tf.SetCount(f.Count());
				iload->Read(tf.Addr(0), sizeof(TVFace)*f.Count(), &nb);
				for (int i=0;i<f.Count();i++)
				{

					f[i]->count  = 3;
					f[i]->t = new int[f[i]->count];
					f[i]->v = new int[f[i]->count];

					f[i]->t[0] = tf[i].t[0];
					f[i]->t[1] = tf[i].t[1];
					f[i]->t[2] = tf[i].t[2];
					f[i]->flags = 0;
					f[i]->vecs = NULL;
				}
				break;
			}
			//old way here for legacy reason only
		case VERTS_CHUNK:
			{
				Tab<Point3> p;
				p.SetCount(v.Count());
//				oldDataPresent = TRUE;

				iload->Read(p.Addr(0), sizeof(Point3)*v.Count(), &nb);

				for (int i=0;i<v.Count();i++)
				{
					v[i].SetP(p[i]);
					v[i].SetFlag(0);
					v[i].SetInfluence(0.0f);
					v[i].SetControlID(-1);
				}
				break;
			}
		case FACE2_CHUNK:
			{
				Tab<UVW_TVFaceOldClass> oldData;
				oldData.SetCount(f.Count());
				iload->ReadVoid(oldData.Addr(0), sizeof(UVW_TVFaceOldClass)*oldData.Count(), &nb);
				for (int i = 0; i < f.Count(); i++)
				{
					//fix for bug 281118 it was checking an uniitiliazed flag
					if (oldData[i].flags & 8)  // not this was FLAG_QUAD but this define got removed
						f[i]->count=4;
					else f[i]->count=3;

					f[i]->t = new int[f[i]->count];
					f[i]->v = new int[f[i]->count];

					for (int j = 0; j < f[i]->count; j++)
						f[i]->t[j] = oldData[i].t[j];
					f[i]->FaceIndex = oldData[i].FaceIndex;
					f[i]->MatID = oldData[i].MatID;
					f[i]->flags = oldData[i].flags;
					f[i]->vecs = NULL;
				}
				/*
				//now compute the geom points
				for (int i = 0; i < f.Count(); i++)
				{
					int pcount = 3;
					pcount = f[i]->count;

					for (int j =0; j < pcount; j++)
					{
						BOOL found = FALSE;
						int index;
						for (int k =0; k < geomPoints.Count();k++)
						{
							if (oldData[i].pt[j] == geomPoints[k])
							{
								found = TRUE;
								index = k;
								k = geomPoints.Count();
							}
						}
						if (found)
						{
							f[i]->v[j] = index;
						}
						else
						{
							f[i]->v[j] = geomPoints.Count();
							geomPoints.Append(1,&oldData[i].pt[j],1);
						}
					}

				}
	*/
				break;
			}

		case FACE4_CHUNK:
			LoadFacesMax9(iload);	

			break;

		case VERTS2_CHUNK:
//fix
			{
				Tab<UVW_TVVertClass_Max9> tempV;
				tempV.SetCount(v.Count());
				iload->ReadVoid(tempV.Addr(0), sizeof(UVW_TVVertClass_Max9)*v.Count(), &nb);
				for (int i=0;i<v.Count();i++)
				{
					v[i].SetP(tempV[i].p);
					v[i].SetFlag(tempV[i].flags);
					v[i].SetInfluence(0.0f);
					v[i].SetControlID(-1);
				}
				break;
			}
/*
		case GEOMPOINTS_CHUNK:
			iload->Read(geomPoints.Addr(0), sizeof(Point3)*geomPoints.Count(), &nb);
			break;
*/
	}

}
Beispiel #9
0
void FExtrudeMod::ModifyTriObject (TimeValue t, ModContext &mc, TriObject *tobj) {
	Mesh &mesh = tobj->GetMesh();
	Interval iv = FOREVER;
	float amount, scale;
	Point3 center;
	int i, j, type;
	
	mp_pblock->GetValue (kFexAmount, t, amount, iv);
	mp_pblock->GetValue (kFexScale, t, scale, iv);
	mp_pblock->GetValue (kFexType, t, type, iv);

	// Extrude the faces -- this just does the topological operation.
	MeshDelta tmd(mesh);
	tmd.ExtrudeFaces (mesh, mesh.faceSel);
	tmd.Apply(mesh);

	// Mark vertices used by selected faces
	BitArray sel;
	sel.SetSize(mesh.getNumVerts());
	for (i=0; i<mesh.getNumFaces(); i++) {
		if (mesh.faceSel[i]) {
			for (int j=0; j<3; j++) sel.Set(mesh.faces[i].v[j],TRUE);
		}
	}

	MeshTempData temp(&mesh);
	Point3 *vertexDir;
	Tab<Point3> centerBasedBuffer;
	if (type<2) {
		int extrusionType = type ? MESH_EXTRUDE_LOCAL : MESH_EXTRUDE_CLUSTER;
		vertexDir = temp.FaceExtDir(extrusionType)->Addr(0);
	} else {
		// We need to move all vertices away from the "center".
		// Compute the center point
		Point3 center;
		mp_base->GetValue(t,&center,iv,CTRL_ABSOLUTE);

		// Create array of vertex directions 
		centerBasedBuffer.SetCount (mesh.numVerts);
		vertexDir = centerBasedBuffer.Addr(0);
		for (i=0; i<mesh.numVerts; i++) {
			if (!sel[i]) continue;
			vertexDir[i] = Normalize((mesh.verts[i] * (*mc.tm)) - center);
		}
	}

	// Actually do the move:
	for (i=0; i<mesh.numVerts; i++) {
		if (!sel[i]) continue;
		mesh.verts[i] += amount * vertexDir[i];
	}

	// Scale verts
	if (scale!=1.0f) {
		temp.freeAll ();
		temp.SetMesh (&mesh);
		FaceClusterList *fc = temp.FaceClusters();
		Tab<Point3> *centers = temp.ClusterCenters (MESH_FACE);

		// Make sure each vertex is only scaled once.
		BitArray done;
		done.SetSize(mesh.getNumVerts());

		// scale each cluster independently
		for (i=0; (DWORD)i<fc->count; i++) {
			Point3 cent = (centers->Addr(0))[i];
			// Scale the cluster about its center
			for (j=0; j<mesh.getNumFaces(); j++) {
				if (fc->clust[j]==(DWORD)i) {
					for (int k=0; k<3; k++) {
						int index = mesh.faces[j].v[k]; 
						if (done[index]) continue;
						done.Set(index);
						mesh.verts[index] = (mesh.verts[index]-cent)*scale + cent;							
					}
				}
			}
		}
	}

	mesh.InvalidateTopologyCache ();
	tobj->UpdateValidity(GEOM_CHAN_NUM,iv);		
}
Beispiel #10
0
void FExtrudeMod::ModifyPolyObject (TimeValue t, ModContext &mc, PolyObject *pobj) {
	MNMesh &mesh = pobj->GetMesh();

	// Luna task 747
	// We cannot support specified normals in Face Extrude at this time.
	mesh.ClearSpecifiedNormals();

	Interval iv = FOREVER;
	float amount, scale;
	Point3 center;
	int type, i, j;

	mp_pblock->GetValue (kFexAmount, t, amount, iv);
	mp_pblock->GetValue (kFexScale, t, scale, iv);
	mp_pblock->GetValue (kFexType, t, type, iv);

	MNTempData temp(&mesh);

	bool abort=false;
	DWORD flag=MN_SEL;	// Later can be used to "inherit" selection from other SO levels.

	switch (type) {
	case 0:	// Group normals
		abort = !mesh.ExtrudeFaceClusters (*(temp.FaceClusters(flag)));
		if (!abort) {
			temp.Invalidate (TOPO_CHANNEL);	// Forces reevaluation of face clusters.
			mesh.GetExtrudeDirection (temp.ChamferData(), temp.FaceClusters(flag),
				temp.ClusterNormals (MNM_SL_FACE, flag)->Addr(0));
		}
		break;

	case 1:	// Local normals
		abort = !mesh.ExtrudeFaceClusters (*(temp.FaceClusters(flag)));
		if (!abort) {
			temp.Invalidate (TOPO_CHANNEL);	// Forces reevaluation of face clusters.
			mesh.GetExtrudeDirection (temp.ChamferData(), flag);
		}
		break;

	case 2:	// from center:
		mp_base->GetValue(t,&center,iv,CTRL_ABSOLUTE);
		abort = !mesh.ExtrudeFaceClusters (*(temp.FaceClusters(flag)));
		if (!abort) {
			temp.Invalidate (GEOM_CHANNEL);
			MNChamferData *mcd = temp.ChamferData();

			mcd->InitToMesh (mesh);
			mcd->ClearLimits ();

			int j, mp;
			// Make clear that there are no map values:
			for (mp=-NUM_HIDDENMAPS; mp<mesh.numm; mp++) mcd->MDir(mp).SetCount(0);

			// Each vertex on flagged faces moves according to the direction from the center:
			for (i=0; i<mesh.numv; i++) {
				mcd->vdir[i] = Point3(0,0,0);
				if (mesh.v[i].GetFlag (MN_DEAD)) continue;
				if (!mesh.vfac[i].Count()) continue;
				bool hasflagged = false;
				for (j=0; j<mesh.vfac[i].Count(); j++) {
					MNFace & mf = mesh.f[mesh.vfac[i][j]];
					if (!mf.GetFlag (MN_SEL)) continue;
					hasflagged = true;
				}
				if (!hasflagged) continue;
				mcd->vdir[i] = Normalize((mesh.P(i)*(*mc.tm))-center);
			}
		}
		break;
	}
	if (abort) return;

	// Move verts
	for (i=0; i<mesh.numv; i++) {
		if (mesh.v[i].GetFlag (MN_DEAD)) continue;
		mesh.v[i].p += temp.ChamferData()->vdir[i]*amount;
	}

	// Scale verts
	if (scale!=1.0f) {
		temp.freeAll ();
		temp.SetMesh (&mesh);
		MNFaceClusters *fc = temp.FaceClusters();
		Tab<Point3> *centers = temp.ClusterCenters (MNM_SL_FACE);

		// Make sure each vertex is only scaled once.
		BitArray done;
		done.SetSize(mesh.numv);

		// scale each cluster independently
		for (i=0; i<fc->count; i++) {
			Point3 cent = (centers->Addr(0))[i];
			// Scale the cluster about its center
			for (j=0; j<mesh.numf; j++) {
				if (fc->clust[j]==i) {
					for (int k=0; k<mesh.f[j].deg; k++) {
						int index = mesh.f[j].vtx[k]; 
						if (done[index]) continue;
						done.Set(index);
						mesh.v[index].p = (mesh.v[index].p-cent)*scale + cent;							
					}
				}
			}
		}
	}

	mesh.InvalidateTopoCache ();
	mesh.FillInMesh ();
	pobj->UpdateValidity(GEOM_CHAN_NUM,iv);
}
Beispiel #11
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;
	}
}
//Some helper functions to handle painter UI
void PaintDeformTest::Paint()
{
	if (pPainter) //need to check this since some one could have taken the painterinterface plugin out
		{
		if (!pPainter->InPaintMode())  
			{
			pPainter->InitializeCallback(this); //initialize the callback
			//load up our nodes
			//gather up all our nodes and local data and store em off
			MyEnumProc dep;              
			DoEnumDependents(&dep);
			Tab<INode *> nodes;
			Tab<ObjectState> objList;
			painterNodeList.ZeroCount();
			TimeValue t = GetCOREInterface()->GetTime();
			for (int  i = 0; i < dep.Nodes.Count(); i++)
				{
				PaintDefromModData *pmd = GetPMD(dep.Nodes[i]);

				if (pmd)
					{
					nodes.Append(1,&dep.Nodes[i]);
					PainterNodeList temp;
					temp.node = dep.Nodes[i];
					temp.pmd = pmd;
					temp.tmToLocalSpace = Inverse(dep.Nodes[i]->GetObjectTM(GetCOREInterface()->GetTime()));
					painterNodeList.Append(1,&temp);
					ObjectState sos;
					sos = dep.Nodes[i]->EvalWorldState(t);
					objList.Append(1,&sos);
					}
				}

//we use the point gather so we need to tell the system to turn it on
			pPainter->SetEnablePointGather(TRUE);
			pPainter->SetBuildNormalData(TRUE);

//this sends all our dependant nodes to the painter
			pPainter->InitializeNodesByObjState(0, nodes,objList);

			BOOL updateMesh = FALSE;
			for (int i = 0; i < nodes.Count(); i++)
				{

				ObjectState os = nodes[i]->EvalWorldState(GetCOREInterface()->GetTime());
				
				int ct = os.obj->NumPoints();
//is our local vertex count does not match or the curremt object count we have some
//sort of topo change above us so we need to load a custom point list
//We really need add normals here
//so right now this does not work with patches, nurbs or things that have different  topos at the top
//top of the stack
				if (os.obj->NumPoints() != painterNodeList[i].pmd->offsetList.Count())
					{
					Tab<Point3> pointList;
					pointList.SetCount(ct);
					Matrix3 tm = nodes[i]->GetObjectTM(GetCOREInterface()->GetTime());
					for (int j =0; j < ct; j++)
						{
						pointList[j] = os.obj->GetPoint(j)*tm;
						}
					pPainter->LoadCustomPointGather(ct, pointList.Addr(0), nodes[i]);
					updateMesh = TRUE;
					}

				}
//reinitialize our nodes if we had a custom list
			if (updateMesh)
				pPainter->UpdateMeshesByObjState(TRUE,objList);

			pPainter->StartPaintSession(); //start the paint session
			iPaintButton->SetCheck(TRUE);
			}
		else //we are currently in a paint mode so turn it off
			{
			pPainter->EndPaintSession(); //end the paint session
			iPaintButton->SetCheck(FALSE);
			}
		}

}
Beispiel #13
0
int TriObject::Display(TimeValue t, INode *inode, ViewExp* vpt, int flags) {

	if ( ! vpt || ! vpt->IsAlive() )
	{
		// why are we here
		DbgAssert(!_T("Invalid viewport!"));
		return FALSE;
	}

	float *vsw = NULL;
	DWORD oldRndLimits, newRndLimits;
	Tab<VertColor> vertexSelColors;
	Tab<TVFace> vertexSelFaces;

	Matrix3 tm;
	GraphicsWindow *gw = vpt->getGW();
	gw->setTransform(inode->GetObjectTM(t));

	newRndLimits = oldRndLimits = gw->getRndLimits();

	// CAL-11/16/01: Use soft selection colors when soft selection is turned on in sub-object mode.
	// The condition is satisfied if the display of vertex/edge/face/poly is requested and
	// the vertex selection weights are set.
	// CAL-12/02/01: Add one more checking to the condition to check if the display of soft
	// selection using wireframe or vertex color shading is requested.
	// CAL-11/16/01: (TODO) To imporvement the performance of this function,
	// vertexSelColors & vertexSelFaces tables can be cached (in Mesh) and used as long as
	// the vertex selection weights are not changed.
	bool dspSoftSelVert = ((gw->getRndMode()&GW_VERT_TICKS) ||
						   ((mesh.dispFlags&DISP_VERTTICKS) && (flags&DISP_SHOWSUBOBJECT))) &&
						  (mesh.dispFlags&DISP_SELVERTS);
	bool dspSoftSelEdFc = ((mesh.dispFlags&DISP_SELEDGES) || (mesh.dispFlags&DISP_SELFACES) ||
						   (mesh.dispFlags&DISP_SELPOLYS)) && (flags&DISP_SHOWSUBOBJECT);
	bool dspWireSoftSel = (oldRndLimits&GW_WIREFRAME) ||
						  ((oldRndLimits&GW_COLOR_VERTS) && (inode->GetVertexColorType() == nvct_soft_select));
	if ((dspSoftSelVert || dspSoftSelEdFc) && dspWireSoftSel &&
		(vsw = mesh.getVSelectionWeights())) {

		Point3 clr = GetUIColor(COLOR_VERT_TICKS);
		
		vertexSelColors.SetCount(mesh.getNumVerts());
		vertexSelFaces.SetCount(mesh.getNumFaces());

		// Create the array of colors, one per vertex:
		for (int i=0; i<mesh.getNumVerts(); i++) {
			// (Note we may want a different color - this gives the appropriate vertex-tick
			// color, which we may not want to use on faces.  Fades from blue to red.)
			vertexSelColors[i] = (vsw[i]) ? SoftSelectionColor(vsw[i]) : clr;
		}

		// Copy over the face topology exactly to the map face topology:
		for (i=0; i<mesh.getNumFaces(); i++) {
			DWORD *pv = mesh.faces[i].v;
			vertexSelFaces[i].setTVerts(pv[0], pv[1], pv[2]);
		}

		// CAL-05/21/02: make sure there's data before accessing it.
		// Set the mesh to use these colors:
		mesh.setVCDisplayData (MESH_USE_EXT_CVARRAY,
			(vertexSelColors.Count() > 0) ? vertexSelColors.Addr(0) : NULL,
			(vertexSelFaces.Count() > 0) ? vertexSelFaces.Addr(0) : NULL);

		// Turn on vertex color mode
		if (oldRndLimits&GW_WIREFRAME) {
			newRndLimits |= GW_COLOR_VERTS;				// turn on vertex colors
			newRndLimits &= ~GW_SHADE_CVERTS;			// turn off vertex color shading
			newRndLimits |= GW_ILLUM;					// turn on lit wire frame
			gw->setRndLimits(newRndLimits);
		}

	} else {
		switch (inode->GetVertexColorType()) {
		case nvct_color:
			if (mesh.curVCChan == 0) break;
			mesh.setVCDisplayData (0);
			break;
		case nvct_illumination:
			if (mesh.curVCChan == MAP_SHADING) break;
			mesh.setVCDisplayData (MAP_SHADING);
			break;
		case nvct_alpha:
			if (mesh.curVCChan == MAP_ALPHA) break;
			mesh.setVCDisplayData (MAP_ALPHA);
			break;
		//case nvct_color_plus_illum:
			// if (mesh.curVCChan == MESH_USE_EXT_CVARRAY) break;
			// Where do I cache the arrays I'll need to create from the color and illum arrays?
			// break;
		// CAL-06/15/03: add a new option to view map channel as vertex color. (FID #1926)
		case nvct_map_channel:
			if (mesh.curVCChan == inode->GetVertexColorMapChannel()) break;
			mesh.setVCDisplayData (inode->GetVertexColorMapChannel());
			break;
		case nvct_soft_select:
			// Turn off vertex color if soft selection is not on.
			if (oldRndLimits&GW_COLOR_VERTS) {
				newRndLimits &= ~GW_COLOR_VERTS;
				gw->setRndLimits(newRndLimits);
			}
			break;
		}
	}

	mesh.render( gw, inode->Mtls(),
		(flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, 
		COMP_ALL | ((flags&DISP_SHOWSUBOBJECT)?COMP_OBJSELECTED:0),
		inode->NumMtls(), (InterfaceServer*)this); // NS: 9/22/00 Added IXTCAccess argument for Vertex Shader support.
		// RB: The mesh flag COMP_OBJSELECTED is sort of misnamed. When this bit is set, sub object things (like ticks and selected faces) will be drawn.

	if ( vsw )
		mesh.setVCDisplayData (MESH_USE_EXT_CVARRAY);

	if (newRndLimits != oldRndLimits)
		gw->setRndLimits(oldRndLimits);

	return(0);
	}
Beispiel #14
0
void BonesDefMod::CanvasStartPaint()
{
	if (iPaintButton!=NULL) iPaintButton->SetCheck(TRUE);
	
	pPainterInterface->SetBuildNormalData(FALSE);
	pPainterInterface->SetEnablePointGather(TRUE);

	//this sends all our dependant nodes to the painter
	MyEnumProc dep;              
	EnumDependents(&dep);
	Tab<INode *> nodes;
	painterData.ZeroCount();
	for (int  i = 0; i < dep.Nodes.Count(); i++)
		{
		BoneModData *bmd = GetBMD(dep.Nodes[i]);

		if (bmd)
			{
			nodes.Append(1,&dep.Nodes[i]);
			ObjectState os;
			PainterSaveData temp;
			temp.node = dep.Nodes[i];
			temp.bmd = bmd;
			painterData.Append(1,&temp);
			}
		}
	pPainterInterface->InitializeNodes(0, nodes);
	BOOL updateMesh = FALSE;
	for (i = 0; i < nodes.Count(); i++)
		{

		ObjectState os = nodes[i]->EvalWorldState(GetCOREInterface()->GetTime());
				
				
		if ( (os.obj->NumPoints() != painterData[i].bmd->VertexData.Count()) ||
			  (painterData[i].bmd->isPatch) || (painterData[i].bmd->inputObjectIsNURBS) )
			{
			int ct = painterData[i].bmd->VertexData.Count();
			Tab<Point3> pointList;
			pointList.SetCount(ct);
			Matrix3 tm = nodes[i]->GetObjectTM(GetCOREInterface()->GetTime());
			for (int j =0; j < ct; j++)
				{
				pointList[j] = painterData[i].bmd->VertexData[j]->LocalPosPostDeform*tm;
				}
			pPainterInterface->LoadCustomPointGather(ct, pointList.Addr(0), nodes[i]);
			updateMesh = TRUE;
			}
		}

	if (updateMesh)
		pPainterInterface->UpdateMeshes(TRUE);

//get mirror nodeindex
	SetMirrorBone();

	for (i = 0; i < nodes.Count(); i++)
		{
	
		painterData[i].node->FlagForeground(GetCOREInterface()->GetTime());
		}
		
//5.1.03
	for (i = 0; i < painterData.Count(); i++)
		{
		BoneModData *bmd = painterData[i].bmd;
//5.1.05
		bmd->BuildEdgeList();
		}		

}