private static void TessellatePath(BezierContour contour, PathProperties pathProps, List <Geometry> geoms, TessellationOptions tessellationOptions) { UnityEngine.Profiling.Profiler.BeginSample("TessellatePath"); if (pathProps.Stroke != null) { Vector2[] vertices; UInt16[] indices; VectorUtils.TessellatePath(contour, pathProps, tessellationOptions, out vertices, out indices); var color = pathProps.Stroke.Color; if (indices.Length > 0) { geoms.Add(new Geometry() { Vertices = vertices, Indices = indices, Color = color }); } } UnityEngine.Profiling.Profiler.EndSample(); }
/// <summary> /// Tessellates a path. /// </summary> /// <param name="contour">The path to tessellate</param> /// <param name="pathProps">The path properties</param> /// <param name="tessellateOptions">The tessellation options</param> /// <param name="vertices">The resulting vertices</param> /// <param name="indices">The resulting triangles</param> /// <remarks> /// The individual line segments generated during tessellation are made out of a set of ordered vertices. It is important /// to honor this ordering so joining and and capping connect properly with the existing vertices without generating dupes. /// The ordering assumed is as follows: /// The last two vertices of a piece must be such that the first is generated at the end with a positive half-thickness /// while the second vertex is at the end too but at a negative half-thickness. /// No assumptions are enforced for other vertices before the two last vertices. /// </remarks> public static void TessellatePath(BezierContour contour, PathProperties pathProps, TessellationOptions tessellateOptions, out Vector2[] vertices, out UInt16[] indices) { if (tessellateOptions.StepDistance < Epsilon) { throw new Exception("stepDistance too small"); } if (contour.Segments.Length < 2) { vertices = new Vector2[0]; indices = new UInt16[0]; return; } UnityEngine.Profiling.Profiler.BeginSample("TessellatePath"); float[] segmentLengths = VectorUtils.SegmentsLengths(contour.Segments, contour.Closed); // Approximate the number of vertices/indices we need to store the results so we reduce memory reallocations during work float approxTotalLength = 0.0f; foreach (var s in segmentLengths) { approxTotalLength += s; } int approxStepCount = Math.Max((int)(approxTotalLength / tessellateOptions.StepDistance + 0.5f), 2); if (pathProps.Stroke.Pattern != null) { approxStepCount += pathProps.Stroke.Pattern.Length * 2; } List <Vector2> verts = new List <Vector2>(approxStepCount * 2 + 32); // A little bit possibly for the endings List <UInt16> inds = new List <UInt16>((int)(verts.Capacity * 1.5f)); // Usually every 4 verts represent a quad that uses 6 indices var patternIt = new PathPatternIterator(pathProps.Stroke.Pattern, pathProps.Stroke.PatternOffset); var pathIt = new PathDistanceForwardIterator(contour.Segments, contour.Closed, tessellateOptions.MaxCordDeviationSquared, tessellateOptions.MaxTanAngleDeviationCosine, tessellateOptions.SamplingStepSize); JoiningInfo[] joiningInfo = new JoiningInfo[2]; HandleNewSegmentJoining(pathIt, patternIt, joiningInfo, pathProps.Stroke.HalfThickness, segmentLengths); int rangeIndex = 0; while (!pathIt.Ended) { if (patternIt.IsSolid) { TessellateRange(patternIt.SegmentLength, pathIt, patternIt, pathProps, tessellateOptions, joiningInfo, segmentLengths, approxTotalLength, rangeIndex++, verts, inds); } else { SkipRange(patternIt.SegmentLength, pathIt, patternIt, pathProps, joiningInfo, segmentLengths); } patternIt.Advance(); } vertices = verts.ToArray(); indices = inds.ToArray(); UnityEngine.Profiling.Profiler.EndSample(); }
static Vector2[] TraceShape(BezierContour contour, Stroke stroke, TessellationOptions tessellateOptions) { if (tessellateOptions.StepDistance < Epsilon) { throw new Exception("stepDistance too small"); } if (contour.Segments.Length < 2) { return(new Vector2[0]); } float[] segmentLengths = VectorUtils.SegmentsLengths(contour.Segments, contour.Closed); // Approximate the number of vertices/indices we need to store the results so we reduce memory reallocations during work float approxTotalLength = 0.0f; foreach (var s in segmentLengths) { approxTotalLength += s; } int approxStepCount = Math.Max((int)(approxTotalLength / tessellateOptions.StepDistance + 0.5f), 2); var strokePattern = stroke != null ? stroke.Pattern : null; var strokePatternOffset = stroke != null ? stroke.PatternOffset : 0.0f; if (strokePattern != null) { approxStepCount += strokePattern.Length * 2; } List <Vector2> verts = new List <Vector2>(approxStepCount); // A little bit possibly for the endings var patternIt = new PathPatternIterator(strokePattern, strokePatternOffset); var pathIt = new PathDistanceForwardIterator(contour.Segments, true, tessellateOptions.MaxCordDeviationSquared, tessellateOptions.MaxTanAngleDeviationCosine, tessellateOptions.SamplingStepSize); verts.Add(pathIt.EvalCurrent()); while (!pathIt.Ended) { float distance = patternIt.SegmentLength; float startingLength = pathIt.LengthSoFar; float unitsRemaining = Mathf.Min(tessellateOptions.StepDistance, distance); bool endedEntirePath = false; for (;;) { var result = pathIt.AdvanceBy(unitsRemaining, out unitsRemaining); if (result == PathDistanceForwardIterator.Result.Ended) { endedEntirePath = true; break; } else if (result == PathDistanceForwardIterator.Result.NewSegment) { verts.Add(pathIt.EvalCurrent()); } if ((unitsRemaining <= Epsilon) && !TryGetMoreRemainingUnits(ref unitsRemaining, pathIt, startingLength, distance, tessellateOptions.StepDistance)) { break; } if (result == PathDistanceForwardIterator.Result.Stepped) { verts.Add(pathIt.EvalCurrent()); } } // Ending if (endedEntirePath) { break; } else { verts.Add(pathIt.EvalCurrent()); } patternIt.Advance(); } if ((verts[0] - verts[verts.Count - 1]).sqrMagnitude < Epsilon) { verts.RemoveAt(verts.Count - 1); } return(verts.ToArray()); // Why not return verts itself? }