void ScubaObject::BuildMesh(TimeValue t) { int segs, smooth, hsegs; float radius,height,pie1, pie2,r2; int doPie, genUVs,con; // Start the validity interval at forever and widdle it down. FixHeight(pblock,t,(pmapParam?pmapParam->GetHWnd():NULL),increate); ivalid = FOREVER; pblock->GetValue(PB_RADIUS,t,radius,ivalid); pblock->GetValue(PB_CENTERS,t,con,ivalid); pblock->GetValue(PB_HEIGHT,t,height,ivalid); r2=2.0f*radius; if (con) height+=(height<0.0f?-r2:r2); pblock->GetValue(PB_SIDES,t,segs,ivalid); pblock->GetValue(PB_HSEGS,t,hsegs,ivalid); pblock->GetValue(PB_SMOOTHON,t,smooth,ivalid); pblock->GetValue(PB_SLICEFROM,t,pie1,ivalid); pblock->GetValue(PB_SLICETO,t,pie2,ivalid); pblock->GetValue(PB_SLICEON,t,doPie,ivalid); pblock->GetValue(PB_GENUVS,t,genUVs,ivalid); LimitValue(radius, MIN_RADIUS, MAX_RADIUS); LimitValue(height, MIN_HEIGHT, MAX_HEIGHT); LimitValue(hsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(segs, MIN_SIDES, MAX_SIDES); LimitValue(smooth, 0, 1); // sides, smooth, cylrad BuildScubaMesh(mesh, segs, smooth, hsegs, doPie,radius, height, pie1, pie2, genUVs, GetUsePhysicalScaleUVs()); }
void PyramidObject::BuildMesh(TimeValue t) { int hsegs,wsegs,dsegs; float height,width,depth; int genUVs; // Start the validity interval at forever and widdle it down. ivalid = FOREVER; pblock->GetValue(PB_HSEGS,t,hsegs,ivalid); pblock->GetValue(PB_WSEGS,t,wsegs,ivalid); pblock->GetValue(PB_DSEGS,t,dsegs,ivalid); pblock->GetValue(PB_HEIGHT,t,height,ivalid); pblock->GetValue(PB_WIDTH,t,width,ivalid); pblock->GetValue(PB_DEPTH,t,depth,ivalid); pblock->GetValue(PB_GENUVS,t,genUVs,ivalid); LimitValue(height, MIN_HEIGHT, MAX_HEIGHT); LimitValue(width, MIN_HEIGHT, MAX_HEIGHT); LimitValue(depth, MIN_HEIGHT, MAX_HEIGHT); LimitValue(hsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(wsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(dsegs, MIN_SEGMENTS, MAX_SEGMENTS); BOOL usePhysUVs = GetUsePhysicalScaleUVs(); BuildPyramidMesh(mesh, hsegs, wsegs, dsegs, height, width, depth, genUVs, usePhysUVs); }
RefTargetHandle RendSpline::Clone(RemapDir& remap) { RendSpline* newmod = new RendSpline(false); newmod->ReplaceReference(PBLOCK_REF,remap.CloneRef(pblock)); BaseClone(this, newmod, remap); newmod->SetUsePhysicalScaleUVs(GetUsePhysicalScaleUVs()); return(newmod); }
RefTargetHandle ExtrudeMod::Clone(RemapDir& remap) { ExtrudeMod* newmod = new ExtrudeMod(false); newmod->ReplaceReference(0,remap.CloneRef(pblock)); BaseClone(this, newmod, remap); newmod->SetUsePhysicalScaleUVs(GetUsePhysicalScaleUVs()); return(newmod); }
RefTargetHandle TorusObject::Clone(RemapDir& remap) { TorusObject* newob = new TorusObject(FALSE); newob->ReplaceReference(0,remap.CloneRef(pblock)); newob->ivalid.SetEmpty(); BaseClone(this, newob, remap); newob->SetUsePhysicalScaleUVs(GetUsePhysicalScaleUVs()); return(newob); }
void TorusObject::SetUsePhysicalScaleUVs(BOOL flag) { BOOL curState = GetUsePhysicalScaleUVs(); if (curState == flag) return; if (theHold.Holding()) theHold.Put(new RealWorldScaleRecord<TorusObject>(this, curState)); ::SetUsePhysicalScaleUVs(this, flag); if (pblock != NULL) pblock->NotifyDependents(FOREVER, PART_GEOM, REFMSG_CHANGE); UpdateUI(); macroRec->SetProperty(this, _T("realWorldMapSize"), mr_bool, flag); }
void CExtObject::BuildMesh(TimeValue t) { int hsegs,tsegs,ssegs,bsegs,wsegs; float height,toplen,sidelen,botlen,topwidth,sidewidth,botwidth; int genUVs; // Start the validity interval at forever and widdle it down. FixTopWidth(pblock,t,(pmapParam?pmapParam->GetHWnd():NULL),increate); FixBotWidth(pblock,t,(pmapParam?pmapParam->GetHWnd():NULL),increate); FixSideWidth(pblock,t,(pmapParam?pmapParam->GetHWnd():NULL),increate); ivalid = FOREVER; pblock->GetValue(PB_HSEGS,t,hsegs,ivalid); pblock->GetValue(PB_TSEGS,t,tsegs,ivalid); pblock->GetValue(PB_SSEGS,t,ssegs,ivalid); pblock->GetValue(PB_BSEGS,t,bsegs,ivalid); pblock->GetValue(PB_WSEGS,t,wsegs,ivalid); pblock->GetValue(PB_TOPLENGTH,t,toplen,ivalid); pblock->GetValue(PB_SIDELENGTH,t,sidelen,ivalid); pblock->GetValue(PB_BOTLENGTH,t,botlen,ivalid); pblock->GetValue(PB_TOPWIDTH,t,topwidth,ivalid); pblock->GetValue(PB_SIDEWIDTH,t,sidewidth,ivalid); pblock->GetValue(PB_BOTWIDTH,t,botwidth,ivalid); pblock->GetValue(PB_HEIGHT,t,height,ivalid); pblock->GetValue(PB_GENUVS,t,genUVs,ivalid); LimitValue(height, MIN_HEIGHT, BMAX_HEIGHT); LimitValue(toplen, MIN_HEIGHT, BMAX_LENGTH); LimitValue(sidelen, MIN_HEIGHT,BMAX_WIDTH); LimitValue(botlen, MIN_HEIGHT, BMAX_HEIGHT); LimitValue(topwidth, BMIN_LENGTH,BMAX_LENGTH); LimitValue(sidewidth, BMIN_WIDTH,BMAX_WIDTH); LimitValue(botwidth, BMIN_HEIGHT,BMAX_HEIGHT); LimitValue(hsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(tsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(ssegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(bsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(wsegs, MIN_SEGMENTS, MAX_SEGMENTS); BuildCExtMesh(mesh,hsegs,tsegs,ssegs,bsegs,wsegs,height, toplen,sidelen,botlen,topwidth,sidewidth,botwidth, genUVs,createmeth,GetUsePhysicalScaleUVs()); }
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(); }
Object* TorusObject::ConvertToType(TimeValue t, Class_ID obtype) { #ifndef NO_PATCHES if (obtype == patchObjectClassID) { Interval valid = FOREVER; float radius1, radius2; int genUVs; pblock->GetValue(PB_RADIUS,t,radius1,valid); pblock->GetValue(PB_RADIUS2,t,radius2,valid); pblock->GetValue(PB_GENUVS,t,genUVs,valid); PatchObject *ob = new PatchObject(); BuildTorusPatch(t,ob->patch,radius1,radius2,genUVs, GetUsePhysicalScaleUVs()); ob->SetChannelValidity(TOPO_CHAN_NUM,valid); ob->SetChannelValidity(GEOM_CHAN_NUM,valid); ob->UnlockObject(); return ob; } #endif #ifndef NO_NURBS if (obtype == EDITABLE_SURF_CLASS_ID) { Interval valid = FOREVER; float radius, radius2, pie1, pie2; int sliceon, genUVs; pblock->GetValue(PB_RADIUS,t,radius,valid); pblock->GetValue(PB_RADIUS2,t,radius2,valid); pblock->GetValue(PB_PIESLICE1,t,pie1,valid); pblock->GetValue(PB_PIESLICE2,t,pie2,valid); pblock->GetValue(PB_SLICEON,t,sliceon,valid); pblock->GetValue(PB_GENUVS,t,genUVs,valid); Object *ob = BuildNURBSTorus(radius, radius2, sliceon, pie1, pie2, genUVs); ob->SetChannelValidity(TOPO_CHAN_NUM,valid); ob->SetChannelValidity(GEOM_CHAN_NUM,valid); ob->UnlockObject(); return ob; } #endif #ifdef DESIGN_VER if (obtype == GENERIC_AMSOLID_CLASS_ID) { Interval valid = FOREVER; float radius1, radius2, pie1, pie2; int sliceon, genUVs, sides, segs; pblock->GetValue(PB_RADIUS,t,radius1,valid); pblock->GetValue(PB_RADIUS2,t,radius2,valid); pblock->GetValue(PB_PIESLICE1,t,pie1,valid); pblock->GetValue(PB_PIESLICE2,t,pie2,valid); pblock->GetValue(PB_SLICEON,t,sliceon,valid); pblock->GetValue(PB_GENUVS,t,genUVs,valid); pblock->GetValue(PB_SIDES,t,sides,valid); pblock->GetValue(PB_SEGMENTS,t,segs,valid); int smooth; pblock->GetValue(PB_SMOOTH,t,smooth,valid); if (radius1 < 0.0f) radius1 = 0.0f; if (radius2 < 0.0f) radius2 = 0.0f; Object* solid = (Object*)CreateInstance(GEOMOBJECT_CLASS_ID, GENERIC_AMSOLID_CLASS_ID); assert(solid); if(solid) { IGeomImp* cacheptr = (IGeomImp*)(solid->GetInterface(I_GEOMIMP)); assert(cacheptr); if(cacheptr) { bool res = cacheptr->createTorus(radius1, radius2, sides, segs, smooth); solid->ReleaseInterface(I_GEOMIMP, cacheptr); if(res) return solid; else { solid->DeleteMe(); } } } return NULL; } #endif return SimpleObject::ConvertToType(t,obtype); }
void ChBoxObject::BuildMesh(TimeValue t) { int smooth,dsegs,vertices; int WLines,HLines,DLines,CLines,VertexPerSlice; int VertexPerFace,FacesPerSlice,chamferend; float usedw,usedd,usedh,cradius,zdelta,CurRadius; Point3 va,vb,p; float depth, width, height; int genUVs = 1,sqvertex,CircleLayers; BOOL bias = 0,minusd; // Start the validity interval at forever and widdle it down. ivalid = FOREVER; pblock->GetValue(PB_LENGTH,t,height,ivalid); pblock->GetValue(PB_WIDTH,t,width,ivalid); pblock->GetValue(PB_HEIGHT,t,depth,ivalid); minusd=depth<0.0f; depth=(float)fabs(depth); pblock->GetValue(PB_RADIUS,t,cradius,ivalid); pblock->GetValue(PB_LSEGS,t,hsegs,ivalid); pblock->GetValue(PB_WSEGS,t,wsegs,ivalid); pblock->GetValue(PB_HSEGS,t,dsegs,ivalid); pblock->GetValue(PB_CSEGS,t,csegs,ivalid); pblock->GetValue(PB_GENUVS,t,genUVs,ivalid); pblock->GetValue(PB_SMOOTH,t,smooth,ivalid); LimitValue(csegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(dsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(wsegs, MIN_SEGMENTS, MAX_SEGMENTS); LimitValue(hsegs, MIN_SEGMENTS, MAX_SEGMENTS); smooth=(smooth>0?1:0); mesh.setSmoothFlags(smooth); float twocrad,usedm,mindim=(height>width?(width>depth?depth:width):(height>depth?depth:height)); usedm=mindim-2*cradius; if (usedm<0.01f) cradius=(mindim-0.01f)/2.0f; twocrad=2.0f*cradius; usedh=height-twocrad; usedw=width-twocrad; usedd=depth-twocrad; float cangincr=PI/(2.0f*csegs),cudelta,udist; CircleLayers=csegs; cudelta=cradius*(float)sqrt(2.0f*(1.0f-(float)cos(cangincr))); udist=4.0f*csegs*cudelta+2.0f*width+2.0f*height-4.0f*cradius; chamferinfo[0].surface=1;chamferinfo[0].deltavert=1; chamferinfo[1].surface=2;chamferinfo[1].deltavert=1; chamferinfo[2].surface=1;chamferinfo[2].deltavert=-1; chamferinfo[3].surface=2;chamferinfo[3].deltavert=-1; WLines=wsegs-1; HLines=hsegs-1; DLines=dsegs-1; CLines=csegs+1; VertexPerSlice=2*(WLines+HLines)+4*CLines; /* WLines*HLines on middle, 2*Clines*(WLines+HLines) on sides, 4*CLines*csegs+4 for circles */ VertexPerFace=WLines*HLines+2*CLines*(WLines+HLines+2*csegs)+4; vertices=VertexPerFace*2+VertexPerSlice*DLines; sqvertex=(wsegs+1)*(hsegs+1); /* 4 vertices, 2 faces/cseg + 2 each hseg & wseg sides, each seg w/ 2 faces*/ SidesPerSlice=2*(2*csegs+hsegs+wsegs); FacesPerSlice=SidesPerSlice*2; /* this one only has 1 face/ cseg */ topchamferfaces=4*(csegs+hsegs+wsegs); /*top chamfer + top face(2 faces/seg)(*2 for bottom) plus any depth faces*/ maxfaces=2*(topchamferfaces+2*hsegs*wsegs)+(2*(CircleLayers-1)+dsegs)*FacesPerSlice; chamferstart=2*hsegs*wsegs; chamferend=chamferstart+topchamferfaces+(CircleLayers-1)*FacesPerSlice; chamferinfo[0].deltavert +=wsegs; chamferinfo[2].deltavert -=wsegs; int bottomvertex,vertexnum,tverts; int twomapped,endvert=vertices+(twomapped=2*VertexPerSlice); float xmax,ymax; mesh.setNumVerts(vertices); mesh.setNumFaces(maxfaces); tverts=endvert+DLines+2; if (genUVs) { mesh.setNumTVerts(tverts); mesh.setNumTVFaces(maxfaces); } else { mesh.setNumTVerts(0); mesh.setNumTVFaces(0); } zdelta=depth/2; wsegcount=0;vertexnum=0; bottomvertex=vertices-1; CornerPt.z=zdelta; CornerPt.x=(xmax=width/2)-cradius; CornerPt.y=(ymax=height/2)-cradius; NewPt.x=Toppt.x=-CornerPt.x; NewPt.y=Toppt.y=CornerPt.y; NewPt.z=Toppt.z=zdelta; /* Do top and bottom faces */ hincr=usedh/hsegs; //yincr wincr=usedw/wsegs; //xincr BOOL usePhysUVs = GetUsePhysicalScaleUVs(); int segcount,topvertex,tvcounter=0,tvbottom=endvert-1; float udiv=usePhysUVs ? 1.0f : 2.0f*xmax,vdiv=usePhysUVs ? 1.0f :2.0f*ymax, u = 0.0f, v = 0.0f; for (hseg=0;hseg<=hsegs;hseg++) { if (hseg>0) {NewPt.y=(hseg==hsegs?-CornerPt.y:Toppt.y-hseg*hincr); NewPt.x=Toppt.x; } for (segcount=0;segcount<=wsegs;segcount++) { /* make top point */ NewPt.z=Toppt.z; NewPt.x=(segcount==wsegs?CornerPt.x:Toppt.x+segcount*wincr); if (genUVs) mesh.setTVert(vertexnum,u=(xmax+NewPt.x)/udiv,v=(ymax+NewPt.y)/vdiv,0.0f); mesh.setVert(vertexnum++,NewPt); /* make bottom pt */ NewPt.z=-zdelta; if (genUVs) mesh.setTVert(tvbottom--,u,(usePhysUVs ? 2.0f*ymax : 1.0f)-v,0.0f); mesh.setVert(bottomvertex--,NewPt); } } /* start on the chamfer */ int layer,vert; layer=0; hseg=0; tvcounter=vertexnum; bottomvertex-=(VertexPerSlice-1); topvertex=vertexnum; BOOL done = FALSE,atedge = FALSE; float dincr=usedd/dsegs,cincr=2.0f*CircleLayers,RotationAngle; float dx,dy; int cornervert[4],PtRotation; for (layer=1;layer<=CircleLayers;layer++) /* add chamfer layer */ { if (layer==CircleLayers) {zdelta=cradius;CurRadius=cradius;} else { RotationAngle=(PI*layer)/cincr; zdelta=cradius-(cradius*(float)cos(RotationAngle)); CurRadius=cradius*(float)sin(RotationAngle); } zdelta=CornerPt.z-zdelta; atedge=(layer==CircleLayers); int vfromedge=0,oldside=0,vfromstart=0; sidenum=0; float u1 = 0.0f, v1 = 0.0f; BOOL atstart=TRUE; while (vertexnum<topvertex+csegs) /* add vertex loop */ { PtRotation=hseg=wsegcount=0;done=FALSE; RotationAngle=(vertexnum-topvertex)*cangincr; curvertex=vert=vertexnum; NewPt.x=Toppt.x-(dx=CurRadius*(float)sin(RotationAngle)); NewPt.y=Toppt.y+(dy=CurRadius*(float)cos(RotationAngle)); NewPt.z=zdelta; while (!done) { mesh.setVert(vert,NewPt); if (genUVs) mesh.setTVert(vert,u1=(xmax+NewPt.x)/udiv,v1=(ymax+NewPt.y)/vdiv,0.0f); /* reflected vertex to second face */ vert=bottomvertex+curvertex-topvertex; NewPt.z=-zdelta; mesh.setVert(vert,NewPt); if (genUVs) mesh.setTVert(vert+twomapped,u1,(usePhysUVs ? 2.0f*ymax : 1.0f)-v1,0.0f); if ((atedge)&&(DLines>0)) /* add non-corner points */ for (segcount=1;segcount<=DLines;segcount++) { NewPt.z=zdelta-segcount*dincr; mesh.setVert(vert=curvertex+VertexPerSlice*segcount,NewPt); } /* Rotate Pt */ done=PtRotation>5; if (done == FALSE) { if (vertexnum==topvertex) { FillinSquare(&PtRotation,cornervert,CurRadius); if (curvertex==topvertex+VertexPerSlice-1) (PtRotation)=6; } else CalculateNewPt(dx,dy,&PtRotation,cornervert,vertexnum-topvertex); vert=curvertex; NewPt.z=zdelta; } } vertexnum++; /* done rotation */ } vertexnum=topvertex +=VertexPerSlice; bottomvertex -=VertexPerSlice; } float dfromedge=0.0f; int tvnum,j,i,chsegs=csegs+1,cwsegs=wsegs; if (genUVs) { u=0.0f; dfromedge=-cudelta; tvnum=vertexnum; vertexnum=topvertex-VertexPerSlice; float uDenom = usePhysUVs ? 1.0f : udist; float vScale = usePhysUVs ? usedd : 1.0f; float maxU = 0.0f; for (j=0;j<2;j++) { int gverts; for (gverts=0;gverts<chsegs;gverts++) { dfromedge+=cudelta; mesh.setTVert(tvnum,u=dfromedge/uDenom,vScale,0.0f); if (u > maxU) maxU = u; for (i=1;i<=dsegs;i++) mesh.setTVert(tvnum+VertexPerSlice*i,u,vScale*(1.0f-(float)i/dsegs),0.0f); vertexnum++; tvnum++; } chsegs=csegs; for (gverts=0;gverts<hsegs;gverts++) { dfromedge+=(float)fabs(mesh.verts[vertexnum].y-mesh.verts[vertexnum-1].y); mesh.setTVert(tvnum,u=dfromedge/uDenom,vScale,0.0f); if (u > maxU) maxU = u; for (i=1;i<=dsegs;i++) mesh.setTVert(tvnum+VertexPerSlice*i,u,vScale*(1.0f-(float)i/dsegs),0.0f); vertexnum++; tvnum++; } for (gverts=0;gverts<csegs;gverts++) { dfromedge+=cudelta; mesh.setTVert(tvnum,u=dfromedge/uDenom,vScale,0.0f); if (u > maxU) maxU = u; for (i=1;i<=dsegs;i++) mesh.setTVert(tvnum+VertexPerSlice*i,u,vScale*(1.0f-(float)i/dsegs),0.0f); vertexnum++; tvnum++; } if (j==1) cwsegs--; for (gverts=0;gverts<cwsegs;gverts++) { dfromedge+=(float)fabs(mesh.verts[vertexnum].x-mesh.verts[vertexnum-1].x); mesh.setTVert(tvnum,u=dfromedge/uDenom,vScale,0.0f); if (u > maxU) maxU = u; for (i=1;i<=dsegs;i++) mesh.setTVert(tvnum+VertexPerSlice*i,u,vScale*(1.0f-(float)i/dsegs),0.0f); vertexnum++; tvnum++; } } int lastvert=endvert; float uScale = usePhysUVs ? udist-4*cradius : 1.0f; mesh.setTVert(lastvert++,uScale, vScale,0.0f); for (j=1;j<dsegs;j++) mesh.setTVert(lastvert++,uScale, vScale*(1.0f-(float)j/dsegs),0.0f); mesh.setTVert(lastvert,uScale, 0.0f,0.0f); } /* all vertices calculated - Now specify faces*/ int tvdelta=0; sidenum=topnum=face=fcount=scount=circleseg=0; curvertex=wsegs+1; firstface=layer=1; // smooth=(csegs>1?1:0); tstartpt=cstartpt=endpt=0; boxpos=topsquare;cstartpt=chamferinfo[0].deltavert; AddFace(&mesh.faces[face],smooth,tvdelta,&mesh.tvFace[face],genUVs); while (face<chamferstart) /* Do Square Layer */ { firstface=!firstface; AddFace(&mesh.faces[face],smooth,tvdelta,&mesh.tvFace[face],genUVs); } boxpos=messyedge;firstface=1; topnum=tstartpt=0; cstartpt=curvertex=topnum+sqvertex;circleseg=1; endpt=hsegs*(wsegs+1); /* Do Chamfer */ while (face<chamferend) { AddFace(&mesh.faces[face],smooth,tvdelta,&mesh.tvFace[face],genUVs); if (circleseg==0) firstface=!firstface; } fcount=scount=0; boxpos=middle;tvdelta+=VertexPerSlice; /*Do box sides */ int tpt,lastv=tverts-1; BOOL inside=TRUE; while (face<maxfaces-chamferstart-topchamferfaces) { tpt=face; AddFace(&mesh.faces[face],smooth,tvdelta,&mesh.tvFace[face],genUVs); if (genUVs && inside) { if ((firstface)&&(mesh.tvFace[tpt].t[2]<mesh.tvFace[tpt].t[1])) mesh.tvFace[tpt].t[2]=endvert+1; else if (mesh.tvFace[tpt].t[2]<mesh.tvFace[tpt].t[0]) { mesh.tvFace[tpt].t[1]=endvert+1; mesh.tvFace[tpt].t[2]=endvert; endvert++; inside=endvert<lastv; if (inside==FALSE) tvdelta+=VertexPerSlice; } } firstface=!firstface; } /* back in chamfer */ circleseg=2;firstface=0; boxpos=bottomedge; sidenum=0;tstartpt=topnum; cstartpt=curvertex=vertices-1; endpt=cstartpt-hsegs*chamferinfo[0].deltavert; while (face<maxfaces-chamferstart) /* Do Second Chamfer */ { AddFace(&mesh.faces[face],smooth,tvdelta,&mesh.tvFace[face],genUVs); if (circleseg==0) firstface=!firstface; } boxpos=bottomsquare; curvertex=topnum; topnum=curvertex+chamferinfo[0].deltavert; firstface=1;fcount=0; while (face<maxfaces) { AddFace(&mesh.faces[face],smooth,tvdelta,&mesh.tvFace[face],genUVs); firstface=!firstface; } float deltaz=(minusd?-depth/2.0f:depth/2.0f); for (i=0;i<vertices;i++) { mesh.verts[i].z+=deltaz; } mesh.InvalidateTopologyCache(); }
void RendSpline::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *node) { Interval valid = GetValidity(t); // and intersect it with the channels we use as input (see ChannelsUsed) valid &= os->obj->ChannelValidity(t,TOPO_CHAN_NUM); valid &= os->obj->ChannelValidity(t,GEOM_CHAN_NUM); // float nlength; BOOL doRender = false, doDisplay = false, doUVW = false, useView = false, autosmooth = false, aspectLock = false, vAspectLock; float threshold, width, length, angle2, vwidth, vlength, vangle2; int rectangular, vRectangular; pblock->GetValue(rnd_thickness,t,nlength,valid); pblock->GetValue(rnd_sides,t,nsides,valid); pblock->GetValue(rnd_angle,t,nangle,valid); pblock->GetValue(rnd_viewThickness,t,vthickness,valid); pblock->GetValue(rnd_viewSides,t,vsides,valid); pblock->GetValue(rnd_viewAngle,t,vangle,valid); pblock->GetValue(rnd_render,t,doRender,valid); pblock->GetValue(rnd_display,t,doDisplay,valid); pblock->GetValue(rnd_genuvw,t,doUVW,valid); pblock->GetValue(rnd_useView,t,useView,valid); pblock->GetValue(rnd_v2_symm_or_rect,t,rectangular,valid); pblock->GetValue(rnd_v2_length,t,length,valid); pblock->GetValue(rnd_v2_width,t,width,valid); pblock->GetValue(rnd_v2_angle2,t,angle2,valid); pblock->GetValue(rnd_v2_aspect_lock,t,aspectLock,valid); pblock->GetValue(rnd_v2_vpt_symm_or_rect,t,vRectangular,valid); pblock->GetValue(rnd_v2_vpt_length,t,vlength,valid); pblock->GetValue(rnd_v2_vpt_width,t,vwidth,valid); pblock->GetValue(rnd_v2_vpt_angle2,t,vangle2,valid); pblock->GetValue(rnd_v2_vpt_aspect_lock,t,vAspectLock,valid); pblock->GetValue(rnd_v2_autosmooth,t,autosmooth,valid); pblock->GetValue(rnd_v2_threshold,t,threshold,valid); BOOL usePhysUVs = GetUsePhysicalScaleUVs(); mAspectLock = aspectLock; theHold.Suspend(); // need to suspend Undo SplineShape *shape = (SplineShape *)os->obj; //->ConvertToType(t,splineShapeClassID); shape->SetRenderable(doRender); shape->SetDispRenderMesh(doDisplay); if(doRender || doDisplay) shape->SetGenUVW(doUVW); nlength = nlength < 0.0f ? 0.0f : (nlength > 1000000.0f ? 1000000.0f : nlength); vthickness = vthickness < 0.0f ? 0.0f : (vthickness > 1000000.0f ? 1000000.0f : vthickness); nsides = nsides < 0 ? 0 : (nsides > 100? 100 : nsides); vsides = vsides < 0 ? 0 : (vsides > 100? 100 : vsides); shape->SetThickness(t,nlength); shape->SetSides(t,nsides); shape->SetAngle(t,nangle); shape->SetViewportAngle(vangle); shape->SetViewportSides(vsides); shape->SetViewportThickness(vthickness); shape->SetUseViewport(useView); shape->SetUsePhysicalScaleUVs(usePhysUVs); IShapeRectRenderParams *rparams = (IShapeRectRenderParams *)shape->GetProperty(SHAPE_RECT_RENDERPARAMS_PROPID); if(rparams) { rparams->SetAutosmooth(t,autosmooth); rparams->SetAutosmoothThreshold(t, threshold); rparams->SetRectangular(t,rectangular == rbRectangular); rparams->SetAngle2(t,angle2); rparams->SetLength(t,length); rparams->SetWidth(t,width); rparams->SetVPTRectangular(t,vRectangular == rbRectangular); rparams->SetVPTAngle2(t,vangle2); rparams->SetVPTLength(t,vlength); rparams->SetVPTWidth(t,vwidth); } shape->shape.UpdateSels(); shape->shape.InvalidateGeomCache(); theHold.Resume(); // it's now safe to resume Undo os->obj->SetChannelValidity(TOPO_CHAN_NUM, valid); os->obj->SetChannelValidity(GEOM_CHAN_NUM, valid); os->obj->SetChannelValidity(TEXMAP_CHAN_NUM, valid); os->obj->SetChannelValidity(MTL_CHAN_NUM, valid); os->obj->SetChannelValidity(SELECT_CHAN_NUM, valid); os->obj->SetChannelValidity(SUBSEL_TYPE_CHAN_NUM, valid); os->obj->SetChannelValidity(DISP_ATTRIB_CHAN_NUM, valid); os->obj = shape; //os->obj->UnlockObject(); }
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(); }
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(); }