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;
}
};