Cleanup code

This commit is contained in:
Wojtek Figat
2024-06-11 09:48:53 +02:00
parent f95e7e96bf
commit 210c443b30
2 changed files with 189 additions and 202 deletions

View File

@@ -579,7 +579,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
const auto rotationAngle = tryGetValue(node->GetBox(1), node->Values[0].AsFloat).AsFloat();
auto c = writeLocal(ValueType::Float, String::Format(TEXT("cos({0})"), rotationAngle.Value), node);
auto s = writeLocal(ValueType::Float, String::Format(TEXT("sin({0})"), rotationAngle.Value), node);
value = writeLocal(ValueType::Float2, String::Format(TEXT("float2({1} * {0}.x + {2} * {0}.y,{1} * {0}.y - {2} * {0}.x)"), uv.Value, c.Value, s.Value), node);
value = writeLocal(ValueType::Float2, String::Format(TEXT("float2({1} * {0}.x + {2} * {0}.y, {1} * {0}.y - {2} * {0}.x)"), uv.Value, c.Value, s.Value), node);
break;
}
// Cone Gradient
@@ -588,7 +588,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
//float gradient = angle - abs(atan2(uv.x,uv.y));
const auto uv = tryGetValue(node->GetBox(0), getUVs).AsFloat2();
const auto rotationAngle = tryGetValue(node->GetBox(1), node->Values[0].AsFloat).AsFloat();
value = writeLocal(ValueType::Float, String::Format(TEXT("{1} - abs(atan2({0}.x,{0}.y))"), uv.Value, rotationAngle.Value), node);
value = writeLocal(ValueType::Float, String::Format(TEXT("{1} - abs(atan2({0}.x, {0}.y))"), uv.Value, rotationAngle.Value), node);
break;
}
// Cycle Gradient
@@ -596,7 +596,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
{
//float gradient = 1 - length(uv * 2);
const auto uv = tryGetValue(node->GetBox(0), getUVs).AsFloat2();
value = writeLocal(ValueType::Float, String::Format(TEXT("1 - length({0} * 2)"), uv.Value), node);
value = writeLocal(ValueType::Float, String::Format(TEXT("1 - length({0} * 2.0)"), uv.Value), node);
break;
}
// Falloff and Offset
@@ -623,7 +623,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
auto c = writeLocal(ValueType::Float, String::Format(TEXT("cos({0})"), rotationAngle.Value), node);
auto s = writeLocal(ValueType::Float, String::Format(TEXT("sin({0})"), rotationAngle.Value), node);
auto a = writeLocal(ValueType::Float2, String::Format(TEXT("1.0 - float2({1} * {0}.x + {2} * {0}.y,{1} * {0}.y - {2} * {0}.x)"), uv.Value, c.Value, s.Value), node);
auto a = writeLocal(ValueType::Float2, String::Format(TEXT("1.0 - float2({1} * {0}.x + {2} * {0}.y, {1} * {0}.y - {2} * {0}.x)"), uv.Value, c.Value, s.Value), node);
value = writeLocal(
ValueType::Float2, String::Format(TEXT
(
@@ -632,16 +632,16 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
node);
break;
}
//Radial Gradient
// Radial Gradient
case 48:
{
//float gradient = clamp(atan2(uv.x,uv.y) - angle,0.0,1.0);
const auto uv = tryGetValue(node->GetBox(0), getUVs).AsFloat2();
const auto rotationAngle = tryGetValue(node->GetBox(1), node->Values[0].AsFloat).AsFloat();
value = writeLocal(ValueType::Float, String::Format(TEXT("clamp(atan2({0}.x,{0}.y) - {1},0.0,1.0)"), uv.Value, rotationAngle.Value), node);
value = writeLocal(ValueType::Float, String::Format(TEXT("saturate(atan2({0}.x, {0}.y) - {1})"), uv.Value, rotationAngle.Value), node);
break;
}
//Ring Gradient
// Ring Gradient
case 49:
{
// Nodes:
@@ -662,11 +662,11 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
const auto outerBounds = tryGetValue(node->GetBox(1), node->Values[0].AsFloat).AsFloat();
const auto innerBounds = tryGetValue(node->GetBox(2), node->Values[1].AsFloat).AsFloat();
const auto falloff = tryGetValue(node->GetBox(3), node->Values[2].AsFloat).AsFloat();
auto c = writeLocal(ValueType::Float, String::Format(TEXT("1 - length({0} * 2)"), uv.Value), node);
auto innerMask = writeLocal(ValueType::Float, String::Format(TEXT("clamp(((({0} - (1 - ({1} - {2}))) + {2}) / {2}),0,1)"), c.Value, outerBounds.Value, falloff.Value), node);
auto outerMask = writeLocal(ValueType::Float, String::Format(TEXT("clamp(((((1-{0}) - (1 - (1-{1}))) + {2}) / {2}),0,1)"), c.Value, innerBounds.Value, falloff.Value), node);
auto c = writeLocal(ValueType::Float, String::Format(TEXT("1 - length({0} * 2.0)"), uv.Value), node);
auto innerMask = writeLocal(ValueType::Float, String::Format(TEXT("saturate(((({0} - (1.0 - ({1} - {2}))) + {2}) / {2}))"), c.Value, outerBounds.Value, falloff.Value), node);
auto outerMask = writeLocal(ValueType::Float, String::Format(TEXT("saturate(((((1.0 - {0}) - (1.0 - (1.0 - {1}))) + {2}) / {2}))"), c.Value, innerBounds.Value, falloff.Value), node);
auto mask = writeLocal(ValueType::Float, String::Format(TEXT("{0} * {1}"), innerMask.Value, outerMask.Value), node);
value = writeLocal(ValueType::Float3, String::Format(TEXT("float3({0},{1},{2})"), innerMask.Value, outerMask.Value, mask.Value), node);
value = writeLocal(ValueType::Float3, String::Format(TEXT("float3({0}, {1}, {2})"), innerMask.Value, outerMask.Value, mask.Value), node);
break;
}
default:

View File

@@ -1,132 +1,134 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FlaxEngine.GUI
{
/// <summary>
///
/// Radial menu control that arranges child controls (of type Image) in a circle.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
public class RadialMenu : ContainerControl
{
[NoSerialize] private bool IsDirty = true;
[NoSerialize] private float m_Angle;
[NoSerialize] private float m_SelectedSegment;
[NoSerialize] private int m_F_SelectedSegment = -1;
private bool _materialIsDirty = true;
private float _angle;
private float _selectedSegment;
private int _highlightSegment = -1;
private MaterialBase _material;
private MaterialInstance _materialInstance;
private int _segmentCount;
private Color _highlightColor;
private Color _foregroundColor;
private Color _selectionColor;
private float _edgeOffset;
private float _thickness = 0.2f;
private MaterialInstance MaterialInstance;
private sbyte m_SegmentCount;
private Color highlightColor;
private Color forgraundColor;
private Color selectionColor;
private float m_EdgeOffset;
private float m_Thickness = 0.0f;
private float USize => Size.X < Size.Y ? Size.X : Size.Y;
private bool ShowMatProp => MaterialInstance != null;
private MaterialBase material;
private bool ShowMatProp => _material != null;
/// <summary>
/// The material
/// The material to use for menu background drawing.
/// </summary>
[EditorOrder(1)]
public MaterialBase Material
{
get => material;
get => _material;
set
{
material = value;
if (material == null)
{
FlaxEngine.Object.DestroyNow(MaterialInstance);
MaterialInstance = null;
}
else
{
IsDirty = true;
}
if (_material == value)
return;
_material = value;
Object.DestroyNow(_materialInstance);
_materialInstance = null;
_materialIsDirty = true;
}
}
/// <summary>
/// Gets or sets the edge offset.
/// </summary>
/// <value>
/// The edge offset.
/// </value>
[EditorOrder(2), Range(0, 1)]
public float EdgeOffset
{
get
{
return m_EdgeOffset;
}
get => _edgeOffset;
set
{
m_EdgeOffset = Math.Clamp(value, 0, 1);
IsDirty = true;
this.PerformLayout();
_edgeOffset = Math.Clamp(value, 0, 1);
_materialIsDirty = true;
PerformLayout();
}
}
/// <summary>
/// Gets or sets the thickness.
/// </summary>
/// <value>
/// The thickness.
/// </value>
[EditorOrder(3), Range(0, 1), VisibleIf("ShowMatProp")]
[EditorOrder(3), Range(0, 1), VisibleIf(nameof(ShowMatProp))]
public float Thickness
{
get
{
return m_Thickness;
}
get => _thickness;
set
{
m_Thickness = Math.Clamp(value, 0, 1);
IsDirty = true;
this.PerformLayout();
_thickness = Math.Clamp(value, 0, 1);
_materialIsDirty = true;
PerformLayout();
}
}
/// <summary>
/// Gets or sets control background color (transparent color (alpha=0) means no background rendering)
/// Gets or sets control background color (transparent color (alpha=0) means no background rendering).
/// </summary>
[VisibleIf("ShowMatProp")]
public new Color BackgroundColor //force overload
[VisibleIf(nameof(ShowMatProp))]
public new Color BackgroundColor
{
get => base.BackgroundColor;
set
{
IsDirty = true;
_materialIsDirty = true;
base.BackgroundColor = value;
}
}
/// <summary>
/// Gets or sets the color of the highlight.
/// </summary>
/// <value>
/// The color of the highlight.
/// </value>
[VisibleIf("ShowMatProp")]
public Color HighlightColor { get => highlightColor; set { IsDirty = true; highlightColor = value; } }
[VisibleIf(nameof(ShowMatProp))]
public Color HighlightColor
{
get => _highlightColor;
set
{
_materialIsDirty = true;
_highlightColor = value;
}
}
/// <summary>
/// Gets or sets the color of the forgraund.
/// Gets or sets the color of the foreground.
/// </summary>
/// <value>
/// The color of the forgraund.
/// </value>
[VisibleIf("ShowMatProp")]
public Color ForgraundColor { get => forgraundColor; set { IsDirty = true; forgraundColor = value; } }
[VisibleIf(nameof(ShowMatProp))]
public Color ForegroundColor
{
get => _foregroundColor;
set
{
_materialIsDirty = true;
_foregroundColor = value;
}
}
/// <summary>
/// Gets or sets the color of the selection.
/// </summary>
/// <value>
/// The color of the selection.
/// </value>
[VisibleIf("ShowMatProp")]
public Color SelectionColor { get => selectionColor; set { IsDirty = true; selectionColor = value; } }
[VisibleIf(nameof(ShowMatProp))]
public Color SelectionColor
{
get => _selectionColor;
set
{
_materialIsDirty = true;
_selectionColor = value;
}
}
/// <summary>
/// The selected callback
@@ -137,15 +139,15 @@ namespace FlaxEngine.GUI
/// <summary>
/// The allow change selection when inside
/// </summary>
[VisibleIf("ShowMatProp")]
[VisibleIf(nameof(ShowMatProp))]
public bool AllowChangeSelectionWhenInside;
/// <summary>
/// The center as button
/// </summary>
[VisibleIf("ShowMatProp")]
[VisibleIf(nameof(ShowMatProp))]
public bool CenterAsButton;
/// <summary>
/// Initializes a new instance of the <see cref="RadialMenu"/> class.
/// </summary>
@@ -169,7 +171,7 @@ namespace FlaxEngine.GUI
{
BackgroundColor = style.BackgroundNormal;
HighlightColor = style.BackgroundSelected;
ForgraundColor = style.BackgroundHighlighted;
ForegroundColor = style.BackgroundHighlighted;
SelectionColor = style.BackgroundSelected;
}
}
@@ -184,199 +186,148 @@ namespace FlaxEngine.GUI
{
}
/// <summary>
/// Draws the control.
/// </summary>
/// <inheritdoc/>
public override void DrawSelf()
{
if (MaterialInstance != null)
if (_materialInstance == null && Material != null)
{
if (IsDirty)
{
MaterialInstance.SetParameterValue("RadialPieMenu_EdgeOffset", Math.Clamp(1 - m_EdgeOffset, 0, 1));
MaterialInstance.SetParameterValue("RadialPieMenu_Thickness", Math.Clamp(m_Thickness, 0, 1));
MaterialInstance.SetParameterValue("RadialPieMenu_Angle", ((float)1 / m_SegmentCount) * Mathf.Pi);
MaterialInstance.SetParameterValue("RadialPieMenu_SCount", m_SegmentCount);
MaterialInstance.SetParameterValue("RadialPieMenu_HighlightColor", HighlightColor);
MaterialInstance.SetParameterValue("RadialPieMenu_ForgraundColor", ForgraundColor);
MaterialInstance.SetParameterValue("RadialPieMenu_BackgroundColor", BackgroundColor);
MaterialInstance.SetParameterValue("RadialPieMenu_Rotation", -m_Angle + Mathf.Pi);
UpdateFSS();
IsDirty = false;
}
Render2D.DrawMaterial(MaterialInstance, new Rectangle(Float2.Zero, new Float2(Size.X < Size.Y ? Size.X : Size.Y)));
_materialInstance = Material.CreateVirtualInstance();
_materialIsDirty = true;
}
else
if (_materialInstance != null)
{
if (Material != null)
if (_materialIsDirty)
{
MaterialInstance = Material.CreateVirtualInstance();
_materialInstance.SetParameterValue("RadialMenu_EdgeOffset", Math.Clamp(1 - _edgeOffset, 0, 1));
_materialInstance.SetParameterValue("RadialMenu_Thickness", Math.Clamp(_thickness, 0, 1));
_materialInstance.SetParameterValue("RadialMenu_Angle", (1.0f / _segmentCount) * Mathf.Pi);
_materialInstance.SetParameterValue("RadialMenu_SegmentCount", _segmentCount);
_materialInstance.SetParameterValue("RadialMenu_HighlightColor", _highlightColor);
_materialInstance.SetParameterValue("RadialMenu_ForegroundColor", _foregroundColor);
_materialInstance.SetParameterValue("RadialMenu_BackgroundColor", BackgroundColor);
_materialInstance.SetParameterValue("RadialMenu_Rotation", -_angle + Mathf.Pi);
UpdateSelectionColor();
_materialIsDirty = false;
}
Render2D.DrawMaterial(_materialInstance, new Rectangle(Float2.Zero, new Float2(Size.X < Size.Y ? Size.X : Size.Y)));
}
}
/// <inheritdoc/>
public override void OnMouseMove(Float2 location)
{
if (MaterialInstance != null)
if (_materialInstance != null)
{
if (m_F_SelectedSegment == -1)
if (_highlightSegment == -1)
{
var min = ((1 - m_EdgeOffset) - m_Thickness) * USize * 0.5f;
var max = (1 - m_EdgeOffset) * USize * 0.5f;
var min = ((1 - _edgeOffset) - _thickness) * USize * 0.5f;
var max = (1 - _edgeOffset) * USize * 0.5f;
var val = ((USize * 0.5f) - location).Length;
if (Mathf.IsInRange(val, min, max) || val < min && AllowChangeSelectionWhenInside)
{
var size = new Float2(USize);
var p = (size * 0.5f) - location;
var Sa = ((float)1 / m_SegmentCount) * Mathf.TwoPi;
m_Angle = Mathf.Atan2(p.X, p.Y);
m_Angle = Mathf.Ceil((m_Angle - (Sa * 0.5f)) / Sa) * Sa;
m_SelectedSegment = m_Angle;
m_SelectedSegment = Mathf.RoundToInt((m_SelectedSegment < 0 ? Mathf.TwoPi + m_SelectedSegment : m_SelectedSegment) / Sa);
if (float.IsNaN(m_Angle) || float.IsInfinity(m_Angle))
m_Angle = 0;
MaterialInstance.SetParameterValue("RadialPieMenu_Rotation", -m_Angle + Mathf.Pi);
UpdateAngle(ref location);
}
}
}
base.OnMouseMove(location);
}
/// <inheritdoc/>
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (MaterialInstance == null)
if (_materialInstance == null)
return base.OnMouseDown(location, button);
var min = ((1 - m_EdgeOffset) - m_Thickness) * USize * 0.5f;
var max = (1 - m_EdgeOffset) * USize * 0.5f;
var min = ((1 - _edgeOffset) - _thickness) * USize * 0.5f;
var max = (1 - _edgeOffset) * USize * 0.5f;
var val = ((USize * 0.5f) - location).Length;
var c = val < min && CenterAsButton;
var selected = (int)m_SelectedSegment;
var selected = (int)_selectedSegment;
selected++;
if (Mathf.IsInRange(val, min, max) || c)
{
if (c)
{
m_F_SelectedSegment = 0;
}
else
{
m_F_SelectedSegment = selected;
}
UpdateFSS();
_highlightSegment = c ? 0 : selected;
UpdateSelectionColor();
return true;
}
else
{
m_F_SelectedSegment = -1;
UpdateFSS();
_highlightSegment = -1;
UpdateSelectionColor();
}
return base.OnMouseDown(location, button);
}
/// <inheritdoc/>
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (MaterialInstance == null)
if (_materialInstance == null)
return base.OnMouseDown(location, button);
if (m_F_SelectedSegment >= 0)
if (_highlightSegment >= 0)
{
if (Selected != null)
{
Selected(m_F_SelectedSegment);
}
m_F_SelectedSegment = -1;
UpdateFSS();
var min = ((1 - m_EdgeOffset) - m_Thickness) * USize * 0.5f;
var max = (1 - m_EdgeOffset) * USize * 0.5f;
Selected?.Invoke(_highlightSegment);
_highlightSegment = -1;
UpdateSelectionColor();
var min = ((1 - _edgeOffset) - _thickness) * USize * 0.5f;
var max = (1 - _edgeOffset) * USize * 0.5f;
var val = ((USize * 0.5f) - location).Length;
if (Mathf.IsInRange(val, min, max) || val < min && AllowChangeSelectionWhenInside)
{
var size = new Float2(USize);
var p = (size * 0.5f) - location;
var Sa = ((float)1 / m_SegmentCount) * Mathf.TwoPi;
m_Angle = Mathf.Atan2(p.X, p.Y);
m_Angle = Mathf.Ceil((m_Angle - (Sa * 0.5f)) / Sa) * Sa;
m_SelectedSegment = m_Angle;
m_SelectedSegment = Mathf.RoundToInt((m_SelectedSegment < 0 ? Mathf.TwoPi + m_SelectedSegment : m_SelectedSegment) / Sa);
if (float.IsNaN(m_Angle) || float.IsInfinity(m_Angle))
m_Angle = 0;
MaterialInstance.SetParameterValue("RadialPieMenu_Rotation", -m_Angle + Mathf.Pi);
UpdateAngle(ref location);
}
}
return base.OnMouseUp(location, button);
}
private void UpdateFSS()
{
if (m_F_SelectedSegment == -1)
{
MaterialInstance.SetParameterValue("RadialPieMenu_SelectionColor", ForgraundColor);
}
else
{
if (CenterAsButton)
{
if (m_F_SelectedSegment > 0)
{
MaterialInstance.SetParameterValue("RadialPieMenu_SelectionColor", SelectionColor);
}
else
{
MaterialInstance.SetParameterValue("RadialPieMenu_SelectionColor", ForgraundColor);
}
}
else
{
MaterialInstance.SetParameterValue("RadialPieMenu_SelectionColor", SelectionColor);
}
}
}
/// <inheritdoc/>
public override void OnMouseLeave()
{
if (MaterialInstance == null)
if (_materialInstance == null)
return;
m_SelectedSegment = 0;
m_F_SelectedSegment = -1;
if (Selected != null)
{
Selected(m_F_SelectedSegment);
}
UpdateFSS();
_selectedSegment = 0;
_highlightSegment = -1;
Selected?.Invoke(_highlightSegment);
UpdateSelectionColor();
}
/// <inheritdoc/>
public override void OnChildrenChanged()
{
m_SegmentCount = 0;
_segmentCount = 0;
for (int i = 0; i < Children.Count; i++)
{
if (Children[i] is Image)
{
m_SegmentCount++;
_segmentCount++;
}
}
IsDirty = true;
_materialIsDirty = true;
base.OnChildrenChanged();
}
/// <inheritdoc/>
public override void PerformLayout(bool force = false)
{
var Sa = -1.0f / m_SegmentCount * Mathf.TwoPi;
var sa = -1.0f / _segmentCount * Mathf.TwoPi;
var midp = USize * 0.5f;
var mp = ((1 - m_EdgeOffset) - (m_Thickness * 0.5f)) * midp;
var mp = ((1 - _edgeOffset) - (_thickness * 0.5f)) * midp;
float f = 0;
if (m_SegmentCount % 2 != 0)
if (_segmentCount % 2 != 0)
{
f += Sa * 0.5f;
f += sa * 0.5f;
}
if (MaterialInstance == null)
if (_materialInstance == null)
{
for (int i = 0; i < Children.Count; i++)
{
Children[i].Center = Rotate2D(new Float2(0, mp), f) + midp;
f += Sa;
f += sa;
}
}
else
@@ -386,17 +337,53 @@ namespace FlaxEngine.GUI
if (Children[i] is Image)
{
Children[i].Center = Rotate2D(new Float2(0, mp), f) + midp;
f += Sa;
f += sa;
}
}
}
base.PerformLayout(force);
}
private Float2 Rotate2D(Float2 point, float angle)
private void UpdateSelectionColor()
{
Color color;
if (_highlightSegment == -1)
{
color = _foregroundColor;
}
else
{
if (CenterAsButton)
{
color = _highlightSegment > 0 ? SelectionColor : _foregroundColor;
}
else
{
color = SelectionColor;
}
}
_materialInstance.SetParameterValue("RadialMenu_SelectionColor", color);
}
private void UpdateAngle(ref Float2 location)
{
var size = new Float2(USize);
var p = (size * 0.5f) - location;
var sa = (1.0f / _segmentCount) * Mathf.TwoPi;
_angle = Mathf.Atan2(p.X, p.Y);
_angle = Mathf.Ceil((_angle - (sa * 0.5f)) / sa) * sa;
_selectedSegment = _angle;
_selectedSegment = Mathf.RoundToInt((_selectedSegment < 0 ? Mathf.TwoPi + _selectedSegment : _selectedSegment) / sa);
if (float.IsNaN(_angle) || float.IsInfinity(_angle))
_angle = 0;
_materialInstance.SetParameterValue("RadialMenu_Rotation", -_angle + Mathf.Pi);
}
private static Float2 Rotate2D(Float2 point, float angle)
{
return new Float2(Mathf.Cos(angle) * point.X + Mathf.Sin(angle) * point.Y,
Mathf.Cos(angle) * point.Y - Mathf.Sin(angle) * point.X);
Mathf.Cos(angle) * point.Y - Mathf.Sin(angle) * point.X);
}
}
}