using System ;
using System.IO ;
using System.Collections.Generic ;
using System.Linq ;
using System.Linq.Expressions ;
namespace UnityEditor.Experimental.Rendering
{
using UnityObject = UnityEngine . Object ;
public static class CoreEditorUtils
{
// GUIContent cache utilities
return group . isExpanded ;
}
static readonly GUIContent [ ] k_DrawVector6Slider_LabelPositives =
static readonly GUIContent [ ] k_DrawVector6_Label =
new GUIContent ( "+X" ) ,
new GUIContent ( "+Y" ) ,
new GUIContent ( "+Z" ) ,
} ;
static readonly GUIContent [ ] k_DrawVector6Slider_LabelNegatives =
{
new GUIContent ( "-X" ) ,
new GUIContent ( "-Y" ) ,
new GUIContent ( "-Z" ) ,
new GUIContent ( "X" ) ,
new GUIContent ( "Y" ) ,
new GUIContent ( "Z" ) ,
public static void DrawVector6Slider ( GUIContent label , SerializedProperty positive , SerializedProperty negative , Vector3 min , Vector3 max )
public static void DrawVector6 ( GUIContent label , SerializedProperty positive , SerializedProperty negative , Vector3 min , Vector3 max , Color [ ] [ ] colors = null )
if ( colors ! = null & & ( colors . Length ! = 2 | | colors [ 0 ] . Length ! = 3 | | colors [ 1 ] . Length ! = 3 ) )
throw new System . ArgumentException ( "Colors must be a 2x3 array." ) ;
EditorGUILayout . LabelField ( label ) ;
if ( label ! = GUIContent . none )
EditorGUILayout . LabelField ( label ) ;
v = DrawVector3Slider ( rect , k_DrawVector6Slider_LabelPositives , v , min , max ) ;
v = DrawVector3 ( rect , k_DrawVector6_Label , v , min , max , false , colors = = null ? null : colors [ 0 ] ) ;
if ( EditorGUI . EndChangeCheck ( ) )
positive . vector3Value = v ;
v = negative . vector3Value ;
EditorGUI . BeginChangeCheck ( ) ;
v = DrawVector3Slider ( rect , k_DrawVector6Slider _LabelNegatives , v , min , max ) ;
v = DrawVector3 ( rect , k_DrawVector6_Label , v , min , max , true , colors = = null ? null : colors [ 1 ] ) ;
if ( EditorGUI . EndChangeCheck ( ) )
negative . vector3Value = v ;
- - EditorGUI . indentLevel ;
static Vector3 DrawVector3Slider ( Rect rect , GUIContent [ ] labels , Vector3 value , Vector3 min , Vector3 max )
static Vector3 DrawVector3 ( Rect rect , GUIContent [ ] labels , Vector3 value , Vector3 min , Vector3 max , bool addMinusPrefix , Color [ ] colors )
// Use a corrected width due to the hacks used for layouting the slider properly below
rect . width - = 2 0 ;
var fieldWidth = rect . width / 3f ;
float [ ] multifloat = new float [ ] { value . x , value . y , value . z } ;
rect = EditorGUI . IndentedRect ( rect ) ;
float fieldWidth = rect . width / 3f ;
EditorGUI . BeginChangeCheck ( ) ;
EditorGUI . MultiFloatField ( rect , labels , multifloat ) ;
if ( EditorGUI . EndChangeCheck ( ) )
{
value . x = Mathf . Max ( Mathf . Min ( multifloat [ 0 ] , max . x ) , min . x ) ;
value . y = Mathf . Max ( Mathf . Min ( multifloat [ 1 ] , max . y ) , min . y ) ;
value . z = Mathf . Max ( Mathf . Min ( multifloat [ 2 ] , max . z ) , min . z ) ;
}
for ( var i = 0 ; i < 3 ; + + i )
//Suffix is a hack as sublabel only work with 1 character
if ( addMinusPrefix )
var c = new Rect ( rect . x + fieldWidth * i , rect . y , fieldWidth , rect . height ) ;
var labelRect = new Rect ( c . x , c . y , k_DrawVector6Slider_LabelSize , c . height ) ;
var sliderRect = new Rect ( labelRect . x + labelRect . width , c . y , c . width - k_DrawVector6Slider_LabelSize - k_DrawVector6Slider_FieldSize + 4 5 , c . height ) ;
var fieldRect = new Rect ( sliderRect . x + sliderRect . width - 2 5 , c . y , k_DrawVector6Slider_FieldSize , c . height ) ;
EditorGUI . LabelField ( labelRect , labels [ i ] ) ;
value [ i ] = GUI . HorizontalSlider ( sliderRect , value [ i ] , min [ i ] , max [ i ] ) ;
value [ i ] = EditorGUI . FloatField ( fieldRect , value [ i ] ) ;
Rect suffixRect = new Rect ( rect . x - 3 3 , rect . y , 1 0 0 , rect . height ) ;
for ( int i = 0 ; i < 3 ; + + i )
{
EditorGUI . LabelField ( suffixRect , "-" ) ;
suffixRect . x + = fieldWidth + . 5f ;
}
}
//Color is a hack as nothing is done to handle this at the moment
if ( colors ! = null )
{
if ( colors . Length ! = 3 )
throw new System . ArgumentException ( "colors must have 3 elements." ) ;
Rect suffixRect = new Rect ( rect . x - 2 3 , rect . y , 1 0 0 , rect . height ) ;
GUIStyle colorMark = new GUIStyle ( EditorStyles . label ) ;
colorMark . normal . textColor = colors [ 0 ] ;
EditorGUI . LabelField ( suffixRect , "|" , colorMark ) ;
suffixRect . x + = 1 ;
EditorGUI . LabelField ( suffixRect , "|" , colorMark ) ;
suffixRect . x + = fieldWidth - . 5f ;
colorMark . normal . textColor = colors [ 1 ] ;
EditorGUI . LabelField ( suffixRect , "|" , colorMark ) ;
suffixRect . x + = 1 ;
EditorGUI . LabelField ( suffixRect , "|" , colorMark ) ;
suffixRect . x + = fieldWidth + . 5f ;
colorMark . normal . textColor = colors [ 2 ] ;
EditorGUI . LabelField ( suffixRect , "|" , colorMark ) ;
suffixRect . x + = 1 ;
EditorGUI . LabelField ( suffixRect , "|" , colorMark ) ;
}
return value ;
}
mode = EditorGUILayout . Popup ( label , mode , options ) ;
if ( EditorGUI . EndChangeCheck ( ) )
{
Undo . RecordObject ( property . objectReferenceValue , property . name ) ;
}
}
public static void DrawCascadeSplitGUI < T > ( ref SerializedProperty shadowCascadeSplit )
return data ;
}
}
static class ShadowCascadeSplitGUI
{
private const int kSliderbarTopMargin = 2 ;
private const int kSliderbarHeight = 2 4 ;
private const int kSliderbarBottomMargin = 2 ;
private const int kPartitionHandleWidth = 2 ;
private const int kPartitionHandleExtraHitAreaWidth = 2 ;
private static readonly Color [ ] kCascadeColors =
{
new Color ( 0.5f , 0.5f , 0.6f , 1.0f ) ,
new Color ( 0.5f , 0.6f , 0.5f , 1.0f ) ,
new Color ( 0.6f , 0.6f , 0.5f , 1.0f ) ,
new Color ( 0.6f , 0.5f , 0.5f , 1.0f ) ,
} ;
// using a LODGroup skin
private static readonly GUIStyle s_CascadeSliderBG = "LODSliderRange" ;
private static readonly GUIStyle s_TextCenteredStyle = new GUIStyle ( EditorStyles . whiteMiniLabel )
static public GameObject CreateGameObject ( GameObject parent , string name , params Type [ ] types )
alignment = TextAnchor . MiddleCenter
} ;
return ObjectFactory . CreateGameObject ( GameObjectUtility . GetUniqueNameForSibling ( parent ! = null ? parent . transform : null , name ) , types ) ;
}
// Internal struct to bundle drag information
private class DragCache
static public string GetCurrentProjectVersion ( )
public int m_ActivePartition ; // the cascade partition that we are currently dragging/resizing
public float m_NormalizedPartitionSize ; // the normalized size of the partition (0.0f < size < 1.0f)
public Vector2 m_LastCachedMousePosition ; // mouse position the last time we registered a drag or mouse down.
public DragCache ( int activePartition , float normalizedPartitionSize , Vector2 currentMousePos )
{
m_ActivePartition = activePartition ;
m_NormalizedPartitionSize = normalizedPartitionSize ;
m_LastCachedMousePosition = currentMousePos ;
}
} ;
private static DragCache s_DragCache ;
private static readonly int s_CascadeSliderId = "s_CascadeSliderId" . GetHashCode ( ) ;
private static SceneView s_RestoreSceneView ;
private static SceneView . CameraMode s_OldSceneDrawMode ;
private static bool s_OldSceneLightingMode ;
string [ ] readText = File . ReadAllLines ( "ProjectSettings/ProjectVersion.txt" ) ;
// format is m_EditorVersion: 2018.2.0b7
string [ ] versionText = readText [ 0 ] . Split ( ' ' ) ;
return versionText [ 1 ] ;
}
/ * *
* Static function to handle the GUI and User input related to the cascade slider .
*
* @param normalizedCascadePartition The array of partition sizes in the range 0.0f - 1.0f ; expects ONE entry if cascades = 2 , and THREE if cascades = 4
* The last entry will be automatically determined by summing up the array , and doing 1.0f - sum
* /
public static void HandleCascadeSliderGUI ( ref float [ ] normalizedCascadePartitions )
static public void CheckOutFile ( bool VCSEnabled , UnityObject mat )
EditorGUILayout . LabelField ( "Cascade splits" ) ;
// get the inspector width since we need it while drawing the partition rects.
// Only way currently is to reserve the block in the layout using GetRect(), and then immediately drawing the empty box
// to match the call to GetRect.
// From this point on, we move to non-layout based code.
var sliderRect = GUILayoutUtility . GetRect ( GUIContent . none
, s_CascadeSliderBG
, GUILayout . Height ( kSliderbarTopMargin + kSliderbarHeight + kSliderbarBottomMargin )
, GUILayout . ExpandWidth ( true ) ) ;
GUI . Box ( sliderRect , GUIContent . none ) ;
float currentX = sliderRect . x ;
float cascadeBoxStartY = sliderRect . y + kSliderbarTopMargin ;
float cascadeSliderWidth = sliderRect . width - ( normalizedCascadePartitions . Length * kPartitionHandleWidth ) ;
Color origTextColor = GUI . color ;
Color origBackgroundColor = GUI . backgroundColor ;
int colorIndex = - 1 ;
// setup the array locally with the last partition
float [ ] adjustedCascadePartitions = new float [ normalizedCascadePartitions . Length + 1 ] ;
System . Array . Copy ( normalizedCascadePartitions , adjustedCascadePartitions , normalizedCascadePartitions . Length ) ;
adjustedCascadePartitions [ adjustedCascadePartitions . Length - 1 ] = 1.0f - normalizedCascadePartitions . Sum ( ) ;
// check for user input on any of the partition handles
// this mechanism gets the current event in the queue... make sure that the mouse is over our control before consuming the event
int sliderControlId = GUIUtility . GetControlID ( s_CascadeSliderId , FocusType . Passive ) ;
Event currentEvent = Event . current ;
int hotPartitionHandleIndex = - 1 ; // the index of any partition handle that we are hovering over or dragging
// draw each cascade partition
for ( int i = 0 ; i < adjustedCascadePartitions . Length ; + + i )
if ( VCSEnabled )
float currentPartition = adjustedCascadePartitions [ i ] ;
colorIndex = ( colorIndex + 1 ) % kCascadeColors . Length ;
GUI . backgroundColor = kCascadeColors [ colorIndex ] ;
float boxLength = ( cascadeSliderWidth * currentPartition ) ;
UnityEditor . VersionControl . Task task = UnityEditor . VersionControl . Provider . Checkout ( mat , UnityEditor . VersionControl . CheckoutMode . Both ) ;
// main cascade box
Rect partitionRect = new Rect ( currentX , cascadeBoxStartY , boxLength , kSliderbarHeight ) ;
GUI . Box ( partitionRect , GUIContent . none , s_CascadeSliderBG ) ;
currentX + = boxLength ;
// cascade box percentage text
GUI . color = Color . white ;
Rect textRect = partitionRect ;
var cascadeText = string . Format ( "{0}\n{1:F1}%" , i , currentPartition * 1 0 0.0f ) ;
GUI . Label ( textRect , cascadeText , s_TextCenteredStyle ) ;
// no need to draw the partition handle for last box
if ( i = = adjustedCascadePartitions . Length - 1 )
break ;
// partition handle
GUI . backgroundColor = Color . black ;
Rect handleRect = partitionRect ;
handleRect . x = currentX ;
handleRect . width = kPartitionHandleWidth ;
GUI . Box ( handleRect , GUIContent . none , s_CascadeSliderBG ) ;
// we want a thin handle visually (since wide black bar looks bad), but a slightly larger
// hit area for easier manipulation
Rect handleHitRect = handleRect ;
handleHitRect . xMin - = kPartitionHandleExtraHitAreaWidth ;
handleHitRect . xMax + = kPartitionHandleExtraHitAreaWidth ;
if ( handleHitRect . Contains ( currentEvent . mousePosition ) )
hotPartitionHandleIndex = i ;
// add regions to slider where the cursor changes to Resize-Horizontal
if ( s_DragCache = = null )
if ( ! task . success )
EditorGUIUtility . AddCursorRect ( handleHitRect , MouseCursor . ResizeHorizontal , sliderControlId ) ;
Debug . Log ( task . text + " " + task . resultCode ) ;
currentX + = kPartitionHandleWidth ;
}
GUI . color = origTextColor ;
GUI . backgroundColor = origBackgroundColor ;
EventType eventType = currentEvent . GetTypeForControl ( sliderControlId ) ;
switch ( eventType )
{
case EventType . MouseDown :
if ( hotPartitionHandleIndex > = 0 )
{
s_DragCache = new DragCache ( hotPartitionHandleIndex , normalizedCascadePartitions [ hotPartitionHandleIndex ] , currentEvent . mousePosition ) ;
if ( GUIUtility . hotControl = = 0 )
GUIUtility . hotControl = sliderControlId ;
currentEvent . Use ( ) ;
// Switch active scene view into shadow cascades visualization mode, once we start
// tweaking cascade splits.
if ( s_RestoreSceneView = = null )
{
s_RestoreSceneView = SceneView . lastActiveSceneView ;
if ( s_RestoreSceneView ! = null )
{
s_OldSceneDrawMode = s_RestoreSceneView . cameraMode ;
s_OldSceneLightingMode = s_RestoreSceneView . m_SceneLighting ;
s_RestoreSceneView . cameraMode = SceneView . GetBuiltinCameraMode ( DrawCameraMode . ShadowCascades ) ;
}
}
}
break ;
case EventType . MouseUp :
// mouseUp event anywhere should release the hotcontrol (if it belongs to us), drags (if any)
if ( GUIUtility . hotControl = = sliderControlId )
{
GUIUtility . hotControl = 0 ;
currentEvent . Use ( ) ;
}
s_DragCache = null ;
// Restore previous scene view drawing mode once we stop tweaking cascade splits.
if ( s_RestoreSceneView ! = null )
{
s_RestoreSceneView . cameraMode = s_OldSceneDrawMode ;
s_RestoreSceneView . m_SceneLighting = s_OldSceneLightingMode ;
s_RestoreSceneView = null ;
}
break ;
case EventType . MouseDrag :
if ( GUIUtility . hotControl ! = sliderControlId )
break ;
// convert the mouse movement to normalized cascade width. Make sure that we are safe to apply the delta before using it.
float delta = ( currentEvent . mousePosition - s_DragCache . m_LastCachedMousePosition ) . x / cascadeSliderWidth ;
bool isLeftPartitionHappy = ( ( adjustedCascadePartitions [ s_DragCache . m_ActivePartition ] + delta ) > 0.0f ) ;
bool isRightPartitionHappy = ( ( adjustedCascadePartitions [ s_DragCache . m_ActivePartition + 1 ] - delta ) > 0.0f ) ;
if ( isLeftPartitionHappy & & isRightPartitionHappy )
{
s_DragCache . m_NormalizedPartitionSize + = delta ;
normalizedCascadePartitions [ s_DragCache . m_ActivePartition ] = s_DragCache . m_NormalizedPartitionSize ;
if ( s_DragCache . m_ActivePartition < normalizedCascadePartitions . Length - 1 )
normalizedCascadePartitions [ s_DragCache . m_ActivePartition + 1 ] - = delta ;
GUI . changed = true ;
}
s_DragCache . m_LastCachedMousePosition = currentEvent . mousePosition ;
currentEvent . Use ( ) ;
break ;
}
}
}