227 lines
8.3 KiB
C#
227 lines
8.3 KiB
C#
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using Object = UnityEngine.Object;
|
|
|
|
// Shapes © Freya Holmér - https://twitter.com/FreyaHolmer/
|
|
// Website & Documentation - https://acegikmo.com/shapes/
|
|
namespace Shapes {
|
|
|
|
public class SceneFillEditor : SceneEditGizmos {
|
|
|
|
SerializedProperty propUseFill;
|
|
SerializedProperty propType;
|
|
SerializedProperty propSpace;
|
|
SerializedProperty propColorStart;
|
|
SerializedProperty propColorEnd;
|
|
SerializedProperty propLinearStart;
|
|
SerializedProperty propLinearEnd;
|
|
SerializedProperty propRadialOrigin;
|
|
SerializedProperty propRadialRadius;
|
|
|
|
SerializedObject soMain;
|
|
|
|
SphereBoundsHandle sphereHandle = ShapesHandles.InitSphereHandle();
|
|
|
|
static bool isEditing;
|
|
protected override bool IsEditing {
|
|
get => isEditing;
|
|
set => isEditing = value;
|
|
}
|
|
|
|
public SceneFillEditor( Editor parentEditor, SerializedProperty propShapeFill, SerializedProperty propUseFill ) {
|
|
this.parentEditor = parentEditor;
|
|
soMain = propShapeFill.serializedObject;
|
|
this.propUseFill = propUseFill;
|
|
propType = propShapeFill.FindPropertyRelative( "type" );
|
|
propSpace = propShapeFill.FindPropertyRelative( "space" );
|
|
propColorStart = propShapeFill.FindPropertyRelative( "colorStart" );
|
|
propColorEnd = propShapeFill.FindPropertyRelative( "colorEnd" );
|
|
propLinearStart = propShapeFill.FindPropertyRelative( "linearStart" );
|
|
propLinearEnd = propShapeFill.FindPropertyRelative( "linearEnd" );
|
|
propRadialOrigin = propShapeFill.FindPropertyRelative( "radialOrigin" );
|
|
propRadialRadius = propShapeFill.FindPropertyRelative( "radialRadius" );
|
|
}
|
|
|
|
|
|
// this runs per object selected
|
|
public bool DoSceneHandles( bool useFill, Object component, ref GradientFill fill, Transform tf ) {
|
|
CheckForCancelEditAction();
|
|
|
|
if( useFill == false )
|
|
return false;
|
|
|
|
bool changed = false;
|
|
Quaternion handleRotation = Tools.pivotRotation == PivotRotation.Global ? Quaternion.identity : tf.rotation;
|
|
|
|
switch( fill.type ) {
|
|
case FillType.LinearGradient:
|
|
|
|
Vector3 linStart = fill.GetLinearStartWorld( tf );
|
|
Vector3 linEnd = fill.GetLinearEndWorld( tf );
|
|
if( isEditing && IsHoldingAlt == false ) {
|
|
linStart = Handles.PositionHandle( linStart, handleRotation );
|
|
if( GUI.changed ) {
|
|
Undo.RecordObject( component, "edit fill start" );
|
|
fill.SetLinearStartWorld( tf, linStart );
|
|
changed = true;
|
|
}
|
|
|
|
linEnd = Handles.PositionHandle( linEnd, handleRotation );
|
|
if( GUI.changed ) {
|
|
Undo.RecordObject( component, "edit fill end" );
|
|
fill.SetLinearEndWorld( tf, linEnd );
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
// line markers
|
|
Handles.DrawAAPolyLine( linStart, linEnd );
|
|
Vector3 camForward = SceneView.currentDrawingSceneView.camera.transform.forward;
|
|
float nootLength = 0.1f * HandleUtility.GetHandleSize( Vector3.Lerp( linStart, linEnd, .5f ) );
|
|
Vector3 lineTangent = ( linEnd - linStart ).normalized;
|
|
Vector3 lineNormal = Vector3.Cross( camForward, lineTangent ).normalized;
|
|
Vector3 nootOffset = lineNormal * nootLength;
|
|
const int nootCount = 5;
|
|
for( int i = 0; i < nootCount; i++ ) {
|
|
float t = i / ( nootCount - 1f );
|
|
Vector3 pos = Vector3.Lerp( linStart, linEnd, t );
|
|
Handles.DrawAAPolyLine( pos + nootOffset, pos - nootOffset );
|
|
}
|
|
|
|
break;
|
|
case FillType.RadialGradient:
|
|
|
|
if( isEditing ) {
|
|
using( new Handles.DrawingScope( Matrix4x4.TRS( fill.GetRadialOriginWorld( tf ), handleRotation, Vector3.one ) ) ) {
|
|
sphereHandle.center = Vector3.zero;
|
|
sphereHandle.radius = fill.GetRadialWorldRadius( tf );
|
|
sphereHandle.DrawHandle();
|
|
if( GUI.changed ) {
|
|
float newWorldRadius = sphereHandle.radius;
|
|
Undo.RecordObject( component, "edit fill radius" );
|
|
fill.SetRadialWorldRadius( tf, newWorldRadius );
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
|
|
if( IsHoldingAlt == false ) {
|
|
Vector3 newOrigin = Handles.PositionHandle( fill.GetRadialOriginWorld( tf ), handleRotation );
|
|
if( GUI.changed ) {
|
|
Undo.RecordObject( component, "edit fill origin" );
|
|
fill.SetRadialOriginWorld( tf, newOrigin );
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
bool ShowFillControls => propUseFill.boolValue == false || propUseFill.hasMultipleDifferentValues;
|
|
|
|
public bool DrawProperties( Editor parentEditor ) {
|
|
bool changed = soMain.ApplyModifiedProperties(); // this is a little cursed
|
|
using( new ShapesUI.GroupScope() )
|
|
using( ShapesUI.TempLabelWidth( 75 ) ) {
|
|
PropertyHeader( ref changed );
|
|
using( new EditorGUI.DisabledScope( ShowFillControls ) ) {
|
|
FillModeProperties( ref changed );
|
|
// edit button
|
|
GUIEditButton( "Edit Fill in Scene" );
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
void PropertyHeader( ref bool changed ) {
|
|
using( ShapesUI.Horizontal ) {
|
|
soMain.Update();
|
|
EditorGUILayout.PropertyField( propUseFill, new GUIContent( "Fill", "Whether or not to override the color fill of this shape" ), GUILayout.ExpandWidth( false ) );
|
|
if( soMain.ApplyModifiedProperties() )
|
|
changed = true;
|
|
|
|
using( new EditorGUI.DisabledScope( ShowFillControls ) ) {
|
|
GUILayout.Space( 5 );
|
|
using( ShapesUI.TempLabelWidth( 45 ) ) {
|
|
SpaceField( ref changed );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SpaceField( ref bool changed ) {
|
|
using( var chChk = new EditorGUI.ChangeCheckScope() ) {
|
|
SerializedObject[] targets = propSpace.serializedObject.targetObjects.Select( obj => new SerializedObject( obj ) ).ToArray();
|
|
FillSpace[] prevSpaceStates = targets.Select( t => (FillSpace)t.FindProperty( "fill.space" ).enumValueIndex ).ToArray();
|
|
// this blob of mess is because we want coordinates to stay at the same world space position when changing space
|
|
soMain.Update();
|
|
EditorGUILayout.PropertyField( propSpace, new GUIContent( "Space" ) );
|
|
if( soMain.ApplyModifiedProperties() )
|
|
changed = true;
|
|
|
|
if( chChk.changed ) {
|
|
FillSpace currentSpace = (FillSpace)propSpace.enumValueIndex;
|
|
for( int i = 0; i < prevSpaceStates.Length; i++ ) {
|
|
FillSpace prevSpace = prevSpaceStates[i];
|
|
if( currentSpace == prevSpace )
|
|
continue;
|
|
|
|
SerializedProperty propLinStart = targets[i].FindProperty( "fill.linearStart" );
|
|
SerializedProperty propLinEnd = targets[i].FindProperty( "fill.linearEnd" );
|
|
SerializedProperty propRadOrigin = targets[i].FindProperty( "fill.radialOrigin" );
|
|
SerializedProperty propRadRadius = targets[i].FindProperty( "fill.radialRadius" );
|
|
Transform tf = ( (Component)( targets[i].targetObject ) ).transform;
|
|
|
|
propLinStart.serializedObject.Update();
|
|
if( currentSpace == FillSpace.World ) {
|
|
// local to world
|
|
propLinStart.vector3Value = tf.TransformPoint( propLinStart.vector3Value );
|
|
propLinEnd.vector3Value = tf.TransformPoint( propLinEnd.vector3Value );
|
|
propRadOrigin.vector3Value = tf.TransformPoint( propRadOrigin.vector3Value );
|
|
propRadRadius.floatValue *= tf.lossyScale.x;
|
|
} else {
|
|
propLinStart.vector3Value = tf.InverseTransformPoint( propLinStart.vector3Value );
|
|
propLinEnd.vector3Value = tf.InverseTransformPoint( propLinEnd.vector3Value );
|
|
propRadOrigin.vector3Value = tf.InverseTransformPoint( propRadOrigin.vector3Value );
|
|
propRadRadius.floatValue /= tf.lossyScale.x;
|
|
}
|
|
|
|
if( propLinStart.serializedObject.ApplyModifiedProperties() )
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void FillModeProperties( ref bool changed ) {
|
|
soMain.Update();
|
|
|
|
EditorGUILayout.PropertyField( propType, new GUIContent( "Type" ) );
|
|
if( propType.enumValueIndex == (int)FillType.LinearGradient ) {
|
|
ShapesUI.PosColorField( "Start", propLinearStart, propColorStart );
|
|
ShapesUI.PosColorField( "End", propLinearEnd, propColorEnd );
|
|
} else if( propType.enumValueIndex == (int)FillType.RadialGradient ) {
|
|
ShapesUI.PosColorField( "Pos", propRadialOrigin, propColorStart );
|
|
using( ShapesUI.Horizontal ) {
|
|
using( ShapesUI.TempLabelWidth( ShapesUI.POS_COLOR_FIELD_LABEL_WIDTH + 17 ) )
|
|
EditorGUILayout.PropertyField( propRadialRadius, new GUIContent( "Radius" ) );
|
|
//GUILayout.FlexibleSpace();
|
|
EditorGUILayout.PropertyField( propColorEnd, GUIContent.none, GUILayout.Width( ShapesUI.POS_COLOR_FIELD_COLOR_WIDTH ) );
|
|
}
|
|
}
|
|
|
|
if( soMain.ApplyModifiedProperties() )
|
|
changed = true;
|
|
}
|
|
|
|
}
|
|
|
|
} |