243 lines
6.5 KiB
C#
243 lines
6.5 KiB
C#
|
using System;
|
||
|
using HG;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.UI;
|
||
|
|
||
|
namespace RoR2.UI;
|
||
|
|
||
|
public class RadialSliceGraphic : MaskableGraphic
|
||
|
{
|
||
|
public struct DisplayData : IEquatable<DisplayData>
|
||
|
{
|
||
|
public Radians start;
|
||
|
|
||
|
public Radians end;
|
||
|
|
||
|
public float startU;
|
||
|
|
||
|
public float endU;
|
||
|
|
||
|
public Material material;
|
||
|
|
||
|
public Texture texture;
|
||
|
|
||
|
public Color color;
|
||
|
|
||
|
public float normalizedInnerRadius;
|
||
|
|
||
|
public Radians maxQuadWidth;
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
if (obj == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (obj is DisplayData other)
|
||
|
{
|
||
|
return Equals(other);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public static bool operator ==(DisplayData left, DisplayData right)
|
||
|
{
|
||
|
return left.Equals(right);
|
||
|
}
|
||
|
|
||
|
public static bool operator !=(DisplayData left, DisplayData right)
|
||
|
{
|
||
|
return !left.Equals(right);
|
||
|
}
|
||
|
|
||
|
public bool Equals(DisplayData other)
|
||
|
{
|
||
|
if (start.Equals(other.start) && end.Equals(other.end) && startU.Equals(other.startU) && endU.Equals(other.endU) && object.Equals(material, other.material) && object.Equals(texture, other.texture) && color.Equals(other.color) && normalizedInnerRadius.Equals(other.normalizedInnerRadius))
|
||
|
{
|
||
|
return maxQuadWidth.Equals(other.maxQuadWidth);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return (((((((((((((((start.GetHashCode() * 397) ^ end.GetHashCode()) * 397) ^ startU.GetHashCode()) * 397) ^ endU.GetHashCode()) * 397) ^ ((material != null) ? material.GetHashCode() : 0)) * 397) ^ ((texture != null) ? texture.GetHashCode() : 0)) * 397) ^ color.GetHashCode()) * 397) ^ normalizedInnerRadius.GetHashCode()) * 397) ^ maxQuadWidth.GetHashCode();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public RectTransform sliceCenterSticker;
|
||
|
|
||
|
private static readonly DisplayData defaultDisplayData;
|
||
|
|
||
|
private DisplayData displayData = defaultDisplayData;
|
||
|
|
||
|
private float currentRadius;
|
||
|
|
||
|
public override Texture mainTexture
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (!displayData.texture)
|
||
|
{
|
||
|
if (!displayData.material)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
return displayData.material.mainTexture;
|
||
|
}
|
||
|
return displayData.texture;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected RadialSliceGraphic()
|
||
|
{
|
||
|
base.useLegacyMeshGeneration = false;
|
||
|
}
|
||
|
|
||
|
public void SetDisplayData(in DisplayData newDisplayData)
|
||
|
{
|
||
|
if (!(newDisplayData == displayData))
|
||
|
{
|
||
|
displayData = newDisplayData;
|
||
|
UpdateDisplayData();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UpdateDisplayData()
|
||
|
{
|
||
|
if (material != displayData.material)
|
||
|
{
|
||
|
material = displayData.material;
|
||
|
}
|
||
|
if (color != displayData.color)
|
||
|
{
|
||
|
color = displayData.color;
|
||
|
}
|
||
|
base.SetVerticesDirty();
|
||
|
}
|
||
|
|
||
|
private static Vector2 GetDirection(Radians radians)
|
||
|
{
|
||
|
return new Vector2(Mathf.Cos((float)radians), Mathf.Sin((float)radians));
|
||
|
}
|
||
|
|
||
|
protected override void OnPopulateMesh(VertexHelper vh)
|
||
|
{
|
||
|
vh.Clear();
|
||
|
Rect rect = base.rectTransform.rect;
|
||
|
currentRadius = Mathf.Min(rect.width, rect.height) * 0.5f;
|
||
|
float outerRadius = currentRadius;
|
||
|
float innerRadius = outerRadius * displayData.normalizedInnerRadius;
|
||
|
Radians right = displayData.start;
|
||
|
Radians left = displayData.end;
|
||
|
float a = displayData.startU;
|
||
|
float b = displayData.endU;
|
||
|
if (left < right)
|
||
|
{
|
||
|
Util.Swap(ref right, ref left);
|
||
|
Util.Swap(ref a, ref b);
|
||
|
}
|
||
|
Radians radians = left - right;
|
||
|
if (!((float)radians <= 0f) && !((float)displayData.maxQuadWidth <= 0f))
|
||
|
{
|
||
|
int right2 = Mathf.CeilToInt((float)radians / (float)displayData.maxQuadWidth);
|
||
|
Radians right3 = radians / right2;
|
||
|
float num = 1f / (float)right2;
|
||
|
float num2 = b - a;
|
||
|
float quadStartU2 = a;
|
||
|
Vector2 startDirection2 = GetDirection(right);
|
||
|
Color color2 = color * displayData.color;
|
||
|
for (int i = 0; i < right2; i++)
|
||
|
{
|
||
|
int left2 = i + 1;
|
||
|
Radians right4 = left2 * right3;
|
||
|
Vector2 endDirection2 = GetDirection(right + right4);
|
||
|
float num3 = a + num2 * ((float)(i + 1) * num);
|
||
|
AddQuad(in startDirection2, in endDirection2, in color2, quadStartU2, num3);
|
||
|
startDirection2 = endDirection2;
|
||
|
quadStartU2 = num3;
|
||
|
}
|
||
|
}
|
||
|
void AddQuad(in Vector2 startDirection, in Vector2 endDirection, in Color color, float quadStartU, float quadEndU)
|
||
|
{
|
||
|
int currentVertCount = vh.currentVertCount;
|
||
|
vh.AddVert(startDirection * innerRadius, color, new Vector2(quadStartU, 0f));
|
||
|
vh.AddVert(startDirection * outerRadius, color, new Vector2(quadStartU, 1f));
|
||
|
vh.AddVert(endDirection * outerRadius, color, new Vector2(quadEndU, 1f));
|
||
|
vh.AddVert(endDirection * innerRadius, color, new Vector2(quadEndU, 0f));
|
||
|
vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2);
|
||
|
vh.AddTriangle(currentVertCount + 2, currentVertCount + 3, currentVertCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool Raycast(Vector2 sp, Camera eventCamera)
|
||
|
{
|
||
|
if (!base.Raycast(sp, eventCamera))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(base.rectTransform, sp, eventCamera, out var localPoint))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
Color white = Color.white;
|
||
|
bool result = PointInArc(localPoint, displayData.start, displayData.end, displayData.normalizedInnerRadius * currentRadius, currentRadius);
|
||
|
color = white;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private static bool PointInArc(Vector2 point, Radians arcStart, Radians arcEnd, float arcInnerRadius, float arcOuterRadius)
|
||
|
{
|
||
|
Radians left = arcStart + arcEnd;
|
||
|
float right = 0.5f;
|
||
|
Vector2 direction = GetDirection(left * right);
|
||
|
Radians radians = (arcEnd - arcStart).absolute;
|
||
|
Vector2 normalized = point.normalized;
|
||
|
float num = Vector2.Dot(direction, normalized);
|
||
|
float num2 = Mathf.Cos((float)radians * 0.5f);
|
||
|
if (num < num2)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
float sqrMagnitude = point.sqrMagnitude;
|
||
|
if (sqrMagnitude < arcInnerRadius * arcInnerRadius)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (sqrMagnitude > arcOuterRadius * arcOuterRadius)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override void GraphicUpdateComplete()
|
||
|
{
|
||
|
base.GraphicUpdateComplete();
|
||
|
if ((bool)sliceCenterSticker)
|
||
|
{
|
||
|
float floatValue = Mathf.LerpAngle((float)displayData.start, (float)displayData.end, 0.5f);
|
||
|
Radians radians = (Radians)floatValue;
|
||
|
float num = Mathf.Lerp(displayData.normalizedInnerRadius, 1f, 0.5f) * currentRadius;
|
||
|
Vector3 localPosition = new Vector3(radians.cos * num, radians.sin * num);
|
||
|
sliceCenterSticker.localPosition = localPosition;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static RadialSliceGraphic()
|
||
|
{
|
||
|
DisplayData displayData = new DisplayData
|
||
|
{
|
||
|
color = Color.white,
|
||
|
start = Radians.FromRevolutions(0f),
|
||
|
end = Radians.FromRevolutions(-0.4f),
|
||
|
startU = 0f,
|
||
|
endU = 1f
|
||
|
};
|
||
|
float floatValue = MathF.PI / 10f;
|
||
|
displayData.maxQuadWidth = (Radians)floatValue;
|
||
|
displayData.normalizedInnerRadius = 0.2f;
|
||
|
defaultDisplayData = displayData;
|
||
|
}
|
||
|
}
|