From 09414f90020eea4b829e199bb43b00ab434982ee Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 10 Dec 2024 10:42:40 +0100 Subject: [PATCH] Add blend space drawing in Multi Blend 2D editor #1980 --- .../Archetypes/Animation.MultiBlend.cs | 326 ++++++++++++++---- Source/Engine/Render2D/Render2D.cpp | 84 ++++- Source/Engine/Render2D/Render2D.h | 25 +- Source/Engine/Utilities/Delaunay2D.h | 54 ++- 4 files changed, 395 insertions(+), 94 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs b/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs index 10a802291..b0d7169cc 100644 --- a/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs +++ b/Source/Editor/Surface/Archetypes/Animation.MultiBlend.cs @@ -30,7 +30,7 @@ namespace FlaxEditor.Surface.Archetypes /// Represents single blend point. /// /// - protected class BlendPoint : Control + internal class BlendPoint : Control { private readonly BlendPointsEditor _editor; private readonly int _index; @@ -48,6 +48,11 @@ namespace FlaxEditor.Surface.Archetypes /// public int Index => _index; + /// + /// Flag that indicates that user is moving this point with a mouse. + /// + public bool IsMouseDown => _isMouseDown; + /// /// Initializes a new instance of the class. /// @@ -211,6 +216,11 @@ namespace FlaxEditor.Surface.Archetypes /// public int PointsCount => (_node.Values.Length - 4) / 2; // 4 node values + 2 per blend point + /// + /// BLend points array. + /// + internal IReadOnlyList BlendPoints => _blendPoints; + /// /// Initializes a new instance of the class. /// @@ -374,6 +384,12 @@ namespace FlaxEditor.Surface.Archetypes /// The blend point control position. public Float2 BlendSpacePosToBlendPointPos(Float2 pos) { + if (_rangeX.IsZero) + { + var data0 = (Float4)_node.Values[0]; + _rangeX = new Float2(data0.X, data0.Y); + _rangeY = _is2D ? new Float2(data0.Z, data0.W) : Float2.Zero; + } GetPointsArea(out var pointsArea); if (_is2D) { @@ -389,7 +405,7 @@ namespace FlaxEditor.Surface.Archetypes pointsArea.Center.Y ); } - return pos - new Float2(BlendPoint.DefaultSize * 0.5f); + return pos; } /// @@ -532,81 +548,18 @@ namespace FlaxEditor.Surface.Archetypes SetAsset((int)b.Tag, Guid.Empty); } - private void DrawAxis(bool vertical, Float2 start, Float2 end, ref Color gridColor, ref Color labelColor, Font labelFont, float value, bool isLast) - { - // Draw line - Render2D.DrawLine(start, end, gridColor); - - // Draw label - var labelWidth = 50.0f; - var labelHeight = 10.0f; - var labelMargin = 2.0f; - string label = Utils.RoundTo2DecimalPlaces(value).ToString(System.Globalization.CultureInfo.InvariantCulture); - var hAlign = TextAlignment.Near; - Rectangle labelRect; - if (vertical) - { - labelRect = new Rectangle(start.X + labelMargin * 2, start.Y, labelWidth, labelHeight); - if (isLast) - return; // Don't overlap with the first horizontal label - } - else - { - labelRect = new Rectangle(start.X + labelMargin, start.Y - labelHeight - labelMargin, labelWidth, labelHeight); - if (isLast) - { - labelRect.X = start.X - labelMargin - labelRect.Width; - hAlign = TextAlignment.Far; - } - } - Render2D.DrawText(labelFont, label, labelRect, labelColor, hAlign, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, 0.7f); - } - /// public override void Draw() { var style = Style.Current; var rect = new Rectangle(Float2.Zero, Size); var containsFocus = ContainsFocus; - GetPointsArea(out var pointsArea); - var data0 = (Float4)_node.Values[0]; - var rangeX = new Float2(data0.X, data0.Y); // Background - Render2D.DrawRectangle(rect, IsMouseOver ? style.TextBoxBackgroundSelected : style.TextBoxBackground); - //Render2D.DrawRectangle(pointsArea, Color.Red); + _node.DrawEditorBackground(ref rect); // Grid - int splits = 10; - var gridColor = style.TextBoxBackgroundSelected * 1.1f; - var labelColor = style.ForegroundDisabled; - var labelFont = style.FontSmall; - //var blendArea = BlendAreaRect; - var blendArea = pointsArea; - - for (int i = 0; i <= splits; i++) - { - float alpha = (float)i / splits; - float x = blendArea.Left + blendArea.Width * alpha; - float value = Mathf.Lerp(rangeX.X, rangeX.Y, alpha); - DrawAxis(false, new Float2(x, rect.Height - 2), new Float2(x, 1), ref gridColor, ref labelColor, labelFont, value, i == splits); - } - if (_is2D) - { - var rangeY = new Float2(data0.Z, data0.W); - for (int i = 0; i <= splits; i++) - { - float alpha = (float)i / splits; - float y = blendArea.Top + blendArea.Height * alpha; - float value = Mathf.Lerp(rangeY.X, rangeY.Y, 1.0f - alpha); - DrawAxis(true, new Float2(1, y), new Float2(rect.Width - 2, y), ref gridColor, ref labelColor, labelFont, value, i == splits); - } - } - else - { - float y = blendArea.Center.Y; - Render2D.DrawLine(new Float2(1, y), new Float2(rect.Width - 2, y), gridColor); - } + _node.DrawEditorGrid(ref rect); base.Draw(); @@ -808,6 +761,87 @@ namespace FlaxEditor.Surface.Archetypes _editor.SetAsset(SelectedAnimationIndex, Guid.Empty); } + private void DrawAxis(bool vertical, Float2 start, Float2 end, ref Color gridColor, ref Color labelColor, Font labelFont, float value, bool isLast) + { + // Draw line + Render2D.DrawLine(start, end, gridColor); + + // Draw label + var labelWidth = 50.0f; + var labelHeight = 10.0f; + var labelMargin = 2.0f; + string label = Utils.RoundTo2DecimalPlaces(value).ToString(System.Globalization.CultureInfo.InvariantCulture); + var hAlign = TextAlignment.Near; + Rectangle labelRect; + if (vertical) + { + labelRect = new Rectangle(start.X + labelMargin * 2, start.Y, labelWidth, labelHeight); + if (isLast) + return; // Don't overlap with the first horizontal label + } + else + { + labelRect = new Rectangle(start.X + labelMargin, start.Y - labelHeight - labelMargin, labelWidth, labelHeight); + if (isLast) + { + labelRect.X = start.X - labelMargin - labelRect.Width; + hAlign = TextAlignment.Far; + } + } + Render2D.DrawText(labelFont, label, labelRect, labelColor, hAlign, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, 0.7f); + } + + /// + /// Custom drawing logic for blend space background. + /// + public virtual void DrawEditorBackground(ref Rectangle rect) + { + var style = Style.Current; + Render2D.FillRectangle(rect, style.Background.AlphaMultiplied(0.5f)); + Render2D.DrawRectangle(rect, IsMouseOver ? style.TextBoxBackgroundSelected : style.TextBoxBackground); + } + + /// + /// Custom drawing logic for blend space grid. + /// + public virtual void DrawEditorGrid(ref Rectangle rect) + { + var style = Style.Current; + _editor.GetPointsArea(out var pointsArea); + var data0 = (Float4)Values[0]; + var rangeX = new Float2(data0.X, data0.Y); + int splits = 10; + var gridColor = style.TextBoxBackgroundSelected * 1.1f; + var labelColor = style.ForegroundDisabled; + var labelFont = style.FontSmall; + //var blendArea = BlendAreaRect; + var blendArea = pointsArea; + + for (int i = 0; i <= splits; i++) + { + float alpha = (float)i / splits; + float x = blendArea.Left + blendArea.Width * alpha; + float value = Mathf.Lerp(rangeX.X, rangeX.Y, alpha); + DrawAxis(false, new Float2(x, rect.Height - 2), new Float2(x, 1), ref gridColor, ref labelColor, labelFont, value, i == splits); + } + if (_editor.Is2D) + { + var rangeY = new Float2(data0.Z, data0.W); + for (int i = 0; i <= splits; i++) + { + float alpha = (float)i / splits; + float y = blendArea.Top + blendArea.Height * alpha; + float value = Mathf.Lerp(rangeY.X, rangeY.Y, 1.0f - alpha); + DrawAxis(true, new Float2(1, y), new Float2(rect.Width - 2, y), ref gridColor, ref labelColor, labelFont, value, i == splits); + } + } + else + { + float y = blendArea.Center.Y; + Render2D.DrawLine(new Float2(1, y), new Float2(rect.Width - 2, y), gridColor); + } + } + /// /// Updates the editor UI. /// @@ -972,6 +1006,10 @@ namespace FlaxEditor.Surface.Archetypes private readonly FloatValueBox _animationX; private readonly Label _animationYLabel; private readonly FloatValueBox _animationY; + private Float2[] _triangles; + private Color[] _triangleColors; + private Float2[] _selectedTriangles; + private Color[] _selectedColors; /// public MultiBlend2D(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) @@ -1040,6 +1078,143 @@ namespace FlaxEditor.Surface.Archetypes } } + private void ClearTriangles() + { + // Remove cache + _triangles = null; + _triangleColors = null; + _selectedTriangles = null; + _selectedColors = null; + } + + private void CacheTriangles() + { + // Get locations of blend point vertices + int pointsCount = _editor.PointsCount; + int count = 0, j = 0; + for (int i = 0; i < pointsCount; i++) + { + var animId = (Guid)Values[5 + i * 2]; + if (animId != Guid.Empty) + count++; + } + var vertices = new Float2[count]; + for (int i = 0; i < pointsCount; i++) + { + var animId = (Guid)Values[5 + i * 2]; + if (animId != Guid.Empty) + { + var dataA = (Float4)Values[4 + i * 2]; + vertices[j++] = new Float2(dataA.X, dataA.Y); + } + } + + // Triangulate + _triangles = FlaxEngine.Utilities.Delaunay2D.Triangulate(vertices); + _triangleColors = null; + + // Fix incorrect triangles (mirror logic in AnimGraphBase::onNodeLoaded) + if (_triangles == null || _triangles.Length == 0) + { + // Insert dummy triangles to have something working (eg. blend points are on the same axis) + var triangles = new List(); + int verticesLeft = vertices.Length; + while (verticesLeft >= 3) + { + verticesLeft -= 3; + triangles.Add(vertices[verticesLeft + 0]); + triangles.Add(vertices[verticesLeft + 1]); + triangles.Add(vertices[verticesLeft + 2]); + } + if (verticesLeft == 1) + { + triangles.Add(vertices[0]); + triangles.Add(vertices[0]); + triangles.Add(vertices[0]); + } + else if (verticesLeft == 2) + { + triangles.Add(vertices[0]); + triangles.Add(vertices[1]); + triangles.Add(vertices[0]); + } + _triangles = triangles.ToArray(); + } + + // Project to the blend space for drawing + for (int i = 0; i < _triangles.Length; i++) + _triangles[i] = _editor.BlendSpacePosToBlendPointPos(_triangles[i]); + + // Check if anything is selected + var selectedIndex = _selectedAnimation.SelectedIndex; + if (selectedIndex != -1) + { + // Find triangles that contain selected point + var dataA = (Float4)Values[4 + selectedIndex * 2]; + var pos = _editor.BlendSpacePosToBlendPointPos(new Float2(dataA.X, dataA.Y)); + var selectedTriangles = new List(); + var selectedColors = new List(); + var style = Style.Current; + var triangleColor = style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f); + var selectedTriangleColor = style.BackgroundSelected.AlphaMultiplied(0.6f); + _triangleColors = new Color[_triangles.Length]; + for (int i = 0; i < _triangles.Length; i += 3) + { + var is0 = Float2.NearEqual(ref _triangles[i + 0], ref pos); + var is1 = Float2.NearEqual(ref _triangles[i + 1], ref pos); + var is2 = Float2.NearEqual(ref _triangles[i + 2], ref pos); + if (is0 || is1 || is2) + { + selectedTriangles.Add(_triangles[i + 0]); + selectedTriangles.Add(_triangles[i + 1]); + selectedTriangles.Add(_triangles[i + 2]); + selectedColors.Add(is0 ? Color.White : Color.Transparent); + selectedColors.Add(is1 ? Color.White : Color.Transparent); + selectedColors.Add(is2 ? Color.White : Color.Transparent); + } + _triangleColors[i + 0] = is0 ? selectedTriangleColor : triangleColor; + _triangleColors[i + 1] = is1 ? selectedTriangleColor : triangleColor; + _triangleColors[i + 2] = is2 ? selectedTriangleColor : triangleColor; + } + _selectedTriangles = selectedTriangles.ToArray(); + _selectedColors = selectedColors.ToArray(); + } + } + + /// + public override void DrawEditorBackground(ref Rectangle rect) + { + base.DrawEditorBackground(ref rect); + + // Draw triangulated multi blend space + var style = Style.Current; + if (_triangles == null) + CacheTriangles(); + if (_triangleColors != null && (ContainsFocus || IsMouseOver)) + Render2D.FillTriangles(_triangles, _triangleColors); + else + Render2D.FillTriangles(_triangles, style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f)); + Render2D.DrawTriangles(_triangles, style.Foreground); + } + + /// + public override void DrawEditorGrid(ref Rectangle rect) + { + base.DrawEditorGrid(ref rect); + + // Highlight selected blend point + var style = Style.Current; + var selectedIndex = _selectedAnimation.SelectedIndex; + if (selectedIndex != -1 && (ContainsFocus || IsMouseOver)) + { + var point = _editor.BlendPoints[selectedIndex]; + var highlightColor = point.IsMouseDown ? style.SelectionBorder : style.BackgroundSelected; + Render2D.PushTint(ref highlightColor); + Render2D.DrawTriangles(_selectedTriangles, _selectedColors); + Render2D.PopTint(); + } + } + /// public override void UpdateUI(int selectedIndex, bool isValid, ref Float4 data0, ref Guid data1) { @@ -1064,6 +1239,23 @@ namespace FlaxEditor.Surface.Archetypes _animationX.Enabled = isValid; _animationYLabel.Enabled = isValid; _animationY.Enabled = isValid; + ClearTriangles(); + } + + /// + public override void OnValuesChanged() + { + base.OnValuesChanged(); + + ClearTriangles(); + } + + /// + public override void OnLoaded(SurfaceNodeActions action) + { + base.OnLoaded(action); + + ClearTriangles(); } } } diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 6f7c7043e..942cb9e0b 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -301,12 +301,12 @@ void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Float2 IBIndex += 3; } -void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Color& color0, const Color& color1, const Color& color2) +FORCE_INLINE void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Color& color0, const Color& color1, const Color& color2) { WriteTri(p0, p1, p2, Float2::Zero, Float2::Zero, Float2::Zero, color0, color1, color2); } -void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Float2& uv0, const Float2& uv1, const Float2& uv2) +FORCE_INLINE void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Float2& uv0, const Float2& uv1, const Float2& uv2) { WriteTri(p0, p1, p2, uv0, uv1, uv2, Color::Black, Color::Black, Color::Black); } @@ -1816,8 +1816,8 @@ void DrawLines(const Float2* points, int32 pointsCount, const Color& color1, con // Ending cap { - ApplyTransform(points[0], p1t); - ApplyTransform(points[1], p2t); + ApplyTransform(points[pointsCount - 2], p1t); + //ApplyTransform(points[pointsCount - 1], p2t); const Float2 capDirection = thicknessHalf * Float2::Normalize(p2t - p1t); @@ -1962,9 +1962,56 @@ void Render2D::DrawBlur(const Rectangle& rect, float blurStrength) WriteRect(rect, Color::White); } +void Render2D::DrawTriangles(const Span& vertices, const Color& color, float thickness) +{ + RENDER2D_CHECK_RENDERING_STATE; + CHECK(vertices.Length() % 3 == 0); + + Float2 points[2]; + for (int32 i = 0; i < vertices.Length(); i += 3) + { +#if 0 + // TODO: fix this + DrawLines(&vertices.Get()[i], 3, color, color, thickness); +#else + points[0] = vertices.Get()[i + 0]; + points[1] = vertices.Get()[i + 1]; + DrawLines(points, 2, color, color, thickness); + points[0] = vertices.Get()[i + 2]; + DrawLines(points, 2, color, color, thickness); + points[1] = vertices.Get()[i + 0]; + DrawLines(points, 2, color, color, thickness); +#endif + } +} + +void Render2D::DrawTriangles(const Span& vertices, const Span& colors, float thickness) +{ + RENDER2D_CHECK_RENDERING_STATE; + CHECK(vertices.Length() % 3 == 0); + + Float2 points[2]; + Color cols[2]; + for (int32 i = 0; i < vertices.Length(); i += 3) + { + points[0] = vertices.Get()[i + 0]; + points[1] = vertices.Get()[i + 1]; + cols[0] = colors.Get()[i + 0]; + cols[1] = colors.Get()[i + 1]; + DrawLines(points, 2, cols[0], cols[1], thickness); + points[0] = vertices.Get()[i + 2]; + cols[0] = colors.Get()[i + 2]; + DrawLines(points, 2, cols[0], cols[1], thickness); + points[1] = vertices.Get()[i + 0]; + cols[1] = colors.Get()[i + 0]; + DrawLines(points, 2, cols[0], cols[1], thickness); + } +} + void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& vertices, const Span& uvs) { RENDER2D_CHECK_RENDERING_STATE; + CHECK(vertices.Length() % 3 == 0); CHECK(vertices.Length() == uvs.Length()); Render2DDrawCall& drawCall = DrawCalls.AddOne(); @@ -1979,14 +2026,24 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& vertices void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& vertices, const Span& uvs, const Color& color) { - Color colors[3] = { (Color)color, (Color)color, (Color)color }; - Span spancolor(colors, 3); - DrawTexturedTriangles(t, vertices, uvs, spancolor); + RENDER2D_CHECK_RENDERING_STATE; + CHECK(vertices.Length() % 3 == 0); + CHECK(vertices.Length() == uvs.Length()); + + Render2DDrawCall& drawCall = DrawCalls.AddOne(); + drawCall.Type = DrawCallType::FillTexture; + drawCall.StartIB = IBIndex; + drawCall.CountIB = vertices.Length(); + drawCall.AsTexture.Ptr = t; + + for (int32 i = 0; i < vertices.Length(); i += 3) + WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], uvs[i], uvs[i + 1], uvs[i + 2], color, color, color); } void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& vertices, const Span& uvs, const Span& colors) { RENDER2D_CHECK_RENDERING_STATE; + CHECK(vertices.Length() % 3 == 0); CHECK(vertices.Length() == uvs.Length()); CHECK(vertices.Length() == colors.Length()); @@ -2021,6 +2078,19 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span& indices, } } +void Render2D::FillTriangles(const Span& vertices, const Color& color) +{ + RENDER2D_CHECK_RENDERING_STATE; + + Render2DDrawCall& drawCall = DrawCalls.AddOne(); + drawCall.Type = NeedAlphaWithTint(color) ? DrawCallType::FillRect : DrawCallType::FillRectNoAlpha; + drawCall.StartIB = IBIndex; + drawCall.CountIB = vertices.Length(); + + for (int32 i = 0; i < vertices.Length(); i += 3) + WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], color, color, color); +} + void Render2D::FillTriangles(const Span& vertices, const Span& colors, bool useAlpha) { CHECK(vertices.Length() == colors.Length()); diff --git a/Source/Engine/Render2D/Render2D.h b/Source/Engine/Render2D/Render2D.h index 5905fa434..886c9e664 100644 --- a/Source/Engine/Render2D/Render2D.h +++ b/Source/Engine/Render2D/Render2D.h @@ -415,6 +415,22 @@ public: /// The blur strength defines how blurry the background is. Larger numbers increase blur, resulting in a larger runtime cost on the GPU. API_FUNCTION() static void DrawBlur(const Rectangle& rect, float blurStrength); + /// + /// Draws vertices array. + /// + /// The vertices array. + /// The color. + /// The line thickness. + API_FUNCTION() static void DrawTriangles(const Span& vertices, const Color& color, float thickness = 1.0f); + + /// + /// Draws vertices array. + /// + /// The vertices array. + /// The colors array. + /// The line thickness. + API_FUNCTION() static void DrawTriangles(const Span& vertices, const Span& colors, float thickness = 1.0f); + /// /// Draws vertices array. /// @@ -451,13 +467,20 @@ public: /// The colors array. API_FUNCTION() static void DrawTexturedTriangles(GPUTexture* t, const Span& indices, const Span& vertices, const Span& uvs, const Span& colors); + /// + /// Draws vertices array. + /// + /// The vertices array. + /// The color. + API_FUNCTION() static void FillTriangles(const Span& vertices, const Color& color); + /// /// Draws vertices array. /// /// The vertices array. /// The colors array. /// If true alpha blending will be enabled. - API_FUNCTION() static void FillTriangles(const Span& vertices, const Span& colors, bool useAlpha); + API_FUNCTION() static void FillTriangles(const Span& vertices, const Span& colors, bool useAlpha = true); /// /// Fills a triangular area. diff --git a/Source/Engine/Utilities/Delaunay2D.h b/Source/Engine/Utilities/Delaunay2D.h index 766824bb9..3f1e25a7d 100644 --- a/Source/Engine/Utilities/Delaunay2D.h +++ b/Source/Engine/Utilities/Delaunay2D.h @@ -7,10 +7,11 @@ #include "Engine/Core/Collections/Array.h" /// -/// Helper class with Delaunay triangulation algorithm implementation, +/// Helper class with Delaunay triangulation algorithm implementation (2D space). /// -class Delaunay2D +API_CLASS(Internal, Static, Namespace="FlaxEngine.Utilities") class Delaunay2D { + DECLARE_SCRIPTING_TYPE_MINIMAL(Delaunay2D); public: struct Triangle { @@ -31,14 +32,35 @@ public: } }; - template - static void Triangulate(const TVertexArray& vertices, TTrianglesArray& triangles) + /// + /// Triangulates input vertices array into the list of triangle vertices. + /// + /// Input list of vertices. + /// Result list of triangles. Each triangle is made out of sequence of 3 vertices. Empty if no valid triangle built. + API_FUNCTION() static Array Triangulate(const Array& vertices) + { + Array triangles; + Triangulate(vertices, triangles); + Array result; + result.Resize(triangles.Count() * 3); + int32 c = 0; + for (const Triangle& t : triangles) + { + result.Get()[c++] = vertices[t.Indices[0]]; + result.Get()[c++] = vertices[t.Indices[1]]; + result.Get()[c++] = vertices[t.Indices[2]]; + } + return result; + } + + template + static void Triangulate(const Array& vertices, TrianglesArray& triangles) { // Skip if no change to produce any triangles - if (vertices.Count() < 3) + if (vertices.Count() < 3) return; - TVertexArray points = vertices; + Array points = vertices; Array polygon; Rectangle rect; @@ -142,8 +164,7 @@ private: } }; - template - static bool CircumCircleContains(const TVertexArray& vertices, const Triangle& triangle, int vertexIndex) + static bool CircumCircleContains(const Array& vertices, const Triangle& triangle, int32 vertexIndex) { Float2 p1 = vertices[triangle.Indices[0]]; Float2 p2 = vertices[triangle.Indices[1]]; @@ -157,25 +178,20 @@ private: (ab * (p3.Y - p2.Y) + cd * (p1.Y - p3.Y) + ef * (p2.Y - p1.Y)) / (p1.X * (p3.Y - p2.Y) + p2.X * (p1.Y - p3.Y) + p3.X * (p2.Y - p1.Y)), (ab * (p3.X - p2.X) + cd * (p1.X - p3.X) + ef * (p2.X - p1.X)) / (p1.Y * (p3.X - p2.X) + p2.Y * (p1.X - p3.X) + p3.Y * (p2.X - p1.X))); - circum *= 0.5; + circum *= 0.5f; float r = Float2::DistanceSquared(p1, circum); float d = Float2::DistanceSquared(vertices[vertexIndex], circum); return d <= r; } - template - static bool EdgeCompare(const TVertexArray& vertices, const Edge& a, const Edge& b) + static bool EdgeCompare(const Array& vertices, const Edge& a, const Edge& b) { - if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[0]]) < ZeroTolerance && Vector2::Distance(vertices[a.Indices[1]], vertices[b.Indices[1]]) < ZeroTolerance) - { + if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[0]]) < ZeroTolerance && + Float2::Distance(vertices[a.Indices[1]], vertices[b.Indices[1]]) < ZeroTolerance) return true; - } - - if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[1]]) < ZeroTolerance && Vector2::Distance(vertices[a.Indices[1]], vertices[b.Indices[0]]) < ZeroTolerance) - { + if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[1]]) < ZeroTolerance && + Float2::Distance(vertices[a.Indices[1]], vertices[b.Indices[0]]) < ZeroTolerance) return true; - } - return false; } };