internal static bool Make(VGPath path, out StencilVertex[] vertices, out int tris) { vertices = null; // Count triangles tris = path.GetCount(VGPath.SegmentType.CurveTo) * 2 + path.GetCount(VGPath.SegmentType.LineTo) + path.GetCount(VGPath.SegmentType._Tesselated); if (tris == 0) return false; // Tesselate vertices = new StencilVertex[tris * 3]; StencilVertex start = new StencilVertex(); Vector2 last = new Vector2(); int index = 0; start.Set(0, 0, Constants.Coef_Solid); for (var s = path.FirstSegment; s != null; s = s.Next) { switch (s.Value.Type) { case VGPath.SegmentType.CurveTo: { vertices[index++].Set(last.X, last.Y, Constants.Coef_Solid); vertices[index++].Set(s.Value.Target.X, s.Value.Target.Y, Constants.Coef_Solid); vertices[index++] = start; vertices[index++].Set(last.X, last.Y, Constants.Coef_BezierStart); vertices[index++].Set(s.Value.Controls[0].X, s.Value.Controls[0].Y, Constants.Coef_BezierControl); vertices[index++].Set(s.Value.Target.X, s.Value.Target.Y, Constants.Coef_BezierEnd); } break; case VGPath.SegmentType.LineTo: case VGPath.SegmentType._Tesselated: { vertices[index++].Set(last.X, last.Y, Constants.Coef_Solid); vertices[index++].Set(s.Value.Target.X, s.Value.Target.Y, Constants.Coef_Solid); vertices[index++] = start; } break; case VGPath.SegmentType.MoveTo: { start.Set(s.Value.Target.X, s.Value.Target.Y, Constants.Coef_Solid); } break; default: continue; } last = s.Value.Target; } return true; }
internal StrokeMesh(GraphicsDevice device, VGPath path, VGLineCap startCap, VGLineCap endCap, VGLineJoin join, float miterLimit) { int solidCount, radialCount, i, j, moves; // No triangles at all, don't bother... if (path.IsEmpty) return; // Approximate triangle counts moves = path.GetCount(VGPath.SegmentType.MoveTo); GetCapTris(startCap, out i, out j); solidCount = moves * i; radialCount = moves * j; GetCapTris(endCap, out i, out j); solidCount += moves * i; radialCount += moves * j; GetJoinTris(join, out i, out j); solidCount += path.Count * i; radialCount += path.Count * j; solidCount += (path.GetCount(VGPath.SegmentType.LineTo) + path.GetCount(VGPath.SegmentType._Tesselated)) * 2; // Initialize _solid = new SolidStrokeBuilder(solidCount, miterLimit); _radial = new RadialStrokeBuilder(radialCount); var startCapFunc = GetCapFunction(startCap); var endCapFunc = GetCapFunction(endCap); var joinFunc = GetJoinFunction(join); // Tesselate VGPath.Segment last = null; Vector2 lastNormal = Vector2.Zero; var lastStart = path.FirstSegment; for (var s = lastStart; s != null; s = s.Next) { switch (s.Value.Type) { case VGPath.SegmentType.LineTo: { Vector2 n, mn; VectorMath.GetLeftNormal(last.Target, s.Value.Target, out n); mn = -n; _solid.AddVertex(last.Target, mn); _solid.AddVertex(last.Target, n); _solid.AddVertex(s.Value.Target, n); _solid.AddVertex(last.Target, mn); _solid.AddVertex(s.Value.Target, n); _solid.AddVertex(s.Value.Target, mn); } break; case VGPath.SegmentType._Tesselated: { if (last.Type != VGPath.SegmentType._Tesselated) VectorMath.GetLeftNormal(last.Target, s.Value.Target, out lastNormal); Vector2 lastRtNormal = -lastNormal; _solid.AddVertex(last.Target, lastRtNormal); _solid.AddVertex(last.Target, lastNormal); _solid.AddVertex(s.Value.Target, s.Value.Controls[0]); _solid.AddVertex(last.Target, lastRtNormal); _solid.AddVertex(s.Value.Target, s.Value.Controls[0]); _solid.AddVertex(s.Value.Target, -s.Value.Controls[0]); lastNormal = s.Value.Controls[0]; } break; case VGPath.SegmentType.MoveTo: { if (s.Previous != null && s.Previous.Value.Type != VGPath.SegmentType.Close && s.Previous.Value.Type != VGPath.SegmentType.MoveTo) { startCapFunc(lastStart, true); endCapFunc(s.Previous, false); } lastStart = s; } break; case VGPath.SegmentType.Close: break; default: throw new InvalidOperationException("Trying to stroke non-flattened path!"); } if (s.Value.MakeJoin && s.Next != null) joinFunc(s); last = s.Value; } // Do the caps if (path.LastSegment.Value.Type != VGPath.SegmentType.Close && path.LastSegment.Value.Type != VGPath.SegmentType.MoveTo) { startCapFunc(lastStart, true); endCapFunc(path.LastSegment, false); } // Create buffer _vertices[0] = _solid.Build(device, out _tris[0]); _vertices[1] = _radial.Build(device, out _tris[1]); // Free builders _radial = null; _solid = null; }