void render2x(bool fill, short colix, int tension, //top strand segment Point3i p0, Point3i p1, Point3i p2, Point3i p3, //bottom strand segment Point3i p4, Point3i p5, Point3i p6, Point3i p7) { Point3i[] endPoints = { p2, p1, p6, p5 }; // stores all points for top+bottom strands of 1 segment List<Point3i> points = new List<Point3i>(10); int whichPoint = 0; int numTopStrandPoints = 2; //first and last points automatically included float numPointsPerSegment = 5.0f;//use 5 for mesh // could make it so you can set this from script command if (fill) numPointsPerSegment = 10.0f; float interval = (1.0f / numPointsPerSegment); float currentInt = 0.0f; int x1 = p1.x, y1 = p1.y, z1 = p1.z; int x2 = p2.x, y2 = p2.y, z2 = p2.z; int xT1 = ((x2 - p0.x) * tension) / 8; int yT1 = ((y2 - p0.y) * tension) / 8; int zT1 = ((z2 - p0.z) * tension) / 8; int xT2 = ((p3.x - x1) * tension) / 8; int yT2 = ((p3.y - y1) * tension) / 8; int zT2 = ((p3.z - z1) * tension) / 8; sLeft[0] = 0; pLeft[0].set_Renamed(p1); sRight[0] = 1; pRight[0].set_Renamed(p2); sp = 0; g3d.setColix(colix); // set colix here for entire routine for (int strands = 2; strands > 0; strands--) { if (strands == 1) { x1 = p5.x; y1 = p5.y; z1 = p5.z; x2 = p6.x; y2 = p6.y; z2 = p6.z; xT1 = ( (x2 - p4.x) * tension) / 8; yT1 = ( (y2 - p4.y) * tension) / 8; zT1 = ( (z2 - p4.z) * tension) / 8; xT2 = ( (p7.x - x1) * tension) / 8; yT2 = ( (p7.y - y1) * tension) / 8; zT2 = ( (p7.z - z1) * tension) / 8; sLeft[0] = 0; pLeft[0].set_Renamed(p5); sRight[0] = 1; pRight[0].set_Renamed(p6); sp = 0; } points.Add(endPoints[whichPoint++]); currentInt = interval; do { Point3i a = pLeft[sp]; Point3i b = pRight[sp]; int dx = b.x - a.x; int dy = b.y - a.y; int dist2 = dx * dx + dy * dy; if (dist2 <= 2) { // mth 2003 10 13 // I tried drawing short cylinder segments here, // but drawing spheres was faster float s = sLeft[sp]; g3d.fillSphereCentered(colix, 3, a); //draw outside edges of mesh if (s < 1.0f - currentInt) { //if first point over the interval Point3i temp = new Point3i(); temp.set_Renamed(a); points.Add(temp); //store it currentInt += interval; // increase to next interval if (strands == 2) { numTopStrandPoints++; } } --sp; } else { double s = (sLeft[sp] + sRight[sp]) / 2; double s2 = s * s; double s3 = s2 * s; double h1 = 2 * s3 - 3 * s2 + 1; double h2 = -2 * s3 + 3 * s2; double h3 = s3 - 2 * s2 + s; double h4 = s3 - s2; Point3i pMid = pRight[sp + 1]; pMid.x = (int)(h1 * x1 + h2 * x2 + h3 * xT1 + h4 * xT2); pMid.y = (int)(h1 * y1 + h2 * y2 + h3 * yT1 + h4 * yT2); pMid.z = (int)(h1 * z1 + h2 * z2 + h3 * zT1 + h4 * zT2); pRight[sp + 1] = pRight[sp]; sRight[sp + 1] = sRight[sp]; pRight[sp] = pMid; sRight[sp] = (float)s; ++sp; pLeft[sp].set_Renamed(pMid); sLeft[sp] = (float)s; } } while (sp >= 0); points.Add(endPoints[whichPoint++]); } //end of for loop - processed top and bottom strands int size = points.Count; if (fill) { //RIBBONS Point3i t1 = null; Point3i b1 = null; Point3i t2 = null; Point3i b2 = null; int top = 1; Vector3[] strip = new Vector3[numTopStrandPoints * 2]; int stIdx = 0; for (; top < numTopStrandPoints && (top + numTopStrandPoints) < size; top++) { t1 = points[top - 1]; b1 = points[numTopStrandPoints + (top - 1)]; strip[stIdx++] = new Vector3(t1.X, t1.y, t1.z); strip[stIdx++] = new Vector3(b1.x, b1.y, b1.z); } if ((numTopStrandPoints * 2) != size) { //BUG(DC09_MAY_2004): not sure why but //sometimes misses triangle at very start of segment //temp fix - will inestigate furture g3d.fillTriangle(p1, p5, t2); g3d.fillTriangle(b2, t2, p5); } g3d.FillTriangleStrip(strip); } else { //MESH for (int top = 0; top < numTopStrandPoints && (top + numTopStrandPoints) < size; top++) { g3d.drawLine(points[top], points[top + numTopStrandPoints]); } } }