void TorusObject::BuildMesh(TimeValue t) { Point3 p; int ix,na,nb,nc,nd,jx,kx; int nf=0,nv=0; float delta,ang; float delta2,ang2; int sides,segs,smooth; float radius,radius2, rotation; float sinang,cosang, sinang2,cosang2,rt; float twist, pie1, pie2, totalPie, startAng = 0.0f; int doPie = TRUE; int genUVs = TRUE; // Start the validity interval at forever and widdle it down. ivalid = FOREVER; pblock->GetValue(PB_RADIUS,t,radius,ivalid); pblock->GetValue(PB_RADIUS2,t,radius2,ivalid); pblock->GetValue(PB_ROTATION,t,rotation,ivalid); pblock->GetValue(PB_TWIST,t,twist,ivalid); pblock->GetValue(PB_SEGMENTS,t,segs,ivalid); pblock->GetValue(PB_SIDES,t,sides,ivalid); pblock->GetValue(PB_SMOOTH,t,smooth,ivalid); pblock->GetValue(PB_PIESLICE1,t,pie1,ivalid); pblock->GetValue(PB_PIESLICE2,t,pie2,ivalid); pblock->GetValue(PB_SLICEON,t,doPie,ivalid); pblock->GetValue(PB_GENUVS,t,genUVs,ivalid); LimitValue( radius, MIN_RADIUS, MAX_RADIUS ); LimitValue( radius2, MIN_RADIUS, MAX_RADIUS ); LimitValue( segs, MIN_SEGMENTS, MAX_SEGMENTS ); LimitValue( sides, MIN_SIDES, MAX_SIDES ); // Convert doPie to a 0 or 1 value since it is used in arithmetic below // Controllers can give it non- 0 or 1 values doPie = doPie ? 1 : 0; // We do the torus backwards from the cylinder pie1 = -pie1; pie2 = -pie2; // Make pie2 < pie1 and pie1-pie2 < TWOPI while (pie1 < pie2) pie1 += TWOPI; while (pie1 > pie2+TWOPI) pie1 -= TWOPI; if (pie1==pie2) totalPie = TWOPI; else totalPie = pie1-pie2; if (doPie) { segs++; //*** O.Z. fix for bug 240436 delta = totalPie/(float)(segs-1); startAng = pie2; } else { delta = (float)2.0*PI/(float)segs; } delta2 = (float)2.0*PI/(float)sides; if (TestAFlag(A_PLUGIN1)) startAng -= HALFPI; int nverts; int nfaces; if (doPie) { nverts = sides*segs + 2; nfaces = 2*sides*segs; } else { nverts = sides*segs; nfaces = 2*sides*segs; } mesh.setNumVerts(nverts); mesh.setNumFaces(nfaces); mesh.setSmoothFlags(smooth); if (genUVs) { if (doPie) { mesh.setNumTVerts((sides+1)*segs+2); mesh.setNumTVFaces(2*sides*segs); } else { mesh.setNumTVerts((sides+1)*(segs+1)); mesh.setNumTVFaces(2*sides*segs); } } else { mesh.setNumTVerts(0); mesh.setNumTVFaces(0); } ang = startAng; // make verts for(ix=0; ix<segs; ix++) { sinang = (float)sin(ang); cosang = (float)cos(ang); ang2 = rotation + twist * float(ix+1)/float(segs); for (jx = 0; jx<sides; jx++) { sinang2 = (float)sin(ang2); cosang2 = (float)cos(ang2); rt = radius+radius2*cosang2; p.x = rt*cosang; p.y = -rt*sinang; p.z = radius2*sinang2; mesh.setVert(nv++, p); ang2 += delta2; } ang += delta; } if (doPie) { p.x = radius * (float)cos(startAng); p.y = -radius * (float)sin(startAng); p.z = 0.0f; mesh.setVert(nv++, p); ang -= delta; p.x = radius * (float)cos(ang); p.y = -radius * (float)sin(ang); p.z = 0.0f; mesh.setVert(nv++, p); } // Make faces BOOL usePhysUVs = GetUsePhysicalScaleUVs(); BitArray startSliceFaces; BitArray endSliceFaces; if (usePhysUVs) { startSliceFaces.SetSize(mesh.numFaces); endSliceFaces.SetSize(mesh.numFaces); } /* Make midsection */ for(ix=0; ix<segs-doPie; ++ix) { jx=ix*sides; for (kx=0; kx<sides; ++kx) { na = jx+kx; nb = (ix==(segs-1))?kx:na+sides; nd = (kx==(sides-1))? jx : na+1; nc = nb+nd-na; DWORD grp = 0; if (smooth==SMOOTH_SIDES) { if (kx==sides-1 && (sides&1)) { grp = (1<<2); } else { grp = (kx&1) ? (1<<0) : (1<<1); } } else if (smooth==SMOOTH_STRIPES) { if (ix==segs-1 && (segs&1)) { grp = (1<<2); } else { grp = (ix&1) ? (1<<0) : (1<<1); } } else if (smooth > 0) { grp = 1; } mesh.faces[nf].setEdgeVisFlags(0,1,1); mesh.faces[nf].setSmGroup(grp); mesh.faces[nf].setMatID(0); mesh.faces[nf++].setVerts( na,nc,nb); mesh.faces[nf].setEdgeVisFlags(1,1,0); mesh.faces[nf].setSmGroup(grp); mesh.faces[nf].setMatID(0); mesh.faces[nf++].setVerts(na,nd,nc); } } if (doPie) { na = nv -2; for(ix=0; ix<sides; ++ix) { nb = ix; nc = (ix==(sides-1))?0:ix+1; mesh.faces[nf].setEdgeVisFlags(0,1,0); mesh.faces[nf].setSmGroup((1<<3)); mesh.faces[nf].setMatID(1); if (usePhysUVs) startSliceFaces.Set(nf); mesh.faces[nf++].setVerts(na,nc,nb); } na = nv -1; jx = sides*(segs-1); for(ix=0; ix<sides; ++ix) { nb = jx+ix; nc = (ix==(sides-1))?jx:nb+1; mesh.faces[nf].setEdgeVisFlags(0,1,0); mesh.faces[nf].setSmGroup((1<<3)); mesh.faces[nf].setMatID(2); if (usePhysUVs) endSliceFaces.Set(nf); mesh.faces[nf++].setVerts(na,nb,nc); } } // UVWs ------------------- if (genUVs) { float uScale = usePhysUVs ? ((float) 2.0f * PI * radius) : 1.0f; float vScale = usePhysUVs ? ((float) 2.0f * PI * radius2) : 1.0f; if (doPie) { float pieScale = float(totalPie/(2.0*PI)); uScale *= float(pieScale); } nv=0; for(ix=0; ix<=segs-doPie; ix++) { for (jx=0; jx<=sides; jx++) { if (usePhysUVs) mesh.setTVert(nv++,uScale*(1.0f - float(ix)/float(segs-doPie)),vScale*float(jx)/float(sides),0.0f); else mesh.setTVert(nv++,float(jx)/float(sides),float(ix)/float(segs),0.0f); } } int pie1 = 0; int pie2 = 0; if (doPie) { pie1 = nv; if (usePhysUVs) mesh.setTVert(nv++,0.0f,vScale*0.5f,0.0f); else mesh.setTVert(nv++,0.5f,1.0f,0.0f); pie2 = nv; if (usePhysUVs) mesh.setTVert(nv++,uScale*0.5f,vScale*0.0f,0.0f); else mesh.setTVert(nv++,1.0f,0.5f,0.0f); } nf=0; for(ix=0; ix<segs-doPie; ix++) { na = ix*(sides+1); nb = (ix+1)*(sides+1); for (jx=0; jx<sides; jx++) { mesh.tvFace[nf++].setTVerts(na,nb+1,nb); mesh.tvFace[nf++].setTVerts(na,na+1,nb+1); na++; nb++; } } if (doPie) { if (usePhysUVs) { Matrix3 tm = RotateZMatrix(startAng) * RotateXMatrix(float(-PI/2.0)); tm.Scale(Point3(-1.0f, 1.0f, 1.0f)); MakeMeshCapTexture(mesh, tm, startSliceFaces, usePhysUVs); tm = RotateZMatrix(ang) * RotateXMatrix(float(-PI/2.0)); MakeMeshCapTexture(mesh, tm, endSliceFaces, usePhysUVs); } else { for (jx=0; jx<sides; jx++) { mesh.tvFace[nf++].setTVerts(pie1,jx+1,jx); } nb = (sides+1)*(segs-1); for (jx=0; jx<sides; jx++) { mesh.tvFace[nf++].setTVerts(pie2,nb,nb+1); nb++; } } } } mesh.InvalidateTopologyCache(); }
void ExtrudeMod::BuildMeshFromShape(TimeValue t,ModContext &mc, ObjectState * os, Mesh &mesh, BOOL simple) { 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); ShapeObject *shape = (ShapeObject *)os->obj; float amount; int levels,capStart,capEnd,capType; pblock->GetValue(PB_AMOUNT,t,amount,FOREVER); if(simple) { levels = 1; capStart = capEnd = FALSE; } else { 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); 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; // Make the shape convert itself to a PolyShape -- This makes our mesh conversion MUCH easier! PolyShape pShape; shape->MakePolyShape(t, pShape); ShapeHierarchy hier; pShape.OrganizeCurves(t, &hier); // Need to flip the reversed curves in the shape! pShape.Reverse(hier.reverse); int polys = pShape.numLines; int levelVerts = 0, levelFaces = 0, levelTVerts = 0; int verts = 0, faces = 0, tVerts = 0; int poly, piece; BOOL anyClosed = FALSE; for(poly = 0; poly < polys; ++poly) { PolyLine &line = pShape.lines[poly]; if(!line.numPts) continue; if(line.IsClosed()) { anyClosed = TRUE; levelTVerts++; } levelVerts += line.numPts; levelTVerts += line.numPts; levelFaces += (line.Segments() * 2); } int vertsPerLevel = levelVerts; int numLevels = levels; verts = levelVerts * (levels + 1); tVerts = levelTVerts * (levels + 1); faces = levelFaces * levels; mesh.setNumVerts(verts); mesh.setNumFaces(faces); if(texturing) { mesh.setNumTVerts(tVerts); mesh.setNumTVFaces(faces); } // Create the vertices! int vert = 0; int tvertex = 0; int level; Point3 offset1, offset2; for(poly = 0; poly < polys; ++poly) { PolyLine &line = pShape.lines[poly]; if(!line.numPts) continue; if(texturing) { //DebugPrint(_T("Texture Verts:\n")); BOOL usePhysUVs = GetUsePhysicalScaleUVs(); int tp; int texPts = line.numPts + (line.IsClosed() ? 1 : 0); float *texPt = new float [texPts]; float lastPt = (float)(texPts - 1); float cumLen = 0.0f; float totLen = line.CurveLength(); Point3 prevPt = line.pts[0].p; for(tp = 0; tp < texPts; ++tp) { int ltp = tp % line.numPts; if(tp == (texPts - 1)) texPt[tp] = usePhysUVs ? totLen : 1.0f; else { Point3 &pt = line.pts[ltp].p; cumLen += Length(pt - prevPt); if (usePhysUVs) texPt[tp] = cumLen; else texPt[tp] = cumLen / totLen; prevPt = pt; } } float flevels = (float)levels; for(level = 0; level <= levels; ++level) { float tV = (float)level / flevels; float vScale = usePhysUVs ? amount : 1.0f; for(tp = 0; tp < texPts; ++tp) { mesh.setTVert(tvertex++, UVVert(texPt[tp], vScale*tV, 0.0f)); } } delete [] texPt; } int lverts = line.numPts; 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(int v = 0; v < lverts; ++v) { line.pts[v].aux = vert; // Gives the capper this vert's location in the mesh! mesh.setVert(vert++, line.pts[v].p + offset); } } } assert(vert == verts); // If capping, do it! if(anyClosed && (capStart || capEnd)) { MeshCapInfo capInfo; pShape.MakeCap(t, capInfo, capType); // Build information for capping MeshCapper capper(pShape); if(capStart) { vert = 0; for(poly = 0; poly < polys; ++poly) { PolyLine &line = pShape.lines[poly]; if(!line.numPts) continue; MeshCapPoly &capline = capper[poly]; int lverts = line.numPts; for(int v = 0; v < lverts; ++v) capline.SetVert(v, vert++); // Gives this vert's location in the mesh! vert += lverts * levels; } // Create a work matrix for grid capping Matrix3 gridMat = TransMatrix(offset1); int oldFaces = mesh.numFaces; capper.CapMesh(mesh, capInfo, TRUE, 16, &gridMat, genMatIDs ? -1 : 0); // If texturing, create the texture faces and vertices if(texturing) MakeMeshCapTexture(mesh, Inverse(gridMat), oldFaces, mesh.numFaces, GetUsePhysicalScaleUVs()); } if(capEnd) { int baseVert = 0; for(poly = 0; poly < polys; ++poly) { PolyLine &line = pShape.lines[poly]; if(!line.numPts) continue; MeshCapPoly &capline = capper[poly]; int lverts = line.numPts; 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); } // Create a work matrix for grid capping Matrix3 gridMat = TransMatrix(offset2); int oldFaces = mesh.numFaces; capper.CapMesh(mesh, capInfo, FALSE, 16, &gridMat, genMatIDs ? -1 : 0); // If texturing, create the texture faces and vertices if(texturing) MakeMeshCapTexture(mesh, Inverse(gridMat), oldFaces, mesh.numFaces, GetUsePhysicalScaleUVs()); } } // Create the faces! int face = 0; int TVface = 0; int baseVert = 0; int baseTVert = 0; for(poly = 0; poly < polys; ++poly) { PolyLine &line = pShape.lines[poly]; if(!line.numPts) continue; int pieces = line.Segments(); int closed = line.IsClosed(); int segVerts = pieces + ((closed) ? 0 : 1); int segTVerts = pieces + 1; for(level = 0; level < levels; ++level) { int sm = 0; // Initial smoothing group BOOL firstSmooth = (line.pts[0].flags & POLYPT_SMOOTH) ? TRUE : FALSE; for(piece = 0; piece < pieces; ++piece) { int v1 = baseVert + piece; int v2 = baseVert + ((piece + 1) % segVerts); int v3 = v1 + segVerts; int v4 = v2 + segVerts; // If the vertex is not smooth, go to the next group! BOOL thisSmooth = line.pts[piece].flags & POLYPT_SMOOTH; MtlID mtl = useShapeIDs ? line.pts[piece].GetMatID() : 2; if(piece > 0 && !thisSmooth) { sm++; if(sm > 2) sm = 1; } DWORD smoothGroup = 1 << sm; // Advance to the next smoothing group right away if(sm == 0) sm++; // Special case for smoothing from first segment if(piece == 1 && thisSmooth) smoothGroup |= 1; // Special case for smoothing from last segment if((piece == pieces - 1) && firstSmooth) smoothGroup |= 1; mesh.faces[face].setEdgeVisFlags(1,1,0); mesh.faces[face].setSmGroup(smooth ? smoothGroup : 0); mesh.faces[face].setMatID(genMatIDs ? mtl : 0); mesh.faces[face++].setVerts(v1, v2, v4); mesh.faces[face].setEdgeVisFlags(0,1,1); mesh.faces[face].setSmGroup(smooth ? smoothGroup : 0); mesh.faces[face].setMatID(genMatIDs ? mtl : 0); mesh.faces[face++].setVerts(v1, v4, v3); //DebugPrint(_T("BV:%d V:%d v1:%d v2:%d v3:%d v4:%d\n"),baseVert, vert, v1, v2, v3, v4); if(texturing) { int tv1 = baseTVert + piece; int tv2 = tv1 + 1; int tv3 = tv1 + segTVerts; int tv4 = tv2 + segTVerts; mesh.tvFace[TVface++].setTVerts(tv1, tv2, tv4); mesh.tvFace[TVface++].setTVerts(tv1, tv4, tv3); } } baseVert += segVerts; baseTVert += segTVerts; } baseVert += segVerts; // Increment to next poly start (skips last verts of this poly) baseTVert += segTVerts; } assert(face == faces); mesh.InvalidateGeomCache(); }