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 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 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(); }
// Edger Delete modifier method void EditPatchMod::DoEdgeDelete() { ModContextList mcList; INodeTab nodes; TimeValue t = ip->GetTime(); int holdNeeded = 0; if (!ip) return; ip->GetModContexts(mcList, nodes); ClearPatchDataFlag(mcList, EPD_BEENDONE); theHold.Begin(); RecordTopologyTags(); for (int i = 0; i < mcList.Count(); i++) { int altered = 0; 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; patchData->RecordTopologyTags(patch); // 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->edgeSel.NumberSet()) { altered = holdNeeded = 1; if (theHold.Holding()) theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoEdgeDelete")); int edges = patch->getNumEdges(); int patches = patch->getNumPatches(); int verts = patch->getNumVerts(); // Tag the patches that are attached to selected edges BitArray delPatches(patches); delPatches.ClearAll(); for (int i = 0; i < edges; ++i) { if (patch->edgeSel[i]) { #if (MAX_RELEASE < 4000) if (patch->edges[i].patch1 >= 0) delPatches.Set(patch->edges[i].patch1); if (patch->edges[i].patch2 >= 0) delPatches.Set(patch->edges[i].patch2); #else // (MAX_RELEASE < 4000) if (patch->edges[i].patches[0] >= 0) delPatches.Set(patch->edges[i].patches[0]); if (patch->edges[i].patches[1] >= 0) delPatches.Set(patch->edges[i].patches[1]); #endif // (MAX_RELEASE < 4000) } } BitArray delVerts(verts); delVerts.ClearAll(); DeletePatchParts(patch, rpatch, delVerts, delPatches); patch->computeInteriors(); patchData->UpdateChanges(patch, rpatch); patchData->TempData(this)->Invalidate(PART_TOPO); } patchData->SetFlag(EPD_BEENDONE, TRUE); } if (holdNeeded) { ResolveTopoChanges(); theHold.Accept(GetString(IDS_TH_EDGEDELETE)); } else { ip->DisplayTempPrompt(GetString(IDS_TH_NOEDGESSEL), PROMPT_TIME); theHold.End(); } nodes.DisposeTemporary(); ClearPatchDataFlag(mcList, EPD_BEENDONE); NotifyDependents(FOREVER, PART_TOPO, REFMSG_CHANGE); ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL); }