internal VGPreparedPath(FillMesh fill, StrokeMesh stroke, VGLineCap startCap, VGLineCap endCap, VGLineJoin join, float miterLimit, Vector4 extents) { Fill = fill; Stroke = stroke; StartCap = startCap; EndCap = endCap; Join = join; MiterLimit = miterLimit; Extents = extents; }
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; }
private void GetCapTris(VGLineCap cap, out int solidTris, out int roundTris) { solidTris = roundTris = 0; switch (cap) { case VGLineCap.Butt: return; case VGLineCap.Round: roundTris = 2; return; case VGLineCap.Triangle: solidTris = 1; break; case VGLineCap.Square: solidTris = 2; break; default: throw new NotImplementedException("This cap style (" + cap + ") is not implemented!"); } }
private _Cap GetCapFunction(VGLineCap cap) { switch (cap) { case VGLineCap.Butt: return (a, b) => { }; case VGLineCap.Round: return MakeRoundCap; case VGLineCap.Triangle: return MakeTriangleCap; case VGLineCap.Square: return MakeSquareCap; default: throw new NotImplementedException("This cap style (" + cap + ") is not implemented!"); } }