RadialMenu and material nodes
This commit is contained in:
@@ -936,6 +936,142 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 43,
|
||||
Title = "Rotate UV [Simple Rotator]",
|
||||
Description = "Rotates 2d vector",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(250, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Uvs", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1,0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 44,
|
||||
Title = "Cone Gradient",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Uvs", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1,0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 45,
|
||||
Title = "Cycle Gradient",
|
||||
Description = "2d verison of sphere mask",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 20),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Uvs", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 1),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 46,
|
||||
Title = "Falloff and Offset",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 60),
|
||||
ConnectionsHints = ConnectionsHint.Numeric,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
0.9f
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Value", true, typeof(float), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Offset", true, typeof(float), 1,0),
|
||||
NodeElementArchetype.Factory.Input(2, "Falloff", true, typeof(float), 2,1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 3),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 47,
|
||||
Title = "Linear Gradient",
|
||||
Description = "x = Gradient along X axis, y = Gradient along Y axis",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 60),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
false
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Uvs", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1,0),
|
||||
NodeElementArchetype.Factory.Input(2, "Mirror", true, typeof(bool), 2,1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 3),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 48,
|
||||
Title = "Radial Gradient",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Uvs", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1,0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 49,
|
||||
Title = "Ring Gradient",
|
||||
Description = "x = InnerMask,y = OuterMask,z = Mask",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 80),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
1.0f,
|
||||
0.8f,
|
||||
0.05f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Uvs", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "OuterBounds", true, typeof(float), 1,0),
|
||||
NodeElementArchetype.Factory.Input(2, "InnerBounds", true, typeof(float), 2,1),
|
||||
NodeElementArchetype.Factory.Input(3, "Falloff", true, typeof(float), 3,2),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float3), 4),
|
||||
]
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,6 +569,110 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
// Do the inverse interpolation and saturate it
|
||||
value = writeLocal(ValueType::Float, String::Format(TEXT("saturate((({0} - {1}) / ({2} - {1})))"), gradient.Value, lowerEdge.Value, upperEdge.Value), node);
|
||||
}
|
||||
// Rotate UV [Rotator Simple]
|
||||
case 43:
|
||||
{
|
||||
//cosine = cos(rotation);
|
||||
//sine = sin(rotation);
|
||||
//float2 out = float2(cosine * uv.x + sine * uv.y,cosine * uv.y - sine * uv.x);
|
||||
const auto uv = tryGetValue(node->GetBox(0), getUVs).AsFloat2();
|
||||
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);
|
||||
break;
|
||||
}
|
||||
// Cone Gradient
|
||||
case 44:
|
||||
{
|
||||
//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);
|
||||
break;
|
||||
}
|
||||
// Cycle Gradient
|
||||
case 45:
|
||||
{
|
||||
//float gradient = 1 - lenght(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);
|
||||
break;
|
||||
}
|
||||
//Falloff and Offset
|
||||
case 46:
|
||||
{
|
||||
//float out = clamp((((Value - (1 - Offset)) + Falloff) / Falloff),0,1)
|
||||
const auto Value = tryGetValue(node->GetBox(0), ShaderGraphValue(0.0f));
|
||||
const auto Offset = tryGetValue(node->GetBox(1), node->Values[0].AsFloat);
|
||||
const auto Falloff = tryGetValue(node->GetBox(2), node->Values[1].AsFloat);
|
||||
|
||||
value = writeLocal(ValueType::Float, String::Format(TEXT("clamp(((({0} - (1 - {1})) + {2}) / {2}),0,1)"), Value.Value, Offset.Value, Falloff.Value), node);
|
||||
break;
|
||||
}
|
||||
//Linear Gradient
|
||||
case 47:
|
||||
{
|
||||
// float2 uv = Input0.xy;
|
||||
// float r = Input0.z;
|
||||
// float2 A = 1.0 - float2(cos(r) * uv.x + sin(r) * uv.y, cos(r) * uv.y - sin(r) * uv.x);
|
||||
// float2 out = float2(Mirror ? abs(A.x < 1.0 ? (A.x - 0.5) * 2 : (2 - ((A.x - 0.5) * 2)) * -1) : A.x < 1.0 ? (A.x - 0.5) * 2 : 1,Mirror ? abs(A.y < 1.0 ? (A.y - 0.5) * 2 : (2 - ((A.y - 0.5) * 2)) * -1) : A.y < 1.0 ? (A.y - 0.5) * 2 : 1);
|
||||
|
||||
const auto uv = tryGetValue(node->GetBox(0), getUVs).AsFloat2();
|
||||
const auto rotationAngle = tryGetValue(node->GetBox(1), node->Values[0].AsFloat).AsFloat();
|
||||
const auto Mirror = tryGetValue(node->GetBox(2), node->Values[1].AsBool).AsBool();
|
||||
|
||||
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);
|
||||
value = writeLocal(
|
||||
ValueType::Float2,
|
||||
String::Format(TEXT
|
||||
(
|
||||
"float2({0} ? abs({1}.x < 1.0 ? ({1}.x - 0.5) * 2 : (2 - (({1}.x - 0.5) * 2)) * -1) : {1}.x < 1.0 ? ({1}.x - 0.5) * 2 : 1,{0} ? abs({1}.y < 1.0 ? ({1}.y - 0.5) * 2 : (2 - (({1}.y - 0.5) * 2)) * -1) : {1}.y < 1.0 ? ({1}.y - 0.5) * 2 : 1)"
|
||||
),
|
||||
Mirror.Value,
|
||||
A.Value),
|
||||
node);
|
||||
break;
|
||||
}
|
||||
//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);
|
||||
break;
|
||||
}
|
||||
//Ring Gradient
|
||||
case 49:
|
||||
{
|
||||
// Nodes:
|
||||
// float c = CycleGradient(uv)
|
||||
// float InnerMask = FalloffAndOffset(c,(OuterBounds - Falloff),Falloff)
|
||||
// float OuterMask = FalloffAndOffset(1-c,1-InnerBounds,Falloff)
|
||||
// float Mask = OuterMask * InnerMask;
|
||||
|
||||
//ToDo: cheak if there is some useless operetors
|
||||
|
||||
//expanded
|
||||
//float cycleGradient = 1 - lenght(uv * 2);
|
||||
//float InnerMask = clamp((((c - (1 - (OuterBounds - Falloff))) + Falloff) / Falloff),0,1)
|
||||
//float OuterMask = clamp(((((1-c) - (1 - (1-InnerBounds))) + Falloff) / Falloff),0,1)
|
||||
//float Mask = OuterMask * InnerMask;
|
||||
|
||||
const auto uv = tryGetValue(node->GetBox(0), getUVs).AsFloat2();
|
||||
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 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);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
402
Source/Engine/UI/GUI/Special/RadialMenu.cs
Normal file
402
Source/Engine/UI/GUI/Special/RadialMenu.cs
Normal file
@@ -0,0 +1,402 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FlaxEngine.GUI
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </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 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;
|
||||
|
||||
/// <summary>
|
||||
/// The material
|
||||
/// </summary>
|
||||
[EditorOrder(1)]
|
||||
public MaterialBase Material
|
||||
{
|
||||
get => material;
|
||||
set
|
||||
{
|
||||
material = value;
|
||||
if (material == null)
|
||||
{
|
||||
FlaxEngine.Object.DestroyNow(MaterialInstance);
|
||||
MaterialInstance = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsDirty = 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;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_EdgeOffset = Math.Clamp(value, 0, 1);
|
||||
IsDirty = true;
|
||||
this.PerformLayout();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the thickness.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The thickness.
|
||||
/// </value>
|
||||
[EditorOrder(3), Range(0, 1), VisibleIf("ShowMatProp")]
|
||||
public float Thickness
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Thickness;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_Thickness = Math.Clamp(value, 0, 1);
|
||||
IsDirty = true;
|
||||
this.PerformLayout();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets control background color (transparent color (alpha=0) means no background rendering)
|
||||
/// </summary>
|
||||
[VisibleIf("ShowMatProp")]
|
||||
public new Color BackgroundColor //force overload
|
||||
{
|
||||
get => base.BackgroundColor;
|
||||
set
|
||||
{
|
||||
IsDirty = 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; } }
|
||||
/// <summary>
|
||||
/// Gets or sets the color of the forgraund.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The color of the forgraund.
|
||||
/// </value>
|
||||
[VisibleIf("ShowMatProp")]
|
||||
public Color ForgraundColor { get => forgraundColor; set { IsDirty = true; forgraundColor = 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; } }
|
||||
|
||||
/// <summary>
|
||||
/// The selected callback
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
public Action<int> Selected;
|
||||
|
||||
/// <summary>
|
||||
/// The allow change selection when inside
|
||||
/// </summary>
|
||||
[VisibleIf("ShowMatProp")]
|
||||
public bool AllowChangeSelectionWhenInside;
|
||||
/// <summary>
|
||||
/// The center as button
|
||||
/// </summary>
|
||||
[VisibleIf("ShowMatProp")]
|
||||
public bool CenterAsButton;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RadialMenu"/> class.
|
||||
/// </summary>
|
||||
public RadialMenu()
|
||||
: this(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RadialMenu"/> class.
|
||||
/// </summary>
|
||||
/// <param name="x">Position X coordinate</param>
|
||||
/// <param name="y">Position Y coordinate</param>
|
||||
/// <param name="width">Width</param>
|
||||
/// <param name="height">Height</param>
|
||||
public RadialMenu(float x, float y, float width = 100, float height = 100)
|
||||
: base(x, y, width, height)
|
||||
{
|
||||
var style = Style.Current;
|
||||
if (style != null)
|
||||
{
|
||||
BackgroundColor = style.BackgroundNormal;
|
||||
HighlightColor = style.BackgroundSelected;
|
||||
ForgraundColor = style.BackgroundHighlighted;
|
||||
SelectionColor = style.BackgroundSelected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RadialMenu"/> class.
|
||||
/// </summary>
|
||||
/// <param name="location">Position</param>
|
||||
/// <param name="size">Size</param>
|
||||
public RadialMenu(Float2 location, Float2 size)
|
||||
: this(location.X, location.Y, size.X, size.Y)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the control.
|
||||
/// </summary>
|
||||
public override void DrawSelf()
|
||||
{
|
||||
if (MaterialInstance != 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)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Material != null)
|
||||
{
|
||||
MaterialInstance = Material.CreateVirtualInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
if (MaterialInstance != null)
|
||||
{
|
||||
if (m_F_SelectedSegment == -1)
|
||||
{
|
||||
var min = ((1 - m_EdgeOffset) - m_Thickness) * USize * 0.5f;
|
||||
var max = (1 - m_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
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 val = ((USize * 0.5f) - location).Length;
|
||||
var c = val < min && CenterAsButton;
|
||||
var selected = (int)m_SelectedSegment;
|
||||
selected++;
|
||||
if (Mathf.IsInRange(val, min, max) || c)
|
||||
{
|
||||
if (c)
|
||||
{
|
||||
m_F_SelectedSegment = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_F_SelectedSegment = selected;
|
||||
}
|
||||
UpdateFSS();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_F_SelectedSegment = -1;
|
||||
UpdateFSS();
|
||||
}
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (MaterialInstance == null)
|
||||
return base.OnMouseDown(location, button);
|
||||
|
||||
if (m_F_SelectedSegment >= 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
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)
|
||||
return;
|
||||
|
||||
m_SelectedSegment = 0;
|
||||
m_F_SelectedSegment = -1;
|
||||
if (Selected != null)
|
||||
{
|
||||
Selected(m_F_SelectedSegment);
|
||||
}
|
||||
UpdateFSS();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void OnChildrenChanged()
|
||||
{
|
||||
m_SegmentCount = 0;
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
if (Children[i] is Image)
|
||||
{
|
||||
m_SegmentCount++;
|
||||
}
|
||||
}
|
||||
IsDirty = true;
|
||||
base.OnChildrenChanged();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public override void PerformLayout(bool force = false)
|
||||
{
|
||||
var Sa = -1.0f / m_SegmentCount * Mathf.TwoPi;
|
||||
var midp = USize * 0.5f;
|
||||
var mp = ((1 - m_EdgeOffset) - (m_Thickness * 0.5f)) * midp;
|
||||
float f = 0;
|
||||
if (m_SegmentCount % 2 != 0)
|
||||
{
|
||||
f += Sa * 0.5f;
|
||||
}
|
||||
if (MaterialInstance == null)
|
||||
{
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
Children[i].Center = Rotate2D(new Float2(0, mp), f) + midp;
|
||||
f += Sa;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
if (Children[i] is Image)
|
||||
{
|
||||
Children[i].Center = Rotate2D(new Float2(0, mp), f) + midp;
|
||||
f += Sa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.PerformLayout(force);
|
||||
}
|
||||
private 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user