void EditPatchMod::ChangeSelVerts(int type) { ModContextList mcList; INodeTab nodes; TimeValue t = ip->GetTime(); BOOL holdNeeded = FALSE; BOOL hadSelected = FALSE; if (!ip) return; ip->GetModContexts(mcList, nodes); ClearPatchDataFlag(mcList, EPD_BEENDONE); theHold.Begin(); for (int i = 0; i < mcList.Count(); i++) { BOOL altered = FALSE; EditPatchData *patchData =(EditPatchData*)mcList[i]->localData; if (!patchData) continue; if (patchData->GetFlag(EPD_BEENDONE)) continue; // If the mesh isn't yet cache, this will cause it to get cached. RPatchMesh *rpatch; PatchMesh *patch = patchData->TempData(this)->GetPatch(t, rpatch); if (!patch) continue; // If this is the first edit, then the delta arrays will be allocated patchData->BeginEdit(t); // If any bits are set in the selection set, let's DO IT!! if (patch->vertSel.NumberSet()) { altered = holdNeeded = TRUE; if (theHold.Holding()) theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "ChangeSelVerts")); // Call the vertex type change function patch->ChangeVertType(-1, type); patchData->UpdateChanges(patch, rpatch, FALSE); patchData->TempData(this)->Invalidate(PART_TOPO); } patchData->SetFlag(EPD_BEENDONE, TRUE); } if (holdNeeded) theHold.Accept(GetString(IDS_TH_VERTCHANGE)); else { ip->DisplayTempPrompt(GetString(IDS_TH_NOVERTSSEL), PROMPT_TIME); theHold.End(); } nodes.DisposeTemporary(); ClearPatchDataFlag(mcList, EPD_BEENDONE); NotifyDependents(FOREVER, PART_TOPO, REFMSG_CHANGE); ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL); }
void EditPatchMod::RecordTopologyTags() { ModContextList mcList; INodeTab nodes; TimeValue t = ip->GetTime(); ip->GetModContexts(mcList, nodes); ClearPatchDataFlag(mcList, EPD_BEENDONE); for (int i = 0; i < mcList.Count(); i++) { EditPatchData *patchData =(EditPatchData*)mcList[i]->localData; if (!patchData) continue; if (patchData->GetFlag(EPD_BEENDONE)) continue; // If the mesh isn't yet cache, this will cause it to get cached. RPatchMesh *rpatch; PatchMesh *patch = patchData->TempData(this)->GetPatch(t, rpatch); if (!patch) continue; patch->RecordTopologyTags(); patchData->SetFlag(EPD_BEENDONE, TRUE); } nodes.DisposeTemporary(); ClearPatchDataFlag(mcList, EPD_BEENDONE); }
int TriPatchObject::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) { if ( ! vpt || ! vpt->IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return FALSE; } Matrix3 tm; GraphicsWindow *gw = vpt->getGW(); gw->setTransform(inode->GetObjectTM(t)); UpdatePatchMesh(t); if(!MaxSDK::Graphics::IsRetainedModeEnabled()) { if(!(gw->getRndMode() & GW_BOX_MODE)) { PrepareMesh(t); Mesh& mesh = patch.GetMesh(); if(mesh.getNumVerts()) { mesh.render( gw, inode->Mtls(), (flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL | (inode->Selected()?COMP_OBJSELECTED:0), inode->NumMtls()); } } } patch.render( gw, inode->Mtls(), (flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL | (inode->Selected()?COMP_OBJSELECTED:0), inode->NumMtls()); return(0); }
//----------------------------------------------------------------------- PatchMeshPtr MeshManager::createBezierPatch(const String& name, const String& groupName, void* controlPointBuffer, VertexDeclaration *declaration, size_t width, size_t height, size_t uMaxSubdivisionLevel, size_t vMaxSubdivisionLevel, PatchSurface::VisibleSide visibleSide, HardwareBuffer::Usage vbUsage, HardwareBuffer::Usage ibUsage, bool vbUseShadow, bool ibUseShadow) { if (width < 3 || height < 3) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Bezier patch require at least 3x3 control points", "MeshManager::createBezierPatch"); } MeshPtr pMesh = getByName(name); if (!pMesh.isNull()) { OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, "A mesh called " + name + " already exists!", "MeshManager::createBezierPatch"); } PatchMesh* pm = OGRE_NEW PatchMesh(this, name, getNextHandle(), groupName); pm->define(controlPointBuffer, declaration, width, height, uMaxSubdivisionLevel, vMaxSubdivisionLevel, visibleSide, vbUsage, ibUsage, vbUseShadow, ibUseShadow); pm->load(); ResourcePtr res(pm); addImpl(res); return res.staticCast<PatchMesh>(); }
void VWeldMod::ConvertPatchSelection (PatchMesh & mesh) { int i; switch (mesh.selLevel) { case PATCH_OBJECT: mesh.vertSel.SetAll (); break; case PATCH_VERTEX: // Don't need to do anything. break; case PATCH_EDGE: mesh.vertSel.ClearAll (); for (i=0; i<mesh.getNumEdges(); i++) { if (!mesh.edgeSel[i]) continue; mesh.vertSel.Set(mesh.edges[i].v1,TRUE); mesh.vertSel.Set(mesh.edges[i].v2,TRUE); } break; case PATCH_PATCH: mesh.vertSel.ClearAll (); for (i=0; i<mesh.getNumPatches(); i++) { if (!mesh.patchSel[i]) continue; for (int j=0; j<mesh.patches[i].type; j++) mesh.vertSel.Set (mesh.patches[i].v[j]); } break; } }
static void MakePatchCapTexture(PatchMesh &pmesh, Matrix3 &itm, int pstart, int pend, BOOL usePhysUVs) { if(pstart == pend) return; // Find out which verts are used by the cap BitArray capVerts(pmesh.numVerts); capVerts.ClearAll(); for(int i = pstart; i < pend; ++i) { Patch &p = pmesh.patches[i]; capVerts.Set(p.v[0]); capVerts.Set(p.v[1]); capVerts.Set(p.v[2]); if(p.type == PATCH_QUAD) capVerts.Set(p.v[3]); } // Minmax the verts involved in X/Y axis and total them Box3 bounds; int numCapVerts = 0; int numCapPatches = pend - pstart; IntTab capIndexes; capIndexes.SetCount(pmesh.numVerts); int baseTVert = pmesh.getNumTVerts(); for(int i = 0; i < pmesh.numVerts; ++i) { if(capVerts[i]) { capIndexes[i] = baseTVert + numCapVerts++; bounds += pmesh.verts[i].p * itm; } } pmesh.setNumTVerts(baseTVert + numCapVerts, TRUE); Point3 s; if (usePhysUVs) s = Point3(1.0f, 1.0f, 0.0f); else s = Point3(1.0f / bounds.Width().x, 1.0f / bounds.Width().y, 0.0f); Point3 t(-bounds.Min().x, -bounds.Min().y, 0.0f); // Do the TVerts for(int i = 0; i < pmesh.numVerts; ++i) { if(capVerts[i]) pmesh.setTVert(baseTVert++, ((pmesh.verts[i].p * itm) + t) * s); } // Do the TVPatches for(int i = pstart; i < pend; ++i) { Patch &p = pmesh.patches[i]; TVPatch &tp = pmesh.getTVPatch(i); if(p.type == PATCH_TRI) tp.setTVerts(capIndexes[p.v[0]], capIndexes[p.v[1]], capIndexes[p.v[2]]); else tp.setTVerts(capIndexes[p.v[0]], capIndexes[p.v[1]], capIndexes[p.v[2]], capIndexes[p.v[3]]); } }
Mesh* TriPatchObject::GetRenderMesh(TimeValue t, INode *inode, View& view, BOOL& needDelete) { UpdatePatchMesh(t); TessApprox tess = patch.GetProdTess(); if (tess.type == TESS_SET) { needDelete = FALSE; patch.InvalidateMesh(); // force this... // temporarlily set the view tess to prod tess TessApprox tempTess = patch.GetViewTess(); patch.SetViewTess(tess); PrepareMesh(t); patch.SetViewTess(tempTess); return &patch.GetMesh(); } else { Mesh *nmesh = new Mesh/*(mesh)*/; Matrix3 otm = inode->GetObjectTM(t); Box3 bbox; GetDeformBBox(t, bbox); tess.merge *= Length(bbox.Width())/1000.0f; TessApprox disp = patch.GetDispTess(); disp.merge *= Length(bbox.Width())/1000.0f; GetGTessFunction(); (*psGTessFunc)(&patch, BEZIER_PATCH, &otm, nmesh, &tess, &disp, &view, inode->GetMtl(), FALSE, FALSE); if (tess.merge > 0.0f && patch.GetProdTessWeld()) WeldMesh(nmesh, tess.merge); needDelete = TRUE; return nmesh; } }
bool TriPatchObject::UpdatePerNodeItems(const MaxSDK::Graphics::UpdateDisplayContext& updateDisplayContext, MaxSDK::Graphics::UpdateNodeContext& nodeContext, MaxSDK::Graphics::IRenderItemContainer& targetRenderItemContainer) { Mesh& mesh = patch.GetMesh(); if(mesh.getNumVerts()>0) { using namespace MaxSDK::Graphics; GenerateMeshRenderItemsContext generateRenderItemsContext; generateRenderItemsContext.GenerateDefaultContext(updateDisplayContext); generateRenderItemsContext.RemoveInvisibleMeshElementDescriptions(nodeContext.GetRenderNode()); IMeshDisplay2* pMeshDisplay = static_cast<IMeshDisplay2*>(mesh.GetInterface(IMesh_DISPLAY2_INTERFACE_ID)); if (NULL == pMeshDisplay) { return false; } pMeshDisplay->GetRenderItems(generateRenderItemsContext,nodeContext,targetRenderItemContainer); return true ; } return false; }
int TriPatchObject::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) { Matrix3 tm; GraphicsWindow *gw = vpt->getGW(); gw->setTransform(inode->GetObjectTM(t)); UpdatePatchMesh(t); if(!(gw->getRndMode() & GW_BOX_MODE)) { PrepareMesh(t); Mesh& mesh = patch.GetMesh(); if(mesh.getNumVerts()) { mesh.render( gw, inode->Mtls(), (flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL | (inode->Selected()?COMP_OBJSELECTED:0), inode->NumMtls()); } } patch.render( gw, inode->Mtls(), (flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect() : NULL, COMP_ALL | (inode->Selected()?COMP_OBJSELECTED:0), inode->NumMtls()); return(0); }
// From BaseObject int TriPatchObject::HitTest(TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt) { HitRegion hitRegion; GraphicsWindow *gw = vpt->getGW(); Material *mtl = gw->getMaterial(); UpdatePatchMesh(t); gw->setTransform(inode->GetObjectTM(t)); MakeHitRegion(hitRegion, type, crossing, 4, p); return patch.select( gw, mtl, &hitRegion, flags & HIT_ABORTONHIT ); }
void TriPatchObject::Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt) { if(creating) // If creating this one, don't try to snap to it! return; Matrix3 tm = inode->GetObjectTM(t); GraphicsWindow *gw = vpt->getGW(); UpdatePatchMesh(t); gw->setTransform(tm); patch.snap( gw, snap, p, tm ); }
Object* TriPatchObject::ConvertToType(TimeValue t, Class_ID obtype) { if(obtype == patchObjectClassID || obtype == defObjectClassID || obtype == mapObjectClassID) { PatchObject *ob; UpdatePatchMesh(t); ob = new PatchObject(); ob->patch = patch; ob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); ob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return ob; } if(obtype == triObjectClassID) { TriObject *ob = CreateNewTriObject(); PrepareMesh(t); ob->GetMesh() = patch.GetMesh(); ob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); ob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return ob; } #ifndef NO_NURBS if (obtype==EDITABLE_SURF_CLASS_ID) { PatchObject *pob; UpdatePatchMesh(t); pob = new PatchObject(); pob->patch = patch; Object *ob = BuildEMObjectFromPatchObject(pob); delete pob; ob->SetChannelValidity(TOPO_CHAN_NUM, ObjectValidity(t)); ob->SetChannelValidity(GEOM_CHAN_NUM, ObjectValidity(t)); return ob; } #endif if (Object::CanConvertToType (obtype)) return Object::ConvertToType (t, obtype); if (CanConvertPatchObject (obtype)) { PatchObject *ob; UpdatePatchMesh(t); ob = new PatchObject(); ob->patch = patch; ob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); ob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); Object *ret = ob->ConvertToType (t, obtype); ob->DeleteThis (); return ret; } return NULL; }
// From BaseObject int TriPatchObject::HitTest(TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt) { if ( ! vpt || ! vpt->IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return FALSE; } HitRegion hitRegion; GraphicsWindow *gw = vpt->getGW(); Material *mtl = gw->getMaterial(); UpdatePatchMesh(t); gw->setTransform(inode->GetObjectTM(t)); MakeHitRegion(hitRegion, type, crossing, 4, p); return patch.select( gw, mtl, &hitRegion, flags & HIT_ABORTONHIT ); }
bool TriPatchObject::UpdateDisplay( const MaxSDK::Graphics::MaxContext& maxContext, const MaxSDK::Graphics::UpdateDisplayContext& displayContext) { // create a mesh to display (leave it in cache) PrepareMesh(displayContext.GetDisplayTime()); Mesh& mesh = patch.GetMesh(); if(mesh.getNumVerts()>0) { using namespace MaxSDK::Graphics; GenerateMeshRenderItemsContext generateRenderItemsContext; generateRenderItemsContext.GenerateDefaultContext(displayContext); mesh.GenerateRenderItems(mRenderItemHandles,generateRenderItemsContext); return true ; } return false; }
void TriPatchObject::Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt) { if ( ! vpt || ! vpt->IsAlive() ) { // why are we here DbgAssert(!_T("Invalid viewport!")); return; } if(creating) // If creating this one, don't try to snap to it! return; Matrix3 tm = inode->GetObjectTM(t); GraphicsWindow *gw = vpt->getGW(); UpdatePatchMesh(t); gw->setTransform(tm); patch.snap( gw, snap, p, tm ); }
bool TriPatchObject::PrepareDisplay(const MaxSDK::Graphics::UpdateDisplayContext& prepareDisplayContext) { PrepareMesh(prepareDisplayContext.GetDisplayTime()); Mesh& mesh = patch.GetMesh(); if(mesh.getNumVerts()>0) { using namespace MaxSDK::Graphics; mRenderItemHandles.ClearAllRenderItems(); IMeshDisplay2* pMeshDisplay = static_cast<IMeshDisplay2*>(mesh.GetInterface(IMesh_DISPLAY2_INTERFACE_ID)); if (NULL == pMeshDisplay) { return false; } GenerateMeshRenderItemsContext generateMeshRenderItemsContext; generateMeshRenderItemsContext.GenerateDefaultContext(prepareDisplayContext); pMeshDisplay->PrepareDisplay(generateMeshRenderItemsContext); return true ; } return false; }
// Selection set, misc fixup utility function // This depends on PatchMesh::RecordTopologyTags being called prior to the topo changes void EditPatchMod::ResolveTopoChanges() { ModContextList mcList; INodeTab nodes; TimeValue t = ip->GetTime(); ip->GetModContexts(mcList, nodes); ClearPatchDataFlag(mcList, EPD_BEENDONE); for (int i = 0; i < mcList.Count(); i++) { EditPatchData *patchData =(EditPatchData*)mcList[i]->localData; if (!patchData) continue; if (patchData->GetFlag(EPD_BEENDONE)) continue; // If the mesh isn't yet cache, this will cause it to get cached. RPatchMesh *rpatch; PatchMesh *patch = patchData->TempData(this)->GetPatch(t, rpatch); if (!patch) continue; // First, the vertex selections int set; for (set = 0; set < patchData->vselSet.Count(); ++set) { BitArray *oldVS = &patchData->vselSet[set]; BitArray newVS; newVS.SetSize(patch->numVerts); for (int vert = 0; vert < patch->numVerts; ++vert) { // Get the knot's previous location, then copy that selection into the new set int tag = patch->verts[vert].aux1; if (tag >= 0) newVS.Set(vert, (*oldVS)[tag]); else newVS.Clear(vert); } if (theHold.Holding()) theHold.Put(new ChangeNamedSetRestore(&patchData->vselSet, set, oldVS)); patchData->vselSet[set] = newVS; } // Now the edge selections for (set = 0; set < patchData->eselSet.Count(); ++set) { BitArray *oldES = &patchData->eselSet[set]; BitArray newES; newES.SetSize(patch->numEdges); for (int edge = 0; edge < patch->numEdges; ++edge) { // Get the knot's previous location, then copy that selection into the new set int tag = patch->edges[edge].aux1; if (tag >= 0) newES.Set(edge, (*oldES)[tag]); else newES.Clear(edge); } if (theHold.Holding()) theHold.Put(new ChangeNamedSetRestore(&patchData->eselSet, set, oldES)); patchData->eselSet[set] = newES; } // Now the patch selections for (set = 0; set < patchData->pselSet.Count(); ++set) { BitArray *oldPS = &patchData->pselSet[set]; BitArray newPS; newPS.SetSize(patch->numPatches); for (int p = 0; p < patch->numPatches; ++p) { // Get the knot's previous location, then copy that selection into the new set int tag = patch->patches[p].aux1; if (tag >= 0) newPS.Set(p, (*oldPS)[tag]); else newPS.Clear(p); } if (theHold.Holding()) theHold.Put(new ChangeNamedSetRestore(&patchData->pselSet, set, oldPS)); patchData->pselSet[set] = newPS; } // watje 4-16-99 patch->HookFixTopology(); patchData->SetFlag(EPD_BEENDONE, TRUE); } nodes.DisposeTemporary(); ClearPatchDataFlag(mcList, EPD_BEENDONE); }
void ExtrudeMod::BuildPatchFromShape(TimeValue t,ModContext &mc, ObjectState * os, PatchMesh &pmesh) { ShapeObject *shape = (ShapeObject *)os->obj; float amount; int levels,capStart,capEnd,capType; pblock->GetValue(PB_AMOUNT,t,amount,FOREVER); pblock->GetValue(PB_SEGS,t,levels,FOREVER); if (levels<1) levels = 1; pblock->GetValue(PB_CAPSTART,t,capStart,FOREVER); pblock->GetValue(PB_CAPEND,t,capEnd,FOREVER); pblock->GetValue(PB_CAPTYPE,t,capType,FOREVER); BOOL texturing; pblock->GetValue(PB_MAPPING, TimeValue(0), texturing, FOREVER); BOOL genMatIDs; pblock->GetValue(PB_GEN_MATIDS, TimeValue(0), genMatIDs, FOREVER); BOOL useShapeIDs; pblock->GetValue(PB_USE_SHAPEIDS, TimeValue(0), useShapeIDs, FOREVER); BOOL smooth; pblock->GetValue(PB_SMOOTH, TimeValue(0), smooth, FOREVER); LimitValue(amount, -1000000.0f, 1000000.0f); // Get the basic dimension stuff float zSize = (float)fabs(amount); float baseZ = 0.0f; if(amount < 0.0f) baseZ = amount; // If the shape can convert itself to a BezierShape, have it do so! BezierShape bShape; if(shape->CanMakeBezier()) shape->MakeBezier(t, bShape); else { PolyShape pShape; shape->MakePolyShape(t, pShape); bShape = pShape; // UGH -- Convert it from a PolyShape -- not good! } //DebugPrint(_T("Extrude organizing shape\n")); ShapeHierarchy hier; bShape.OrganizeCurves(t, &hier); // Need to flip the reversed polys... bShape.Reverse(hier.reverse); // ...and tell the hierarchy they're no longer reversed! hier.reverse.ClearAll(); // Our shapes are now organized for patch-making -- Let's do the sides! int polys = bShape.splineCount; int poly, knot; int levelVerts = 0, levelVecs = 0, levelPatches = 0, nverts = 0, nvecs = 0, npatches = 0; int TVlevels = levels + 1, levelTVerts = 0, ntverts = 0, ntpatches = 0; BOOL anyClosed = FALSE; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; if(spline->Closed()) anyClosed = TRUE; levelVerts += spline->KnotCount(); levelTVerts += (spline->Segments() + 1); levelVecs += (spline->Segments() * 2); levelPatches += spline->Segments(); } nverts = levelVerts * (levels + 1); npatches = levelPatches * levels; nvecs = (levelVecs * (levels + 1)) + levels * levelVerts * 2 + npatches * 4; if(texturing) { ntverts = levelTVerts * TVlevels; ntpatches = npatches; } pmesh.setNumVerts(nverts); pmesh.setNumVecs(nvecs); pmesh.setNumPatches(npatches); pmesh.setNumTVerts(ntverts); pmesh.setNumTVPatches(ntpatches); // Create the vertices! int vert = 0; int level; Point3 offset1, offset2; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int knots = spline->KnotCount(); for(level = 0; level <= levels; ++level) { Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize); if(level == 0) offset1 = offset; else if(level == levels) offset2 = offset; for(knot = 0; knot < knots; ++knot) { Point3 p = spline->GetKnotPoint(knot); pmesh.setVert(vert++, p + offset); } } } assert(vert == nverts); BOOL usePhysUVs = GetUsePhysicalScaleUVs(); // Maybe create the texture vertices if(texturing) { int tvert = 0; int level; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; // Make it a polyline PolyLine pline; spline->MakePolyLine(pline, 10); int knots = spline->KnotCount(); for(level = 0; level < TVlevels; ++level) { float tV = (float)level / (float)(TVlevels - 1); float vScale = usePhysUVs ? amount : 1.0f; int lverts = pline.numPts; int tp = 0; int texPts = spline->Segments() + 1; float cumLen = 0.0f; float totLen = pline.CurveLength(); float uScale = usePhysUVs ? totLen : 1.0f; Point3 prevPt = pline.pts[0].p; int plix = 0; while(tp < texPts) { Point3 &pt = pline[plix].p; cumLen += Length(pt - prevPt); prevPt = pt; if(pline[plix].flags & POLYPT_KNOT) { float tU; if(tp == (texPts - 1)) tU = 1.0f; else tU = cumLen / totLen; pmesh.setTVert(tvert++, UVVert(uScale*tU, vScale*tV, 0.0f)); tp++; } plix = (plix + 1) % pline.numPts; } } } assert(tvert == ntverts); } // Create the vectors! int seg; int vec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int segs = spline->Segments(); int knots = spline->KnotCount(); // First, the vectors on each level for(level = 0; level <= levels; ++level) { Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize); for(seg = 0; seg < segs; ++seg) { int seg2 = (seg + 1) % knots; if(spline->GetLineType(seg) == LTYPE_CURVE) { Point3 p = spline->GetOutVec(seg); pmesh.setVec(vec++, p + offset); p = spline->GetInVec(seg2); pmesh.setVec(vec++, p + offset); } else { Point3 p = spline->InterpBezier3D(seg, 0.333333f); pmesh.setVec(vec++, p + offset); p = spline->InterpBezier3D(seg, 0.666666f); pmesh.setVec(vec++, p + offset); } } } // Now, the vectors between the levels int baseVec = vec; for(level = 0; level < levels; ++level) { Point3 offsetA = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize); Point3 offsetB = Point3(0.0f, 0.0f, baseZ + (float)(level + 1) / (float)levels * zSize); Point3 offset1 = offsetA + (offsetB - offsetA) * 0.333333333f; Point3 offset2 = offsetA + (offsetB - offsetA) * 0.666666666f; for(knot = 0; knot < knots; ++knot) { Point3 p = spline->GetKnotPoint(knot); pmesh.setVec(vec++, p + offset1); pmesh.setVec(vec++, p + offset2); } } } // Create the patches! int np = 0; int baseVert = 0; int baseVec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int knots = spline->KnotCount(); int segs = spline->Segments(); int baseVec1 = baseVec; // Base vector index for this level int baseVec2 = baseVec + segs * 2 * (levels + 1); // Base vector index for between levels for(level = 0; level < levels; ++level) { int sm = 0; BOOL firstSmooth = (spline->GetLineType(0) == LTYPE_CURVE && spline->GetLineType(segs-1) == LTYPE_CURVE && (spline->GetKnotType(0) == KTYPE_AUTO || spline->GetKnotType(0) == KTYPE_BEZIER)) ? TRUE : FALSE; for(seg = 0; seg < segs; ++seg, vec += 4) { int prevseg = (seg + segs - 1) % segs; int seg2 = (seg + 1) % knots; int a,b,c,d,ab,ba,bc,cb,cd,dc,da,ad; MtlID mtl = useShapeIDs ? spline->GetMatID(seg) : 2; a = baseVert + seg; b = baseVert + seg2; c = b + knots; d = a + knots; ab = baseVec1 + seg * 2; ba = ab + 1; bc = baseVec2 + seg2 * 2; cb = bc + 1; cd = ba + (segs * 2); dc = ab + (segs * 2); da = baseVec2 + seg * 2 + 1; ad = da - 1; //DebugPrint(_T("Making patch %d: %d (%d %d) %d (%d %d) %d (%d %d) %d (%d %d)\n"),np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad); // If the vertex is not smooth, go to the next group! if(seg > 0 && !(spline->GetLineType(prevseg) == LTYPE_CURVE && spline->GetLineType(seg) == LTYPE_CURVE && (spline->GetKnotType(seg) == KTYPE_AUTO || spline->GetKnotType(seg) == KTYPE_BEZIER))) { sm++; if(sm > 2) sm = 1; } DWORD smoothGroup = 1 << sm; if(seg == segs - 1 && firstSmooth) { smoothGroup |= 1; } pmesh.MakeQuadPatch(np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad, vec, vec+1, vec+2, vec+3, smooth ? smoothGroup : 0); pmesh.setPatchMtlIndex(np++, genMatIDs ? mtl : 0); } baseVert += knots; baseVec1 += (segs * 2); baseVec2 += (knots * 2); } baseVert += knots; baseVec += (segs * 2 * (levels + 1) + knots * 2 * levels); } assert(vec == nvecs); assert(np == npatches); // Maybe create the texture patches! if(texturing) { int ntp = 0; int baseTVert = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; int pknots = spline->Segments() + 1; int pverts = pknots * TVlevels; int segs = spline->Segments(); for(level = 0; level < levels; ++level) { for(seg = 0; seg < segs; ++seg) { int prevseg = (seg + segs - 1) % segs; int seg2 = seg + 1; int a,b,c,d; a = baseTVert + seg; b = baseTVert + seg2; c = b + pknots; d = a + pknots; TVPatch &tp = pmesh.getTVPatch(ntp++); tp.setTVerts(a, b, c, d); } baseTVert += pknots; } baseTVert += pknots; } assert(ntp == ntpatches); } // If capping, do it! if(anyClosed && (capStart || capEnd)) { PatchCapInfo capInfo; bShape.MakeCap(t, capInfo); // Build information for capping PatchCapper capper(bShape); if(capStart) { vert = 0; int baseVec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; PatchCapPoly &capline = capper[poly]; int lverts = spline->KnotCount(); for(int v = 0; v < lverts; ++v) capline.SetVert(v, vert++); // Gives this vert's location in the mesh! vert += lverts * levels; vec = baseVec; int lvecs = spline->Segments() * 2; for(int v = 0; v < lvecs; ++v) capline.SetVec(v, vec++); // Gives this vec's location in the mesh! baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2; } // Create a work matrix for capping Matrix3 mat = TransMatrix(offset1); int oldPatches = pmesh.numPatches; capper.CapPatchMesh(pmesh, capInfo, TRUE, 16, &mat, genMatIDs ? -1 : 0); // If texturing, create the texture patches and vertices if(texturing) MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs); } if(capEnd) { int baseVert = 0; int baseVec = 0; for(poly = 0; poly < polys; ++poly) { Spline3D *spline = bShape.splines[poly]; if(!spline->KnotCount()) continue; PatchCapPoly &capline = capper[poly]; int lverts = spline->KnotCount(); int vert = baseVert + lverts * levels; for(int v = 0; v < lverts; ++v) capline.SetVert(v, vert++); // Gives this vert's location in the mesh! baseVert += lverts * (levels + 1); int lvecs = spline->Segments()*2; int vec = baseVec + lvecs * levels; for(int v = 0; v < lvecs; ++v) capline.SetVec(v, vec++); // Gives this vec's location in the mesh! baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2; } // Create a work matrix for grid capping Matrix3 mat = TransMatrix(offset2); int oldPatches = pmesh.numPatches; capper.CapPatchMesh(pmesh, capInfo, FALSE, 16, &mat, genMatIDs ? -1 : 0); // If texturing, create the texture patches and vertices if(texturing) MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs); } } //watje new mapping if(texturing) { if (ver < 4) { for (int i = 0; i < pmesh.numPatches; i++) pmesh.patches[i].flags |= PATCH_LINEARMAPPING; } } // Ready the patch representation! if( !pmesh.buildLinkages() ) { assert(0); } pmesh.computeInteriors(); }
void PasteSkinWeights::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *node) { //TODO: Add the code for actually modifying the object Mesh *mesh = NULL; MNMesh *mnmesh = NULL; PatchMesh *pmesh = NULL; TriObject *collapsedtobj = NULL; if (os->obj->IsSubClassOf(triObjectClassID)) { TriObject *tobj = (TriObject*)os->obj; mesh = &tobj->GetMesh(); } else if (os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject *pobj = (PolyObject*)os->obj; mnmesh = &pobj->GetMesh(); } else if (os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *pobj = (PatchObject*)os->obj; pmesh = &pobj->patch; } if (mnmesh) { int numMaps = mnmesh->numm; mnmesh->SetMapNum(numMaps+1); int numGFaces = mnmesh->numf; int numGVerts = mnmesh->numv; numMaps = boneList.Count()/3+1; mnmesh->SetMapNum(numMaps); for (int i = 0; i < boneList.Count(); i++) { int mapID = i/3; int subID = i%3; if (subID==0) //create our face data { mnmesh->InitMap(mapID); mnmesh->M(mapID)->setNumVerts(numGVerts); // mnmesh->setNumMapVerts(mapID,numGVerts); } // TVFace *tvFace = mnmesh->mapFaces(mapID); MNMapFace *uvwFace = mnmesh->M(mapID)->f; UVVert *tvVerts = mnmesh->M(mapID)->v;//mnmesh->mapVerts(mapID); if (subID==0) //create our face data { //copy our original //copy our geo faces to the texture faces for (int j = 0; j < numGFaces; j++) { int deg = mnmesh->f[j].deg; uvwFace[j].MakePoly(deg,mnmesh->f[j].vtx); } for (int j = 0; j < numGVerts; j++) { tvVerts[j] = Point3(0.0f,0.0f,0.0f); } } for (int j = 0; j < boneList[i]->weights.Count(); j++) { int vertIndex = boneList[i]->weights[j].vertIndex; float vertWeight = boneList[i]->weights[j].vertWeight; tvVerts[vertIndex][subID] = vertWeight; } } } else if (mesh) { int numMaps = mesh->getNumMaps(); int numGFaces = mesh->numFaces; int numGVerts = mesh->numVerts; numMaps = boneList.Count()/3+1; mesh->setNumMaps(numMaps, FALSE); for (int i = 0; i < boneList.Count(); i++) { int mapID = i/3; int subID = i%3; if (subID==0) //create our face data { mesh->setMapSupport(mapID); mesh->setNumMapVerts(mapID,numGVerts); } TVFace *tvFace = mesh->mapFaces(mapID); UVVert *tvVerts = mesh->mapVerts(mapID); if (subID==0) //create our face data { //copy our original //copy our geo faces to the texture faces for (int j = 0; j < numGFaces; j++) { for (int k = 0; k < 3; k++) { tvFace[j].t[k] = mesh->faces[j].v[k]; } } for (int j = 0; j < numGVerts; j++) { tvVerts[j] = Point3(0.0f,0.0f,0.0f); } } for (int j = 0; j < boneList[i]->weights.Count(); j++) { int vertIndex = boneList[i]->weights[j].vertIndex; float vertWeight = boneList[i]->weights[j].vertWeight; tvVerts[vertIndex][subID] = vertWeight; } } } else if (pmesh) { int numMaps = pmesh->getNumMaps(); int numGFaces = pmesh->numPatches; int numGVerts = pmesh->numVerts+pmesh->numVecs; numMaps = boneList.Count()/3+1; pmesh->setNumMaps(numMaps, FALSE); for (int i = 0; i < boneList.Count(); i++) { int mapID = i/3; int subID = i%3; if (subID==0) //create our face data { pmesh->setMapSupport(mapID); pmesh->setNumMapVerts(mapID,numGVerts); } TVPatch *tvFace = pmesh->tvPatches[mapID];;//TVFace *tvFace = pmesh->mapFaces(mapID); PatchTVert *tvVerts = pmesh->mapVerts(mapID); if (subID==0) //create our face data { //copy our original //copy our geo faces to the texture faces for (int j = 0; j < numGFaces; j++) { int deg = 3; if (pmesh->patches[j].type == PATCH_QUAD) deg = 4; for (int k = 0; k < deg; k++) { int vindex = pmesh->patches[j].v[k]; tvFace[j].tv[k] = pmesh->patches[j].v[k]; tvFace[j].interiors[k] = pmesh->patches[j].interior[k]+pmesh->numVerts; tvFace[j].handles[k*2] = pmesh->patches[j].vec[k*2]+pmesh->numVerts; tvFace[j].handles[k*2+1] = pmesh->patches[j].vec[k*2+1]+pmesh->numVerts; } } for (int j = 0; j < numGVerts; j++) { tvVerts[j] = Point3(0.0f,0.0f,0.0f); } } for (int j = 0; j < boneList[i]->weights.Count(); j++) { int vertIndex = boneList[i]->weights[j].vertIndex; float vertWeight = boneList[i]->weights[j].vertWeight; //DebugPrint(_T("bone %d vert %d weight %f\n"),i,vertIndex,vertWeight); tvVerts[vertIndex].p[subID] = vertWeight; } } } Interval iv; iv = FOREVER; os->obj->PointsWereChanged(); iv &= os->obj->ChannelValidity (t, VERT_COLOR_CHAN_NUM); iv &= os->obj->ChannelValidity (t, TEXMAP_CHAN_NUM); iv = iv & os->obj->ChannelValidity(t,GEOM_CHAN_NUM); iv = iv & os->obj->ChannelValidity(t,TOPO_CHAN_NUM); os->obj->UpdateValidity(GEOM_CHAN_NUM,iv); os->obj->UpdateValidity (VERT_COLOR_CHAN_NUM, iv); os->obj->UpdateValidity(TEXMAP_CHAN_NUM,iv); }
void TriPatchObject::GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm, BOOL useSel ) { UpdatePatchMesh(t); patch.GetDeformBBox(box, tm, useSel); }
ObjectHandle TriPatchObject::CreateTriObjRep(TimeValue t) { TriObject *tri = CreateNewTriObject(); PrepareMesh(t); // Turn it into a mesh tri->GetMesh() = patch.GetMesh(); // Place it into the TriObject return(ObjectHandle(tri)); }
// From GeomObject int TriPatchObject::IntersectRay(TimeValue t, Ray& r, float& at, Point3& norm) { PrepareMesh(t); // Turn it into a mesh return patch.IntersectRay(r, at, norm); }
void TriPatchObject::PrepareMesh(TimeValue t) { UpdatePatchMesh(t); patch.PrepareMesh(); }
int EditPatchMod::DoAttach(INode *node, PatchMesh *attPatch, RPatchMesh *rattPatch, bool & canUndo) { ModContextList mcList; INodeTab nodes; if (!ip) return 0; ip->GetModContexts(mcList, nodes); if (mcList.Count() != 1) { nodes.DisposeTemporary(); return 0; } EditPatchData *patchData =(EditPatchData*)mcList[0]->localData; if (!patchData) { nodes.DisposeTemporary(); return 0; } patchData->BeginEdit(ip->GetTime()); // If the mesh isn't yet cached, this will cause it to get cached. RPatchMesh *rpatch; PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch); if (!patch) { nodes.DisposeTemporary(); return 0; } patchData->RecordTopologyTags(patch); RecordTopologyTags(); // Transform the shape for attachment: // If reorienting, just translate to align pivots // Otherwise, transform to match our transform Matrix3 attMat(1); if (attachReorient) { Matrix3 thisTM = nodes[0]->GetNodeTM(ip->GetTime()); Matrix3 thisOTMBWSM = nodes[0]->GetObjTMBeforeWSM(ip->GetTime()); Matrix3 thisPivTM = thisTM * Inverse(thisOTMBWSM); Matrix3 otherTM = node->GetNodeTM(ip->GetTime()); Matrix3 otherOTMBWSM = node->GetObjTMBeforeWSM(ip->GetTime()); Matrix3 otherPivTM = otherTM * Inverse(otherOTMBWSM); Point3 otherObjOffset = node->GetObjOffsetPos(); attMat = Inverse(otherPivTM) * thisPivTM; } else { attMat = node->GetObjectTM(ip->GetTime()) * Inverse(nodes[0]->GetObjectTM(ip->GetTime())); } // RB 3-17-96 : Check for mirroring AffineParts parts; decomp_affine(attMat, &parts); if (parts.f < 0.0f) { int v[8], ct, ct2, j; Point3 p[9]; for (int i = 0; i < attPatch->numPatches; i++) { // Re-order rpatch if (attPatch->patches[i].type == PATCH_QUAD) { UI_PATCH rpatch=rattPatch->getUIPatch (i); int ctU=rpatch.NbTilesU<<1; int ctV=rpatch.NbTilesV<<1; int nU; for (nU=0; nU<ctU; nU++) { for (int nV=0; nV<ctV; nV++) { rattPatch->getUIPatch (i).getTileDesc (nU+nV*ctU)=rpatch.getTileDesc (ctU-1-nU+(ctV-1-nV)*ctU); } } for (nU=0; nU<ctU+1; nU++) { for (int nV=0; nV<ctV+1; nV++) { rattPatch->getUIPatch (i).setColor (nU+nV*(ctU+1), rpatch.getColor (ctU-nU+(ctV-nV)*ctU)); } } } // Re-order vertices ct = attPatch->patches[i].type == PATCH_QUAD ? 4 : 3; for (j = 0; j < ct; j++) { v[j] = attPatch->patches[i].v[j]; } for (j = 0; j < ct; j++) { attPatch->patches[i].v[j] = v[ct - j - 1]; } // Re-order vecs ct = attPatch->patches[i].type == PATCH_QUAD ? 8 : 6; ct2 = attPatch->patches[i].type == PATCH_QUAD ? 5 : 3; for (j = 0; j < ct; j++) { v[j] = attPatch->patches[i].vec[j]; } for (j = 0; j < ct; j++, ct2--) { if (ct2 < 0) ct2 = ct - 1; attPatch->patches[i].vec[j] = v[ct2]; } // Re-order enteriors if (attPatch->patches[i].type == PATCH_QUAD) { ct = 4; for (j = 0; j < ct; j++) { v[j] = attPatch->patches[i].interior[j]; } for (j = 0; j < ct; j++) { attPatch->patches[i].interior[j] = v[ct - j - 1]; } } // Re-order aux if (attPatch->patches[i].type == PATCH_TRI) { ct = 9; for (j = 0; j < ct; j++) { p[j] = attPatch->patches[i].aux[j]; } for (j = 0; j < ct; j++) { attPatch->patches[i].aux[j] = p[ct - j - 1]; } } // Re-order TV faces if present for (int chan = 0; chan < patch->getNumMaps(); ++chan) { if (attPatch->tvPatches[chan]) { ct = 4; for (j = 0; j < ct; j++) { v[j] = attPatch->tvPatches[chan][i].tv[j]; } for (j = 0; j < ct; j++) { attPatch->tvPatches[chan][i].tv[j] = v[ct - j - 1]; } } } } } int i; for (i = 0; i < attPatch->numVerts; ++i) attPatch->verts[i].p = attPatch->verts[i].p * attMat; for (i = 0; i < attPatch->numVecs; ++i) attPatch->vecs[i].p = attPatch->vecs[i].p * attMat; attPatch->computeInteriors(); theHold.Begin(); // Combine the materials of the two nodes. int mat2Offset = 0; Mtl *m1 = nodes[0]->GetMtl(); Mtl *m2 = node->GetMtl(); bool condenseMe = FALSE; if (m1 && m2 &&(m1 != m2)) { if (attachMat == ATTACHMAT_IDTOMAT) { int ct = 1; if (m1->IsMultiMtl()) ct = m1->NumSubMtls(); for (int i = 0; i < patch->numPatches; ++i) { int mtid = patch->getPatchMtlIndex(i); if (mtid >= ct) patch->setPatchMtlIndex(i, mtid % ct); } FitPatchIDsToMaterial(*attPatch, m2); if (condenseMat) condenseMe = TRUE; } // the theHold calls here were a vain attempt to make this all undoable. // This should be revisited in the future so we don't have to use the SYSSET_CLEAR_UNDO. theHold.Suspend(); if (attachMat == ATTACHMAT_MATTOID) { m1 = FitMaterialToPatchIDs(*patch, m1); m2 = FitMaterialToPatchIDs(*attPatch, m2); } Mtl *multi = CombineMaterials(m1, m2, mat2Offset); if (attachMat == ATTACHMAT_NEITHER) mat2Offset = 0; theHold.Resume(); // We can't be in face subobject mode, else we screw up the materials: DWORD oldSL = patch->selLevel; DWORD roldSL = patch->selLevel; patch->selLevel = PATCH_OBJECT; rpatch->SetSelLevel (EP_OBJECT); nodes[0]->SetMtl(multi); patch->selLevel = oldSL; rpatch->SetSelLevel (roldSL); m1 = multi; canUndo = FALSE; // Absolutely cannot undo material combinations. } if (!m1 && m2) { // We can't be in face subobject mode, else we screw up the materials: DWORD oldSL = patch->selLevel; DWORD roldSL = rpatch->GetSelLevel(); patch->selLevel = PATCH_OBJECT; rpatch->SetSelLevel (EP_OBJECT); nodes[0]->SetMtl(m2); patch->selLevel = oldSL; rpatch->SetSelLevel (roldSL); m1 = m2; } // Start a restore object... if (theHold.Holding()) theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoAttach")); // Do the attach patch->Attach(attPatch, mat2Offset); rpatch->Attach(rattPatch, *patch); patchData->UpdateChanges(patch, rpatch); patchData->TempData(this)->Invalidate(PART_TOPO | PART_GEOM); // Get rid of the original node ip->DeleteNode(node); ResolveTopoChanges(); theHold.Accept(GetString(IDS_TH_ATTACH)); if (m1 && condenseMe) { // Following clears undo stack. patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch); m1 = CondenseMatAssignments(*patch, m1); } nodes.DisposeTemporary(); ClearPatchDataFlag(mcList, EPD_BEENDONE); NotifyDependents(FOREVER, PART_TOPO | PART_GEOM, REFMSG_CHANGE); ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL); return 1; }
void BuildTorusPatch( TimeValue t, PatchMesh &patch, float radius1, float radius2, int genUVs, BOOL usePhysUVs) { int segs = 8, sides = 4; int nverts = segs * sides; int nvecs = segs*sides*8; int npatches = segs * sides; patch.setNumVerts(nverts); patch.setNumTVerts(genUVs ? (segs + 1) * (sides + 1) : 0); patch.setNumVecs(nvecs); patch.setNumPatches(npatches); patch.setNumTVPatches(genUVs ? npatches : 0); int ix=0, jx=0, kx=sides*segs*4, i, j; float ang1 = 0.0f, delta1 = TWOPI/float(segs); float ang2 = 0.0f, delta2 = TWOPI/float(sides); float circleLenIn = CIRCLE_FACT8*(radius1-radius2); float circleLenOut = CIRCLE_FACT8*(radius1+radius2); float circleLenMid = CIRCLE_FACT4*radius2; float circleLen; float sinang1, cosang1, sinang2, cosang2, rt, u; Point3 p, v; DWORD a, b, c, d; for (i=0; i<segs; i++) { sinang1 = (float)sin(ang1); cosang1 = (float)cos(ang1); ang2 = 0.0f; for (j=0; j<sides; j++) { sinang2 = (float)sin(ang2); cosang2 = (float)cos(ang2); rt = radius1+radius2*cosang2; // Vertex p.x = rt*cosang1; p.y = rt*sinang1; p.z = radius2*sinang2; patch.setVert(ix, p); // Tangents u = (cosang2+1.0f)/2.0f; circleLen = u*circleLenOut + (1.0f-u)*circleLenIn; v.x = -sinang1*circleLen; v.y = cosang1*circleLen; v.z = 0.0f; patch.setVec(jx++,patch.verts[ix] + v); v.x = sinang1*circleLen; v.y = -cosang1*circleLen; v.z = 0.0f; patch.setVec(jx++,patch.verts[ix] + v); v.x = -sinang2*cosang1*circleLenMid; v.y = -sinang2*sinang1*circleLenMid; v.z = cosang2*circleLenMid; patch.setVec(jx++,patch.verts[ix] + v); v.x = sinang2*cosang1*circleLenMid; v.y = sinang2*sinang1*circleLenMid; v.z = -cosang2*circleLenMid; patch.setVec(jx++,patch.verts[ix] + v); // Build the patch a = ((i+1)%segs)*sides + (j+1)%sides; b = i*sides + (j+1)%sides; c = i*sides + j; d = ((i+1)%segs)*sides + j; patch.patches[ix].SetType(PATCH_QUAD); patch.patches[ix].setVerts(a, b, c, d); patch.patches[ix].setVecs( Tang(a,1),Tang(b,0),Tang(b,3),Tang(c,2), Tang(c,0),Tang(d,1),Tang(d,2),Tang(a,3)); patch.patches[ix].setInteriors(kx, kx+1, kx+2, kx+3); patch.patches[ix].smGroup = 1; kx += 4; ix++; ang2 += delta2; } ang1 += delta1; } if(genUVs) { int tv = 0; int tvp = 0; float fsegs = (float)segs; float fsides = (float)sides; float uScale = usePhysUVs ? ((float) 2.0f * PI * radius1) : 1.0f; float vScale = usePhysUVs ? ((float) 2.0f * PI * radius2) : 1.0f; for (i=0; i<=segs; i++) { float u = (float)i / (fsegs-1); for (j=0; j<=sides; j++,++tv) { float v = (float)j / (fsides-1); if (usePhysUVs) patch.setTVert(tv, UVVert(vScale*v, uScale*u, 0.0f)); else patch.setTVert(tv, UVVert(uScale*(1.0f-u), vScale*v, 0.0f)); if(j < sides && i < segs) patch.getTVPatch(tvp++).setTVerts(tv, tv+1, tv+sides+2, tv+sides+1); } } } if( !patch.buildLinkages() ) { assert(0); } patch.computeInteriors(); patch.InvalidateGeomCache(); }
void TriPatchObject::BuildPatch(TimeValue t,PatchMesh& amesh) { int nverts = 4; int nvecs = 16; float l, w; int tex; // Start the validity interval at forever and whittle it down. ivalid = FOREVER; pblock->GetValue( PB_LENGTH, t, l, ivalid ); pblock->GetValue( PB_WIDTH, t, w, ivalid ); pblock->GetValue( PB_TEXTURE, t, tex, ivalid ); amesh.setNumVerts(nverts); amesh.setNumTVerts(tex ? nverts : 0); amesh.setNumVecs(nvecs); amesh.setNumPatches(2); amesh.setNumTVPatches(tex ? 2 : 0); Point3 v0 = Point3(-w, -l, 0.0f) / 2.0f; Point3 v1 = v0 + Point3(w, 0.0f, 0.0f); Point3 v2 = v0 + Point3(w, l, 0.0f); Point3 v3 = v0 + Point3(0.0f, l, 0.0f); // Create the vertices. amesh.verts[0].flags = PVERT_COPLANAR; amesh.verts[1].flags = PVERT_COPLANAR; amesh.verts[2].flags = PVERT_COPLANAR; amesh.verts[3].flags = PVERT_COPLANAR; if(tex) { amesh.setTVert(0, UVVert(0,0,0)); amesh.setTVert(1, UVVert(1,0,0)); amesh.setTVert(2, UVVert(1,1,0)); amesh.setTVert(3, UVVert(0,1,0)); } amesh.setVert(0, v0); amesh.setVert(1, v1); amesh.setVert(2, v2); amesh.setVert(3, v3); // Create the vectors MAKEVEC(0, v0, v1); MAKEVEC(2, v1, v2); MAKEVEC(4, v2, v3); MAKEVEC(6, v3, v0); MAKEVEC(8, v3, v1); // Create patches. amesh.MakeTriPatch(0, 0, 0, 1, 1, 9, 8, 3, 6, 7, 10, 11, 12, 1); amesh.MakeTriPatch(1, 1, 2, 3, 2, 4, 5, 3, 8, 9, 13, 14, 15, 1); Patch &p1 = amesh.patches[0]; Patch &p2 = amesh.patches[1]; if(tex) { amesh.getTVPatch(0).setTVerts(0,1,3); amesh.getTVPatch(1).setTVerts(1,2,3); } // Finish up patch internal linkages (and bail out if it fails!) assert(amesh.buildLinkages()); // Calculate the interior bezier points on the PatchMesh's patches amesh.computeInteriors(); amesh.InvalidateGeomCache(); // Tell the PatchMesh it just got changed amesh.InvalidateMesh(); }
void EditPatchMod::ActivateSubobjSel(int level, XFormModes& modes) { ModContextList mcList; INodeTab nodes; int old = selLevel; if (!ip) return; ip->GetModContexts(mcList, nodes); selLevel = level; // 3-10-99 watje if (level != EP_PATCH) { if (ip->GetCommandMode() == bevelMode) ip->SetStdCommandMode(CID_OBJMOVE); if (ip->GetCommandMode() == extrudeMode) ip->SetStdCommandMode(CID_OBJMOVE); if (inBevel) { ISpinnerControl *spin; spin = GetISpinner(GetDlgItem(hOpsPanel, IDC_EP_OUTLINESPINNER)); if (spin) { HWND hWnd = spin->GetHwnd(); SendMessage(hWnd, WM_LBUTTONUP, 0, 0); ReleaseISpinner(spin); } } if (inExtrude) { ISpinnerControl *spin; spin = GetISpinner(GetDlgItem(hOpsPanel, IDC_EP_EXTRUDESPINNER)); if (spin) { HWND hWnd = spin->GetHwnd(); SendMessage(hWnd, WM_LBUTTONUP, 0, 0); ReleaseISpinner(spin); } } } if (level != EP_VERTEX) { if (ip->GetCommandMode() == bindMode) ip->SetStdCommandMode(CID_OBJMOVE); } switch (level) { case EP_OBJECT: // Not imp. break; case EP_PATCH: modes = XFormModes(moveMode, rotMode, nuscaleMode, uscaleMode, squashMode, selectMode); break; case EP_EDGE: modes = XFormModes(moveMode, rotMode, nuscaleMode, uscaleMode, squashMode, selectMode); break; case EP_VERTEX: modes = XFormModes(moveMode, rotMode, nuscaleMode, uscaleMode, squashMode, selectMode); break; case EP_TILE: modes = XFormModes(NULL, NULL, NULL, NULL, NULL, selectMode); break; } if (selLevel != old) { SetSubobjectLevel(level); // Modify the caches to reflect the new sel level. for (int i = 0; i < mcList.Count(); i++) { EditPatchData *patchData =(EditPatchData*)mcList[i]->localData; if (!patchData) continue; if (patchData->tempData && patchData->TempData(this)->PatchCached(ip->GetTime())) { RPatchMesh *rpatch; PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch); if (patch) { if (selLevel == EP_VERTEX) patch->dispFlags = DISP_VERTS; else patch->dispFlags = 0; if (displayLattice) patch->SetDispFlag(DISP_LATTICE); patch->SetDispFlag(patchLevelDispFlags[selLevel]); patch->selLevel = patchLevel[selLevel]; rpatch->SetSelLevel (selLevel); } } } NotifyDependents(FOREVER, PART_SUBSEL_TYPE | PART_DISPLAY, REFMSG_CHANGE); ip->PipeSelLevelChanged(); // Update selection UI display, named sel SelectionChanged(); } nodes.DisposeTemporary(); }
void MeshTopoData::SetCache(PatchMesh &patch, int mapChannel) { FreeCache(); this->patch = new PatchMesh(patch); //build TVMAP and edge data mFSelPrevious.SetSize(patch.patchSel.GetSize()); mFSelPrevious = patch.patchSel; if ( (patch.selLevel==PATCH_PATCH) && (patch.patchSel.NumberSet() == 0) ) { TVMaps.SetCountFaces(0); TVMaps.v.SetCount(0); TVMaps.FreeEdges(); TVMaps.FreeGeomEdges(); mVSel.SetSize(0); mESel.SetSize(0); mFSel.SetSize(0); mGESel.SetSize(0); mGVSel.SetSize(0); return; } //loop through all maps //get channel from mesh TVMaps.channel = mapChannel; //get from mesh based on cahne PatchTVert *tVerts = NULL; TVPatch *tvFace = NULL; if (!patch.getMapSupport(mapChannel)) { patch.setNumMaps(mapChannel+1); } tVerts = patch.tVerts[mapChannel]; tvFace = patch.tvPatches[mapChannel]; if (patch.selLevel!=PATCH_PATCH ) { //copy into our structs TVMaps.SetCountFaces(patch.getNumPatches()); TVMaps.v.SetCount(patch.getNumMapVerts(mapChannel)); mVSel.SetSize(patch.getNumMapVerts (mapChannel)); TVMaps.geomPoints.SetCount(patch.getNumVerts()+patch.getNumVecs()); for (int j=0; j<TVMaps.f.Count(); j++) { TVMaps.f[j]->flags = 0; int pcount = 3; if (patch.patches[j].type == PATCH_QUAD) { pcount = 4; } TVMaps.f[j]->t = new int[pcount]; TVMaps.f[j]->v = new int[pcount]; if (tvFace == NULL) { TVMaps.f[j]->t[0] = 0; TVMaps.f[j]->t[1] = 0; TVMaps.f[j]->t[2] = 0; if (pcount ==4) TVMaps.f[j]->t[3] = 0; TVMaps.f[j]->FaceIndex = j; TVMaps.f[j]->MatID = patch.getPatchMtlIndex(j); TVMaps.f[j]->flags = 0; TVMaps.f[j]->count = pcount; TVMaps.f[j]->vecs = NULL; UVW_TVVectorClass *tempv = NULL; //new an instance if (!(patch.patches[j].flags & PATCH_AUTO)) TVMaps.f[j]->flags |= FLAG_INTERIOR; if (!(patch.patches[j].flags & PATCH_LINEARMAPPING)) { tempv = new UVW_TVVectorClass(); TVMaps.f[j]->flags |= FLAG_CURVEDMAPPING; } TVMaps.f[j]->vecs = tempv; for (int k = 0; k < pcount; k++) { int index = patch.patches[j].v[k]; TVMaps.f[j]->v[k] = index; TVMaps.geomPoints[index] = patch.verts[index].p; //do handles and interiors //check if linear if (!(patch.patches[j].flags & PATCH_LINEARMAPPING)) { //do geometric points index = patch.patches[j].interior[k]; TVMaps.f[j]->vecs->vinteriors[k] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2]; TVMaps.f[j]->vecs->vhandles[k*2] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2+1]; TVMaps.f[j]->vecs->vhandles[k*2+1] =patch.getNumVerts()+index; // do texture points do't need to since they don't exist in this case TVMaps.f[j]->vecs->interiors[k] =0; TVMaps.f[j]->vecs->handles[k*2] =0; TVMaps.f[j]->vecs->handles[k*2+1] =0; } } } else { TVMaps.f[j]->t[0] = tvFace[j].tv[0]; TVMaps.f[j]->t[1] = tvFace[j].tv[1]; TVMaps.f[j]->t[2] = tvFace[j].tv[2]; if (pcount ==4) TVMaps.f[j]->t[3] = tvFace[j].tv[3]; TVMaps.f[j]->FaceIndex = j; TVMaps.f[j]->MatID = patch.getPatchMtlIndex(j); TVMaps.f[j]->flags = 0; TVMaps.f[j]->count = pcount; TVMaps.f[j]->vecs = NULL; UVW_TVVectorClass *tempv = NULL; if (!(patch.patches[j].flags & PATCH_AUTO)) TVMaps.f[j]->flags |= FLAG_INTERIOR; //new an instance if (!(patch.patches[j].flags & PATCH_LINEARMAPPING)) { BOOL mapLinear = FALSE; for (int tvCount = 0; tvCount < patch.patches[j].type*2; tvCount++) { if (tvFace[j].handles[tvCount] < 0) mapLinear = TRUE; } if (!(patch.patches[j].flags & PATCH_AUTO)) { for (int tvCount = 0; tvCount < patch.patches[j].type; tvCount++) { if (tvFace[j].interiors[tvCount] < 0) mapLinear = TRUE; } } if (!mapLinear) { tempv = new UVW_TVVectorClass(); TVMaps.f[j]->flags |= FLAG_CURVEDMAPPING; } } TVMaps.f[j]->vecs = tempv; if ((patch.selLevel==PATCH_PATCH ) && (patch.patchSel[j] == 0)) TVMaps.f[j]->flags |= FLAG_DEAD; for (int k = 0; k < pcount; k++) { int index = patch.patches[j].v[k]; TVMaps.f[j]->v[k] = index; TVMaps.geomPoints[index] = patch.verts[index].p; // TVMaps.f[j].pt[k] = patch.verts[index].p; //do handles and interiors //check if linear if (TVMaps.f[j]->flags & FLAG_CURVEDMAPPING) { //do geometric points index = patch.patches[j].interior[k]; TVMaps.f[j]->vecs->vinteriors[k] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2]; TVMaps.f[j]->vecs->vhandles[k*2] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2+1]; TVMaps.f[j]->vecs->vhandles[k*2+1] =patch.getNumVerts()+index; // do texture points do't need to since they don't exist in this case if (TVMaps.f[j]->flags & FLAG_INTERIOR) { index = tvFace[j].interiors[k]; TVMaps.f[j]->vecs->interiors[k] =index; } index = tvFace[j].handles[k*2]; TVMaps.f[j]->vecs->handles[k*2] =index; index = tvFace[j].handles[k*2+1]; TVMaps.f[j]->vecs->handles[k*2+1] =index; } } } } for (int geomvecs =0; geomvecs < patch.getNumVecs(); geomvecs++) { TVMaps.geomPoints[geomvecs+patch.getNumVerts()] = patch.vecs[geomvecs].p; } for ( int j=0; j<TVMaps.v.Count(); j++) { TVMaps.v[j].SetFlag(0); if (tVerts) TVMaps.v[j].SetP(tVerts[j]); else TVMaps.v[j].SetP(Point3(0.0f,0.0f,0.0f)); TVMaps.v[j].SetInfluence(0.0f); TVMaps.v[j].SetControlID(-1); } if (tvFace == NULL) BuildInitialMapping(&patch); TVMaps.mSystemLockedFlag.SetSize(TVMaps.v.Count()); TVMaps.mSystemLockedFlag.ClearAll(); } else { //copy into our structs TVMaps.SetCountFaces(patch.getNumPatches()); TVMaps.v.SetCount(patch.getNumMapVerts (mapChannel)); mVSel.SetSize(patch.getNumMapVerts (mapChannel)); TVMaps.geomPoints.SetCount(patch.getNumVerts()+patch.getNumVecs()); for (int j=0; j<TVMaps.f.Count(); j++) { TVMaps.f[j]->flags = 0; int pcount = 3; if (patch.patches[j].type == PATCH_QUAD) { pcount = 4; } TVMaps.f[j]->t = new int[pcount]; TVMaps.f[j]->v = new int[pcount]; if (tvFace == NULL) { TVMaps.f[j]->t[0] = 0; TVMaps.f[j]->t[1] = 0; TVMaps.f[j]->t[2] = 0; if (pcount == 4) TVMaps.f[j]->t[3] = 0; TVMaps.f[j]->FaceIndex = j; TVMaps.f[j]->MatID = patch.patches[j].getMatID(); if (patch.patchSel[j]) TVMaps.f[j]->flags = 0; else TVMaps.f[j]->flags = FLAG_DEAD; TVMaps.f[j]->count = pcount; TVMaps.f[j]->vecs = NULL; UVW_TVVectorClass *tempv = NULL; if (!(patch.patches[j].flags & PATCH_AUTO)) TVMaps.f[j]->flags |= FLAG_INTERIOR; //new an instance if (!(patch.patches[j].flags & PATCH_LINEARMAPPING)) { tempv = new UVW_TVVectorClass(); TVMaps.f[j]->flags |= FLAG_CURVEDMAPPING; } TVMaps.f[j]->vecs = tempv; for (int k = 0; k < pcount; k++) { int index = patch.patches[j].v[k]; TVMaps.f[j]->v[k] = index; TVMaps.geomPoints[index] = patch.verts[index].p; // TVMaps.f[j].pt[k] = patch.verts[index].p; //check if linear if (!(patch.patches[j].flags & PATCH_LINEARMAPPING)) { //do geometric points index = patch.patches[j].interior[k]; TVMaps.f[j]->vecs->vinteriors[k] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2]; TVMaps.f[j]->vecs->vhandles[k*2] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2+1]; TVMaps.f[j]->vecs->vhandles[k*2+1] =patch.getNumVerts()+index; // do texture points do't need to since they don't exist in this case TVMaps.f[j]->vecs->interiors[k] =0; TVMaps.f[j]->vecs->handles[k*2] =0; TVMaps.f[j]->vecs->handles[k*2+1] =0; } } } else { TVMaps.f[j]->t[0] = tvFace[j].tv[0]; TVMaps.f[j]->t[1] = tvFace[j].tv[1]; TVMaps.f[j]->t[2] = tvFace[j].tv[2]; if (pcount == 4) TVMaps.f[j]->t[3] = tvFace[j].tv[3]; TVMaps.f[j]->FaceIndex = j; TVMaps.f[j]->MatID = patch.patches[j].getMatID(); if (patch.patchSel[j]) TVMaps.f[j]->flags = 0; else TVMaps.f[j]->flags = FLAG_DEAD; int pcount = 3; if (patch.patches[j].type == PATCH_QUAD) { pcount = 4; } TVMaps.f[j]->count = pcount; TVMaps.f[j]->vecs = NULL; UVW_TVVectorClass *tempv = NULL; if (!(patch.patches[j].flags & PATCH_AUTO)) TVMaps.f[j]->flags |= FLAG_INTERIOR; //new an instance if (!(patch.patches[j].flags & PATCH_LINEARMAPPING)) { BOOL mapLinear = FALSE; for (int tvCount = 0; tvCount < patch.patches[j].type*2; tvCount++) { if (tvFace[j].handles[tvCount] < 0) mapLinear = TRUE; } if (!(patch.patches[j].flags & PATCH_AUTO)) { for (int tvCount = 0; tvCount < patch.patches[j].type; tvCount++) { if (tvFace[j].interiors[tvCount] < 0) mapLinear = TRUE; } } if (!mapLinear) { tempv = new UVW_TVVectorClass(); TVMaps.f[j]->flags |= FLAG_CURVEDMAPPING; } } TVMaps.f[j]->vecs = tempv; for (int k = 0; k < pcount; k++) { int index = patch.patches[j].v[k]; TVMaps.f[j]->v[k] = index; TVMaps.geomPoints[index] = patch.verts[index].p; // TVMaps.f[j].pt[k] = patch.verts[index].p; //do handles and interiors //check if linear if (TVMaps.f[j]->flags & FLAG_CURVEDMAPPING) { //do geometric points index = patch.patches[j].interior[k]; TVMaps.f[j]->vecs->vinteriors[k] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2]; TVMaps.f[j]->vecs->vhandles[k*2] =patch.getNumVerts()+index; index = patch.patches[j].vec[k*2+1]; TVMaps.f[j]->vecs->vhandles[k*2+1] =patch.getNumVerts()+index; // do texture points do't need to since they don't exist in this case if (TVMaps.f[j]->flags & FLAG_INTERIOR) { index = tvFace[j].interiors[k]; TVMaps.f[j]->vecs->interiors[k] =index; } index = tvFace[j].handles[k*2]; TVMaps.f[j]->vecs->handles[k*2] =index; index = tvFace[j].handles[k*2+1]; TVMaps.f[j]->vecs->handles[k*2+1] =index; } } } } for (int j =0; j < patch.getNumVecs(); j++) { TVMaps.geomPoints[j+patch.getNumVerts()] = patch.vecs[j].p; } for (int j=0; j<TVMaps.v.Count(); j++) { // TVMaps.v[j].SystemLocked(TRUE); if (tVerts) TVMaps.v[j].SetP(tVerts[j]); else TVMaps.v[j].SetP(Point3(.0f,0.0f,0.0f)); //check if vertex for this face selected TVMaps.v[j].SetInfluence(0.0f); TVMaps.v[j].SetControlID(-1); } if (tvFace == NULL) BuildInitialMapping(&patch); TVMaps.mSystemLockedFlag.SetSize(TVMaps.v.Count()); TVMaps.mSystemLockedFlag.SetAll(); for (int j=0; j<TVMaps.f.Count(); j++) { if (!(TVMaps.f[j]->flags & FLAG_DEAD)) { int a; a = TVMaps.f[j]->t[0]; TVMaps.v[a].SetFlag(0); TVMaps.mSystemLockedFlag.Set(a,FALSE); a = TVMaps.f[j]->t[1]; TVMaps.v[a].SetFlag(0); TVMaps.mSystemLockedFlag.Set(a,FALSE); a = TVMaps.f[j]->t[2]; TVMaps.v[a].SetFlag(0); TVMaps.mSystemLockedFlag.Set(a,FALSE); if (TVMaps.f[j]->count > 3) { a = TVMaps.f[j]->t[3]; TVMaps.v[a].SetFlag(0); TVMaps.mSystemLockedFlag.Set(a,FALSE); } if ( (TVMaps.f[j]->flags & FLAG_CURVEDMAPPING) && (TVMaps.f[j]->vecs)) { for (int m =0; m < TVMaps.f[j]->count; m++) { int hid = TVMaps.f[j]->vecs->handles[m*2]; TVMaps.v[hid].SetFlag(0) ; TVMaps.mSystemLockedFlag.Set(hid,FALSE); hid = TVMaps.f[j]->vecs->handles[m*2+1]; TVMaps.v[hid].SetFlag(0) ; TVMaps.mSystemLockedFlag.Set(hid,FALSE); } if (TVMaps.f[j]->flags & FLAG_INTERIOR) { for (int m =0; m < TVMaps.f[j]->count; m++) { int iid = TVMaps.f[j]->vecs->interiors[m]; TVMaps.v[iid].SetFlag(0); TVMaps.mSystemLockedFlag.Set(iid,FALSE); } } } } } } }
void MeshTopoData::ApplyMapping(PatchMesh &patch, int mapChannel) { //get from mesh if (!patch.getMapSupport(mapChannel) ) { patch.setNumMaps (mapChannel+1); } TVPatch *tvFace = patch.tvPatches[mapChannel]; int tvFaceCount = patch.numPatches; if (patch.selLevel!=PATCH_PATCH) { //copy into mesh struct if (!tvFace) { // Create tvfaces and init to 0 patch.setNumMapPatches(mapChannel,patch.getNumPatches()); tvFace = patch.tvPatches[mapChannel]; for (int k=0; k<patch.getNumPatches(); k++) { for (int j=0; j<TVMaps.f[k]->count; j++) { tvFace[k].tv[j] = 0; tvFace[k].interiors[j] = 0; tvFace[k].handles[j*2] = 0; tvFace[k].handles[j*2+1] = 0; } } } for (int k=0; k<tvFaceCount; k++) { if (k < TVMaps.f.Count()) { tvFace[k].tv[0] = TVMaps.f[k]->t[0]; tvFace[k].tv[1] = TVMaps.f[k]->t[1]; tvFace[k].tv[2] = TVMaps.f[k]->t[2]; if (TVMaps.f[k]->count == 4) tvFace[k].tv[3] = TVMaps.f[k]->t[3]; if (TVMaps.f[k]->flags & FLAG_CURVEDMAPPING) { patch.patches[k].flags &= ~PATCH_LINEARMAPPING; if (TVMaps.f[k]->vecs) { for (int m = 0;m < TVMaps.f[k]->count;m++) { if (TVMaps.f[k]->flags & FLAG_INTERIOR) { tvFace[k].interiors[m] = TVMaps.f[k]->vecs->interiors[m]; } tvFace[k].handles[m*2] = TVMaps.f[k]->vecs->handles[m*2]; tvFace[k].handles[m*2+1] = TVMaps.f[k]->vecs->handles[m*2+1]; } } } else patch.patches[k].flags |= PATCH_LINEARMAPPING; } else{ tvFace[k].tv[0] = 0; tvFace[k].tv[1] = 0; tvFace[k].tv[2] = 0; if (TVMaps.f[k]->count == 4) tvFace[k].tv[3] = 0; for (int m = 0;m < TVMaps.f[k]->count;m++) { tvFace[k].interiors[m] = 0; tvFace[k].handles[m*2] = 0; tvFace[k].handles[m*2+1] = 0; } } } //match verts patch.setNumMapVerts (mapChannel,TVMaps.v.Count()); PatchTVert *tVerts = patch.tVerts[mapChannel]; for (int k=0; k<TVMaps.v.Count(); k++) tVerts[k].p = GetTVVert(k); } else { //copy into mesh struct if (!tvFace) { // Create tvfaces and init to 0 patch.setNumMapPatches (mapChannel,patch.getNumPatches()); tvFace = patch.tvPatches[mapChannel]; for (int k=0; k<patch.getNumPatches(); k++) { for (int j=0; j<TVMaps.f[k]->count; j++) { tvFace[k].tv[j] = 0; tvFace[k].interiors[j] = 0; tvFace[k].handles[j*2] = 0; tvFace[k].handles[j*2+1] = 0; } } } int offset = patch.getNumMapVerts (mapChannel); for (int k=0; k<tvFaceCount; k++) { //copy if face is selected if (patch.patchSel[k]) { tvFace[k].tv[0] = TVMaps.f[k]->t[0]+offset; tvFace[k].tv[1] = TVMaps.f[k]->t[1]+offset; tvFace[k].tv[2] = TVMaps.f[k]->t[2]+offset; if (TVMaps.f[k]->count == 4) tvFace[k].tv[3] = TVMaps.f[k]->t[3]+offset; if (TVMaps.f[k]->flags & FLAG_CURVEDMAPPING) { patch.patches[k].flags &= ~PATCH_LINEARMAPPING; if (TVMaps.f[k]->vecs) { for (int m = 0;m < TVMaps.f[k]->count;m++) { if (TVMaps.f[k]->flags & FLAG_INTERIOR) { tvFace[k].interiors[m] = TVMaps.f[k]->vecs->interiors[m]+offset; } tvFace[k].handles[m*2] = TVMaps.f[k]->vecs->handles[m*2]+offset; tvFace[k].handles[m*2+1] = TVMaps.f[k]->vecs->handles[m*2+1]+offset; } } } else patch.patches[k].flags |= PATCH_LINEARMAPPING; } } //match verts patch.setNumMapVerts (mapChannel,TVMaps.v.Count()+offset,TRUE); PatchTVert *tVerts = patch.tVerts[mapChannel]; for ( int k=0; k<TVMaps.v.Count(); k++) tVerts[k+offset].p = GetTVVert(k); } RemoveDeadVerts(&patch,mapChannel); }
void TriPatchObject::FreeCaches() { ivalid.SetEmpty(); patch.FreeAll(); }