Пример #1
0
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();
	}
Пример #2
0
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();
	}
Пример #3
0
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();
	}
Пример #4
0
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();
	}