private const float RightStartAngle = 0; private const float RightEndAngle = (float) (2 * Math.PI); private void FillTriangleFan(Vector2 center, ref Span vs, Color color, Texture2D texture) { var c = vs.Length; if (c < 2) throw new ArgumentException(@"Need at least 3 vertices for a triangle fan.", nameof(vs)); var renderItem = MakeRenderItem(texture, color.A); var texWidth = texture?.Width ?? 1; var texHeight = texture?.Height ?? 1; var texDiameter = (float) Math.Min(texWidth, texHeight); var u = texDiameter / (float) texWidth; var v = texDiameter / (float) texHeight; var ul = (1f - u) / 2; var ut = (1f - v) / 2; var point5 = new Vector2(0.5f, 0.5f); var centerIndex = AddVertex(center, color, point5); var rs = Vector2.Distance(center, vs[0]); var imageRect = Rectangle.FromHalfExtents(center, rs); var uvRect = new Rectangle(ul, ut, u, v); var uv1 = Rectangle.MapVec2(vs[0], imageRect, uvRect); var v1 = AddVertex(vs[0], color, uv1); for (var i = 1; i < c; i++) { var uv = Rectangle.MapVec2(vs[i], imageRect, uvRect); var v2 = AddVertex(vs[i], color, uv); renderItem.AddIndex(centerIndex); renderItem.AddIndex(v1); renderItem.AddIndex(v2); v1 = v2; } IncreaseLayer(); } /// /// Draws a filled circle. /// /// The center point of the circle. /// The radius of the circle. /// The color to draw the circle with. /// https://youtu.be/hQ3GW7lVBWY public void FillCircle(Vector2 center, float radius, Color color, float maxError = 0.25f) { FillCircle(center, radius, color, null, maxError); } public void FillCircle(Vector2 center, float radius, Color color, Texture2D texture, float maxError = 0.000001f) { FillCircleSegment(center, radius, RightStartAngle, RightEndAngle, color, texture, maxError); } void IFontStashRenderer.Draw(object texture, Vector2 pos, System.Drawing.Rectangle? src, System.Drawing.Color color, float rotation, Vector2 origin, Vector2 scale, float depth) { var tsTexture = texture as Texture2D; // var rotate = Matrix4x4.CreateRotationZ(rotation); // var scaleMatrix = Matrix4x4.CreateScale(scale.X, scale.Y, 1); // var transform = scaleMatrix * rotate; pos -= origin; var tsColor = new Color(color.R, color.G, color.B, color.A); var tsRectangle = Rectangle.Unit; var tsDrawRect = new Rectangle(0, 0, tsTexture.Width, tsTexture.Height); if (src != null) { tsRectangle.X = (float) src?.Left / tsTexture.Width; tsRectangle.Width = (float) src?.Width / tsTexture.Width; tsRectangle.Y = (float) src?.Top / tsTexture.Height; tsRectangle.Height = (float) src?.Height / tsTexture.Height; tsDrawRect.Width = (float) src?.Width; tsDrawRect.Height = (float) src?.Height; } tsDrawRect.X = pos.X; tsDrawRect.Y = pos.Y; // We can't use this method to draw the text // since it increases the sort layer. // // So we'll do it ourselves, in-line. // FillRectangle(tsDrawRect, tsColor, tsTexture, tsRectangle); var ri = MakeRenderItem(tsTexture, tsColor.A); var vtl = AddVertex(tsDrawRect.Location, tsColor, tsRectangle.Location); var vbr = AddVertex(tsDrawRect.Location + tsDrawRect.Size, tsColor, tsRectangle.Location + tsRectangle.Size); var vbl = AddVertex(tsDrawRect.Location + new Vector2(0, tsDrawRect.Height), tsColor, tsRectangle.Location + new Vector2(0, tsRectangle.Height)); var vtr = AddVertex(tsDrawRect.Location + new Vector2(tsDrawRect.Width, 0), tsColor, tsRectangle.Location + new Vector2(tsRectangle.Width, 0)); ri.AddIndex(vtl); ri.AddIndex(vtr); ri.AddIndex(vbl); ri.AddIndex(vtr); ri.AddIndex(vbr); ri.AddIndex(vbl); } private static void CreateCircleSegment(Vector2 center, float radius, float step, float start, float end, ref Span result) { var i = 0; float theta; for (theta = start; theta < end; theta += step) result[i++] = new Vector2((float) (center.X + radius * Math.Cos(theta)), (float) (center.Y + radius * Math.Sin(theta))); if (theta != end) result[i] = center + new Vector2((float) (radius * Math.Cos(end)), (float) (radius * Math.Sin(end))); } private void FillCircleSegment(Vector2 center, float radius, float start, float end, Color color, Texture2D texture, float maxError) { if (radius <= 0) return; if (color.A <= 0) return; ComputeCircleSegments(radius, maxError, end - start, out var step, out var segments); if (segments <= 0) return; Span points = stackalloc Vector2[segments + 1]; CreateCircleSegment(center, radius, step, start, end, ref points); FillTriangleFan(center, ref points, color, texture); } private void ComputeCircleSegments(float radius, float maxError, float range, out float step, out int segments) { var invErrRad = 1 - maxError / radius; step = (float) Math.Acos(2 * invErrRad * invErrRad - 1); segments = (int) (range / step + 0.999f); }