Files
aibis-dream/Assets/Shapes/Scripts/Runtime/Components/Quad.cs
T
2025-05-07 15:07:44 +08:00

292 lines
9.7 KiB
C#

using System;
using UnityEngine;
// Shapes © Freya Holmér - https://twitter.com/FreyaHolmer/
// Website & Documentation - https://acegikmo.com/shapes/
namespace Shapes {
/// <summary>A Quad shape component</summary>
[ExecuteAlways]
[AddComponentMenu( "Shapes/Quad" )]
public class Quad : ShapeRenderer {
/// <summary>Gradient color modes for the quad shape</summary>
public enum QuadColorMode {
/// <summary>A single color for the whole quad</summary>
Single,
/// <summary>Two colors running horizontally across the quad</summary>
Horizontal,
/// <summary>Two colors running vertically across the quad</summary>
Vertical,
/// <summary>One color per corner of the quad</summary>
PerCorner
}
/// <summary>Get or set vertex positions by index (clockwise)</summary>
/// <param name="index">A value from 0 to 3</param>
/// <exception cref="IndexOutOfRangeException"></exception>
public Vector3 this[ int index ] {
get {
switch( index ) {
case 0: return A;
case 1: return B;
case 2: return C;
case 3: return D;
default:
throw new IndexOutOfRangeException( $"Quad only has four vertices, 0 to 3, you tried to access element {index}" );
}
}
set {
switch( index ) {
case 0:
A = value;
break;
case 1:
B = value;
break;
case 2:
C = value;
break;
case 3:
D = value;
break;
default:
throw new IndexOutOfRangeException( $"Quad only has four vertices, 0 to 3, you tried to set element {index}" );
}
}
}
/// <summary>Get vertex positions by index (clockwise)</summary>
/// <param name="index">An index from 0 to 3</param>
public Vector3 GetQuadVertex( int index ) => this[index];
/// <summary>Set vertex positions by index (clockwise)</summary>
/// <param name="index">An index from 0 to 3</param>
/// <param name="value">The position to set the vertex to</param>
public Vector3 SetQuadVertex( int index, Vector3 value ) => this[index] = value;
/// <summary>Get vertex color by index (clockwise)</summary>
/// <param name="index">An index from 0 to 3</param>
public Color GetQuadColor( int index ) {
switch( index ) {
case 0: return Color;
case 1: return ColorB;
case 2: return ColorC;
case 3: return ColorD;
default:
throw new IndexOutOfRangeException( $"Quad only has four vertices, 0 to 3, you tried to access element {index}" );
}
}
/// <summary>Set vertex color by index (clockwise)</summary>
/// <param name="index">An index from 0 to 3</param>
/// <param name="color">The color to set the vertex to</param>
public void SetQuadColor( int index, Color color ) {
switch( index ) {
case 0:
Color = color;
break;
case 1:
ColorB = color;
break;
case 2:
ColorC = color;
break;
case 3:
ColorD = color;
break;
default:
throw new IndexOutOfRangeException( $"Quad only has four vertices, 0 to 3, you tried to set element {index}" );
}
}
[SerializeField] QuadColorMode colorMode = QuadColorMode.Single;
/// <summary>The color gradient mode to use on this quad</summary>
public QuadColorMode ColorMode {
get => colorMode;
set {
colorMode = value;
ApplyProperties();
}
}
[SerializeField] Vector3 a = new Vector2( -0.5f, -0.5f );
/// <summary>Get or set the position of the first vertex (clockwise)</summary>
public Vector3 A {
get => a;
set {
SetVector3Now( ShapesMaterialUtils.propA, a = value );
CheckAutoSetD();
}
}
[SerializeField] Vector3 b = new Vector2( -0.5f, 0.5f );
/// <summary>Get or set the position of the second vertex (clockwise)</summary>
public Vector3 B {
get => b;
set {
SetVector3Now( ShapesMaterialUtils.propB, b = value );
CheckAutoSetD();
}
}
[SerializeField] Vector3 c = new Vector2( 0.5f, 0.5f );
/// <summary>Get or set the position of the third vertex (clockwise)</summary>
public Vector3 C {
get => c;
set {
SetVector3Now( ShapesMaterialUtils.propC, c = value );
CheckAutoSetD();
}
}
[SerializeField] Vector3 d = new Vector2( 0.5f, -0.5f );
/// <summary>Get or set the position of the fourth vertex (clockwise)</summary>
public Vector3 D {
get => d;
set {
if( autoSetD )
Debug.LogWarning( "tried to set D when auto-set is enabled, you might want to turn off auto-set on this object", gameObject );
else
SetVector3Now( ShapesMaterialUtils.propD, d = value );
}
}
/// <summary>Whether or not the position of D should be automatically set based on the other points</summary>
public bool IsUsingAutoD {
get => autoSetD;
set {
autoSetD = value;
AutoSetD();
}
}
[SerializeField] bool autoSetD = false;
/// <summary>Get an auto-calculated fourth position based on the first three vertices</summary>
public Vector3 DAuto => A + ( C - B );
void AutoSetD() => SetVector3( ShapesMaterialUtils.propD, DAuto );
void CheckAutoSetD() {
if( autoSetD )
AutoSetD();
}
/// <summary>The color of this shape. The alpha channel is used for opacity/intensity in all blend modes</summary>
public override Color Color {
get => color;
set {
SetColor( ShapesMaterialUtils.propColor, color = value );
SetColor( ShapesMaterialUtils.propColorB, colorB = value );
SetColor( ShapesMaterialUtils.propColorC, colorC = value );
SetColorNow( ShapesMaterialUtils.propColorD, colorD = value );
}
}
/// <summary>The color on the left side (A and B) of this shape when using the horizontal gradient color mode</summary>
public Color ColorLeft {
get => color;
set {
SetColor( ShapesMaterialUtils.propColor, color = value );
SetColorNow( ShapesMaterialUtils.propColorB, colorB = value );
}
}
/// <summary>The color on the top side (B and C) of this shape when using the vertical gradient color mode</summary>
public Color ColorTop {
get => colorB;
set {
SetColor( ShapesMaterialUtils.propColorB, colorB = value );
SetColorNow( ShapesMaterialUtils.propColorC, colorC = value );
}
}
/// <summary>The color on the right side (C and D) of this shape when using the horizontal gradient color mode</summary>
public Color ColorRight {
get => colorC;
set {
SetColor( ShapesMaterialUtils.propColorC, colorC = value );
SetColorNow( ShapesMaterialUtils.propColorD, colorD = value );
}
}
/// <summary>The color on the bottom side (D and A) of this shape when using the vertical gradient color mode</summary>
public Color ColorBottom {
get => colorD;
set {
SetColor( ShapesMaterialUtils.propColorD, colorD = value );
SetColorNow( ShapesMaterialUtils.propColor, color = value );
}
}
/// <summary>Get or set the color of the first vertex (clockwise), when using the per-corner color mode</summary>
public Color ColorA {
get => color;
set => SetColorNow( ShapesMaterialUtils.propColor, color = value );
}
[SerializeField] [ShapesColorField( true )] Color colorB = Color.white;
/// <summary>Get or set the color of the second vertex (clockwise), when using the per-corner color mode</summary>
public Color ColorB {
get => colorB;
set => SetColorNow( ShapesMaterialUtils.propColorB, colorB = value );
}
[SerializeField] [ShapesColorField( true )] Color colorC = Color.white;
/// <summary>Get or set the color of the third vertex (clockwise), when using the per-corner color mode</summary>
public Color ColorC {
get => colorC;
set => SetColorNow( ShapesMaterialUtils.propColorC, colorC = value );
}
[SerializeField] [ShapesColorField( true )] Color colorD = Color.white;
/// <summary>Get or set the color of the fourth vertex (clockwise), when using the per-corner color mode</summary>
public Color ColorD {
get => colorD;
set => SetColorNow( ShapesMaterialUtils.propColorD, colorD = value );
}
private protected override void SetAllMaterialProperties() {
SetVector3( ShapesMaterialUtils.propA, a );
SetVector3( ShapesMaterialUtils.propB, b );
SetVector3( ShapesMaterialUtils.propC, c );
if( autoSetD )
AutoSetD();
else
SetVector3( ShapesMaterialUtils.propD, d );
switch( colorMode ) {
case QuadColorMode.Single:
SetColor( ShapesMaterialUtils.propColorB, Color );
SetColor( ShapesMaterialUtils.propColorC, Color );
SetColor( ShapesMaterialUtils.propColorD, Color );
break;
case QuadColorMode.Horizontal:
SetColor( ShapesMaterialUtils.propColorB, Color );
SetColor( ShapesMaterialUtils.propColorC, colorC );
SetColor( ShapesMaterialUtils.propColorD, colorC );
break;
case QuadColorMode.Vertical:
SetColor( ShapesMaterialUtils.propColor, colorD ); // todo: this is a double-assign, it's already set before this, but to the wrong value :c
SetColor( ShapesMaterialUtils.propColorB, colorB );
SetColor( ShapesMaterialUtils.propColorC, colorB );
SetColor( ShapesMaterialUtils.propColorD, colorD );
break;
case QuadColorMode.PerCorner:
SetColor( ShapesMaterialUtils.propColorB, colorB );
SetColor( ShapesMaterialUtils.propColorC, colorC );
SetColor( ShapesMaterialUtils.propColorD, colorD );
break;
default:
throw new ArgumentOutOfRangeException();
}
}
internal override bool HasDetailLevels => false;
internal override bool HasScaleModes => false;
private protected override Mesh GetInitialMeshAsset() => ShapesMeshUtils.QuadMesh[0];
private protected override Material[] GetMaterials() => new[] { ShapesMaterialUtils.matQuad[BlendMode] };
private protected override Bounds GetBounds_Internal() {
Vector3 min = Vector3.Min( Vector3.Min( a, b ), c );
Vector3 max = Vector3.Max( Vector3.Max( a, b ), c );
return new Bounds( ( min + max ) / 2, ShapesMath.Abs( max - min ) );
}
}
}