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; }
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); }
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; }
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; }
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; */ } }
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,¢er,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); }
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,¢er,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); }
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); } } }
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); }
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(); } }