mixedreality/com.microsoft.mixedreality..../SDK/Editor/Migration/BoundsControlMigrationHandl...

313 lines
16 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.UI;
using Microsoft.MixedReality.Toolkit.UI.BoundsControl;
using Microsoft.MixedReality.Toolkit.UI.BoundsControlTypes;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Utilities
{
/// <summary>
/// Migration handler for migrating bounding box gameobjects to bounds control gameobjects.
/// </summary>
public class BoundsControlMigrationHandler : IMigrationHandler
{
/// <inheritdoc />
public bool CanMigrate(GameObject gameObject)
{
return gameObject.GetComponent<BoundingBox>() != null;
}
/// <inheritdoc />
public void Migrate(GameObject gameObject)
{
var boundingBox = gameObject.GetComponent<BoundingBox>();
var boundsControl = gameObject.EnsureComponent<BoundsControl>();
boundsControl.enabled = boundingBox.enabled;
{
Undo.RecordObject(gameObject, "BoundsControl migration: swapping BoundingBox with BoundsControl.");
// migrate logic settings
boundsControl.Target = boundingBox.Target;
boundsControl.BoundsOverride = boundingBox.BoundsOverride;
boundsControl.CalculationMethod = MigrateCalculationMethod(boundingBox.CalculationMethod);
boundsControl.BoundsControlActivation = MigrateActivationFlag(boundingBox.BoundingBoxActivation);
// only carry over min max scaling values if user hasn't attached min max scale constraint component yet
if (gameObject.GetComponent<MinMaxScaleConstraint>() == null)
{
#pragma warning disable 0618
// create a minmaxscaleconstraint in case there's a min max scale set up
if (boundingBox.ScaleMinimum != 0.0f || boundingBox.ScaleMaximum != 0.0f)
{
MinMaxScaleConstraint scaleConstraint = gameObject.AddComponent<MinMaxScaleConstraint>();
scaleConstraint.ScaleMinimum = boundingBox.ScaleMinimum;
scaleConstraint.ScaleMaximum = boundingBox.ScaleMaximum;
}
#pragma warning restore 0618
}
// migrate visuals
boundsControl.FlattenAxis = MigrateFlattenAxis(boundingBox.FlattenAxis);
boundsControl.BoxPadding = boundingBox.BoxPadding;
MigrateBoxDisplay(boundsControl, boundingBox);
MigrateLinks(boundsControl, boundingBox);
MigrateScaleHandles(boundsControl, boundingBox);
MigrateRotationHandles(boundsControl, boundingBox);
MigrateProximityEffect(boundsControl, boundingBox);
// debug properties
boundsControl.DebugText = boundingBox.debugText;
boundsControl.HideElementsInInspector = boundingBox.HideElementsInInspector;
// events
boundsControl.RotateStarted = boundingBox.RotateStarted;
boundsControl.RotateStopped = boundingBox.RotateStopped;
boundsControl.ScaleStarted = boundingBox.ScaleStarted;
boundsControl.ScaleStopped = boundingBox.ScaleStopped;
}
// look in the scene for app bars and upgrade them too to point to the new component
MigrateAppBar(boundingBox, boundsControl);
{
Undo.RecordObject(gameObject, "Removing obsolete BoundingBox component");
// destroy obsolete component
Object.DestroyImmediate(boundingBox);
}
}
#region Flags Migration
private BoundsCalculationMethod MigrateCalculationMethod(BoundingBox.BoundsCalculationMethod calculationMethod)
{
switch (calculationMethod)
{
case BoundingBox.BoundsCalculationMethod.RendererOverCollider:
return BoundsCalculationMethod.RendererOverCollider;
case BoundingBox.BoundsCalculationMethod.ColliderOverRenderer:
return BoundsCalculationMethod.ColliderOverRenderer;
case BoundingBox.BoundsCalculationMethod.ColliderOnly:
return BoundsCalculationMethod.ColliderOnly;
case BoundingBox.BoundsCalculationMethod.RendererOnly:
return BoundsCalculationMethod.RendererOnly;
}
Debug.Assert(false, "Tried to migrate unsupported bounds calculation method in bounding box / bounds control");
return BoundsCalculationMethod.RendererOverCollider;
}
private BoundsControlActivationType MigrateActivationFlag(BoundingBox.BoundingBoxActivationType activationFlag)
{
switch (activationFlag)
{
case BoundingBox.BoundingBoxActivationType.ActivateOnStart:
return BoundsControlActivationType.ActivateOnStart;
case BoundingBox.BoundingBoxActivationType.ActivateByProximity:
return BoundsControlActivationType.ActivateByProximity;
case BoundingBox.BoundingBoxActivationType.ActivateByPointer:
return BoundsControlActivationType.ActivateByPointer;
case BoundingBox.BoundingBoxActivationType.ActivateByProximityAndPointer:
return BoundsControlActivationType.ActivateByProximityAndPointer;
case BoundingBox.BoundingBoxActivationType.ActivateManually:
return BoundsControlActivationType.ActivateManually;
}
Debug.Assert(false, "Tried to migrate unsupported activation flag in bounding box / bounds control");
return BoundsControlActivationType.ActivateOnStart;
}
private FlattenModeType MigrateFlattenAxis(BoundingBox.FlattenModeType flattenAxisType)
{
switch (flattenAxisType)
{
case BoundingBox.FlattenModeType.DoNotFlatten:
return FlattenModeType.DoNotFlatten;
case BoundingBox.FlattenModeType.FlattenX:
return FlattenModeType.FlattenX;
case BoundingBox.FlattenModeType.FlattenY:
return FlattenModeType.FlattenY;
case BoundingBox.FlattenModeType.FlattenZ:
return FlattenModeType.FlattenZ;
case BoundingBox.FlattenModeType.FlattenAuto:
return FlattenModeType.FlattenAuto;
}
Debug.Assert(false, "Tried to migrate unsupported flatten axis type in bounding box / bounds control");
return FlattenModeType.DoNotFlatten;
}
private WireframeType MigrateWireframeShape(BoundingBox.WireframeType wireframeType)
{
switch (wireframeType)
{
case BoundingBox.WireframeType.Cubic:
return WireframeType.Cubic;
case BoundingBox.WireframeType.Cylindrical:
return WireframeType.Cylindrical;
}
Debug.Assert(false, "Tried to migrate unsupported wireframe type in bounding box / bounds control");
return WireframeType.Cubic;
}
private HandlePrefabCollider MigrateRotationHandleColliderType(BoundingBox.RotationHandlePrefabCollider rotationHandlePrefabColliderType)
{
switch (rotationHandlePrefabColliderType)
{
case BoundingBox.RotationHandlePrefabCollider.Sphere:
return HandlePrefabCollider.Sphere;
case BoundingBox.RotationHandlePrefabCollider.Box:
return HandlePrefabCollider.Box;
}
Debug.Assert(false, "Tried to migrate unsupported rotation handle collider type in bounding box / bounds control");
return HandlePrefabCollider.Sphere;
}
#endregion Flags Migration
#region Visuals Configuration Migration
private T EnsureConfiguration<T>(GameObject owner, T config, bool enforceScriptableCreation) where T : ScriptableObject
{
var instance = config;
if (instance == null || enforceScriptableCreation)
{
instance = ScriptableObject.CreateInstance<T>();
// scriptables in prefabs need to be added into their asset file as serializedobject, else they won't get stored
string objectPath = owner.scene.path;
if (objectPath.EndsWith(".prefab"))
{
instance.name = instance.GetType().Name;
AssetDatabase.AddObjectToAsset(instance, objectPath);
}
}
return instance;
}
/// <summary>
/// This method checks if the given object has a property override for any of the given property names.
/// It's used to figure out if scriptable objects have to be created for the current prefab / gameobject instance level.
/// </summary>
/// <param name="target">The target object (can be prefab component or component instance).</param>
/// <param name="propertyNames">Property names to be checked.</param>
/// <returns>Returns true if any of the passed property names have an override.</returns>
bool HasPropertyOverrides(Object target, List<string> propertyNames)
{
var propertyModifications = PrefabUtility.GetPropertyModifications(target);
if (propertyModifications != null)
{
foreach (var propertyMod in propertyModifications)
{
if (propertyNames.Contains(propertyMod.propertyPath))
{
return true;
}
}
}
return false;
}
private void MigrateBoxDisplay(BoundsControl control, BoundingBox box)
{
List<string> propertyPaths = new List<string> { "boxMaterial", "boxGrabbedMaterial", "flattenAxisDisplayScale" };
BoxDisplayConfiguration config = EnsureConfiguration(control.gameObject, control.BoxDisplayConfig, HasPropertyOverrides(box, propertyPaths));
config.BoxMaterial = box.BoxMaterial;
config.BoxGrabbedMaterial = box.BoxGrabbedMaterial;
config.FlattenAxisDisplayScale = box.FlattenAxisDisplayScale;
control.BoxDisplayConfig = config;
}
private void MigrateLinks(BoundsControl control, BoundingBox box)
{
List<string> propertyPaths = new List<string> { "wireframeMaterial", "wireframeEdgeRadius", "wireframeShape", "showWireFrame" };
LinksConfiguration config = EnsureConfiguration(control.gameObject, control.LinksConfig, HasPropertyOverrides(box, propertyPaths));
config.WireframeMaterial = box.WireframeMaterial;
config.WireframeEdgeRadius = box.WireframeEdgeRadius;
config.WireframeShape = MigrateWireframeShape(box.WireframeShape);
config.ShowWireFrame = box.ShowWireFrame;
control.LinksConfig = config;
}
private void MigrateScaleHandles(BoundsControl control, BoundingBox box)
{
List<string> propertyPaths = new List<string> { "scaleHandleSlatePrefab", "showScaleHandles", "handleMaterial", "handleGrabbedMaterial",
"scaleHandlePrefab", "scaleHandleSize", "scaleHandleColliderPadding", "drawTetherWhenManipulating", "handlesIgnoreCollider"};
ScaleHandlesConfiguration config = EnsureConfiguration(control.gameObject, control.ScaleHandlesConfig, HasPropertyOverrides(box, propertyPaths));
config.HandleSlatePrefab = box.ScaleHandleSlatePrefab;
config.ShowScaleHandles = box.ShowScaleHandles;
config.HandleMaterial = box.HandleMaterial;
config.HandleGrabbedMaterial = box.HandleGrabbedMaterial;
config.HandlePrefab = box.ScaleHandlePrefab;
config.HandleSize = box.ScaleHandleSize;
config.ColliderPadding = box.ScaleHandleColliderPadding;
config.DrawTetherWhenManipulating = box.DrawTetherWhenManipulating;
config.HandlesIgnoreCollider = box.HandlesIgnoreCollider;
control.ScaleHandlesConfig = config;
}
private void MigrateRotationHandles(BoundsControl control, BoundingBox box)
{
List<string> propertyPaths = new List<string> { "rotationHandlePrefabColliderType", "showRotationHandleForX", "showRotationHandleForY",
"showRotationHandleForZ", "handleMaterial", "handleGrabbedMaterial", "rotationHandlePrefab", "rotationHandleSize", "rotateHandleColliderPadding",
"drawTetherWhenManipulating", "handlesIgnoreCollider"};
RotationHandlesConfiguration config = EnsureConfiguration(control.gameObject, control.RotationHandlesConfig, HasPropertyOverrides(box, propertyPaths));
config.HandlePrefabColliderType = MigrateRotationHandleColliderType(box.RotationHandlePrefabColliderType);
config.ShowHandleForX = box.ShowRotationHandleForX;
config.ShowHandleForY = box.ShowRotationHandleForY;
config.ShowHandleForZ = box.ShowRotationHandleForZ;
config.HandleMaterial = box.HandleMaterial;
config.HandleGrabbedMaterial = box.HandleGrabbedMaterial;
config.HandlePrefab = box.RotationHandlePrefab;
config.HandleSize = box.RotationHandleSize;
config.ColliderPadding = box.RotateHandleColliderPadding;
config.DrawTetherWhenManipulating = box.DrawTetherWhenManipulating;
config.HandlesIgnoreCollider = box.HandlesIgnoreCollider;
control.RotationHandlesConfig = config;
}
private void MigrateProximityEffect(BoundsControl control, BoundingBox box)
{
List<string> propertyPaths = new List<string> { "proximityEffectActive", "handleMediumProximity", "handleCloseProximity", "farScale",
"mediumScale", "closeScale", "farGrowRate", "mediumGrowRate", "closeGrowRate"};
ProximityEffectConfiguration config = EnsureConfiguration(control.gameObject, control.HandleProximityEffectConfig, HasPropertyOverrides(box, propertyPaths));
config.ProximityEffectActive = box.ProximityEffectActive;
config.ObjectMediumProximity = box.HandleMediumProximity;
config.ObjectCloseProximity = box.HandleCloseProximity;
config.FarScale = box.FarScale;
config.MediumScale = box.MediumScale;
config.CloseScale = box.CloseScale;
config.FarGrowRate = box.FarGrowRate;
config.MediumGrowRate = box.MediumGrowRate;
config.CloseGrowRate = box.CloseGrowRate;
control.HandleProximityEffectConfig = config;
}
#endregion Visuals Configuration Migration
private void MigrateAppBar(BoundingBox boundingBox, BoundsControl boundsControl)
{
// note: this might be expensive for larger scenes but we don't know where the appbar is
// placed in the hierarchy so we have to search the scene for it
AppBar[] appBars = Object.FindObjectsOfType<AppBar>();
for (int i = 0; i < appBars.Length; ++i)
{
AppBar appBar = appBars[i];
if (appBar.Target == boundingBox)
{
Undo.RecordObject(appBar, "BoundsControl migration: changed target of app bar.");
appBar.Target = boundsControl;
EditorUtility.SetDirty(appBar);
}
}
}
}
}