private static Path GeneratePathPolygon(LLObject.ObjectData prim, int sides, float startOff, float endScale, float twistScale) { Path path = new Path(); path.Points = new List<PathPoint>(); float revolutions = prim.PathRevolutions; float skew = prim.PathSkew; float skewMag = (float)Math.Abs(skew); float holeX = prim.PathScaleX * (1f - skewMag); float holeY = prim.PathScaleY; // Calculate taper begin/end for x,y (Negative means taper the beginning) float taperXBegin = 1f; float taperXEnd = 1f - prim.PathTaperX; float taperYBegin = 1f; float taperYEnd = 1f - prim.PathTaperY; if (taperXEnd > 1f) { // Flip tapering taperXBegin = 2f - taperXEnd; taperXEnd = 1f; } if (taperYEnd > 1f) { // Flip tapering taperYBegin = 2f - taperYEnd; taperYEnd = 1f; } // For spheres, the radius is usually zero float radiusStart = 0.5f; if (sides < 8) radiusStart = TABLE_SCALE[sides]; // Scale the radius to take the hole size into account radiusStart *= 1f - holeY; // Now check the radius offset to calculate the start,end radius. (Negative means // decrease the start radius instead) float radiusEnd = radiusStart; float radiusOffset = prim.PathRadiusOffset; if (radiusOffset < 0f) radiusStart *= 1f + radiusOffset; else radiusEnd *= 1f - radiusOffset; // Is the path NOT a closed loop? path.Open = ((prim.PathEnd * endScale - prim.PathBegin < 1f) || (skewMag > 0.001f) || (Math.Abs(taperXEnd - taperXBegin) > 0.001d) || (Math.Abs(taperYEnd - taperYBegin) > 0.001d) || (Math.Abs(radiusEnd - radiusStart) > 0.001d)); float ang, c, s; Quaternion twist = Quaternion.Identity; Quaternion qang = Quaternion.Identity; PathPoint point; Vector3 pathAxis = new Vector3(1f, 0f, 0f); float twistBegin = prim.PathTwistBegin * twistScale; float twistEnd = prim.PathTwist * twistScale; // We run through this once before the main loop, to make sure // the path begins at the correct cut float step = 1f / sides; float t = prim.PathBegin; ang = 2f * F_PI * revolutions * t; s = (float)Math.Sin(ang) * MathHelper.Lerp(radiusStart, radiusEnd, t); c = (float)Math.Cos(ang) * MathHelper.Lerp(radiusStart, radiusEnd, t); point = new PathPoint(); point.Position = new Vector3( 0 + MathHelper.Lerp(0, prim.PathShearX, s) + 0 + MathHelper.Lerp(-skew, skew, t) * 0.5f, c + MathHelper.Lerp(0, prim.PathShearY, s), s); point.Scale.X = holeX * MathHelper.Lerp(taperXBegin, taperXEnd, t); point.Scale.Y = holeY * MathHelper.Lerp(taperYBegin, taperYEnd, t); point.TexT = t; // Twist rotates the path along the x,y plane twist = Quaternion.CreateFromAxisAngle(MathHelper.Lerp(twistBegin, twistEnd, t) * 2f * F_PI - F_PI, 0f, 0f, 1f); // Rotate the point around the circle's center qang = Quaternion.CreateFromAxisAngle(pathAxis, ang); point.Rotation = twist * qang; path.Points.Add(point); t += step; // Snap to a quantized parameter, so that cut does not // affect most sample points t = ((int)(t * sides)) / (float)sides; // Run through the non-cut dependent points point = new PathPoint(); while (t < prim.PathEnd) { ang = 2f * F_PI * revolutions * t; c = (float)Math.Cos(ang) * MathHelper.Lerp(radiusStart, radiusEnd, t); s = (float)Math.Sin(ang) * MathHelper.Lerp(radiusStart, radiusEnd, t); point.Position = new Vector3( 0 + MathHelper.Lerp(0, prim.PathShearX, s) + 0 + MathHelper.Lerp(-skew, skew, t) * 0.5f, c + MathHelper.Lerp(0, prim.PathShearY, s), s); point.Scale.X = holeX * MathHelper.Lerp(taperXBegin, taperXEnd, t); point.Scale.Y = holeY * MathHelper.Lerp(taperYBegin, taperYEnd, t); point.TexT = t; // Twist rotates the path along the x,y plane twist = Quaternion.CreateFromAxisAngle(MathHelper.Lerp(twistBegin, twistEnd, t) * 2f * F_PI - F_PI, 0f, 0f, 1f); // Rotate the point around the circle's center qang = Quaternion.CreateFromAxisAngle(pathAxis, ang); point.Rotation = twist * qang; path.Points.Add(point); t += step; } // Make one final pass for the end cut t = prim.PathEnd; point = new PathPoint(); ang = 2f * F_PI * revolutions * t; c = (float)Math.Cos(ang) * MathHelper.Lerp(radiusStart, radiusEnd, t); s = (float)Math.Sin(ang) * MathHelper.Lerp(radiusStart, radiusEnd, t); point.Position = new Vector3( MathHelper.Lerp(0, prim.PathShearX, s) + MathHelper.Lerp(-skew, skew, t) * 0.5f, c + MathHelper.Lerp(0, prim.PathShearY, s), s); point.Scale.X = holeX * MathHelper.Lerp(taperXBegin, taperXEnd, t); point.Scale.Y = holeY * MathHelper.Lerp(taperYBegin, taperYEnd, t); point.TexT = t; // Twist rotates the path along the x,y plane twist = Quaternion.CreateFromAxisAngle(MathHelper.Lerp(twistBegin, twistEnd, t) * 2f * F_PI - F_PI, 0f, 0f, 1f); qang = Quaternion.CreateFromAxisAngle(pathAxis, ang); point.Rotation = twist * qang; path.Points.Add(point); return path; }
private static Path GeneratePath(LLObject.ObjectData prim, float detail) { Path path; path.Open = true; int np = 2; // Hardcode for line float step; switch (prim.PathCurve) { default: case LLObject.PathCurve.Line: { // Take the begin/end twist into account for detail np = (int)Math.Floor(Math.Abs(prim.PathTwistBegin - prim.PathTwist) * 3.5f * (detail - 0.5f)) + 2; path.Points = new List<PathPoint>(np); step = 1f / (np - 1); Vector2 startScale = prim.PathBeginScale; Vector2 endScale = prim.PathEndScale; for (int i = 0; i < np; i++) { PathPoint point = new PathPoint(); float t = MathHelper.Lerp(prim.PathBegin, prim.PathEnd, (float)i * step); point.Position = new Vector3( MathHelper.Lerp(0, prim.PathShearX, t), MathHelper.Lerp(0, prim.PathShearY, t), t - 0.5f); point.Rotation = Quaternion.CreateFromAxisAngle(MathHelper.Lerp(F_PI * prim.PathTwistBegin, F_PI * prim.PathTwist, t), 0f, 0f, 1f); point.Scale.X = MathHelper.Lerp(startScale.X, endScale.X, t); point.Scale.Y = MathHelper.Lerp(startScale.Y, endScale.Y, t); point.TexT = t; path.Points.Add(point); } } break; case LLObject.PathCurve.Circle: { // Increase the detail as the revolutions and twist increase float twistMag = Math.Abs(prim.PathTwistBegin - prim.PathTwist); int sides = (int)Math.Floor( Math.Floor(MIN_DETAIL_FACES * detail + twistMag * 3.5f * (detail - 0.5f)) * prim.PathRevolutions); // FIXME: Sculpty support //if (is_sculpted) // sides = sculpt_sides(detail); path = GeneratePathPolygon(prim, sides); } break; case LLObject.PathCurve.Circle2: { if (prim.PathEnd - prim.PathBegin >= 0.99f && prim.PathScaleX >= 0.99f) path.Open = false; path = GeneratePathPolygon(prim, (int)Math.Floor(MIN_DETAIL_FACES * detail)); float t = 0f; float tStep = 1f / path.Points.Count; float toggle = 0.5f; for (int i = 0; i < path.Points.Count; i++) { PathPoint point = path.Points[i]; point.Position.X = toggle; path.Points[i] = point; if (toggle == 0.5f) toggle = -0.5f; else toggle = 0.5f; t += tStep; } } break; case LLObject.PathCurve.Test: throw new NotImplementedException("PathCurve.Test is not supported"); } if (prim.PathTwist != prim.PathTwistBegin) path.Open = true; return path; }