diff --git a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs index 0ec559ae1..89fff4646 100644 --- a/Editor/Mono/AssemblyInfo/AssemblyInfo.cs +++ b/Editor/Mono/AssemblyInfo/AssemblyInfo.cs @@ -142,6 +142,7 @@ [assembly: InternalsVisibleTo("Unity.Testing.VisualEffectGraph.EditorTests")] [assembly: InternalsVisibleTo("Unity.VisualEffectGraph.EditorTests")] [assembly: InternalsVisibleTo("Unity.RenderPipelines.Multiple_SRP.EditorTests")] +[assembly: InternalsVisibleTo("Unity.ShaderGraph.Editor")] [assembly: InternalsVisibleTo("Unity.SceneTemplate.Editor")] [assembly: InternalsVisibleTo("com.unity.purchasing.udp.Editor")] diff --git a/Editor/Mono/FileUtil.bindings.cs b/Editor/Mono/FileUtil.bindings.cs index 8673c6650..be31e80a2 100644 --- a/Editor/Mono/FileUtil.bindings.cs +++ b/Editor/Mono/FileUtil.bindings.cs @@ -151,8 +151,12 @@ public static void ReplaceFile(string src, string dst) public static void ReplaceDirectory(string src, string dst) { if (Directory.Exists(dst)) - FileUtil.DeleteFileOrDirectory(dst); - + { + bool succesfullyDeletedDirectory = FileUtil.DeleteFileOrDirectory(dst); + if (succesfullyDeletedDirectory == false) + throw new System.IO.IOException(string.Format( + "Failed to delete directory '{0}'.", dst)); + } FileUtil.CopyFileOrDirectory(src, dst); } diff --git a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs index 7d1d49f88..cadf25094 100644 --- a/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs +++ b/Editor/Mono/Inspector/PlayerSettingsEditor/PlayerSettingsEditor.cs @@ -2465,13 +2465,13 @@ private void OtherSectionRenderingGUI(BuildPlatform platform, ISettingEditorExte using (new EditorGUI.DisabledScope(EditorApplication.isPlaying || Lightmapping.isRunning)) { EditorGUI.BeginChangeCheck(); - NormalMapEncoding oldEncoding = PlayerSettings.GetNormalMapEncoding(platform.namedBuildTarget); + var oldEncoding = PlayerSettings.GetNormalMapEncoding_Internal(m_CurrentTarget, platform.name); NormalMapEncoding[] encodingValues = { NormalMapEncoding.XYZ, NormalMapEncoding.DXT5nm }; - NormalMapEncoding newEncoding = BuildEnumPopup(SettingsContent.normalMapEncodingLabel, oldEncoding, encodingValues, SettingsContent.normalMapEncodingNames); + var newEncoding = BuildEnumPopup(SettingsContent.normalMapEncodingLabel, oldEncoding, encodingValues, SettingsContent.normalMapEncodingNames); if (EditorGUI.EndChangeCheck() && newEncoding != oldEncoding) { - PlayerSettings.SetNormalMapEncoding(platform.namedBuildTarget, newEncoding); - serializedObject.ApplyModifiedProperties(); + PlayerSettings.SetNormalMapEncoding_Internal(m_CurrentTarget, platform.name, newEncoding); + m_OnTrackSerializedObjectValueChanged?.Invoke(serializedObject); GUIUtility.ExitGUI(); } } diff --git a/Editor/Mono/PlayerSettings.bindings.cs b/Editor/Mono/PlayerSettings.bindings.cs index 2e3aacc27..a2a1f68f4 100644 --- a/Editor/Mono/PlayerSettings.bindings.cs +++ b/Editor/Mono/PlayerSettings.bindings.cs @@ -1825,6 +1825,12 @@ internal static extern bool iosCopyPluginsCodeInsteadOfSymlink [StaticAccessor("PlayerSettingsBindings", StaticAccessorType.DoubleColon)] internal static extern void SetShaderChunkCountForPlatform_Internal(PlayerSettings instance, BuildTarget buildTarget, int chunkCount); + [StaticAccessor("PlayerSettingsBindings", StaticAccessorType.DoubleColon)] + internal static extern NormalMapEncoding GetNormalMapEncoding_Internal(PlayerSettings instance, string platform); + + [StaticAccessor("PlayerSettingsBindings", StaticAccessorType.DoubleColon)] + internal static extern void SetNormalMapEncoding_Internal(PlayerSettings instance, string platform, NormalMapEncoding encoding); + /* * Internal non-static getter/setters referenced when reading/writing to non-active player settings object. */ diff --git a/Editor/Mono/Tools/EditorToolManager.cs b/Editor/Mono/Tools/EditorToolManager.cs index 08ac6d2a6..c3d3ccfd2 100644 --- a/Editor/Mono/Tools/EditorToolManager.cs +++ b/Editor/Mono/Tools/EditorToolManager.cs @@ -28,8 +28,6 @@ sealed class EditorToolManager : ScriptableSingleton [SerializeField] Tool m_LastBuiltinTool = Tool.Move; - Type m_LastCustomContext; - [SerializeField] EditorTool m_LastCustomTool; @@ -100,9 +98,6 @@ internal static EditorToolContext activeToolContext if (prev != null) { prev.Deactivate(); - - if (!(prev is GameObjectToolContext)) - instance.m_LastCustomContext = prev.GetType(); } ToolManager.ActiveContextWillChange(); @@ -495,8 +490,6 @@ internal EditorTool lastManipulationTool internal static EditorTool lastCustomTool => instance.m_LastCustomTool; - internal static Type lastCustomContext => instance.m_LastCustomContext; - public static void RestorePreviousPersistentTool() { activeTool = instance.lastManipulationTool; diff --git a/Editor/Mono/Tools/ToolManager.cs b/Editor/Mono/Tools/ToolManager.cs index 3e48c19de..8e420874b 100644 --- a/Editor/Mono/Tools/ToolManager.cs +++ b/Editor/Mono/Tools/ToolManager.cs @@ -163,45 +163,30 @@ internal static IEnumerable allContextsExceptGameObject } } - internal static Type GetLastContextType() - { - var lastContext = EditorToolManager.lastCustomContext; - if (lastContext != null && lastContext != typeof(GameObjectToolContext)) - return lastContext; - - return allContextsExceptGameObject.FirstOrDefault(); - } - [Shortcut("Tools/Enter GameObject Mode", typeof(ToolShortcutContext))] internal static void ExitToolContext() { SetActiveContext(); } - [Shortcut("Tools/Cycle Tool Modes", typeof(ToolShortcutContext))] + [Shortcut("Tools/Cycle Tool Modes", typeof(ToolShortcutContext), KeyCode.G)] internal static void CycleToolContexts() { if (EditorToolUtility.toolContextsInProject < 2) return; var active = EditorToolManager.activeToolContext; - - if (active is GameObjectToolContext && EditorToolManager.lastCustomContext != null) - { - var instance = allContextsExceptGameObject.FirstOrDefault(x => x == EditorToolManager.lastCustomContext); - - if (instance != null) - { - SetActiveContext(instance); - return; - } - } - using var all = allContextsExceptGameObject.GetEnumerator(); if (!all.MoveNext()) return; + if (active is GameObjectToolContext) + { + SetActiveContext(all.Current); + return; + } + // Select the next available context after the active while (all.Current != active.GetType()) { @@ -219,7 +204,7 @@ internal static void CycleToolContexts() if (all.MoveNext()) SetActiveContext(all.Current); else - SetActiveContext(allContextsExceptGameObject.First()); + SetActiveContext(typeof(GameObjectToolContext)); } } } diff --git a/Modules/EditorToolbar/Controls/ToolContextButton.cs b/Modules/EditorToolbar/Controls/ToolContextButton.cs index c0a4d9ca7..5cea5aa4d 100644 --- a/Modules/EditorToolbar/Controls/ToolContextButton.cs +++ b/Modules/EditorToolbar/Controls/ToolContextButton.cs @@ -105,12 +105,7 @@ void RefreshActiveContext() { if (isGOToolContext) { - var lastContextType = ToolManager.GetLastContextType(); - // JIRA: UUM-16237. Use the content of the last context only if the current selection is associated with the same type of context. - if (ToolManager.allContextsExceptGameObject.Contains(lastContextType)) - activeContextType = lastContextType; - else - activeContextType = ToolManager.allContextsExceptGameObject.FirstOrDefault(); + activeContextType = ToolManager.allContextsExceptGameObject.FirstOrDefault(); } else activeContextType = ToolManager.activeContextType; diff --git a/Modules/GraphViewEditor/Elements/ElementResizer.cs b/Modules/GraphViewEditor/Elements/ElementResizer.cs index 5e0768b1f..6de73e72e 100644 --- a/Modules/GraphViewEditor/Elements/ElementResizer.cs +++ b/Modules/GraphViewEditor/Elements/ElementResizer.cs @@ -79,7 +79,7 @@ void OnMouseDown(MouseDownEvent e) target.RegisterCallback(OnMouseMove); e.StopPropagation(); target.CaptureMouse(); - m_StartMouse = resizedBase.WorldToLocal(e.mousePosition); + m_StartMouse = e.mousePosition; m_StartSize = new Vector2(resizedTarget.resolvedStyle.width, resizedTarget.resolvedStyle.height); m_StartPosition = new Vector2(resizedTarget.resolvedStyle.left, resizedTarget.resolvedStyle.top); @@ -104,8 +104,10 @@ void OnMouseMove(MouseMoveEvent e) VisualElement resizedTarget = resizedElement.parent; VisualElement resizedBase = resizedTarget.parent; + var validResizeBase = resizedBase; + FindValidBaseElement(ref validResizeBase); - Vector2 mousePos = resizedBase.WorldToLocal(e.mousePosition); + Vector2 mousePos = e.mousePosition; if (!m_DragStarted) { if (resizedTarget is IResizable) @@ -149,27 +151,48 @@ void OnMouseMove(MouseMoveEvent e) { if ((direction & ResizerDirection.Right) != 0) { - resizedTarget.style.width = Mathf.Clamp(m_StartSize.x + mousePos.x - m_StartMouse.x, m_MinSize.x, Mathf.Min(m_MaxSize.x, resizedBase.layout.xMax - resizedTarget.layout.xMin)); + var worldZero = validResizeBase.LocalToWorld(Vector2.zero); + var localZero = resizedBase.WorldToLocal(worldZero); + var localWidth = validResizeBase.layout.width / resizedTarget.worldTransform.lossyScale.x; + var newWidth = Mathf.Min(m_StartSize.x + (mousePos.x - m_StartMouse.x) / resizedTarget.worldTransform.lossyScale.x, this.m_MaxSize.x); + var newRight = Mathf.Clamp(resizedTarget.layout.xMin + newWidth, resizedTarget.layout.xMin + m_MinSize.x, localZero.x + localWidth); + resizedTarget.style.width = newRight - resizedTarget.layout.xMin; } else if ((direction & ResizerDirection.Left) != 0) { - float delta = mousePos.x - m_StartMouse.x; - float previousLeft = resizedTarget.style.left.value.value; - - resizedTarget.style.left = Mathf.Clamp(delta + m_StartPosition.x, 0, resizedTarget.layout.xMax - m_MinSize.x); - resizedTarget.style.width = resizedTarget.resolvedStyle.width + previousLeft - resizedTarget.style.left.value.value; + var worldZero = validResizeBase.LocalToWorld(Vector2.zero); + var localZero = resizedBase.WorldToLocal(worldZero); + var delta = (mousePos.x - m_StartMouse.x) / resizedTarget.worldTransform.lossyScale.x; + var newLeft = Mathf.Clamp(m_StartPosition.x + delta, localZero.x, localZero.x + validResizeBase.layout.width); + var newWidth = resizedTarget.layout.xMax - newLeft; + if (newWidth >= m_MinSize.x && newWidth <= m_MaxSize.x) + { + resizedTarget.style.left = newLeft; + resizedTarget.style.width = newWidth; + } } if ((direction & ResizerDirection.Bottom) != 0) { - resizedTarget.style.height = Mathf.Min(m_MaxSize.y, Mathf.Max(m_MinSize.y, m_StartSize.y + mousePos.y - m_StartMouse.y)); + var worldZero = validResizeBase.LocalToWorld(Vector2.zero); + var localZero = resizedBase.WorldToLocal(worldZero); + var localHeight = validResizeBase.layout.height / resizedTarget.worldTransform.lossyScale.x; + var newHeight = m_StartSize.y + (mousePos.y - m_StartMouse.y) / resizedTarget.worldTransform.lossyScale.x; + var newBottom = Mathf.Clamp(resizedTarget.layout.yMin + newHeight, resizedTarget.layout.yMin + m_MinSize.y, localZero.y + localHeight); + resizedTarget.style.height = newBottom - resizedTarget.layout.yMin; } else if ((direction & ResizerDirection.Top) != 0) { - float delta = mousePos.y - m_StartMouse.y; - float previousTop = resizedTarget.style.top.value.value; - - resizedTarget.style.top = Mathf.Clamp(delta + m_StartPosition.y, 0, m_StartSize.y - 1); - resizedTarget.style.height = resizedTarget.resolvedStyle.height + previousTop - resizedTarget.style.top.value.value; + var worldZero = validResizeBase.LocalToWorld(Vector2.zero); + var localZero = resizedBase.WorldToLocal(worldZero); + var localHeight = validResizeBase.layout.height / resizedTarget.worldTransform.lossyScale.x; + var delta = (mousePos.y - m_StartMouse.y) / resizedTarget.worldTransform.lossyScale.x; + var newTop = Mathf.Clamp(m_StartPosition.y + delta, localZero.y, localZero.y + localHeight); + var newHeight = resizedTarget.layout.yMax - newTop; + if (newHeight >= m_MinSize.y && newHeight <= m_MaxSize.y) + { + resizedTarget.style.top = newTop; + resizedTarget.style.height = newHeight; + } } } e.StopPropagation(); @@ -195,5 +218,20 @@ void OnMouseUp(MouseUpEvent e) m_Active = false; } } + + void FindValidBaseElement(ref VisualElement resizedBase) + { + // For unknown reason, layers have zero height, which completely break resizing algorithm + // So we look for a parent with proper dimension + while (resizedBase.layout.width == 0 || resizedBase.layout.height == 0) + { + if (resizedBase.parent == null) + { + break; + } + + resizedBase = resizedBase.parent; + } + } } } diff --git a/Modules/IMGUI/TextEditingUtilities.cs b/Modules/IMGUI/TextEditingUtilities.cs index 6b042ac9b..4259b5b9e 100644 --- a/Modules/IMGUI/TextEditingUtilities.cs +++ b/Modules/IMGUI/TextEditingUtilities.cs @@ -341,7 +341,6 @@ void InitKeyActions() } } - // Deletes previous text on the line public bool DeleteLineBack() { @@ -353,6 +352,18 @@ public bool DeleteLineBack() return true; } + if (textHandle.useAdvancedText) + { + var start = textHandle.GetFirstCharacterIndexOnLine(cursorIndex); + if (start != cursorIndex) + { + text = text.Remove(start, stringCursorIndex - start); + cursorIndex = selectIndex = start; + return true; + } + return false; + } + var currentLineInfo = textHandle.GetLineInfoFromCharacterIndex(cursorIndex); var startIndex = currentLineInfo.firstCharacterIndex; var stringStartIndex = textHandle.GetCorrespondingStringIndex(startIndex); @@ -422,7 +433,11 @@ public bool Delete() } else if (stringCursorIndex < text.Length) { - var count = textHandle.textInfo.textElementInfo[cursorIndex].stringLength; + int count; + if (textHandle.useAdvancedText) + count = textHandle.NextCodePointIndex(cursorIndex) - cursorIndex; + else + count = textHandle.textInfo.textElementInfo[cursorIndex].stringLength; text = text.Remove(stringCursorIndex, count); return true; } @@ -442,10 +457,15 @@ public bool Backspace() else if (cursorIndex > 0) { var startIndex = m_TextSelectingUtility.PreviousCodePointIndex(cursorIndex); - var count = textHandle.textInfo.textElementInfo[cursorIndex - 1].stringLength; + int count; + if (textHandle.useAdvancedText) + count = (char.IsSurrogate(text[cursorIndex - 1]) ? 2 : 1); + else + count = textHandle.textInfo.textElementInfo[cursorIndex - 1].stringLength; + text = text.Remove(stringCursorIndex - count, count); - cursorIndex = startIndex; - selectIndex = startIndex; + cursorIndex = textHandle.useAdvancedText ? Math.Max(0, cursorIndex - count) : startIndex; + selectIndex = textHandle.useAdvancedText ? Math.Max(0, selectIndex - count) : startIndex; m_TextSelectingUtility.ClearCursorPos(); return true; } @@ -479,7 +499,8 @@ public void ReplaceSelection(string replace) DeleteSelection(); text = text.Insert(stringCursorIndex, replace); - var newIndex = cursorIndexNoValidation + new StringInfo(replace).LengthInTextElements; + int length = textHandle.useAdvancedText ? replace.Length : new StringInfo(replace).LengthInTextElements; + var newIndex = cursorIndexNoValidation + length; cursorIndexNoValidation = newIndex; selectIndexNoValidation = newIndex; m_TextSelectingUtility.ClearCursorPos(); @@ -538,6 +559,7 @@ public bool Cut() m_TextSelectingUtility.Copy(); return DeleteSelection(); } + public bool Paste() { RestoreCursorState(); diff --git a/Modules/PackageManagerUI/Editor/Extensions/ExtendableToolbarMenu.cs b/Modules/PackageManagerUI/Editor/Extensions/ExtendableToolbarMenu.cs index 33ce18802..7e02c2c3e 100644 --- a/Modules/PackageManagerUI/Editor/Extensions/ExtendableToolbarMenu.cs +++ b/Modules/PackageManagerUI/Editor/Extensions/ExtendableToolbarMenu.cs @@ -92,14 +92,8 @@ public void Remove(MenuDropdownItem item) public void ShowInputDropdown(InputDropdownArgs args) { - var rect = GUIUtility.GUIToScreenRect(worldBound); - - // GUIToScreenRect calculates screen space coordinates in relation to contextual menu - // which is the last active view. Since we know the exact offset of contextual menu in - // relation to package manager we can compensate this by subtracting contextual menu origin. - rect.y -= worldBound.yMax; - - var dropdown = new GenericInputDropdown(m_ResourceLoader, PackageManagerWindow.instance, args) { position = rect }; + var position = PackageManagerWindow.instance.CalculateDropdownPosition(this); + var dropdown = new GenericInputDropdown(m_ResourceLoader, PackageManagerWindow.instance, args) { position = position }; DropdownContainer.ShowDropdown(dropdown); } } diff --git a/Modules/PackageManagerUI/Editor/UI/DropdownContainer.cs b/Modules/PackageManagerUI/Editor/UI/DropdownContainer.cs index d75ebb6a0..68e5f0b47 100644 --- a/Modules/PackageManagerUI/Editor/UI/DropdownContainer.cs +++ b/Modules/PackageManagerUI/Editor/UI/DropdownContainer.cs @@ -40,14 +40,5 @@ public static void ShowDropdown(DropdownContent content) instance.ShowAsDropDown(content.position, content.windowSize); content.OnDropdownShown(); } - - static void ShowDropdownContainer() - { - instance.ShowAsDropDown(instance.m_Content.position, instance.m_Content.windowSize); - instance.m_Content.OnDropdownShown(); - - // Make sure delayCall has no chance to execute twice or more for the same menu. We had some issues like this in UI Elements tests suite - EditorApplication.delayCall -= ShowDropdownContainer; - } } } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs index 65a535365..a73feddb6 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerToolbar.cs @@ -219,8 +219,8 @@ private void SetupInProgressSpinner() if (!inProgressSpinner.started) return; - var rect = GUIUtility.GUIToScreenRect(spinnerButtonContainer.worldBound); - var dropdown = new InProgressDropdown(m_ResourceLoader, m_UpmClient, m_AssetStoreDownloadManager, m_PackageDatabase, m_PageManager) { position = rect }; + var position = PackageManagerWindow.instance.CalculateDropdownPosition(spinnerButtonContainer); + var dropdown = new InProgressDropdown(m_ResourceLoader, m_UpmClient, m_AssetStoreDownloadManager, m_PackageDatabase, m_PageManager) { position = position }; DropdownContainer.ShowDropdown(dropdown); }); } @@ -341,9 +341,6 @@ private void SetupAddMenu() }, windowSize = new Vector2(resolvedStyle.width, 50) }; - // If a background GUI painted before, the coordinates got could be different. - // Repaint the package manager to ensure the coordinates retrieved is from packmanager. - PackageManagerWindow.GetWindow().RepaintImmediately(); addMenu.ShowInputDropdown(args); }; @@ -352,18 +349,8 @@ private void SetupAddMenu() dropdownItem.userData = "AddByName"; dropdownItem.action = () => { - // If a background GUI painted before, the coordinates got could be different. - // Repaint the package manager to ensure the coordinates retrieved is from packmanager. - PackageManagerWindow.GetWindow().RepaintImmediately(); - // Same as above, the worldBound of the toolbar is used rather than the addMenu - var rect = GUIUtility.GUIToScreenRect(worldBound); - - // GUIToScreenRect calculates screen space coordinates in relation to contextual menu - // which is the last active view. Since we know the exact offset of contextual menu in - // relation to package manager we can compensate this by subtracting contextual menu origin. - rect.y -= worldBound.yMax; - - var dropdown = new AddPackageByNameDropdown(m_ResourceLoader, m_UpmClient, m_PackageDatabase, m_PageManager, m_OperationDispatcher, PackageManagerWindow.instance) { position = rect }; + var position = PackageManagerWindow.instance.CalculateDropdownPosition(addMenu); + var dropdown = new AddPackageByNameDropdown(m_ResourceLoader, m_UpmClient, m_PackageDatabase, m_PageManager, m_OperationDispatcher, PackageManagerWindow.instance) { position = position}; DropdownContainer.ShowDropdown(dropdown); }; } diff --git a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs index 3039027f4..36269af0c 100644 --- a/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs +++ b/Modules/PackageManagerUI/Editor/UI/PackageManagerWindow.cs @@ -194,6 +194,14 @@ void OnLostFocus() m_Root?.OnLostFocus(); } + internal Rect CalculateDropdownPosition(VisualElement anchorElement) + { + // If a background GUI painted before, the coordinates got could be different. + // Repaint the package manager to ensure the coordinates retrieved is from Package Manager Window. + RepaintImmediately(); + return GUIUtility.GUIToScreenRect(anchorElement.worldBound); + } + [UsedByNativeCode] internal static void OpenURL(string url) { @@ -317,18 +325,6 @@ internal static void SelectPackageAndPageStatic(string packageToSelect = null, s instance.Show(); } - internal static void CloseAll() - { - var windows = Resources.FindObjectsOfTypeAll(); - if (windows == null) - return; - - foreach (var window in windows) - window.Close(); - - instance = null; - } - private static void CheckInnerException(TargetInvocationException e) where T : Exception { var originalException = e; diff --git a/Modules/TextCoreTextEngine/Managed/TextHandle.cs b/Modules/TextCoreTextEngine/Managed/TextHandle.cs index 9a8a7c248..3d3213c53 100644 --- a/Modules/TextCoreTextEngine/Managed/TextHandle.cs +++ b/Modules/TextCoreTextEngine/Managed/TextHandle.cs @@ -362,13 +362,8 @@ internal static float GetLineHeightDefault(TextGenerationSettings settings) public virtual Vector2 GetCursorPositionFromStringIndexUsingCharacterHeight(int index, bool inverseYAxis = true) { - if (useAdvancedText) - { - Debug.LogError("Cannot use GetCursorPositionFromStringIndexUsingCharacterHeight while using Advanced Text"); - return Vector2.zero; - } AddTextInfoToPermanentCache(); - return textInfo.GetCursorPositionFromStringIndexUsingCharacterHeight(index, m_ScreenRect, m_LineHeightDefault, inverseYAxis); + return useAdvancedText ? TextSelectionService.GetCursorPositionFromLogicalIndex(textGenerationInfo, index) : textInfo.GetCursorPositionFromStringIndexUsingCharacterHeight(index, m_ScreenRect, m_LineHeightDefault, inverseYAxis); } public Vector2 GetCursorPositionFromStringIndexUsingLineHeight(int index, bool useXAdvance = false, bool inverseYAxis = true) diff --git a/Modules/UIElements/Core/GameObjects/UIDocument.cs b/Modules/UIElements/Core/GameObjects/UIDocument.cs index 34360a48d..e6d9a6e5c 100644 --- a/Modules/UIElements/Core/GameObjects/UIDocument.cs +++ b/Modules/UIElements/Core/GameObjects/UIDocument.cs @@ -483,16 +483,16 @@ void ComputeTransform(Transform transform, out Matrix4x4 matrix) } else { - var ui2World = Matrix4x4.TRS(Vector3.zero, flipRotation, scale); - var world2UI = ui2World.inverse; + var ui2Go = Matrix4x4.TRS(Vector3.zero, flipRotation, scale); + var go2Ui = ui2Go.inverse; var childGoToWorld = transform.localToWorldMatrix; var worldToParentGo = parentUI.transform.worldToLocalMatrix; - // (GOa - To - World) * (UI2W) * (VEb - Space - To - VEa - Space) = (GOb - To - World) * (UI2W) - // (VEb - Space - To - VEa - Space) = (UI2W) ^ -1 * (GOa - To - World) ^ -1 * (GOb - To - World) * (UI2W) - - matrix = world2UI * worldToParentGo * childGoToWorld * ui2World; + // (VEa To World) * (VEb To VEa) = (VEb To World) + // (GOa To World) * (UI2GO) * (VEb To VEa) = (GOb To World) * (UI2GO) + // (VEb To VEa) = (UI2GO) ^ -1 * (GOa To World) ^ -1 * (GOb To World) * (UI2GO) + matrix = go2Ui * worldToParentGo * childGoToWorld * ui2Go; } } diff --git a/Modules/UIElements/Core/Renderer/UIREntryPool.cs b/Modules/UIElements/Core/Renderer/UIREntryPool.cs index 5de02ecf5..75c0242a8 100644 --- a/Modules/UIElements/Core/Renderer/UIREntryPool.cs +++ b/Modules/UIElements/Core/Renderer/UIREntryPool.cs @@ -27,6 +27,7 @@ class EntryPool e.texture = null; e.material = null; e.gradientsOwner = null; + e.flags = 0; }; public EntryPool(int maxCapacity = 1024) diff --git a/Modules/UIElements/Core/Renderer/UIREntryPreProcessor.cs b/Modules/UIElements/Core/Renderer/UIREntryPreProcessor.cs index d149b55ff..bf0e42e35 100644 --- a/Modules/UIElements/Core/Renderer/UIREntryPreProcessor.cs +++ b/Modules/UIElements/Core/Renderer/UIREntryPreProcessor.cs @@ -62,7 +62,7 @@ void DoEvaluate(Entry entry) case EntryType.DrawSolidMesh: case EntryType.DrawTexturedMesh: case EntryType.DrawTexturedMeshSkipAtlas: - case EntryType.DrawSdfTextMesh: + case EntryType.DrawTextMesh: case EntryType.DrawGradients: Debug.Assert(entry.vertices.Length <= UIRenderDevice.maxVerticesPerPage); Add(entry.vertices.Length, entry.indices.Length); diff --git a/Modules/UIElements/Core/Renderer/UIREntryProcessor.cs b/Modules/UIElements/Core/Renderer/UIREntryProcessor.cs index 41f0c84bd..9e9021d03 100644 --- a/Modules/UIElements/Core/Renderer/UIREntryProcessor.cs +++ b/Modules/UIElements/Core/Renderer/UIREntryProcessor.cs @@ -219,7 +219,7 @@ void ProcessRange(int first, int last) ProcessMeshEntry(entry, textureId); break; } - case EntryType.DrawSdfTextMesh: + case EntryType.DrawTextMesh: { m_RenderType = VertexFlags.IsText; TextureId textureId = TextureRegistry.instance.Acquire(entry.texture); @@ -439,7 +439,7 @@ unsafe void ProcessMeshEntry(Entry entry, TextureId textureId) Color32 xformClipPages = new Color32(m_TransformData.r, m_TransformData.g, clipRectData.r, clipRectData.g); Color32 addFlags = new Color32((byte)m_RenderType, 0, 0, 0); - if (entry.type == EntryType.DrawSdfTextMesh) + if ((entry.flags & EntryFlags.UsesTextCoreSettings) != 0) { // It's important to avoid writing these values when the vertices aren't for text, // as some of these settings are shared with the vector graphics gradients. @@ -469,7 +469,7 @@ unsafe void ProcessMeshEntry(Entry entry, TextureId textureId) addFlags = addFlags, opacityPage = opacityPage, textCoreSettingsPage = m_TextCoreSettingsPage, - isSdfText = entry.type == EntryType.DrawSdfTextMesh ? 1 : 0, + usesTextCoreSettings = (entry.flags & EntryFlags.UsesTextCoreSettings) != 0 ? 1 : 0, textureId = textureId.ConvertToGpu(), gradientSettingsIndexOffset = m_GradientSettingIndexOffset, @@ -500,7 +500,7 @@ unsafe void ProcessMeshEntry(Entry entry, TextureId textureId) var cmd = CreateMeshDrawCommand(m_Mesh, entryIndexCount, m_IndicesFilled, entry.material, textureId); AppendCommand(cmd); - if (entry.type == EntryType.DrawSdfTextMesh) + if (entry.type == EntryType.DrawTextMesh) { // Set font atlas texture gradient scale cmd.state.sdfScale = entry.textScale; diff --git a/Modules/UIElements/Core/Renderer/UIREntryRecorder.cs b/Modules/UIElements/Core/Renderer/UIREntryRecorder.cs index c471c74bc..b08828782 100644 --- a/Modules/UIElements/Core/Renderer/UIREntryRecorder.cs +++ b/Modules/UIElements/Core/Renderer/UIREntryRecorder.cs @@ -8,12 +8,12 @@ namespace UnityEngine.UIElements.UIR { - enum EntryType + enum EntryType : ushort { DrawSolidMesh, DrawTexturedMesh, DrawTexturedMeshSkipAtlas, - DrawSdfTextMesh, + DrawTextMesh, DrawGradients, DrawImmediate, DrawImmediateCull, @@ -35,9 +35,16 @@ enum EntryType DedicatedPlaceholder } + [Flags] + enum EntryFlags : ushort + { + UsesTextCoreSettings = 1 << 0, + } + class Entry { public EntryType type; + public EntryFlags flags; // In an entry, the winding order is ALWAYS clockwise (front-facing) public NativeSlice vertices; @@ -89,10 +96,24 @@ public void DrawMesh(Entry parentEntry, NativeSlice vertices, NativeSlic AppendMeshEntry(parentEntry, entry); } + public void DrawRasterText(Entry parentEntry, NativeSlice vertices, NativeSlice indices, Texture texture, bool multiChannel) + { + var entry = m_EntryPool.Get(); + entry.type = multiChannel ? EntryType.DrawTexturedMeshSkipAtlas : EntryType.DrawTextMesh; + entry.flags = EntryFlags.UsesTextCoreSettings; // For dynamic color + entry.vertices = vertices; + entry.indices = indices; + entry.texture = texture; + entry.textScale = 0; // Used in the shader to indicate raster text + entry.fontSharpness = 0; // N/A + AppendMeshEntry(parentEntry, entry); + } + public void DrawSdfText(Entry parentEntry, NativeSlice vertices, NativeSlice indices, Texture texture, float scale, float sharpness) { var entry = m_EntryPool.Get(); - entry.type = EntryType.DrawSdfTextMesh; + entry.type = EntryType.DrawTextMesh; + entry.flags = EntryFlags.UsesTextCoreSettings; entry.vertices = vertices; entry.indices = indices; entry.texture = texture; diff --git a/Modules/UIElements/Core/Renderer/UIRJobManager.cs b/Modules/UIElements/Core/Renderer/UIRJobManager.cs index 93136b2f6..edd6cc42d 100644 --- a/Modules/UIElements/Core/Renderer/UIRJobManager.cs +++ b/Modules/UIElements/Core/Renderer/UIRJobManager.cs @@ -115,7 +115,7 @@ struct ConvertMeshJobData public Color32 addFlags; public Color32 opacityPage; public Color32 textCoreSettingsPage; - public int isSdfText; + public int usesTextCoreSettings; public float textureId; public int gradientSettingsIndexOffset; diff --git a/Modules/UIElements/Core/Renderer/UIRMeshGenerator.cs b/Modules/UIElements/Core/Renderer/UIRMeshGenerator.cs index c3d49b006..dd6dc02b1 100644 --- a/Modules/UIElements/Core/Renderer/UIRMeshGenerator.cs +++ b/Modules/UIElements/Core/Renderer/UIRMeshGenerator.cs @@ -756,7 +756,8 @@ void DrawTextInfo(List> vertices, List> indices[i], false, 0, - 0); + 0, + true); } else { @@ -782,7 +783,8 @@ void DrawTextInfo(List> vertices, List> indices[i], true, sdfScale, - sharpness); + sharpness, + false); } } } @@ -799,16 +801,16 @@ internal static Vertex ConvertTextVertexToUIRVertex(TextCoreVertex vertex, Vecto uv = new Vector2(vertex.uv0.x, vertex.uv0.y), tint = vertex.color, // TODO: Don't set the flags here. The mesh conversion should perform these changes - flags = new Color32(0, (byte)(dilate * 255), 0, isDynamicColor ? (byte)1 : (byte)0) + flags = new Color32(0, (byte)(dilate * 255), 0, isDynamicColor ? (byte)UIRUtility.k_DynamicColorEnabledText : (byte)UIRUtility.k_DynamicColorDisabled) }; } - void MakeText(Texture texture, NativeSlice vertices, NativeSlice indices, bool isSdf, float sdfScale, float sharpness) + void MakeText(Texture texture, NativeSlice vertices, NativeSlice indices, bool isSdf, float sdfScale, float sharpness, bool multiChannel) { if (isSdf) m_MeshGenerationContext.entryRecorder.DrawSdfText(m_MeshGenerationContext.parentEntry, vertices, indices, texture, sdfScale, sharpness); else - m_MeshGenerationContext.entryRecorder.DrawMesh(m_MeshGenerationContext.parentEntry, vertices, indices, texture, true); + m_MeshGenerationContext.entryRecorder.DrawRasterText(m_MeshGenerationContext.parentEntry, vertices, indices, texture, multiChannel); } public void DrawRectangle(RectangleParams rectParams) diff --git a/Modules/UIElements/Core/Renderer/UIRRenderEvents.cs b/Modules/UIElements/Core/Renderer/UIRRenderEvents.cs index da34d9d3c..2db71f1a4 100644 --- a/Modules/UIElements/Core/Renderer/UIRRenderEvents.cs +++ b/Modules/UIElements/Core/Renderer/UIRRenderEvents.cs @@ -653,7 +653,7 @@ public static bool UpdateTextCoreSettings(RenderChain renderChain, VisualElement bool allocatesID = RenderChainVEData.AllocatesID(ve.renderChainData.textCoreSettingsID); - var settings = TextUtilities.GetTextCoreSettingsForElement(ve); + var settings = TextUtilities.GetTextCoreSettingsForElement(ve, false); // If we aren't using a color ID (the DynamicColor flag), the text color will be stored in the vertex data, // so there's no need for a color match with the default TextCore settings. @@ -881,7 +881,7 @@ internal static bool NeedsColorID(VisualElement ve) internal static bool NeedsTextCoreSettings(VisualElement ve) { // We may require a color ID when using non-trivial TextCore settings. - var settings = TextUtilities.GetTextCoreSettingsForElement(ve); + var settings = TextUtilities.GetTextCoreSettingsForElement(ve, true); if (settings.outlineWidth != 0.0f || settings.underlayOffset != Vector2.zero || settings.underlaySoftness != 0.0f) return true; diff --git a/Modules/UIElements/Core/Renderer/UIRUtility.cs b/Modules/UIElements/Core/Renderer/UIRUtility.cs index 0ff6551ff..ca50407dd 100644 --- a/Modules/UIElements/Core/Renderer/UIRUtility.cs +++ b/Modules/UIElements/Core/Renderer/UIRUtility.cs @@ -26,6 +26,11 @@ static class UIRUtility public const float k_MaskPosZ = 1.0f; // The correct z value to push/pop a mask public const int k_MaxMaskDepth = 7; // Requires 3 bits in the stencil + // Keep in sync with UIRVertexUtility.h + public const byte k_DynamicColorDisabled = 0; + public const byte k_DynamicColorEnabled = 1; + public const byte k_DynamicColorEnabledText = 2; + [MethodImpl(MethodImplOptionsEx.AggressiveInlining)] public static bool ShapeWindingIsClockwise(int maskDepth, int stencilRef) { diff --git a/Modules/UIElements/Core/Text/TextUtilities.cs b/Modules/UIElements/Core/Text/TextUtilities.cs index 944b264e2..f66630663 100644 --- a/Modules/UIElements/Core/Text/TextUtilities.cs +++ b/Modules/UIElements/Core/Text/TextUtilities.cs @@ -138,7 +138,7 @@ internal static bool IsAdvancedTextEnabledForElement(TextElement te) return isAdvancedTextGeneratorEnabledOnTextElement && isAdvancedTextGeneratorEnabledOnProject; } - internal static TextCoreSettings GetTextCoreSettingsForElement(VisualElement ve) + internal static TextCoreSettings GetTextCoreSettingsForElement(VisualElement ve, bool ignoreColors) { var fontAsset = GetFontAsset(ve); if (fontAsset == null) @@ -146,27 +146,60 @@ internal static TextCoreSettings GetTextCoreSettingsForElement(VisualElement ve) var resolvedStyle = ve.resolvedStyle; var computedStyle = ve.computedStyle; + TextShadow textShadow = computedStyle.textShadow; float factor = TextHandle.ConvertPixelUnitsToTextCoreRelativeUnits(computedStyle.fontSize.value, fontAsset); float outlineWidth = Mathf.Clamp(resolvedStyle.unityTextOutlineWidth * factor, 0.0f, 1.0f); - float underlaySoftness = Mathf.Clamp(computedStyle.textShadow.blurRadius * factor, 0.0f, 1.0f); + float underlaySoftness = Mathf.Clamp(textShadow.blurRadius * factor, 0.0f, 1.0f); - float underlayOffsetX = computedStyle.textShadow.offset.x < 0 ? Mathf.Max(computedStyle.textShadow.offset.x * factor, -1.0f) : Mathf.Min(computedStyle.textShadow.offset.x * factor, 1.0f); - float underlayOffsetY = computedStyle.textShadow.offset.y < 0 ? Mathf.Max(computedStyle.textShadow.offset.y * factor, -1.0f) : Mathf.Min(computedStyle.textShadow.offset.y * factor, 1.0f); + float underlayOffsetX = textShadow.offset.x < 0 ? Mathf.Max(textShadow.offset.x * factor, -1.0f) : Mathf.Min(textShadow.offset.x * factor, 1.0f); + float underlayOffsetY = textShadow.offset.y < 0 ? Mathf.Max(textShadow.offset.y * factor, -1.0f) : Mathf.Min(textShadow.offset.y * factor, 1.0f); Vector2 underlayOffset = new Vector2(underlayOffsetX, underlayOffsetY); - var faceColor = resolvedStyle.color; - var outlineColor = resolvedStyle.unityTextOutlineColor; - if (outlineWidth < UIRUtility.k_Epsilon) - outlineColor.a = 0.0f; + Color faceColor, underlayColor, outlineColor; + if (ignoreColors) + { + faceColor = Color.white; + underlayColor = Color.white; + outlineColor = Color.white; + } + else + { + bool isMultiChannel = ((Texture2D)fontAsset.material.mainTexture).format != TextureFormat.Alpha8; + faceColor = resolvedStyle.color; + outlineColor = resolvedStyle.unityTextOutlineColor; + if (outlineWidth < UIRUtility.k_Epsilon) + outlineColor.a = 0.0f; + underlayColor = textShadow.color; + + if (isMultiChannel) + { + // "Textured" Shader Path + // With colored emojis, the render type is "textured" + // The TextCore data will be used if the DynamicColor usage hint is set + // We don't premultiply but we use the alpha only + faceColor = new Color(1, 1, 1, faceColor.a); + } + else + { + // "Text" Shader Path + // These are only used for SDF, independently of DynamicColor + underlayColor.r *= faceColor.a; + underlayColor.g *= faceColor.a; + underlayColor.b *= faceColor.a; + outlineColor.r *= outlineColor.a; + outlineColor.g *= outlineColor.a; + outlineColor.b *= outlineColor.a; + } + } return new TextCoreSettings() { faceColor = faceColor, outlineColor = outlineColor, outlineWidth = outlineWidth, - underlayColor = computedStyle.textShadow.color, + underlayColor = textShadow.color, underlayOffset = underlayOffset, underlaySoftness = underlaySoftness }; diff --git a/README.md b/README.md index c5b3018c0..7a583118e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Unity 6000.0.20f1 C# reference source code +## Unity 6000.0.21f1 C# reference source code The C# part of the Unity engine and editor source code. May be used for reference purposes only.