Browse Source

[unity] SkeletonGraphic now supports automatic scaling based on RectTransform bounds. Closes #1640.

Harald Csaszar 2 years ago
parent
commit
91cc6ddfaa

+ 1 - 0
CHANGELOG.md

@@ -97,6 +97,7 @@
   * `SkeletonRenderTexture` and `SkeletonGraphicRenderTexture` components now support automatic down-scaling when required size on screen exceeds `Max Render Texture Size`.
   * `SkeletonRenderTexture` and `SkeletonGraphicRenderTexture` components now support automatic down-scaling when required size on screen exceeds `Max Render Texture Size`.
   * Added `Spine/SkeletonGraphic Fill` shader to provide functionality of `Spine/Skeleton Fill` shader for `SkeletonGraphic`.
   * Added `Spine/SkeletonGraphic Fill` shader to provide functionality of `Spine/Skeleton Fill` shader for `SkeletonGraphic`.
   * Lit Spine URP shaders (`Universal Render Pipeline/Spine/Sprite` and `Universal Render Pipeline/Spine/Skeleton Lit`) now support `Forward+` rendering path as introduced by Unity 2022.2 and URP version 14.
   * Lit Spine URP shaders (`Universal Render Pipeline/Spine/Sprite` and `Universal Render Pipeline/Spine/Skeleton Lit`) now support `Forward+` rendering path as introduced by Unity 2022.2 and URP version 14.
+  * `SkeletonGraphic` now supports automatic scaling based on its `RectTransform` bounds. Automatic scaling can be enabled by setting the added `Layout Scale Mode` Inspector property to either `Width Controls Height`, `Height Controls Width`, `FitInParent` or `EnvelopeParent`. It is set to `None` by default to keep previous behaviour and avoid breaking existing projects. To modify the reference layout bounds, hit the additional `Edit Layout Bounds` toggle button to switch into edit mode, adjust the bounds or hit `Match RectTransform with Mesh`, and hit the button again when done adjusting. The skeleton will now be scaled accordingly to fit the reference layout bounds to the object's `RectTransform`.
  
  
 * **Breaking changes**
 * **Breaking changes**
   * Made `SkeletonGraphic.unscaledTime` parameter protected, use the new property `UnscaledTime` instead.
   * Made `SkeletonGraphic.unscaledTime` parameter protected, use the new property `UnscaledTime` instead.

+ 45 - 10
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs

@@ -57,7 +57,7 @@ namespace Spine.Unity.Editor {
 		SerializedProperty additiveMaterial, multiplyMaterial, screenMaterial;
 		SerializedProperty additiveMaterial, multiplyMaterial, screenMaterial;
 		SerializedProperty skeletonDataAsset, initialSkinName;
 		SerializedProperty skeletonDataAsset, initialSkinName;
 		SerializedProperty startingAnimation, startingLoop, timeScale, freeze,
 		SerializedProperty startingAnimation, startingLoop, timeScale, freeze,
-			updateTiming, updateWhenInvisible, unscaledTime, tintBlack;
+			updateTiming, updateWhenInvisible, unscaledTime, tintBlack, layoutScaleMode, editReferenceRect;
 		SerializedProperty initialFlipX, initialFlipY;
 		SerializedProperty initialFlipX, initialFlipY;
 		SerializedProperty meshGeneratorSettings;
 		SerializedProperty meshGeneratorSettings;
 		SerializedProperty allowMultipleCanvasRenderers, separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation;
 		SerializedProperty allowMultipleCanvasRenderers, separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation;
@@ -76,8 +76,8 @@ namespace Spine.Unity.Editor {
 		protected bool TargetIsValid {
 		protected bool TargetIsValid {
 			get {
 			get {
 				if (serializedObject.isEditingMultipleObjects) {
 				if (serializedObject.isEditingMultipleObjects) {
-					foreach (UnityEngine.Object o in targets) {
-						SkeletonGraphic component = (SkeletonGraphic)o;
+					foreach (UnityEngine.Object c in targets) {
+						SkeletonGraphic component = (SkeletonGraphic)c;
 						if (!component.IsValid)
 						if (!component.IsValid)
 							return false;
 							return false;
 					}
 					}
@@ -129,6 +129,8 @@ namespace Spine.Unity.Editor {
 			freeze = so.FindProperty("freeze");
 			freeze = so.FindProperty("freeze");
 			updateTiming = so.FindProperty("updateTiming");
 			updateTiming = so.FindProperty("updateTiming");
 			updateWhenInvisible = so.FindProperty("updateWhenInvisible");
 			updateWhenInvisible = so.FindProperty("updateWhenInvisible");
+			layoutScaleMode = so.FindProperty("layoutScaleMode");
+			editReferenceRect = so.FindProperty("editReferenceRect");
 
 
 			meshGeneratorSettings = so.FindProperty("meshGenerator").FindPropertyRelative("settings");
 			meshGeneratorSettings = so.FindProperty("meshGenerator").FindPropertyRelative("settings");
 			meshGeneratorSettings.isExpanded = SkeletonRendererInspector.advancedFoldout;
 			meshGeneratorSettings.isExpanded = SkeletonRendererInspector.advancedFoldout;
@@ -141,6 +143,13 @@ namespace Spine.Unity.Editor {
 			separatorSlotNames.isExpanded = true;
 			separatorSlotNames.isExpanded = true;
 		}
 		}
 
 
+		void OnDisable () {
+			foreach (UnityEngine.Object c in targets) {
+				SkeletonGraphic component = (SkeletonGraphic)c;
+				component.EditReferenceRect = false;
+			}
+		}
+
 		public override void OnInspectorGUI () {
 		public override void OnInspectorGUI () {
 
 
 			if (UnityEngine.Event.current.type == EventType.Layout) {
 			if (UnityEngine.Event.current.type == EventType.Layout) {
@@ -299,14 +308,29 @@ namespace Spine.Unity.Editor {
 			EditorGUILayout.PropertyField(raycastTarget);
 			EditorGUILayout.PropertyField(raycastTarget);
 			if (maskable != null) EditorGUILayout.PropertyField(maskable);
 			if (maskable != null) EditorGUILayout.PropertyField(maskable);
 
 
-			EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
-			EditorGUILayout.PrefixLabel("Match RectTransform with Mesh");
-			if (GUILayout.Button("Match", EditorStyles.miniButton, GUILayout.Width(65f))) {
-				foreach (UnityEngine.Object skeletonGraphic in targets) {
-					MatchRectTransformWithBounds((SkeletonGraphic)skeletonGraphic);
+			EditorGUILayout.PropertyField(layoutScaleMode);
+
+			using (new EditorGUI.DisabledGroupScope(layoutScaleMode.intValue == 0)) {
+				EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
+				EditorGUILayout.PrefixLabel("Edit Layout Bounds");
+				editReferenceRect.boolValue = GUILayout.Toggle(editReferenceRect.boolValue,
+					EditorGUIUtility.IconContent("EditCollider"), EditorStyles.miniButton, GUILayout.Width(40f));
+				EditorGUILayout.EndHorizontal();
+			}
+			if (layoutScaleMode.intValue == 0) {
+				editReferenceRect.boolValue = false;
+			}
+
+			using (new EditorGUI.DisabledGroupScope(editReferenceRect.boolValue == false && layoutScaleMode.intValue != 0)) {
+				EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
+				EditorGUILayout.PrefixLabel("Match RectTransform with Mesh");
+				if (GUILayout.Button("Match", EditorStyles.miniButton, GUILayout.Width(65f))) {
+					foreach (UnityEngine.Object skeletonGraphic in targets) {
+						MatchRectTransformWithBounds((SkeletonGraphic)skeletonGraphic);
+					}
 				}
 				}
+				EditorGUILayout.EndHorizontal();
 			}
 			}
-			EditorGUILayout.EndHorizontal();
 
 
 			if (TargetIsValid && !isInspectingPrefab) {
 			if (TargetIsValid && !isInspectingPrefab) {
 				EditorGUILayout.Space();
 				EditorGUILayout.Space();
@@ -320,7 +344,6 @@ namespace Spine.Unity.Editor {
 			}
 			}
 
 
 			wasChanged |= EditorGUI.EndChangeCheck();
 			wasChanged |= EditorGUI.EndChangeCheck();
-
 			if (wasChanged) {
 			if (wasChanged) {
 				serializedObject.ApplyModifiedProperties();
 				serializedObject.ApplyModifiedProperties();
 				slotsReapplyRequired = true;
 				slotsReapplyRequired = true;
@@ -346,6 +369,18 @@ namespace Spine.Unity.Editor {
 			return false;
 			return false;
 		}
 		}
 
 
+		protected void OnSceneGUI () {
+			SkeletonGraphic skeletonGraphic = (SkeletonGraphic)target;
+			if (skeletonGraphic.EditReferenceRect) {
+				SpineHandles.DrawRectTransformRect(skeletonGraphic, Color.gray);
+				SpineHandles.DrawReferenceRect(skeletonGraphic, Color.green);
+			} else {
+				SpineHandles.DrawReferenceRect(skeletonGraphic, Color.blue);
+			}
+
+
+		}
+
 		protected void AssignDefaultBlendModeMaterials () {
 		protected void AssignDefaultBlendModeMaterials () {
 			foreach (UnityEngine.Object target in targets) {
 			foreach (UnityEngine.Object target in targets) {
 				SkeletonGraphic skeletonGraphic = (SkeletonGraphic)target;
 				SkeletonGraphic skeletonGraphic = (SkeletonGraphic)target;

+ 36 - 0
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineHandles.cs

@@ -424,6 +424,42 @@ namespace Spine.Unity.Editor {
 			}
 			}
 		}
 		}
 
 
+		public static void DrawReferenceRect (SkeletonGraphic skeletonGraphic, Color color) {
+			RectTransform rectTransform = skeletonGraphic.rectTransform;
+			Vector2 referenceRectSize = skeletonGraphic.GetReferenceRectSize();
+			Vector3 position = rectTransform.position;
+			Vector3 right = rectTransform.TransformVector(Vector3.right * referenceRectSize.x);
+			Vector3 up = rectTransform.TransformVector(Vector3.up * referenceRectSize.y);
+
+			Vector3 cornerVertexBL = position - rectTransform.pivot.x * right - rectTransform.pivot.y * up;
+			DrawRect(cornerVertexBL, right, up, color);
+		}
+
+		public static void DrawRectTransformRect (SkeletonGraphic skeletonGraphic, Color color) {
+			RectTransform rectTransform = skeletonGraphic.rectTransform;
+			Vector2 rectTransformSize = skeletonGraphic.RectTransformSize;
+			Vector3 position = rectTransform.position;
+			Vector3 right = rectTransform.TransformVector(Vector3.right * rectTransformSize.x);
+			Vector3 up = rectTransform.TransformVector(Vector3.up * rectTransformSize.y);
+
+			Vector3 cornerVertexBL = position - rectTransform.pivot.x * right - rectTransform.pivot.y * up;
+			DrawRect(cornerVertexBL, right, up, color);
+		}
+
+		public static void DrawRect (Vector3 cornerVertexBL, Vector3 right, Vector3 up, Color color) {
+			Vector3 v0 = cornerVertexBL;
+			Vector3 v1 = v0 + right;
+			Vector3 v2 = v0 + right + up;
+			Vector3 v3 = v0 + up;
+			Color previousColor = UnityEditor.Handles.color;
+			UnityEditor.Handles.color = color;
+			UnityEditor.Handles.DrawLine(v0, v1);
+			UnityEditor.Handles.DrawLine(v1, v2);
+			UnityEditor.Handles.DrawLine(v2, v3);
+			UnityEditor.Handles.DrawLine(v3, v0);
+			UnityEditor.Handles.color = previousColor;
+		}
+
 		static void DrawCrosshairs2D (Vector3 position, float scale, float skeletonRenderScale = 1f) {
 		static void DrawCrosshairs2D (Vector3 position, float scale, float skeletonRenderScale = 1f) {
 			scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
 			scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
 			Handles.DrawLine(position + new Vector3(-scale, 0), position + new Vector3(scale, 0));
 			Handles.DrawLine(position + new Vector3(-scale, 0), position + new Vector3(scale, 0));

+ 145 - 14
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs

@@ -68,8 +68,29 @@ namespace Spine.Unity {
 		public float timeScale = 1f;
 		public float timeScale = 1f;
 		public bool freeze;
 		public bool freeze;
 
 
-		/// <summary>Update mode to optionally limit updates to e.g. only apply animations but not update the mesh.</summary>
-		public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } }
+		public enum LayoutMode {
+			None = 0,
+			WidthControlsHeight,
+			HeightControlsWidth,
+			FitInParent,
+			EnvelopeParent
+		}
+		public LayoutMode layoutScaleMode = LayoutMode.None;
+		[SerializeField] protected Vector2 referenceSize = Vector2.one;
+		[SerializeField] protected float referenceScale = 1f;
+#if UNITY_EDITOR
+		protected LayoutMode previousLayoutScaleMode = LayoutMode.None;
+		[SerializeField] protected Vector2 rectTransformSize = Vector2.zero;
+		[SerializeField] protected bool editReferenceRect = false;
+		protected bool previousEditReferenceRect = false;
+
+		public bool EditReferenceRect { get { return editReferenceRect; } set { editReferenceRect = value; } }
+		public Vector2 RectTransformSize { get { return rectTransformSize; } }
+#else
+		protected const bool EditReferenceRect = false;
+#endif
+/// <summary>Update mode to optionally limit updates to e.g. only apply animations but not update the mesh.</summary>
+public UpdateMode UpdateMode { get { return updateMode; } set { updateMode = value; } }
 		protected UpdateMode updateMode = UpdateMode.FullUpdate;
 		protected UpdateMode updateMode = UpdateMode.FullUpdate;
 
 
 		/// <summary>Update mode used when the MeshRenderer becomes invisible
 		/// <summary>Update mode used when the MeshRenderer becomes invisible
@@ -273,6 +294,10 @@ namespace Spine.Unity {
 				Initialize(false);
 				Initialize(false);
 				Rebuild(CanvasUpdate.PreRender);
 				Rebuild(CanvasUpdate.PreRender);
 			}
 			}
+
+#if UNITY_EDITOR
+			InitLayoutScaleParameters();
+#endif
 		}
 		}
 
 
 		protected override void OnDestroy () {
 		protected override void OnDestroy () {
@@ -297,6 +322,7 @@ namespace Spine.Unity {
 		public virtual void Update () {
 		public virtual void Update () {
 #if UNITY_EDITOR
 #if UNITY_EDITOR
 			if (!Application.isPlaying) {
 			if (!Application.isPlaying) {
+				UpdateReferenceRectSizes();
 				Update(0f);
 				Update(0f);
 				return;
 				return;
 			}
 			}
@@ -316,7 +342,6 @@ namespace Spine.Unity {
 			wasUpdatedAfterInit = true;
 			wasUpdatedAfterInit = true;
 			if (updateMode < UpdateMode.OnlyAnimationStatus)
 			if (updateMode < UpdateMode.OnlyAnimationStatus)
 				return;
 				return;
-
 			UpdateAnimationStatus(deltaTime);
 			UpdateAnimationStatus(deltaTime);
 
 
 			if (updateMode == UpdateMode.OnlyAnimationStatus) {
 			if (updateMode == UpdateMode.OnlyAnimationStatus) {
@@ -547,15 +572,26 @@ namespace Spine.Unity {
 				0.5f - (center.y / size.y)
 				0.5f - (center.y / size.y)
 			);
 			);
 
 
-			this.rectTransform.sizeDelta = size;
+			SetRectTransformSize(this, size);
 			this.rectTransform.pivot = p;
 			this.rectTransform.pivot = p;
 
 
 			foreach (SkeletonSubmeshGraphic submeshGraphic in submeshGraphics) {
 			foreach (SkeletonSubmeshGraphic submeshGraphic in submeshGraphics) {
-				submeshGraphic.rectTransform.sizeDelta = size;
+				SetRectTransformSize(submeshGraphic, size);
 				submeshGraphic.rectTransform.pivot = p;
 				submeshGraphic.rectTransform.pivot = p;
 			}
 			}
 		}
 		}
 
 
+		public static void SetRectTransformSize (Graphic target, Vector2 size) {
+			Vector2 parentSize = Vector2.zero;
+			if (target.rectTransform.parent != null) {
+				RectTransform parentTransform = target.rectTransform.parent.GetComponent<RectTransform>();
+				if (parentTransform)
+					parentSize = parentTransform.rect.size;
+			}
+			Vector2 anchorAreaSize = target.rectTransform.anchorMax * parentSize - target.rectTransform.anchorMin * parentSize;
+			target.rectTransform.sizeDelta = size - anchorAreaSize;
+		}
+
 		/// <summary>OnAnimationRebuild is raised after the SkeletonAnimation component is successfully initialized.</summary>
 		/// <summary>OnAnimationRebuild is raised after the SkeletonAnimation component is successfully initialized.</summary>
 		public event ISkeletonAnimationDelegate OnAnimationRebuild;
 		public event ISkeletonAnimationDelegate OnAnimationRebuild;
 		public event UpdateBonesDelegate BeforeApply;
 		public event UpdateBonesDelegate BeforeApply;
@@ -731,7 +767,13 @@ namespace Spine.Unity {
 				meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
 				meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles);
 			}
 			}
 
 
-			if (canvas != null) meshGenerator.ScaleVertexData(canvas.referencePixelsPerUnit);
+			float scale = (canvas == null) ? 100 : canvas.referencePixelsPerUnit;
+			if (layoutScaleMode != LayoutMode.None) {
+				scale *= referenceScale;
+				if (!EditReferenceRect)
+					scale *= GetLayoutScale(layoutScaleMode);
+			}
+			meshGenerator.ScaleVertexData(scale);
 			if (OnPostProcessVertices != null) OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
 			if (OnPostProcessVertices != null) OnPostProcessVertices.Invoke(this.meshGenerator.Buffers);
 
 
 			Mesh mesh = smartMesh.mesh;
 			Mesh mesh = smartMesh.mesh;
@@ -803,9 +845,12 @@ namespace Spine.Unity {
 		}
 		}
 
 
 		protected void UpdateMeshMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) {
 		protected void UpdateMeshMultipleCanvasRenderers (SkeletonRendererInstruction currentInstructions) {
-			Canvas c = canvas;
-			float scale = (c == null) ? 100 : c.referencePixelsPerUnit;
-
+			float scale = (canvas == null) ? 100 : canvas.referencePixelsPerUnit;
+			if (layoutScaleMode != LayoutMode.None) {
+				scale *= referenceScale;
+				if (!EditReferenceRect)
+					scale *= GetLayoutScale(layoutScaleMode);
+			}
 			// Generate meshes.
 			// Generate meshes.
 			int submeshCount = currentInstructions.submeshInstructions.Count;
 			int submeshCount = currentInstructions.submeshInstructions.Count;
 			Mesh[] meshesItems = meshes.Items;
 			Mesh[] meshesItems = meshes.Items;
@@ -893,14 +938,19 @@ namespace Spine.Unity {
 
 
 			for (int i = 0; i < submeshCount; i++) {
 			for (int i = 0; i < submeshCount; i++) {
 				CanvasRenderer canvasRenderer = canvasRenderers[i];
 				CanvasRenderer canvasRenderer = canvasRenderers[i];
-				if (i >= usedRenderersCount) {
+				if (i >= usedRenderersCount)
 					canvasRenderer.gameObject.SetActive(true);
 					canvasRenderer.gameObject.SetActive(true);
-				}
-				if (canvasRenderer.transform.parent != parent.transform) {
+
+				if (canvasRenderer.transform.parent != parent.transform)
 					canvasRenderer.transform.SetParent(parent.transform, false);
 					canvasRenderer.transform.SetParent(parent.transform, false);
-					canvasRenderer.transform.localPosition = Vector3.zero;
-				}
+
 				canvasRenderer.transform.SetSiblingIndex(targetSiblingIndex++);
 				canvasRenderer.transform.SetSiblingIndex(targetSiblingIndex++);
+				RectTransform dstTransform = submeshGraphics[i].rectTransform;
+				dstTransform.localPosition = Vector3.zero;
+				dstTransform.pivot = rectTransform.pivot;
+				dstTransform.anchorMin = Vector2.zero;
+				dstTransform.anchorMax = Vector2.one;
+				dstTransform.sizeDelta = Vector2.zero;
 
 
 				SubmeshInstruction submeshInstructionItem = currentInstructions.submeshInstructions.Items[i];
 				SubmeshInstruction submeshInstructionItem = currentInstructions.submeshInstructions.Items[i];
 				if (submeshInstructionItem.forceSeparate) {
 				if (submeshInstructionItem.forceSeparate) {
@@ -1027,6 +1077,87 @@ namespace Spine.Unity {
 				}
 				}
 			}
 			}
 		}
 		}
+
+		protected void InitLayoutScaleParameters () {
+			previousLayoutScaleMode = layoutScaleMode;
+		}
+
+		protected void UpdateReferenceRectSizes () {
+			if (rectTransformSize == Vector2.zero)
+				rectTransformSize = GetCurrentRectSize();
+
+			HandleChangedEditReferenceRect();
+
+			if (layoutScaleMode != previousLayoutScaleMode) {
+				if (layoutScaleMode != LayoutMode.None) {
+					SetRectTransformSize(this, rectTransformSize);
+				} else {
+					rectTransformSize = referenceSize / referenceScale;
+					referenceScale = 1f;
+					SetRectTransformSize(this, rectTransformSize);
+				}
+			}
+			if (editReferenceRect || layoutScaleMode == LayoutMode.None) {
+				referenceSize = GetCurrentRectSize();
+			}
+			previousLayoutScaleMode = layoutScaleMode;
+		}
+
+		protected void HandleChangedEditReferenceRect () {
+			if (editReferenceRect == previousEditReferenceRect) return;
+			previousEditReferenceRect = editReferenceRect;
+
+			if (editReferenceRect) {
+				rectTransformSize = GetCurrentRectSize();
+				ResetRectToReferenceRectSize();
+			} else {
+				SetRectTransformSize(this, rectTransformSize);
+			}
+		}
+
+		public void ResetRectToReferenceRectSize () {
+			referenceScale = referenceScale * GetLayoutScale(previousLayoutScaleMode);
+			float referenceAspect = referenceSize.x / referenceSize.y;
+			Vector2 newSize = GetCurrentRectSize();
+
+			LayoutMode mode = previousLayoutScaleMode;
+			float frameAspect = newSize.x / newSize.y;
+			if (mode == LayoutMode.FitInParent)
+				mode = frameAspect > referenceAspect ? LayoutMode.HeightControlsWidth : LayoutMode.WidthControlsHeight;
+			else if (mode == LayoutMode.EnvelopeParent)
+				mode = frameAspect > referenceAspect ? LayoutMode.WidthControlsHeight : LayoutMode.HeightControlsWidth;
+
+			if (mode == LayoutMode.WidthControlsHeight)
+				newSize.y = newSize.x / referenceAspect;
+			else if (mode == LayoutMode.HeightControlsWidth)
+				newSize.x = newSize.y * referenceAspect;
+			SetRectTransformSize(this, newSize);
+		}
+
+		public Vector2 GetReferenceRectSize () {
+			return referenceSize * GetLayoutScale(layoutScaleMode);
+		}
 #endif
 #endif
+
+		protected float GetLayoutScale (LayoutMode mode) {
+			Vector2 currentSize = GetCurrentRectSize();
+			float referenceAspect = referenceSize.x / referenceSize.y;
+				float frameAspect = currentSize.x / currentSize.y;
+			if (mode == LayoutMode.FitInParent)
+				mode = frameAspect > referenceAspect ? LayoutMode.HeightControlsWidth : LayoutMode.WidthControlsHeight;
+			else if (mode == LayoutMode.EnvelopeParent)
+				mode = frameAspect > referenceAspect ? LayoutMode.WidthControlsHeight : LayoutMode.HeightControlsWidth;
+
+			if (mode == LayoutMode.WidthControlsHeight) {
+				return currentSize.x / referenceSize.x;
+			} else if (mode == LayoutMode.HeightControlsWidth) {
+				return currentSize.y / referenceSize.y;
+			}
+			return 1f;
+		}
+
+		private Vector2 GetCurrentRectSize () {
+			return this.rectTransform.rect.size;
+		}
 	}
 	}
 }
 }