diff --git a/PackageEditor.sh b/PackageEditor.sh new file mode 100755 index 000000000..865013285 --- /dev/null +++ b/PackageEditor.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. + +set -e + +echo Building and packaging Flax Editor... + +# Change the path to the script root +cd "`dirname "$0"`" + +# Run Flax.Build (also pass the arguments) +bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployEditor --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@" diff --git a/PackagePlatforms.sh b/PackagePlatforms.sh index 83cf9f4a5..0e1ae76f8 100755 --- a/PackagePlatforms.sh +++ b/PackagePlatforms.sh @@ -8,5 +8,5 @@ echo Building and packaging platforms data... # Change the path to the script root cd "`dirname "$0"`" -# Run Flax.Build to generate project files (also pass the arguments) +# Run Flax.Build (also pass the arguments) bash ./Development/Scripts/Linux/CallBuildTool.sh --deploy --deployPlatforms --verbose --log --logFile="Cache/Intermediate/PackageLog.txt" "$@" diff --git a/Source/Editor/Content/Items/VisualScriptItem.cs b/Source/Editor/Content/Items/VisualScriptItem.cs index fd23887ec..22f1d75cc 100644 --- a/Source/Editor/Content/Items/VisualScriptItem.cs +++ b/Source/Editor/Content/Items/VisualScriptItem.cs @@ -75,6 +75,8 @@ namespace FlaxEditor.Content } } + public int MetadataToken => 0; + /// public bool HasAttribute(Type attributeType, bool inherit) { @@ -195,6 +197,8 @@ namespace FlaxEditor.Content /// public ScriptType ValueType => _returnType; + public int MetadataToken => 0; + /// public bool HasAttribute(Type attributeType, bool inherit) { diff --git a/Source/Editor/Content/Proxy/ShaderProxy.cs b/Source/Editor/Content/Proxy/ShaderProxy.cs index e6e288318..71350e277 100644 --- a/Source/Editor/Content/Proxy/ShaderProxy.cs +++ b/Source/Editor/Content/Proxy/ShaderProxy.cs @@ -29,7 +29,7 @@ namespace FlaxEditor.Content if (asset) { var source = Editor.GetShaderSourceCode(asset); - Utilities.Utils.ShowSourceCodeWindow(source, "Shader Source"); + Utilities.Utils.ShowSourceCodeWindow(source, "Shader Source", item.RootWindow.Window); } return null; } diff --git a/Source/Editor/Cooker/Platform/Linux/LinuxPlatformTools.cpp b/Source/Editor/Cooker/Platform/Linux/LinuxPlatformTools.cpp index fa47c5ee5..69521e172 100644 --- a/Source/Editor/Cooker/Platform/Linux/LinuxPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/Linux/LinuxPlatformTools.cpp @@ -79,6 +79,11 @@ bool LinuxPlatformTools::OnDeployBinaries(CookingData& data) const String gameExePath = outputPath / TEXT("FlaxGame"); #endif + // Ensure the output binary can be executed +#if PLATFORM_LINUX + system(*StringAnsi(String::Format(TEXT("chmod +x \"{0}\""), gameExePath))); +#endif + // Apply game icon TextureData iconData; if (!EditorUtilities::GetApplicationImage(platformSettings->OverrideIcon, iconData)) diff --git a/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp b/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp index 91f22abae..c5c585f60 100644 --- a/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp +++ b/Source/Editor/Cooker/Steps/CompileScriptsStep.cpp @@ -101,7 +101,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c // Deploy files Array files(16); const String outputPath = StringUtils::GetDirectoryName(path); - FileSystem::DirectoryGetFiles(files, outputPath, TEXT("*.*"), DirectorySearchOption::TopDirectoryOnly); + FileSystem::DirectoryGetFiles(files, outputPath, TEXT("*"), DirectorySearchOption::TopDirectoryOnly); for (int32 i = files.Count() - 1; i >= 0; i--) { bool skip = false; diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index be4dca78d..84f2ec8f3 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -368,6 +368,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass // Compile for a target platform switch (data.Data.Platform) { +#if PLATFORM_TOOLS_WINDOWS case BuildPlatform::Windows32: case BuildPlatform::Windows64: { @@ -391,6 +392,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass } break; } +#endif #if PLATFORM_TOOLS_UWP case BuildPlatform::UWPx86: case BuildPlatform::UWPx64: @@ -408,12 +410,14 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass break; } #endif +#if PLATFORM_TOOLS_UWP case BuildPlatform::XboxOne: { const char* platformDefineName = "PLATFORM_XBOX_ONE"; COMPILE_PROFILE(DirectX_SM4, SHADER_FILE_CHUNK_INTERNAL_D3D_SM4_CACHE); break; } +#endif #if PLATFORM_TOOLS_LINUX case BuildPlatform::LinuxX64: { @@ -426,24 +430,30 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass break; } #endif +#if PLATFORM_TOOLS_PS4 case BuildPlatform::PS4: { const char* platformDefineName = "PLATFORM_PS4"; COMPILE_PROFILE(PS4, SHADER_FILE_CHUNK_INTERNAL_GENERIC_CACHE); break; } +#endif +#if PLATFORM_TOOLS_XBOX_SCARLETT case BuildPlatform::XboxScarlett: { const char* platformDefineName = "PLATFORM_XBOX_SCARLETT"; COMPILE_PROFILE(DirectX_SM6, SHADER_FILE_CHUNK_INTERNAL_D3D_SM6_CACHE); break; } +#endif +#if PLATFORM_TOOLS_ANDROID case BuildPlatform::AndroidARM64: { const char* platformDefineName = "PLATFORM_ANDROID"; COMPILE_PROFILE(Vulkan_SM5, SHADER_FILE_CHUNK_INTERNAL_VULKAN_SM5_CACHE); break; } +#endif default: { LOG(Warning, "Not implemented platform or shaders not supported."); @@ -895,21 +905,27 @@ bool CookAssetsStep::Perform(CookingData& data) cache.Load(data); // Update build settings +#if PLATFORM_TOOLS_WINDOWS { const auto settings = WindowsPlatformSettings::Get(); cache.Settings.Windows.SupportDX11 = settings->SupportDX11; cache.Settings.Windows.SupportDX10 = settings->SupportDX10; cache.Settings.Windows.SupportVulkan = settings->SupportVulkan; } +#endif +#if PLATFORM_TOOLS_UWP { const auto settings = UWPPlatformSettings::Get(); cache.Settings.UWP.SupportDX11 = settings->SupportDX11; cache.Settings.UWP.SupportDX10 = settings->SupportDX10; } +#endif +#if PLATFORM_TOOLS_LINUX { const auto settings = LinuxPlatformSettings::Get(); cache.Settings.Linux.SupportVulkan = settings->SupportVulkan; } +#endif { cache.Settings.Global.ShadersNoOptimize = buildSettings->ShadersNoOptimize; cache.Settings.Global.ShadersGenerateDebugData = buildSettings->ShadersGenerateDebugData; diff --git a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs index 0fcf9d78a..e176f2b70 100644 --- a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs @@ -2,7 +2,9 @@ using System; using System.Linq; +using System.Reflection; using FlaxEditor.CustomEditors.Editors; +using FlaxEditor.CustomEditors.Elements; using FlaxEditor.GUI; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.Scripting; @@ -349,6 +351,176 @@ namespace FlaxEditor.CustomEditors.Dedicated // Show control properties base.Initialize(layout); + + for (int i = 0; i < layout.Children.Count; i++) + { + if (layout.Children[i] is GroupElement group && group.Panel.HeaderText == "Transform") + { + VerticalPanelElement mainHor = VerticalPanelWithoutMargin(group); + CreateTransformElements(mainHor, ValuesTypes); + group.ContainerControl.ChangeChildIndex(mainHor.Control, 0); + break; + } + } + } + + private void CreateTransformElements(LayoutElementsContainer main, ScriptType[] valueTypes) + { + main.Space(10); + HorizontalPanelElement sidePanel = main.HorizontalPanel(); + sidePanel.Panel.ClipChildren = false; + + ScriptMemberInfo anchorInfo = valueTypes[0].GetProperty("AnchorPreset"); + ItemInfo anchorItem = new ItemInfo(anchorInfo); + sidePanel.Object(anchorItem.GetValues(Values)); + + VerticalPanelElement group = VerticalPanelWithoutMargin(sidePanel); + + group.Panel.AnchorPreset = AnchorPresets.HorizontalStretchTop; + group.Panel.Offsets = new Margin(100, 10, 0, 0); + + var horUp = UniformGridTwoByOne(group); + horUp.CustomControl.Height = TextBoxBase.DefaultHeight; + var horDown = UniformGridTwoByOne(group); + horDown.CustomControl.Height = TextBoxBase.DefaultHeight; + + GetAnchorEquality(out _cachedXEq, out _cachedYEq, valueTypes); + + BuildLocationSizeOffsets(horUp, horDown, _cachedXEq, _cachedYEq, valueTypes); + + main.Space(10); + BuildAnchorsDropper(main, valueTypes); + } + + private void BuildAnchorsDropper(LayoutElementsContainer main, ScriptType[] valueTypes) + { + ScriptMemberInfo minInfo = valueTypes[0].GetProperty("AnchorMin"); + ScriptMemberInfo maxInfo = valueTypes[0].GetProperty("AnchorMax"); + ItemInfo minItem = new ItemInfo(minInfo); + ItemInfo maxItem = new ItemInfo(maxInfo); + + GroupElement ng = main.Group("Anchors", true); + ng.Panel.Close(false); + ng.Property("Min", minItem.GetValues(Values)); + ng.Property("Max", maxItem.GetValues(Values)); + } + + private void GetAnchorEquality(out bool xEq, out bool yEq, ScriptType[] valueTypes) + { + ScriptMemberInfo minInfo = valueTypes[0].GetProperty("AnchorMin"); + ScriptMemberInfo maxInfo = valueTypes[0].GetProperty("AnchorMax"); + ItemInfo minItem = new ItemInfo(minInfo); + ItemInfo maxItem = new ItemInfo(maxInfo); + ValueContainer minVal = minItem.GetValues(Values); + ValueContainer maxVal = maxItem.GetValues(Values); + + ItemInfo xItem = new ItemInfo(minInfo.ValueType.GetField("X")); + ItemInfo yItem = new ItemInfo(minInfo.ValueType.GetField("Y")); + + xEq = xItem.GetValues(minVal).ToList().Any(xItem.GetValues(maxVal).ToList().Contains); + yEq = yItem.GetValues(minVal).ToList().Any(yItem.GetValues(maxVal).ToList().Contains); + } + + private void BuildLocationSizeOffsets(LayoutElementsContainer horUp, LayoutElementsContainer horDown, bool xEq, bool yEq, ScriptType[] valueTypes) + { + ScriptMemberInfo xInfo = valueTypes[0].GetProperty("X"); + ItemInfo xItem = new ItemInfo(xInfo); + ScriptMemberInfo yInfo = valueTypes[0].GetProperty("Y"); + ItemInfo yItem = new ItemInfo(yInfo); + ScriptMemberInfo widthInfo = valueTypes[0].GetProperty("Width"); + ItemInfo widthItem = new ItemInfo(widthInfo); + ScriptMemberInfo heightInfo = valueTypes[0].GetProperty("Height"); + ItemInfo heightItem = new ItemInfo(heightInfo); + + ScriptMemberInfo leftInfo = valueTypes[0].GetProperty("Proxy_Offset_Left", BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + ItemInfo leftItem = new ItemInfo(leftInfo); + ScriptMemberInfo rightInfo = valueTypes[0].GetProperty("Proxy_Offset_Right", BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + ItemInfo rightItem = new ItemInfo(rightInfo); + ScriptMemberInfo topInfo = valueTypes[0].GetProperty("Proxy_Offset_Top", BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + ItemInfo topItem = new ItemInfo(topInfo); + ScriptMemberInfo bottomInfo = valueTypes[0].GetProperty("Proxy_Offset_Bottom", BindingFlags.Default | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + ItemInfo bottomItem = new ItemInfo(bottomInfo); + + LayoutElementsContainer xEl; + LayoutElementsContainer yEl; + LayoutElementsContainer hEl; + LayoutElementsContainer vEl; + if (xEq) + { + xEl = UniformPanelCapsuleForObjectWithText(horUp, "X: ", xItem.GetValues(Values)); + vEl = UniformPanelCapsuleForObjectWithText(horDown, "Width: ", widthItem.GetValues(Values)); + } + else + { + xEl = UniformPanelCapsuleForObjectWithText(horUp, "Left: ", leftItem.GetValues(Values)); + vEl = UniformPanelCapsuleForObjectWithText(horDown, "Right: ", rightItem.GetValues(Values)); + } + if (yEq) + { + yEl = UniformPanelCapsuleForObjectWithText(horUp, "Y: ", yItem.GetValues(Values)); + hEl = UniformPanelCapsuleForObjectWithText(horDown, "Height: ", heightItem.GetValues(Values)); + } + else + { + yEl = UniformPanelCapsuleForObjectWithText(horUp, "Top: ", topItem.GetValues(Values)); + hEl = UniformPanelCapsuleForObjectWithText(horDown, "Bottom: ", bottomItem.GetValues(Values)); + } + xEl.Control.AnchorMin = new Vector2(0, xEl.Control.AnchorMin.Y); + xEl.Control.AnchorMax = new Vector2(0.5f, xEl.Control.AnchorMax.Y); + + vEl.Control.AnchorMin = new Vector2(0, xEl.Control.AnchorMin.Y); + vEl.Control.AnchorMax = new Vector2(0.5f, xEl.Control.AnchorMax.Y); + + yEl.Control.AnchorMin = new Vector2(0.5f, xEl.Control.AnchorMin.Y); + yEl.Control.AnchorMax = new Vector2(1, xEl.Control.AnchorMax.Y); + + hEl.Control.AnchorMin = new Vector2(0.5f, xEl.Control.AnchorMin.Y); + hEl.Control.AnchorMax = new Vector2(1, xEl.Control.AnchorMax.Y); + } + + private VerticalPanelElement VerticalPanelWithoutMargin(LayoutElementsContainer cont) + { + var horUp = cont.VerticalPanel(); + horUp.Panel.Margin = Margin.Zero; + return horUp; + } + + private CustomElementsContainer UniformGridTwoByOne(LayoutElementsContainer cont) + { + var horUp = cont.CustomContainer(); + horUp.CustomControl.SlotsHorizontally = 2; + horUp.CustomControl.SlotsVertically = 1; + horUp.CustomControl.SlotPadding = Margin.Zero; + horUp.CustomControl.ClipChildren = false; + return horUp; + } + + private CustomElementsContainer UniformPanelCapsuleForObjectWithText(LayoutElementsContainer el, string text, ValueContainer values) + { + CustomElementsContainer hor = UniformGridTwoByOne(el); + hor.CustomControl.SlotPadding = new Margin(5, 5, 0, 0); + LabelElement lab = hor.Label(text); + hor.Object(values); + return hor; + } + + private bool _cachedXEq; + private bool _cachedYEq; + + /// + /// Refreshes if equality of anchors does not correspond to the cached equality + /// + public void RefreshBaseOnAnchorsEquality() + { + if (Values.HasNull) + return; + + GetAnchorEquality(out bool xEq, out bool yEq, ValuesTypes); + if (xEq != _cachedXEq || yEq != _cachedYEq) + { + RebuildLayout(); + return; + } } /// @@ -361,6 +533,8 @@ namespace FlaxEditor.CustomEditors.Dedicated RebuildLayout(); return; } + RefreshBaseOnAnchorsEquality(); + //RefreshValues(); base.Refresh(); } @@ -405,7 +579,13 @@ namespace FlaxEditor.CustomEditors.Dedicated for (int i = 0; i < uiControls.Count; i++) { var uiControl = (UIControl)uiControls[i]; + string previousName = uiControl.Control?.GetType()?.Name ?? typeof(UIControl).Name; uiControl.Control = (Control)controlType.CreateInstance(); + if (uiControl.Name.StartsWith(previousName)) + { + string newName = controlType.Name + uiControl.Name.Substring(previousName.Length); + uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null); + } } } } @@ -414,7 +594,13 @@ namespace FlaxEditor.CustomEditors.Dedicated for (int i = 0; i < uiControls.Count; i++) { var uiControl = (UIControl)uiControls[i]; + string previousName = uiControl.Control?.GetType()?.Name ?? typeof(UIControl).Name; uiControl.Control = (Control)controlType.CreateInstance(); + if (uiControl.Name.StartsWith(previousName)) + { + string newName = controlType.Name + uiControl.Name.Substring(previousName.Length); + uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null); + } } } diff --git a/Source/Editor/CustomEditors/Editors/GenericEditor.cs b/Source/Editor/CustomEditors/Editors/GenericEditor.cs index ed6d88e9e..264aaeeff 100644 --- a/Source/Editor/CustomEditors/Editors/GenericEditor.cs +++ b/Source/Editor/CustomEditors/Editors/GenericEditor.cs @@ -173,6 +173,15 @@ namespace FlaxEditor.CustomEditors.Editors return string.Compare(Display.Group, other.Display.Group, StringComparison.InvariantCulture); } + if (Editor.Instance.Options.Options.General.ScriptMembersOrder == Options.GeneralOptions.MembersOrder.Declaration) + { + // By declaration order + if (Info.MetadataToken > other.Info.MetadataToken) + return 1; + if (Info.MetadataToken < other.Info.MetadataToken) + return -1; + } + // By name return string.Compare(Info.Name, other.Info.Name, StringComparison.InvariantCulture); } diff --git a/Source/Editor/Editor.Build.cs b/Source/Editor/Editor.Build.cs index 3ca463a2c..69c842820 100644 --- a/Source/Editor/Editor.Build.cs +++ b/Source/Editor/Editor.Build.cs @@ -51,14 +51,17 @@ public class Editor : EditorModule var platformToolsRoot = Path.Combine(FolderPath, "Cooker", "Platform"); var platformToolsRootExternal = Path.Combine(Globals.EngineRoot, "Source", "Platforms"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Windows", "PLATFORM_TOOLS_WINDOWS"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "UWP", "PLATFORM_TOOLS_UWP"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "UWP", "PLATFORM_TOOLS_XBOX_ONE"); + if (options.Platform.Target == TargetPlatform.Windows) + { + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Windows", "PLATFORM_TOOLS_WINDOWS"); + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "UWP", "PLATFORM_TOOLS_UWP"); + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "UWP", "PLATFORM_TOOLS_XBOX_ONE"); + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "PS4", "PLATFORM_TOOLS_PS4"); + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "XboxScarlett", "PLATFORM_TOOLS_XBOX_SCARLETT"); + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID"); + AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Switch", "PLATFORM_TOOLS_SWITCH"); + } AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Linux", "PLATFORM_TOOLS_LINUX"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "PS4", "PLATFORM_TOOLS_PS4"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "XboxScarlett", "PLATFORM_TOOLS_XBOX_SCARLETT"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Android", "PLATFORM_TOOLS_ANDROID"); - AddPlatformTools(options, platformToolsRoot, platformToolsRootExternal, "Switch", "PLATFORM_TOOLS_SWITCH"); // Visual Studio integration if (options.Platform.Target == TargetPlatform.Windows) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 3aa8346c8..408dddbd6 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -1181,7 +1181,7 @@ namespace FlaxEditor var win = Windows.GameWin.Root; if (win != null && win.RootWindow is WindowRootControl root && root.Window.IsFocused) { - pos = Vector2.Round(Windows.GameWin.Viewport.PointFromWindow(root.Window.ScreenToClient(pos))); + pos = Vector2.Round(Windows.GameWin.Viewport.PointFromScreen(pos) * root.DpiScale); } else { @@ -1201,7 +1201,7 @@ namespace FlaxEditor var win = Windows.GameWin.Root; if (win != null && win.RootWindow is WindowRootControl root && root.Window.IsFocused) { - pos = Vector2.Round(root.Window.ClientToScreen(Windows.GameWin.Viewport.PointToWindow(pos))); + pos = Vector2.Round(Windows.GameWin.Viewport.PointToScreen(pos / root.DpiScale)); } else { @@ -1231,13 +1231,18 @@ namespace FlaxEditor var gameWin = Windows.GameWin; if (gameWin != null) { - // Handle case when Game window is not selected in tab view - var dockedTo = gameWin.ParentDockPanel; - if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null) - resultAsRef = dockedTo.SelectedTab.Size; - else - resultAsRef = gameWin.Size; - resultAsRef = Vector2.Round(resultAsRef); + var win = gameWin.Root; + if (win != null && win.RootWindow is WindowRootControl root) + { + // Handle case when Game window is not selected in tab view + var dockedTo = gameWin.ParentDockPanel; + if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null) + resultAsRef = dockedTo.SelectedTab.Size * root.DpiScale; + else + resultAsRef = gameWin.Size * root.DpiScale; + + resultAsRef = Vector2.Round(resultAsRef); + } } } diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index 6caf7f651..247844659 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -124,7 +124,7 @@ namespace FlaxEditor.GUI.ContextMenu PerformLayout(); // Calculate popup direction and initial location (fit on a single monitor) - var dpiScale = Platform.DpiScale; + var dpiScale = parentWin.DpiScale; Vector2 dpiSize = Size * dpiScale; Vector2 locationWS = parent.PointToWindow(location); Vector2 locationSS = parentWin.PointToScreen(locationWS); @@ -275,7 +275,7 @@ namespace FlaxEditor.GUI.ContextMenu { if (_window != null) { - _window.ClientSize = Size * Platform.DpiScale; + _window.ClientSize = Size * _window.DpiScale; } } diff --git a/Source/Editor/GUI/Dialogs/Dialog.cs b/Source/Editor/GUI/Dialogs/Dialog.cs index 173dd9128..c33429609 100644 --- a/Source/Editor/GUI/Dialogs/Dialog.cs +++ b/Source/Editor/GUI/Dialogs/Dialog.cs @@ -143,7 +143,7 @@ namespace FlaxEditor.GUI.Dialogs // Setup initial window settings CreateWindowSettings settings = CreateWindowSettings.Default; settings.Title = _title; - settings.Size = _dialogSize * Platform.DpiScale; + settings.Size = _dialogSize * parentWindow.DpiScale; settings.AllowMaximize = false; settings.AllowMinimize = false; settings.HasSizingFrame = false; diff --git a/Source/Editor/GUI/Docking/DockPanel.cs b/Source/Editor/GUI/Docking/DockPanel.cs index 2865515da..74f2d5ab0 100644 --- a/Source/Editor/GUI/Docking/DockPanel.cs +++ b/Source/Editor/GUI/Docking/DockPanel.cs @@ -123,9 +123,8 @@ namespace FlaxEditor.GUI.Docking if (parentWin == null) throw new InvalidOperationException("Missing parent window."); var control = _tabsProxy != null ? (Control)_tabsProxy : this; - var dpiScale = Platform.DpiScale; var clientPos = control.PointToWindow(Vector2.Zero); - return new Rectangle(parentWin.PointToScreen(clientPos), control.Size * dpiScale); + return new Rectangle(parentWin.PointToScreen(clientPos), control.Size * RootWindow.DpiScale); } } @@ -290,6 +289,10 @@ namespace FlaxEditor.GUI.Docking } OnSelectedTabChanged(); } + else if (autoFocus && _selectedTab != null && !_selectedTab.ContainsFocus) + { + _selectedTab.Focus(); + } } /// diff --git a/Source/Editor/GUI/MainMenu.cs b/Source/Editor/GUI/MainMenu.cs index ff4e02c4b..bf375a358 100644 --- a/Source/Editor/GUI/MainMenu.cs +++ b/Source/Editor/GUI/MainMenu.cs @@ -190,15 +190,15 @@ namespace FlaxEditor.GUI private WindowHitCodes OnHitTest(ref Vector2 mouse) { - var pos = _window.ScreenToClient(mouse * Platform.DpiScale); + var dpiScale = _window.DpiScale; if (_window.IsMinimized) return WindowHitCodes.NoWhere; if (!_window.IsMaximized) { - var dpiScale = Platform.DpiScale; - var winSize = RootWindow.Size * dpiScale; + var pos = _window.ScreenToClient(mouse * dpiScale); // pos is not DPI adjusted + var winSize = _window.Size; // Distance from which the mouse is considered to be on the border/corner float distance = 5.0f * dpiScale; @@ -228,11 +228,11 @@ namespace FlaxEditor.GUI return WindowHitCodes.Bottom; } - var menuPos = PointFromWindow(pos); - var controlUnderMouse = GetChildAt(menuPos); + var mousePos = PointFromScreen(mouse * dpiScale); + var controlUnderMouse = GetChildAt(mousePos); var isMouseOverSth = controlUnderMouse != null && controlUnderMouse != _title; var rb = GetRightButton(); - if (rb != null && _minimizeButton != null && new Rectangle(rb.UpperRight * Platform.DpiScale, (_minimizeButton.BottomLeft - rb.UpperRight) * Platform.DpiScale).Contains(ref menuPos) && !isMouseOverSth) + if (rb != null && _minimizeButton != null && new Rectangle(rb.UpperRight, _minimizeButton.BottomLeft - rb.UpperRight).Contains(ref mousePos) && !isMouseOverSth) return WindowHitCodes.Caption; return WindowHitCodes.Client; diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs index f38f6fe3b..5267da01f 100644 --- a/Source/Editor/Modules/WindowsModule.cs +++ b/Source/Editor/Modules/WindowsModule.cs @@ -707,8 +707,9 @@ namespace FlaxEditor.Modules var dpiScale = Platform.DpiScale; var settings = CreateWindowSettings.Default; settings.Title = "Flax Editor"; - settings.Size = new Vector2(1300 * dpiScale, 900 * dpiScale); + settings.Size = Platform.DesktopSize; settings.StartPosition = WindowStartPosition.CenterScreen; + settings.ShowAfterFirstPaint = true; #if PLATFORM_WINDOWS if (!Editor.Instance.Options.Options.Interface.UseNativeWindowSystem) diff --git a/Source/Editor/Options/GeneralOptions.cs b/Source/Editor/Options/GeneralOptions.cs index 85174030f..c260ae8b8 100644 --- a/Source/Editor/Options/GeneralOptions.cs +++ b/Source/Editor/Options/GeneralOptions.cs @@ -68,6 +68,24 @@ namespace FlaxEditor.Options CompileScripts, } + /// + /// Order of script members show in editor + /// + public enum MembersOrder + { + /// + /// Shows properties/fields in alphabetical order + /// + [Tooltip("Shows properties/fields in alphabetical order")] + Alphabetical, + + /// + /// Shows properties/fields in declaration order + /// + [Tooltip("Shows properties/fields in declaration order")] + Declaration + } + /// /// Gets or sets the scene to load on editor startup. /// @@ -116,6 +134,13 @@ namespace FlaxEditor.Options [EditorDisplay("Scripting", "Force Script Compilation On Startup"), EditorOrder(501), Tooltip("Determines whether automatically compile game scripts before starting the editor.")] public bool ForceScriptCompilationOnStartup { get; set; } = true; + /// + /// Gets or sets an order of script properties/fields in properties panel. + /// + [DefaultValue(MembersOrder.Alphabetical)] + [EditorDisplay("Scripting", "Script Members Order"), EditorOrder(503), Tooltip("Order of script properties/fields in properties panel")] + public MembersOrder ScriptMembersOrder { get; set; } = MembersOrder.Alphabetical; + /// /// Gets or sets a value indicating whether automatically save the Visual Script asset editors when starting the play mode in editor. /// diff --git a/Source/Editor/Options/ViewportOptions.cs b/Source/Editor/Options/ViewportOptions.cs index 5558ac89d..0a8d78c26 100644 --- a/Source/Editor/Options/ViewportOptions.cs +++ b/Source/Editor/Options/ViewportOptions.cs @@ -18,6 +18,13 @@ namespace FlaxEditor.Options [EditorDisplay("General"), EditorOrder(100), Tooltip("The mouse movement sensitivity scale applied when using the viewport camera.")] public float MouseSensitivity { get; set; } = 1.0f; + /// + /// Gets or sets the mouse wheel sensitivity applied to zoom in orthographic mode. + /// + [DefaultValue(1.0f), Limit(0.01f, 100.0f)] + [EditorDisplay("General"), EditorOrder(101), Tooltip("The mouse wheel sensitivity applied to zoom in orthographic mode.")] + public float MouseWheelSensitivity { get; set; } = 1.0f; + /// /// Gets or sets the default movement speed for the viewport camera (must match the dropdown menu values in the viewport). /// diff --git a/Source/Editor/Scripting/ScriptType.cs b/Source/Editor/Scripting/ScriptType.cs index 53c84a1b5..870d68eba 100644 --- a/Source/Editor/Scripting/ScriptType.cs +++ b/Source/Editor/Scripting/ScriptType.cs @@ -40,6 +40,27 @@ namespace FlaxEditor.Scripting /// public string Name => _managed?.Name ?? _custom?.Name; + /// + /// Gets a metadata token for sorting so it may not be the actual token. + /// + public int MetadataToken + { + get + { + int standardToken = _managed?.MetadataToken ?? _custom?.MetadataToken ?? 0; + if (_managed is PropertyInfo && _managed.DeclaringType != null) + { + var field = _managed.DeclaringType.GetField(string.Format("<{0}>k__BackingField", Name), BindingFlags.Instance | BindingFlags.NonPublic); + if (field == null || field.MetadataToken == 0) + { + return standardToken; + } + return field.MetadataToken; + } + return standardToken; + } + } + /// /// Gets a value indicating whether the type is declared public. /// @@ -1444,6 +1465,11 @@ namespace FlaxEditor.Scripting /// string Name { get; } + /// + /// Gets a metadata token for sorting so it may not be the actual token. + /// + int MetadataToken { get; } + /// /// Gets a value indicating whether the type is declared public. /// diff --git a/Source/Editor/Surface/ContextMenu/ContentFinder.cs b/Source/Editor/Surface/ContextMenu/ContentFinder.cs index 76e8d2e33..6089c2ca7 100644 --- a/Source/Editor/Surface/ContextMenu/ContentFinder.cs +++ b/Source/Editor/Surface/ContextMenu/ContentFinder.cs @@ -108,11 +108,13 @@ namespace FlaxEditor.Surface.ContextMenu { _resultPanel.DisposeChildren(); + var dpiScale = RootWindow.DpiScale; + if (items.Count == 0) { Height = _searchBox.Height + 1; _resultPanel.ScrollBars = ScrollBars.None; - RootWindow.Window.ClientSize = new Vector2(RootWindow.Window.ClientSize.X, Height * Platform.DpiScale); + RootWindow.Window.ClientSize = new Vector2(RootWindow.Window.ClientSize.X, Height * dpiScale); return; } @@ -146,7 +148,7 @@ namespace FlaxEditor.Surface.ContextMenu MatchedItems.Add(searchItem); } - RootWindow.Window.ClientSize = new Vector2(RootWindow.Window.ClientSize.X, Height * Platform.DpiScale); + RootWindow.Window.ClientSize = new Vector2(RootWindow.Window.ClientSize.X, Height * dpiScale); PerformLayout(); } diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs index a13d441d9..b5c835d70 100644 --- a/Source/Editor/Utilities/Utils.cs +++ b/Source/Editor/Utilities/Utils.cs @@ -1646,8 +1646,8 @@ namespace FlaxEditor.Utilities /// /// The source code. /// The window title. - /// The context control used to show source code window popup in a proper location. - public static void ShowSourceCodeWindow(string source, string title, Control control = null) + /// The optional parent window. + public static void ShowSourceCodeWindow(string source, string title, Window parentWindow = null) { if (string.IsNullOrEmpty(source)) { @@ -1661,8 +1661,8 @@ namespace FlaxEditor.Utilities settings.AllowMinimize = false; settings.HasSizingFrame = false; settings.StartPosition = WindowStartPosition.CenterParent; - settings.Size = new Vector2(500, 600) * Platform.DpiScale; - settings.Parent = control?.RootWindow?.Window ?? Editor.Instance.Windows.MainWindow; + settings.Size = new Vector2(500, 600) * (parentWindow?.DpiScale ?? Platform.DpiScale); + settings.Parent = parentWindow; settings.Title = title; var dialog = Platform.CreateWindow(ref settings); diff --git a/Source/Editor/Viewport/Cameras/FPSCamera.cs b/Source/Editor/Viewport/Cameras/FPSCamera.cs index 6d0376a89..e60def838 100644 --- a/Source/Editor/Viewport/Cameras/FPSCamera.cs +++ b/Source/Editor/Viewport/Cameras/FPSCamera.cs @@ -88,6 +88,17 @@ namespace FlaxEditor.Viewport.Cameras Editor.GetActorEditorSphere(actor, out BoundingSphere sphere); ShowSphere(ref sphere); } + + /// + /// Moves the viewport to visualize selected actors. + /// + /// The actors to show. + /// The used orientation. + public void ShowActor(Actor actor, ref Quaternion orientation) + { + Editor.GetActorEditorSphere(actor, out BoundingSphere sphere); + ShowSphere(ref sphere, ref orientation); + } /// /// Moves the viewport to visualize selected actors. @@ -111,17 +122,50 @@ namespace FlaxEditor.Viewport.Cameras ShowSphere(ref mergesSphere); } + /// + /// Moves the viewport to visualize selected actors. + /// + /// The actors to show. + /// The used orientation. + public void ShowActors(List actors, ref Quaternion orientation) + { + if (actors.Count == 0) + return; + + BoundingSphere mergesSphere = BoundingSphere.Empty; + for (int i = 0; i < actors.Count; i++) + { + if (actors[i] is ActorNode actor) + { + Editor.GetActorEditorSphere(actor.Actor, out BoundingSphere sphere); + BoundingSphere.Merge(ref mergesSphere, ref sphere, out mergesSphere); + } + } + + ShowSphere(ref mergesSphere, ref orientation); + } + private void ShowSphere(ref BoundingSphere sphere) { - // Calculate view transform - Quaternion orientation = new Quaternion(0.424461186f, -0.0940724313f, 0.0443938486f, 0.899451137f); - Vector3 position = sphere.Center - Vector3.Forward * orientation * (sphere.Radius * 2.5f); - - // Move viewport - TargetPoint = sphere.Center; - MoveViewport(position, orientation); + var q = new Quaternion(0.424461186f, -0.0940724313f, 0.0443938486f, 0.899451137f); + ShowSphere(ref sphere, ref q); } + private void ShowSphere(ref BoundingSphere sphere, ref Quaternion orientation) + { + Vector3 position; + + if (Viewport.UseOrthographicProjection) + { + position = sphere.Center + Vector3.Backward * orientation * (sphere.Radius * 5.0f); + Viewport.OrthographicScale = Vector3.Distance(position, sphere.Center) / 1000; + } + else + position = sphere.Center - Vector3.Forward * orientation * (sphere.Radius * 2.5f); + TargetPoint = position; + MoveViewport(position, orientation); + } + /// public override void Update(float deltaTime) { diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 5aeba8b28..562381805 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; +using FlaxEditor.Gizmo; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Input; using FlaxEditor.Options; @@ -538,21 +539,30 @@ namespace FlaxEditor.Viewport { _isOrtho = checkBox.Checked; ViewWidgetButtonMenu.Hide(); + if (_isOrtho) + { + var orient = ViewOrientation; + OrientViewport(ref orient); + } } }; ViewWidgetButtonMenu.VisibleChanged += control => orthoValue.Checked = _isOrtho; } - // Cara Orientation + // Camera Viewpoints { - var cameraView = ViewWidgetButtonMenu.AddChildMenu("Orientation").ContextMenu; - for (int i = 0; i < EditorViewportCameraOrientationValues.Length; i++) + var cameraView = ViewWidgetButtonMenu.AddChildMenu("Viewpoints").ContextMenu; + for (int i = 0; i < EditorViewportCameraViewpointValues.Length; i++) { - var co = EditorViewportCameraOrientationValues[i]; + var co = EditorViewportCameraViewpointValues[i]; var button = cameraView.AddButton(co.Name); button.Tag = co.Orientation; } - cameraView.ButtonClicked += button => ViewOrientation = Quaternion.Euler((Vector3)button.Tag); + cameraView.ButtonClicked += button => + { + var orient = Quaternion.Euler((Vector3)button.Tag); + OrientViewport(ref orient); + }; } // Field of View @@ -654,6 +664,19 @@ namespace FlaxEditor.Viewport task.Begin += OnRenderBegin; } + private void OrientViewport(ref Quaternion orientation) + { + if (Editor.Instance.SceneEditing.HasSthSelected) + { + ((FPSCamera)ViewportCamera).ShowActors(Editor.Instance.Windows.EditWin.Viewport.TransformGizmo.SelectedParents, ref orientation); + } + else + { + var pos = new Vector3(0.0f) + Vector3.Backward * orientation * 2000.0f; + ((FPSCamera)ViewportCamera).MoveViewport(pos, orientation); + } + } + private void OnEditorOptionsChanged(EditorOptions options) { _mouseSensitivity = options.Viewport.MouseSensitivity; @@ -994,6 +1017,7 @@ namespace FlaxEditor.Viewport var options = Editor.Instance.Options.Options.Input; if (_isControllingMouse) { + var rmbWheel = false; // Gather input { bool isAltDown = _input.IsAltDown; @@ -1009,10 +1033,11 @@ namespace FlaxEditor.Viewport _input.IsOrbiting = isAltDown && lbDown && !mbDown && !rbDown; // Control move speed with RMB+Wheel - if (useMovementSpeed && _input.IsMouseRightDown && wheelInUse) + rmbWheel = useMovementSpeed && _input.IsMouseRightDown && wheelInUse; + if (rmbWheel) { float step = 4.0f; - _wheelMovementChangeDeltaSum += _input.MouseWheelDelta; + _wheelMovementChangeDeltaSum += _input.MouseWheelDelta * Editor.Instance.Options.Options.Viewport.MouseWheelSensitivity; int camValueIndex = -1; for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++) { @@ -1076,7 +1101,7 @@ namespace FlaxEditor.Viewport // Calculate smooth mouse delta not dependant on viewport size Vector2 offset = _viewMousePos - _startPos; - if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown) + if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel) { offset = Vector2.Zero; } @@ -1125,6 +1150,14 @@ namespace FlaxEditor.Viewport Vector2 center = PointToWindow(_startPos); win.MousePosition = center; } + + // Change Ortho size on mouse scroll + if (_isOrtho && !rmbWheel) + { + var scroll = _input.MouseWheelDelta; + if (scroll > Mathf.Epsilon || scroll < -Mathf.Epsilon) + _orthoSize -= scroll * Editor.Instance.Options.Options.Viewport.MouseWheelSensitivity * 0.2f * _orthoSize; + } } else { @@ -1260,26 +1293,26 @@ namespace FlaxEditor.Viewport base.OnDestroy(); } - private struct CameraOrientation + private struct CameraViewpoint { public readonly string Name; public readonly Vector3 Orientation; - public CameraOrientation(string name, Vector3 orientation) + public CameraViewpoint(string name, Vector3 orientation) { Name = name; Orientation = orientation; } } - private readonly CameraOrientation[] EditorViewportCameraOrientationValues = + private readonly CameraViewpoint[] EditorViewportCameraViewpointValues = { - new CameraOrientation("Front", new Vector3(0, 0, 0)), - new CameraOrientation("Back", new Vector3(0, 180, 0)), - new CameraOrientation("Left", new Vector3(0, -90, 0)), - new CameraOrientation("Right", new Vector3(0, 90, 0)), - new CameraOrientation("Top", new Vector3(90, 0, 0)), - new CameraOrientation("Bottom", new Vector3(-90, 0, 0)) + new CameraViewpoint("Front", new Vector3(0, 180, 0)), + new CameraViewpoint("Back", new Vector3(0, 0, 0)), + new CameraViewpoint("Left", new Vector3(0, 90, 0)), + new CameraViewpoint("Right", new Vector3(0, -90, 0)), + new CameraViewpoint("Top", new Vector3(90, 0, 0)), + new CameraViewpoint("Bottom", new Vector3(-90, 0, 0)) }; private readonly float[] EditorViewportCameraSpeedValues = diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index c734b3127..a0f2eb044 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -1042,10 +1042,12 @@ namespace FlaxEditor.Viewport DisposeModes(); _debugDrawData.Dispose(); - //Object.Destroy(ref SelectionOutline); - //Object.Destroy(ref EditorPrimitives); - //Object.Destroy(ref _editorSpritesRenderer); - //Object.Destroy(ref _customSelectionOutline); + if (_task != null) + { + // Release if task is not used to save screenshot for project icon + Object.Destroy(ref _task); + ReleaseResources(); + } base.OnDestroy(); } @@ -1062,7 +1064,6 @@ namespace FlaxEditor.Viewport _task = null; _backBuffer = null; - _editorSpritesRenderer = null; } internal void SaveProjectIconEnd() @@ -1070,9 +1071,19 @@ namespace FlaxEditor.Viewport if (_savedTask) { _savedTask.Enabled = false; + Object.Destroy(_savedTask); + ReleaseResources(); _savedTask = null; } Object.Destroy(ref _savedBackBuffer); } + + private void ReleaseResources() + { + Object.Destroy(ref SelectionOutline); + Object.Destroy(ref EditorPrimitives); + Object.Destroy(ref _editorSpritesRenderer); + Object.Destroy(ref _customSelectionOutline); + } } } diff --git a/Source/Editor/Windows/Assets/MaterialWindow.cs b/Source/Editor/Windows/Assets/MaterialWindow.cs index 53d85f493..3e0ac8fb1 100644 --- a/Source/Editor/Windows/Assets/MaterialWindow.cs +++ b/Source/Editor/Windows/Assets/MaterialWindow.cs @@ -240,7 +240,7 @@ namespace FlaxEditor.Windows.Assets private void ShowSourceCode() { var source = Editor.GetShaderSourceCode(_asset); - Utilities.Utils.ShowSourceCodeWindow(source, "Material Source", this); + Utilities.Utils.ShowSourceCodeWindow(source, "Material Source", RootWindow.Window); } /// diff --git a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs index ab61a9d68..21107452f 100644 --- a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs @@ -146,7 +146,7 @@ namespace FlaxEditor.Windows.Assets private void ShowSourceCode() { var source = Editor.GetShaderSourceCode(_asset); - Utilities.Utils.ShowSourceCodeWindow(source, "Particle Emitter GPU Simulation Source", this); + Utilities.Utils.ShowSourceCodeWindow(source, "Particle Emitter GPU Simulation Source", RootWindow.Window); } /// diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index 350714bb3..cd92bc300 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -371,7 +371,7 @@ namespace FlaxEditor.Windows // Focus content window Focus(); - RootWindow?.Window.Focus(); + RootWindow?.Focus(); } // Refresh database and view now diff --git a/Source/Editor/Windows/EditGameWindow.cs b/Source/Editor/Windows/EditGameWindow.cs index 0d3a8bf95..4025f68ab 100644 --- a/Source/Editor/Windows/EditGameWindow.cs +++ b/Source/Editor/Windows/EditGameWindow.cs @@ -243,7 +243,13 @@ namespace FlaxEditor.Windows /// public void ShowSelectedActors() { - ((FPSCamera)Viewport.ViewportCamera).ShowActors(Viewport.TransformGizmo.SelectedParents); + if (Viewport.UseOrthographicProjection) + { + var orient = Viewport.ViewOrientation; + ((FPSCamera)Viewport.ViewportCamera).ShowActors(Viewport.TransformGizmo.SelectedParents, ref orient); + } + else + ((FPSCamera)Viewport.ViewportCamera).ShowActors(Viewport.TransformGizmo.SelectedParents); } /// diff --git a/Source/Editor/Windows/GameCookerWindow.cs b/Source/Editor/Windows/GameCookerWindow.cs index 278ce69d3..2562f3db8 100644 --- a/Source/Editor/Windows/GameCookerWindow.cs +++ b/Source/Editor/Windows/GameCookerWindow.cs @@ -61,6 +61,9 @@ namespace FlaxEditor.Windows public abstract class Platform { + [HideInEditor] + public bool IsSupported; + [HideInEditor] public bool IsAvailable; @@ -93,6 +96,23 @@ namespace FlaxEditor.Windows { Output = output; + // Check if can build on that platform +#if PLATFORM_WINDOWS + IsSupported = true; +#elif PLATFORM_LINUX + switch (BuildPlatform) + { + case BuildPlatform.LinuxX64: + IsSupported = true; + break; + default: + IsSupported = false; + break; + } +#else +#error "Unknown platform." +#endif + // TODO: restore build settings from the Editor cache! // Check if can find installed tools for this platform @@ -179,7 +199,11 @@ namespace FlaxEditor.Windows _platform = proxy.Selector.Selected; var platformObj = proxy.PerPlatformOptions[_platform]; - if (platformObj.IsAvailable) + if (!platformObj.IsSupported) + { + layout.Label("This platform is not supported on this system.", TextAlignment.Center); + } + else if (platformObj.IsAvailable) { string name; switch (_platform) diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 3db4df799..5f6ab1613 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -222,7 +222,7 @@ namespace FlaxEditor.Windows } else if (((ContainerControl)_tree.GetChild(0)).ChildrenCount == 0) { - overlayText = "No scene"; + overlayText = "No scene\nOpen one from the content window"; } if (overlayText != null) { diff --git a/Source/Engine/Core/Config/GameSettings.cpp b/Source/Engine/Core/Config/GameSettings.cpp index 424eddaa1..e2789c0e2 100644 --- a/Source/Engine/Core/Config/GameSettings.cpp +++ b/Source/Engine/Core/Config/GameSettings.cpp @@ -100,7 +100,12 @@ bool GameSettings::Load() auto settings = Get(); if (!settings) { +#if USE_EDITOR + // Allow lack of Game Settings in Editor + return false; +#else return true; +#endif } // Preload all settings assets diff --git a/Source/Engine/Core/Log.cpp b/Source/Engine/Core/Log.cpp index cb73a79e1..29099ad80 100644 --- a/Source/Engine/Core/Log.cpp +++ b/Source/Engine/Core/Log.cpp @@ -156,9 +156,9 @@ void Log::Logger::Dispose() WriteFloor(); // Close - LogAfterInit = false; if (LogAfterInit) { + LogAfterInit = false; LogFile->Close(); Delete(LogFile); LogFile = nullptr; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp index 6ebd55384..e9d83bfc3 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp @@ -99,8 +99,6 @@ void GPUSwapChainDX11::SetFullscreen(bool isFullscreen) swapChainDesc.BufferDesc = outputDX.DesktopViewMode; } - releaseBackBuffer(); - if (FAILED(_swapChain->ResizeTarget(&swapChainDesc.BufferDesc))) { LOG(Warning, "Swapchain resize failed."); @@ -110,10 +108,6 @@ void GPUSwapChainDX11::SetFullscreen(bool isFullscreen) { LOG(Warning, "Cannot change fullscreen mode for '{0}' to {1}.", ToString(), isFullscreen); } - - VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, _width, _height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags)); - - getBackBuffer(); } #else LOG(Info, "Cannot change fullscreen mode on this platform"); @@ -208,7 +202,7 @@ bool GPUSwapChainDX11::Resize(int32 width, int32 height) ASSERT(_swapChain); // Disable DXGI changes to the window - VALIDATE_DIRECTX_RESULT(dxgi->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER)); + VALIDATE_DIRECTX_RESULT(dxgi->MakeWindowAssociation(_windowHandle, 0)); #else auto dxgiFactory = (IDXGIFactory2*)_device->GetDXGIFactory(); VALIDATE_DIRECTX_RESULT(dxgiFactory->CreateSwapChainForCoreWindow(_device->GetDevice(), static_cast(_windowHandle), &swapChainDesc, nullptr, &_swapChain)); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp index 669b217e4..b8ac22bba 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp @@ -124,8 +124,6 @@ void GPUSwapChainDX12::SetFullscreen(bool isFullscreen) swapChainDesc.BufferDesc = outputDX.DesktopViewMode; } - releaseBackBuffer(); - if (FAILED(_swapChain->ResizeTarget(&swapChainDesc.BufferDesc))) { LOG(Warning, "Swapchain resize failed."); @@ -136,10 +134,6 @@ void GPUSwapChainDX12::SetFullscreen(bool isFullscreen) LOG(Warning, "Cannot change fullscreen mode for '{0}' to {1}.", ToString(), isFullscreen); } - VALIDATE_DIRECTX_RESULT(_swapChain->ResizeBuffers(swapChainDesc.BufferCount, _width, _height, swapChainDesc.BufferDesc.Format, swapChainDesc.Flags)); - - getBackBuffer(); - _isFullscreen = isFullscreen; } #else @@ -223,7 +217,7 @@ bool GPUSwapChainDX12::Resize(int32 width, int32 height) _backBuffers.Resize(swapChainDesc.BufferCount); // Disable DXGI changes to the window - dxgiFactory->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER); + dxgiFactory->MakeWindowAssociation(_windowHandle, 0); } else { diff --git a/Source/Engine/Platform/Android/AndroidWindow.cpp b/Source/Engine/Platform/Android/AndroidWindow.cpp index abfee9d13..4d3c4ca67 100644 --- a/Source/Engine/Platform/Android/AndroidWindow.cpp +++ b/Source/Engine/Platform/Android/AndroidWindow.cpp @@ -6,10 +6,14 @@ #include "Engine/Graphics/RenderTask.h" #include +#define DefaultDPI 96 + AndroidWindow::AndroidWindow(const CreateWindowSettings& settings) : WindowBase(settings) { _clientSize = settings.Size; + _dpi = DefaultDPI; + _dpiScale = (float)_dpi / (float)DefaultDPI; } AndroidWindow::~AndroidWindow() diff --git a/Source/Engine/Platform/Base/PlatformBase.h b/Source/Engine/Platform/Base/PlatformBase.h index c6c99a2c6..0d972f412 100644 --- a/Source/Engine/Platform/Base/PlatformBase.h +++ b/Source/Engine/Platform/Base/PlatformBase.h @@ -569,17 +569,17 @@ public: API_PROPERTY() static BatteryInfo GetBatteryInfo(); /// - /// Gets the screen DPI setting. + /// Gets the primary monitor's DPI setting. /// API_PROPERTY() static int32 GetDpi(); /// - /// Gets the screen DPI setting scale factor (1 is default). Includes custom DPI scale. + /// Gets the primary monitor's DPI setting scale factor (1 is default). Includes custom DPI scale. /// API_PROPERTY() static float GetDpiScale(); /// - /// The custom screen DPI scale factor to apply globally. Can be used to adjust the User Interface scale (resolution). + /// The custom DPI scale factor to apply globally. Can be used to adjust the User Interface scale (resolution). /// API_FIELD() static float CustomDpiScale; diff --git a/Source/Engine/Platform/Base/WindowBase.h b/Source/Engine/Platform/Base/WindowBase.h index a8215bc8b..b432a8a4d 100644 --- a/Source/Engine/Platform/Base/WindowBase.h +++ b/Source/Engine/Platform/Base/WindowBase.h @@ -281,6 +281,8 @@ protected: String _title; CursorType _cursor; Vector2 _clientSize; + int _dpi; + float _dpiScale; Vector2 _trackingMouseOffset; bool _isUsingMouseOffset; @@ -542,6 +544,21 @@ public: /// The screen space position. API_FUNCTION() virtual Vector2 ClientToScreen(const Vector2& clientPos) const = 0; + /// + /// Gets the window DPI setting. + /// + API_PROPERTY() int GetDpi() const + { + return _dpi; + } + + /// + /// Gets the window DPI scale factor (1 is default). Includes custom DPI scale + /// + API_PROPERTY() float GetDpiScale() const + { + return Platform::CustomDpiScale * _dpiScale; + } public: /// diff --git a/Source/Engine/Platform/Linux/LinuxWindow.cpp b/Source/Engine/Platform/Linux/LinuxWindow.cpp index 32a511834..8714a130c 100644 --- a/Source/Engine/Platform/Linux/LinuxWindow.cpp +++ b/Source/Engine/Platform/Linux/LinuxWindow.cpp @@ -31,6 +31,7 @@ #define _NET_WM_STATE_REMOVE 0L // remove/unset property #define _NET_WM_STATE_ADD 1L // add/set property #define _NET_WM_STATE_TOGGLE 2L // toggle property +#define DefaultDPI 96 // Window routines function prolog #define LINUX_WINDOW_PROLOG X11::Display* display = (X11::Display*)LinuxPlatform::GetXDisplay(); X11::Window window = (X11::Window)_window @@ -150,7 +151,10 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings) X11::XSetTransientForHint(display, window, (X11::Window)((LinuxWindow*)settings.Parent)->GetNativePtr()); } - // Set events mask + _dpi = Platform::GetDpi(); + _dpiScale = (float)_dpi / (float)DefaultDPI; + + // Set input mask long eventMask = ExposureMask | FocusChangeMask | KeyPressMask | KeyReleaseMask | diff --git a/Source/Engine/Platform/UWP/UWPWindow.h b/Source/Engine/Platform/UWP/UWPWindow.h index e687ba32a..f73a046dc 100644 --- a/Source/Engine/Platform/UWP/UWPWindow.h +++ b/Source/Engine/Platform/UWP/UWPWindow.h @@ -100,7 +100,6 @@ private: UWPWindowImpl* _impl; - float _dpi, _dpiScale; Vector2 _logicalSize; public: diff --git a/Source/Engine/Platform/Window.cs b/Source/Engine/Platform/Window.cs index 8a8a19c01..d000c6f90 100644 --- a/Source/Engine/Platform/Window.cs +++ b/Source/Engine/Platform/Window.cs @@ -7,8 +7,6 @@ namespace FlaxEngine { partial class Window { - internal float _dpiScale; - /// /// Window closing delegate. /// @@ -176,7 +174,6 @@ namespace FlaxEngine private Window() { GUI = new WindowRootControl(this); - _dpiScale = Platform.DpiScale; } internal void Internal_OnShow() @@ -192,7 +189,7 @@ namespace FlaxEngine internal void Internal_OnDraw() { - Matrix3x3.Scaling(_dpiScale, out var scale); + Matrix3x3.Scaling(DpiScale, out var scale); Render2D.PushTransform(ref scale); GUI.Draw(); Render2D.PopTransform(); @@ -200,7 +197,7 @@ namespace FlaxEngine internal void Internal_OnResize(int width, int height) { - GUI.Size = new Vector2(width / _dpiScale, height / _dpiScale); + GUI.Size = new Vector2(width / DpiScale, height / DpiScale); } internal void Internal_OnCharInput(char c) @@ -223,7 +220,7 @@ namespace FlaxEngine internal void Internal_OnMouseDown(ref Vector2 mousePos, MouseButton button) { - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; bool handled = false; MouseDown?.Invoke(ref pos, button, ref handled); @@ -235,7 +232,7 @@ namespace FlaxEngine internal void Internal_OnMouseUp(ref Vector2 mousePos, MouseButton button) { - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; bool handled = false; MouseUp?.Invoke(ref pos, button, ref handled); @@ -247,7 +244,7 @@ namespace FlaxEngine internal void Internal_OnMouseDoubleClick(ref Vector2 mousePos, MouseButton button) { - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; bool handled = false; MouseDoubleClick?.Invoke(ref pos, button, ref handled); @@ -259,7 +256,7 @@ namespace FlaxEngine internal void Internal_OnMouseWheel(ref Vector2 mousePos, float delta) { - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; bool handled = false; MouseWheel?.Invoke(ref pos, delta, ref handled); @@ -271,7 +268,7 @@ namespace FlaxEngine internal void Internal_OnMouseMove(ref Vector2 mousePos) { - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; MouseMove?.Invoke(ref pos); GUI.OnMouseMove(pos); @@ -285,7 +282,7 @@ namespace FlaxEngine internal void Internal_OnTouchDown(ref Vector2 pointerPosition, int pointerId) { - Vector2 pos = pointerPosition / _dpiScale; + Vector2 pos = pointerPosition / DpiScale; bool handled = false; TouchDown?.Invoke(ref pos, pointerId, ref handled); @@ -297,7 +294,7 @@ namespace FlaxEngine internal void Internal_OnTouchMove(ref Vector2 pointerPosition, int pointerId) { - Vector2 pos = pointerPosition / _dpiScale; + Vector2 pos = pointerPosition / DpiScale; bool handled = false; TouchMove?.Invoke(ref pos, pointerId, ref handled); @@ -309,7 +306,7 @@ namespace FlaxEngine internal void Internal_OnTouchUp(ref Vector2 pointerPosition, int pointerId) { - Vector2 pos = pointerPosition / _dpiScale; + Vector2 pos = pointerPosition / DpiScale; bool handled = false; TouchUp?.Invoke(ref pos, pointerId, ref handled); @@ -335,7 +332,7 @@ namespace FlaxEngine { if (HitTest != null) { - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; result = HitTest(ref pos); handled = true; } @@ -356,7 +353,7 @@ namespace FlaxEngine dragData = new DragDataText(data[0]); else dragData = new DragDataFiles(data); - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; return GUI.OnDragEnter(ref pos, dragData); } @@ -367,7 +364,7 @@ namespace FlaxEngine dragData = new DragDataText(data[0]); else dragData = new DragDataFiles(data); - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; return GUI.OnDragMove(ref pos, dragData); } @@ -378,7 +375,7 @@ namespace FlaxEngine dragData = new DragDataText(data[0]); else dragData = new DragDataFiles(data); - Vector2 pos = mousePos / _dpiScale; + Vector2 pos = mousePos / DpiScale; return GUI.OnDragDrop(ref pos, dragData); } diff --git a/Source/Engine/Platform/Windows/WindowsFileSystemWatcher.cpp b/Source/Engine/Platform/Windows/WindowsFileSystemWatcher.cpp index 63e610cd1..832fd9bb2 100644 --- a/Source/Engine/Platform/Windows/WindowsFileSystemWatcher.cpp +++ b/Source/Engine/Platform/Windows/WindowsFileSystemWatcher.cpp @@ -182,6 +182,7 @@ WindowsFileSystemWatcher::~WindowsFileSystemWatcher() FileSystemWatchers::ThreadActive = false; QueueUserAPC(FileSystemWatchers::StopProc, FileSystemWatchers::Thread->GetHandle(), 0); FileSystemWatchers::Thread->Join(); + Delete(FileSystemWatchers::Thread); FileSystemWatchers::Thread = nullptr; } FileSystemWatchers::Locker.Unlock(); diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index 4dd2164ae..1b8942dec 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -673,7 +673,7 @@ void WindowsPlatform::SetHighDpiAwarenessEnabled(bool enable) if (setProcessDpiAwareness) { - setProcessDpiAwareness(enable ? PROCESS_SYSTEM_DPI_AWARE : PROCESS_DPI_UNAWARE); + setProcessDpiAwareness(enable ? PROCESS_PER_MONITOR_DPI_AWARE : PROCESS_DPI_UNAWARE); } SystemDpi = CalculateDpi(shCoreDll); diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 3a35d24e9..b3687cf78 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -13,6 +13,8 @@ #include "../Win32/IncludeWindowsHeaders.h" #include +#define DefaultDPI 96 + // Use improved borderless window support for Editor #define WINDOWS_USE_NEW_BORDER_LESS USE_EDITOR && 0 #if WINDOWS_USE_NEW_BORDER_LESS @@ -123,6 +125,21 @@ WindowsWindow::WindowsWindow(const CreateWindowSettings& settings) (HINSTANCE)Platform::Instance, nullptr); + // Query DPI + _dpi = Platform::GetDpi(); + const HMODULE user32Dll = LoadLibraryW(L"user32.dll"); + if (user32Dll) + { + typedef UINT (STDAPICALLTYPE* GetDpiForWindowProc)(HWND hwnd); + const GetDpiForWindowProc getDpiForWindowProc = (GetDpiForWindowProc)GetProcAddress(user32Dll, "GetDpiForWindow"); + if (getDpiForWindowProc) + { + _dpi = getDpiForWindowProc(_handle); + } + FreeLibrary(user32Dll); + } + _dpiScale = (float)_dpi / (float)DefaultDPI; + // Validate result if (!HasHWND()) { @@ -1021,6 +1038,22 @@ LRESULT WindowsWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) } break; } + case WM_DPICHANGED: + { + // Maybe https://stackoverflow.com/a/45110656 + _dpi = HIWORD(wParam); + _dpiScale = (float)_dpi / (float)DefaultDPI; + RECT* windowRect = (RECT*)lParam; + SetWindowPos(_handle, + nullptr, + windowRect->left, + windowRect->top, + windowRect->right - windowRect->left, + windowRect->bottom - windowRect->top, + SWP_NOZORDER | SWP_NOACTIVATE); + // TODO: Recalculate fonts + return 0; + } case WM_ENTERSIZEMOVE: { _isResizing = true; diff --git a/Source/Engine/Render2D/FontManager.cpp b/Source/Engine/Render2D/FontManager.cpp index ec7a61257..13b46991f 100644 --- a/Source/Engine/Render2D/FontManager.cpp +++ b/Source/Engine/Render2D/FontManager.cpp @@ -67,7 +67,7 @@ bool FontManagerService::Init() ASSERT(Library == nullptr); // Scale UI fonts to match the monitor DPI - FontManager::FontScale = (float)Platform::GetDpi() / (float)DefaultDPI; + FontManager::FontScale = (float)Platform::GetDpi() / (float)DefaultDPI; // TODO: Adjust this at runtime // Init Free Type FreeTypeMemory.user = nullptr; @@ -109,7 +109,7 @@ void FontManagerService::Dispose() FontTextureAtlas* FontManager::GetAtlas(int32 index) { - return Atlases[index]; + return index >= 0 && index < Atlases.Count() ? Atlases.Get()[index] : nullptr; } bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry) @@ -206,6 +206,7 @@ bool FontManager::AddNewEntry(Font* font, Char c, FontCharacterEntry& entry) // End for empty glyphs if (GlyphImageData.IsEmpty()) { + entry.TextureIndex = MAX_uint8; if (bitmap == &tmpBitmap) { FT_Bitmap_Done(Library, bitmap); diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index c79a59d95..64517ce03 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -1137,11 +1137,17 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, // Get texture atlas that contains current character fontAtlasIndex = entry.TextureIndex; fontAtlas = FontManager::GetAtlas(fontAtlasIndex); - fontAtlas->EnsureTextureCreated(); - drawCall.AsChar.Tex = fontAtlas->GetTexture(); - - // Cache atlas inverted size (inverted to improve performance) - invAtlasSize = 1.0f / fontAtlas->GetSize(); + if (fontAtlas) + { + fontAtlas->EnsureTextureCreated(); + drawCall.AsChar.Tex = fontAtlas->GetTexture(); + invAtlasSize = 1.0f / fontAtlas->GetSize(); + } + else + { + drawCall.AsChar.Tex = nullptr; + invAtlasSize = 1.0f; + } } // Check if character is a whitespace @@ -1250,9 +1256,17 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, // Get texture atlas that contains current character fontAtlasIndex = entry.TextureIndex; fontAtlas = FontManager::GetAtlas(fontAtlasIndex); - fontAtlas->EnsureTextureCreated(); - invAtlasSize = 1.0f / fontAtlas->GetSize(); - drawCall.AsChar.Tex = fontAtlas->GetTexture(); + if (fontAtlas) + { + fontAtlas->EnsureTextureCreated(); + invAtlasSize = 1.0f / fontAtlas->GetSize(); + drawCall.AsChar.Tex = fontAtlas->GetTexture(); + } + else + { + invAtlasSize = 1.0f; + drawCall.AsChar.Tex = nullptr; + } } // Get kerning diff --git a/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp b/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp index 40eaf3b00..7d00c1b8c 100644 --- a/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp @@ -123,7 +123,6 @@ void MAssembly::Unload(bool isReloading) LOG(Info, "Unloading managed assembly \'{0}\' (is reloading)", String(_name)); mono_assembly_close(_monoAssembly); - mono_image_close(_monoImage); } else { @@ -306,11 +305,9 @@ bool MAssembly::LoadWithImage(const String& assemblyPath) // Setup assembly const auto assembly = mono_assembly_load_from_full(assemblyImage, name.Substring(0, name.Length() - 3).Get(), &status, false); + mono_image_close(assemblyImage); if (status != MONO_IMAGE_OK || assembly == nullptr) { - // Close image if error occurred - mono_image_close(assemblyImage); - Log::CLRInnerException(TEXT("Mono assembly image is corrupted at ") + assemblyPath); return true; } diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp index a8ad6e49f..97f336dc5 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.Mono.cpp @@ -508,8 +508,9 @@ bool MCore::LoadEngine() Thread::ThreadExiting.Bind(); // Info - const String buildInfo(mono_get_runtime_build_info()); - LOG(Info, "Mono version: {0}", buildInfo); + char* buildInfo = mono_get_runtime_build_info(); + LOG(Info, "Mono version: {0}", String(buildInfo)); + mono_free(buildInfo); return false; } diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 2919ce1ae..7f87178fd 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -518,7 +518,7 @@ void Scripting::Release() module->Destroy(false); } - _nonNativeModules.Clear(); + _nonNativeModules.ClearDelete(); _hasGameModulesLoaded = false; } @@ -619,7 +619,7 @@ void Scripting::Reload(bool canTriggerSceneReload) module->Destroy(true); } modules.Clear(); - _nonNativeModules.Clear(); + _nonNativeModules.ClearDelete(); _hasGameModulesLoaded = false; // Give GC a try to cleanup old user objects and the other mess diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs index d3300dd23..127fa4d87 100644 --- a/Source/Engine/Serialization/JsonSerializer.cs +++ b/Source/Engine/Serialization/JsonSerializer.cs @@ -165,17 +165,19 @@ namespace FlaxEngine.Json public StringWriter StringWriter; public JsonTextWriter JsonWriter; public JsonSerializerInternalWriter SerializerWriter; - public UnmanagedStringReader StringReader; + public UnmanagedMemoryStream MemoryStream; + public StreamReader Reader; public bool IsDuringSerialization; - public SerializerCache(JsonSerializerSettings settings) + public unsafe SerializerCache(JsonSerializerSettings settings) { JsonSerializer = Newtonsoft.Json.JsonSerializer.CreateDefault(settings); JsonSerializer.Formatting = Formatting.Indented; StringBuilder = new StringBuilder(256); StringWriter = new StringWriter(StringBuilder, CultureInfo.InvariantCulture); SerializerWriter = new JsonSerializerInternalWriter(JsonSerializer); - StringReader = new UnmanagedStringReader(); + MemoryStream = new UnmanagedMemoryStream((byte*)0, 0); + Reader = new StreamReader(MemoryStream, Encoding.UTF8, false); JsonWriter = new JsonTextWriter(StringWriter) { IndentChar = '\t', @@ -404,14 +406,15 @@ namespace FlaxEngine.Json /// The object. /// The input json data buffer (raw, fixed memory buffer). /// The input json data buffer length (characters count). - public static unsafe void Deserialize(object input, void* jsonBuffer, int jsonLength) + public static unsafe void Deserialize(object input, byte* jsonBuffer, int jsonLength) { var cache = Cache.Value; cache.IsDuringSerialization = false; Current.Value = cache; - cache.StringReader.Initialize(jsonBuffer, jsonLength); - var jsonReader = new JsonTextReader(cache.StringReader); + cache.MemoryStream.Initialize(jsonBuffer, jsonLength); + cache.Reader.DiscardBufferedData(); + var jsonReader = new JsonTextReader(cache.Reader); cache.JsonSerializer.Populate(jsonReader, input); if (!cache.JsonSerializer.CheckAdditionalContent) diff --git a/Source/Engine/Serialization/UnmanagedMemoryStream.cs b/Source/Engine/Serialization/UnmanagedMemoryStream.cs new file mode 100644 index 000000000..12b7c4634 --- /dev/null +++ b/Source/Engine/Serialization/UnmanagedMemoryStream.cs @@ -0,0 +1,157 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace FlaxEngine.Json +{ + /// + /// Implements a that reads from unmanaged buffer (provided as raw pointer and length). + /// + internal class UnmanagedMemoryStream : Stream + { + private unsafe byte* _ptr; + private int _length; + private int _pos; + private FileAccess _access; + internal bool _isOpen; + private Task _lastReadTask; + + internal UnmanagedMemoryStream() + { + } + + internal unsafe UnmanagedMemoryStream(byte* pointer, int length, FileAccess access = FileAccess.Read) => Initialize(pointer, length, access); + + internal unsafe void Initialize(byte* pointer, int length, FileAccess access = FileAccess.Read) + { + _ptr = pointer; + _length = length; + _pos = 0; + _access = access; + _isOpen = true; + _lastReadTask = null; + } + + public override bool CanRead => _isOpen && (uint)(_access & FileAccess.Read) > 0U; + + public override bool CanSeek => _isOpen; + + public override bool CanWrite => _isOpen && (uint)(_access & FileAccess.Write) > 0U; + + protected override unsafe void Dispose(bool disposing) + { + _isOpen = false; + _ptr = null; + base.Dispose(disposing); + } + + public override void Flush() + { + } + + public override Task FlushAsync(CancellationToken cancellationToken) + { + Flush(); + return Task.FromResult(0); + } + + public unsafe byte* Pointer => _ptr; + + public override long Length => _length; + + public long Capacity => _length; + + public override long Position + { + get => _pos; + set => _pos = (int)value; + } + + public unsafe byte* PositionPointer + { + get => _ptr + _pos; + set => _pos = (int)(value - _ptr); + } + + public override unsafe int Read(byte[] buffer, int offset, int count) + { + int toRead = _length - _pos; + if (toRead > count) + toRead = count; + if (toRead <= 0) + return 0; + fixed (byte* bufferPtr = buffer) + Utils.MemoryCopy(new IntPtr(_ptr + _pos), new IntPtr(bufferPtr), toRead); + _pos += toRead; + return toRead; + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + int result = Read(buffer, offset, count); + return _lastReadTask == null || _lastReadTask.Result != result ? (_lastReadTask = Task.FromResult(result)) : _lastReadTask; + } + + public override unsafe int ReadByte() + { + int index = _pos; + if (index >= _length) + return -1; + _pos = index + 1; + return _ptr[index]; + } + + public override long Seek(long offset, SeekOrigin loc) + { + switch (loc) + { + case SeekOrigin.Begin: + _pos = (int)offset; + break; + case SeekOrigin.Current: + _pos += (int)offset; + break; + case SeekOrigin.End: + _pos = _length + (int)offset; + break; + default: throw new ArgumentOutOfRangeException(); + } + return _pos; + } + + public override void SetLength(long value) + { + _length = (int)value; + if (_pos > value) + _pos = _length; + } + + public override unsafe void Write(byte[] buffer, int offset, int count) + { + int newPos = _pos + count; + if (newPos > _length) + _length = newPos; + fixed (byte* bufferPtr = buffer) + Utils.MemoryCopy(new IntPtr(_pos + _pos), new IntPtr(bufferPtr), count); + _pos = newPos; + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + Write(buffer, offset, count); + return Task.FromResult(0); + } + + public override unsafe void WriteByte(byte value) + { + long newPos = _pos + 1; + if (_pos >= _length) + _length = (int)newPos; + _ptr[_pos] = value; + _pos = (int)newPos; + } + } +} diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp index 50914ea2e..04101bc0b 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp @@ -518,29 +518,33 @@ bool ImportMaterials(AssimpImporterData& data, String& errorMsg) if (aMaterial->Get(AI_MATKEY_NAME, aName) == AI_SUCCESS) materialSlot.Name = String(aName.C_Str()).TrimTrailing(); materialSlot.AssetID = Guid::Empty; - aiColor3D aColor; - if (aMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, aColor) == AI_SUCCESS) - materialSlot.Diffuse.Color = ToColor(aColor); - bool aBoolean; - if (aMaterial->Get(AI_MATKEY_TWOSIDED, aBoolean) == AI_SUCCESS) - materialSlot.TwoSided = aBoolean; - bool aFloat; - if (aMaterial->Get(AI_MATKEY_OPACITY, aFloat) == AI_SUCCESS) - materialSlot.Opacity.Value = aFloat; - if (data.Model.Types & ImportDataTypes::Textures) + if (data.Model.Types & ImportDataTypes::Materials) { - ImportMaterialTexture(data, aMaterial, aiTextureType_DIFFUSE, materialSlot.Diffuse.TextureIndex, TextureEntry::TypeHint::ColorRGB); - ImportMaterialTexture(data, aMaterial, aiTextureType_EMISSIVE, materialSlot.Emissive.TextureIndex, TextureEntry::TypeHint::ColorRGB); - ImportMaterialTexture(data, aMaterial, aiTextureType_NORMALS, materialSlot.Normals.TextureIndex, TextureEntry::TypeHint::Normals); - ImportMaterialTexture(data, aMaterial, aiTextureType_OPACITY, materialSlot.Opacity.TextureIndex, TextureEntry::TypeHint::ColorRGBA); + aiColor3D aColor; + if (aMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, aColor) == AI_SUCCESS) + materialSlot.Diffuse.Color = ToColor(aColor); + bool aBoolean; + if (aMaterial->Get(AI_MATKEY_TWOSIDED, aBoolean) == AI_SUCCESS) + materialSlot.TwoSided = aBoolean; + bool aFloat; + if (aMaterial->Get(AI_MATKEY_OPACITY, aFloat) == AI_SUCCESS) + materialSlot.Opacity.Value = aFloat; - if (materialSlot.Diffuse.TextureIndex != -1) + if (data.Model.Types & ImportDataTypes::Textures) { - // Detect using alpha mask in diffuse texture - materialSlot.Diffuse.HasAlphaMask = TextureTool::HasAlpha(data.Model.Textures[materialSlot.Diffuse.TextureIndex].FilePath); - if (materialSlot.Diffuse.HasAlphaMask) - data.Model.Textures[materialSlot.Diffuse.TextureIndex].Type = TextureEntry::TypeHint::ColorRGBA; + ImportMaterialTexture(data, aMaterial, aiTextureType_DIFFUSE, materialSlot.Diffuse.TextureIndex, TextureEntry::TypeHint::ColorRGB); + ImportMaterialTexture(data, aMaterial, aiTextureType_EMISSIVE, materialSlot.Emissive.TextureIndex, TextureEntry::TypeHint::ColorRGB); + ImportMaterialTexture(data, aMaterial, aiTextureType_NORMALS, materialSlot.Normals.TextureIndex, TextureEntry::TypeHint::Normals); + ImportMaterialTexture(data, aMaterial, aiTextureType_OPACITY, materialSlot.Opacity.TextureIndex, TextureEntry::TypeHint::ColorRGBA); + + if (materialSlot.Diffuse.TextureIndex != -1) + { + // Detect using alpha mask in diffuse texture + materialSlot.Diffuse.HasAlphaMask = TextureTool::HasAlpha(data.Model.Textures[materialSlot.Diffuse.TextureIndex].FilePath); + if (materialSlot.Diffuse.HasAlphaMask) + data.Model.Textures[materialSlot.Diffuse.TextureIndex].Type = TextureEntry::TypeHint::ColorRGBA; + } } } } @@ -691,13 +695,10 @@ bool ModelTool::ImportDataAssimp(const char* path, ImportedModelData& data, cons ProcessNodes(assimpData, scene->mRootNode, -1); // Import materials - if (data.Types & ImportDataTypes::Materials) + if (ImportMaterials(assimpData, errorMsg)) { - if (ImportMaterials(assimpData, errorMsg)) - { - LOG(Warning, "Failed to import materials."); - return true; - } + LOG(Warning, "Failed to import materials."); + return true; } // Import geometry diff --git a/Source/Engine/Tools/TextureTool/TextureTool.Build.cs b/Source/Engine/Tools/TextureTool/TextureTool.Build.cs index c584b6c31..6d98a0651 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.Build.cs +++ b/Source/Engine/Tools/TextureTool/TextureTool.Build.cs @@ -48,6 +48,11 @@ public class TextureTool : EngineModule { options.PrivateDependencies.Add("stb"); options.SourceFiles.Add(Path.Combine(FolderPath, "TextureTool.stb.cpp")); + if (options.Target.IsEditor) + { + // Use helper lib for decompression + options.PrivateDependencies.Add("detex"); + } } options.PublicDefinitions.Add("COMPILE_WITH_TEXTURE_TOOL"); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.cpp b/Source/Engine/Tools/TextureTool/TextureTool.cpp index e98cde7bf..b5e22c84c 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.cpp @@ -250,6 +250,8 @@ bool TextureTool::ImportTexture(const StringView& path, TextureData& textureData bool hasAlpha = false; #if COMPILE_WITH_DIRECTXTEX const auto failed = ImportTextureDirectXTex(type, path, textureData, options, errorMsg, hasAlpha); +#elif COMPILE_WITH_STB + const auto failed = ImportTextureStb(type, path, textureData, options, errorMsg, hasAlpha); #else const auto failed = true; LOG(Warning, "Importing textures is not supported on this platform."); @@ -327,6 +329,8 @@ bool TextureTool::Convert(TextureData& dst, const TextureData& src, const PixelF #if COMPILE_WITH_DIRECTXTEX return ConvertDirectXTex(dst, src, dstFormat); +#elif COMPILE_WITH_STB + return ConvertStb(dst, src, dstFormat); #else LOG(Warning, "Converting textures is not supported on this platform."); return true; @@ -441,11 +445,12 @@ TextureTool::PixelFormatSampler PixelFormatSamplers[] = sizeof(Color32), [](const void* ptr) { - return Color(*(Color32*)ptr); + return Color::SrgbToLinear(Color(*(Color32*)ptr)); }, [](const void* ptr, const Color& color) { - *(Color32*)ptr = Color32(color); + Color srgb = Color::LinearToSrgb(color); + *(Color32*)ptr = Color32(srgb); }, }, { @@ -553,11 +558,12 @@ TextureTool::PixelFormatSampler PixelFormatSamplers[] = [](const void* ptr) { const Color32 bgra = *(Color32*)ptr; - return Color(Color32(bgra.B, bgra.G, bgra.R, bgra.A)); + return Color::SrgbToLinear(Color(Color32(bgra.B, bgra.G, bgra.R, bgra.A))); }, [](const void* ptr, const Color& color) { - *(Color32*)ptr = Color32(byte(color.B * MAX_uint8), byte(color.G * MAX_uint8), byte(color.R * MAX_uint8), byte(color.A * MAX_uint8)); + Color srgb = Color::LinearToSrgb(color); + *(Color32*)ptr = Color32(byte(srgb.B * MAX_uint8), byte(srgb.G * MAX_uint8), byte(srgb.R * MAX_uint8), byte(srgb.A * MAX_uint8)); }, }, { @@ -579,11 +585,12 @@ TextureTool::PixelFormatSampler PixelFormatSamplers[] = [](const void* ptr) { const Color32 bgra = *(Color32*)ptr; - return Color(Color32(bgra.B, bgra.G, bgra.R, MAX_uint8)); + return Color::SrgbToLinear(Color(Color32(bgra.B, bgra.G, bgra.R, MAX_uint8))); }, [](const void* ptr, const Color& color) { - *(Color32*)ptr = Color32(byte(color.B * MAX_uint8), byte(color.G * MAX_uint8), byte(color.R * MAX_uint8), MAX_uint8); + Color srgb = Color::LinearToSrgb(color); + *(Color32*)ptr = Color32(byte(srgb.B * MAX_uint8), byte(srgb.G * MAX_uint8), byte(srgb.R * MAX_uint8), MAX_uint8); }, }, { diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 447bf30ea..6337406ae 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -218,7 +218,7 @@ public: /// The Y texture coordinates (normalized to range 0-height). /// The data pointer for the texture slice (1D or 2D image). /// The row pitch (in bytes). The offset between each image rows. - /// The color to store. + /// The color to store (linear). static void Store(const PixelFormatSampler* sampler, int32 x, int32 y, const void* data, int32 rowPitch, const Color& color); /// @@ -232,7 +232,7 @@ public: /// The data pointer for the texture slice (1D or 2D image). /// The size of the input texture (in pixels). /// The row pitch (in bytes). The offset between each image rows. - /// The sampled color. + /// The sampled color (linear). static Color SamplePoint(const PixelFormatSampler* sampler, const Vector2& uv, const void* data, const Int2& size, int32 rowPitch); /// @@ -246,7 +246,7 @@ public: /// The Y texture coordinates (normalized to range 0-height). /// The data pointer for the texture slice (1D or 2D image). /// The row pitch (in bytes). The offset between each image rows. - /// The sampled color. + /// The sampled color (linear). static Color SamplePoint(const PixelFormatSampler* sampler, int32 x, int32 y, const void* data, int32 rowPitch); /// @@ -260,7 +260,7 @@ public: /// The data pointer for the texture slice (1D or 2D image). /// The size of the input texture (in pixels). /// The row pitch (in bytes). The offset between each image rows. - /// The sampled color. + /// The sampled color (linear). static Color SampleLinear(const PixelFormatSampler* sampler, const Vector2& uv, const void* data, const Int2& size, int32 rowPitch); private: @@ -291,6 +291,9 @@ private: #if COMPILE_WITH_STB static bool ExportTextureStb(ImageType type, const StringView& path, const TextureData& textureData); static bool ImportTextureStb(ImageType type, const StringView& path, TextureData& textureData, bool& hasAlpha); + static bool ImportTextureStb(ImageType type, const StringView& path, TextureData& textureData, const Options& options, String& errorMsg, bool& hasAlpha); + static bool ConvertStb(TextureData& dst, const TextureData& src, const PixelFormat dstFormat); + static bool ResizeStb(PixelFormat format, TextureMipData& dstMip, const TextureMipData& srcMip, int32 dstMipWidth, int32 dstMipHeight); static bool ResizeStb(TextureData& dst, const TextureData& src, int32 dstWidth, int32 dstHeight); #endif }; diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index 3baa47f6a..cf018776e 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -6,7 +6,9 @@ #include "Engine/Core/Log.h" #include "Engine/Core/Math/Color32.h" #include "Engine/Serialization/FileWriteStream.h" +#include "Engine/Graphics/RenderTools.h" #include "Engine/Graphics/Textures/TextureData.h" +#include "Engine/Graphics/Textures/TextureUtils.h" #include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Platform/File.h" @@ -37,6 +39,17 @@ #define STB_IMAGE_RESIZE_IMPLEMENTATION #include +#define STBD_ABS(i) Math::Abs(i) +#define STBD_FABS(x) Math::Abs(x) +#define STB_DXT_IMPLEMENTATION +#include + +#if USE_EDITOR + +#include + +#endif + static void stbWrite(void* context, void* data, int size) { auto file = (FileWriteStream*)context; @@ -50,46 +63,142 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const LOG(Warning, "Exporting texture arrays and cubemaps is not supported by stb library."); } + TextureData const* texture = &textureData; + +#if USE_EDITOR + // Handle compressed textures + TextureData decompressed; + if (PixelFormatExtensions::IsCompressed(textureData.Format)) + { + decompressed.Format = PixelFormatExtensions::IsSRGB(textureData.Format) ? PixelFormat::R8G8B8A8_UNorm_sRGB : PixelFormat::R8G8B8A8_UNorm; + decompressed.Width = textureData.Width; + decompressed.Height = textureData.Height; + decompressed.Depth = textureData.Depth; + decompressed.Items.Resize(1); + decompressed.Items[0].Mips.Resize(1); + + auto decompressedData = decompressed.GetData(0, 0); + decompressedData->RowPitch = textureData.Width * sizeof(Color32); + decompressedData->Lines = textureData.Height; + decompressedData->DepthPitch = decompressedData->RowPitch * decompressedData->Lines; + decompressedData->Data.Allocate(decompressedData->DepthPitch); + + Color32 colors[16]; + int32 blocksWidth = textureData.Width / 4; + int32 blocksHeight = textureData.Height / 4; + const auto blocksData = texture->GetData(0, 0); + byte* decompressedBytes = decompressedData->Data.Get(); + + switch (textureData.Format) + { + case PixelFormat::BC1_UNorm: + case PixelFormat::BC1_UNorm_sRGB: + { + for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++) + { + for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++) + { + const byte* block = blocksData->Data.Get() + yBlock * 4 * blocksData->RowPitch + xBlock * 8; + detexDecompressBlockBC1(block, 0, 0, (byte*)&colors); + for (int32 y = 0; y < 4; y++) + { + for (int32 x = 0; x < 4; x++) + { + *((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x]; + } + } + } + } + break; + } + case PixelFormat::BC2_UNorm: + case PixelFormat::BC2_UNorm_sRGB: + { + for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++) + { + for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++) + { + const byte* block = blocksData->Data.Get() + yBlock * 4 * blocksData->RowPitch + xBlock * 16; + detexDecompressBlockBC2(block, 0, 0, (byte*)&colors); + for (int32 y = 0; y < 4; y++) + { + for (int32 x = 0; x < 4; x++) + { + *((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x]; + } + } + } + } + break; + } + case PixelFormat::BC3_UNorm: + case PixelFormat::BC3_UNorm_sRGB: + { + for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++) + { + for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++) + { + const byte* block = blocksData->Data.Get() + yBlock * 4 * blocksData->RowPitch + xBlock * 16; + detexDecompressBlockBC3(block, 0, 0, (byte*)&colors); + for (int32 y = 0; y < 4; y++) + { + for (int32 x = 0; x < 4; x++) + { + *((Color32*)decompressedBytes + (yBlock * 4 + y) * textureData.Width + (xBlock * 4 + x)) = colors[y * 4 + x]; + } + } + } + } + break; + } + default: + LOG(Warning, "Texture data format {0} is not supported by stb library.", (int32)textureData.Format); + return true; + } + texture = &decompressed; + } +#endif + // Convert into RGBA8 - const auto sampler = GetSampler(textureData.Format); + const auto sampler = GetSampler(texture->Format); if (sampler == nullptr) { LOG(Warning, "Texture data format {0} is not supported by stb library.", (int32)textureData.Format); return true; } - const auto srcData = textureData.GetData(0, 0); + const auto srcData = texture->GetData(0, 0); const int comp = 4; Array data; - bool sRGB = PixelFormatExtensions::IsSRGB(textureData.Format); + bool sRGB = PixelFormatExtensions::IsSRGB(texture->Format); if (type == ImageType::HDR) { - data.Resize(sizeof(float) * comp * textureData.Width * textureData.Height); + data.Resize(sizeof(float) * comp * texture->Width * texture->Height); auto ptr = (Vector4*)data.Get(); - for (int32 y = 0; y < textureData.Height; y++) + for (int32 y = 0; y < texture->Height; y++) { - for (int32 x = 0; x < textureData.Width; x++) + for (int32 x = 0; x < texture->Width; x++) { Color color = SamplePoint(sampler, x, y, srcData->Data.Get(), srcData->RowPitch); if (sRGB) color = Color::SrgbToLinear(color); - *(ptr + x + y * textureData.Width) = color.ToVector4(); + *(ptr + x + y * texture->Width) = color.ToVector4(); } } } else { - data.Resize(sizeof(Color32) * comp * textureData.Width * textureData.Height); + data.Resize(sizeof(Color32) * comp * texture->Width * texture->Height); auto ptr = (Color32*)data.Get(); - for (int32 y = 0; y < textureData.Height; y++) + for (int32 y = 0; y < texture->Height; y++) { - for (int32 x = 0; x < textureData.Width; x++) + for (int32 x = 0; x < texture->Width; x++) { Color color = SamplePoint(sampler, x, y, srcData->Data.Get(), srcData->RowPitch); if (sRGB) color = Color::SrgbToLinear(color); - *(ptr + x + y * textureData.Width) = Color32(color); + *(ptr + x + y * texture->Width) = Color32(color); } } } @@ -109,21 +218,21 @@ bool TextureTool::ExportTextureStb(ImageType type, const StringView& path, const switch (type) { case ImageType::BMP: - result = stbi_write_bmp_core(&s, textureData.Width, textureData.Height, comp, data.Get()); + result = stbi_write_bmp_core(&s, texture->Width, texture->Height, comp, data.Get()); break; case ImageType::JPEG: - result = stbi_write_jpg_core(&s, textureData.Width, textureData.Height, comp, data.Get(), 90); + result = stbi_write_jpg_core(&s, texture->Width, texture->Height, comp, data.Get(), 90); break; case ImageType::TGA: - result = stbi_write_tga_core(&s, textureData.Width, textureData.Height, comp, data.Get()); + result = stbi_write_tga_core(&s, texture->Width, texture->Height, comp, data.Get()); break; case ImageType::HDR: - result = stbi_write_hdr_core(&s, textureData.Width, textureData.Height, comp, (float*)data.Get()); + result = stbi_write_hdr_core(&s, texture->Width, texture->Height, comp, (float*)data.Get()); break; case ImageType::PNG: { int32 ptrSize = 0; - const auto ptr = stbi_write_png_to_mem(data.Get(), 0, textureData.Width, textureData.Height, comp, &ptrSize); + const auto ptr = stbi_write_png_to_mem(data.Get(), 0, texture->Width, texture->Height, comp, &ptrSize); if (ptr) { file->WriteBytes(ptr, ptrSize); @@ -185,9 +294,10 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu stbi_uc* stbData = stbi_load_from_memory(fileData.Get(), fileData.Count(), &width, &height, &components, 4); if (!stbData) { - LOG(Warning, "Failed to load image."); + LOG(Warning, "Failed to load image. {0}", String(stbi_failure_reason())); return false; } + fileData.Resize(0); // Setup texture data textureData.Width = width; @@ -260,6 +370,370 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu return false; } +bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, TextureData& textureData, const Options& options, String& errorMsg, bool& hasAlpha) +{ + // Load image data + if (type == ImageType::Internal) + { + if (options.FlipY) + { + errorMsg = TEXT("Flipping images imported from Internal source is not supported by stb."); + return true; + } + + MISSING_CODE("Importing internal textures with STB."); + return true; + } + else + { + stbi_set_flip_vertically_on_load_thread(options.FlipY); + bool failed = ImportTextureStb(type, path, textureData, hasAlpha); + stbi_set_flip_vertically_on_load_thread(false); + if (failed) + { + return true; + } + } + + // Use two data containers for texture importing for more optimzied performance + TextureData textureDataTmp; + TextureData* textureDataSrc = &textureData; + TextureData* textureDataDst = &textureDataTmp; + + // Check if resize source image + const int32 sourceWidth = textureData.Width; + const int32 sourceHeight = textureData.Height; + int32 width = Math::Clamp(options.Resize ? options.SizeX : static_cast(sourceWidth * options.Scale), 1, options.MaxSize); + int32 height = Math::Clamp(options.Resize ? options.SizeY : static_cast(sourceHeight * options.Scale), 1, options.MaxSize); + if (sourceWidth != width || sourceHeight != height) + { + // During resizing we need to keep texture aspect ratio + const bool keepAspectRatio = false; // TODO: expose as import option + if (keepAspectRatio) + { + const float aspectRatio = static_cast(sourceWidth) / sourceHeight; + if (width >= height) + height = Math::CeilToInt(width / aspectRatio); + else + width = Math::CeilToInt(height / aspectRatio); + } + + // Resize source texture + LOG(Info, "Resizing texture from {0}x{1} to {2}x{3}.", sourceWidth, sourceHeight, width, height); + if (ResizeStb(*textureDataDst, *textureDataSrc, width, height)) + { + errorMsg = String::Format(TEXT("Cannot resize texture.")); + return true; + } + ::Swap(textureDataSrc, textureDataDst); + } + + // Cache data + float alphaThreshold = 0.3f; + bool isPowerOfTwo = Math::IsPowerOfTwo(width) && Math::IsPowerOfTwo(height); + PixelFormat targetFormat = TextureUtils::ToPixelFormat(options.Type, width, height, options.Compress); + if (options.sRGB) + targetFormat = PixelFormatExtensions::TosRGB(targetFormat); + + // Check mip levels + int32 sourceMipLevels = textureDataSrc->GetMipLevels(); + bool hasSourceMipLevels = isPowerOfTwo && sourceMipLevels > 1; + bool useMipLevels = isPowerOfTwo && (options.GenerateMipMaps || hasSourceMipLevels) && (width > 1 || height > 1); + int32 arraySize = (int32)textureDataSrc->GetArraySize(); + int32 mipLevels = MipLevelsCount(width, height, useMipLevels); + if (useMipLevels && !options.GenerateMipMaps && mipLevels != sourceMipLevels) + { + errorMsg = String::Format(TEXT("Imported texture has not full mip chain, loaded mips count: {0}, expected: {1}"), sourceMipLevels, mipLevels); + return true; + } + + // Decompress if texture is compressed (next steps need decompressed input data, for eg. mip maps generation or format changing) + if (PixelFormatExtensions::IsCompressed(textureDataSrc->Format)) + { + // TODO: implement texture decompression + errorMsg = String::Format(TEXT("Imported texture used compressed format {0}. Not supported for importing on this platform.."), (int32)textureDataSrc->Format); + return true; + } + + // Generate mip maps chain + if (useMipLevels && options.GenerateMipMaps) + { + for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) + { + auto& slice = textureDataSrc->Items[arrayIndex]; + slice.Mips.Resize(mipLevels); + for (int32 mipIndex = 1; mipIndex < mipLevels; mipIndex++) + { + const auto& srcMip = slice.Mips[mipIndex - 1]; + auto& dstMip = slice.Mips[mipIndex]; + auto dstMipWidth = Math::Max(textureDataSrc->Width >> mipIndex, 1); + auto dstMipHeight = Math::Max(textureDataSrc->Height >> mipIndex, 1); + if (ResizeStb(textureDataSrc->Format, dstMip, srcMip, dstMipWidth, dstMipHeight)) + { + errorMsg = TEXT("Failed to generate mip texture."); + return true; + } + } + } + } + + // Preserve mipmap alpha coverage (if requested) + if (PixelFormatExtensions::HasAlpha(textureDataSrc->Format) && options.PreserveAlphaCoverage && useMipLevels) + { + // TODO: implement alpha coverage preserving + errorMsg = TEXT("Importing textures with alpha coverage preserving is not supported on this platform."); + return true; + } + + // Compress mip maps or convert image + if (targetFormat != textureDataSrc->Format) + { + if (ConvertStb(*textureDataDst, *textureDataSrc, targetFormat)) + { + errorMsg = String::Format(TEXT("Cannot convert/compress texture.")); + return true; + } + ::Swap(textureDataSrc, textureDataDst); + } + + // Copy data to the output if not in the result container + if (textureDataSrc != &textureData) + { + textureData = textureDataTmp; + } + + return false; +} + +bool TextureTool::ConvertStb(TextureData& dst, const TextureData& src, const PixelFormat dstFormat) +{ + // Setup + auto arraySize = src.GetArraySize(); + dst.Width = src.Width; + dst.Height = src.Height; + dst.Depth = src.Depth; + dst.Format = dstFormat; + dst.Items.Resize(arraySize, false); + auto formatSize = PixelFormatExtensions::SizeInBytes(src.Format); + auto components = PixelFormatExtensions::ComputeComponentsCount(src.Format); + auto sampler = TextureTool::GetSampler(src.Format); + if (!sampler) + { + LOG(Warning, "Cannot convert image. Unsupported format {0}", static_cast(src.Format)); + return true; + } + + if (PixelFormatExtensions::IsCompressed(dstFormat)) + { + int32 bytesPerBlock; + switch (dstFormat) + { + case PixelFormat::BC1_UNorm: + case PixelFormat::BC1_UNorm_sRGB: + case PixelFormat::BC4_UNorm: + bytesPerBlock = 8; + break; + default: + bytesPerBlock = 16; + break; + } + bool isDstSRGB = PixelFormatExtensions::IsSRGB(dstFormat); + + // Compress all array slices + for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) + { + const auto& srcSlice = src.Items[arrayIndex]; + auto& dstSlice = dst.Items[arrayIndex]; + auto mipLevels = srcSlice.Mips.Count(); + dstSlice.Mips.Resize(mipLevels, false); + + // Compress all mip levels + for (int32 mipIndex = 0; mipIndex < mipLevels; mipIndex++) + { + const auto& srcMip = srcSlice.Mips[mipIndex]; + auto& dstMip = dstSlice.Mips[mipIndex]; + auto mipWidth = Math::Max(src.Width >> mipIndex, 1); + auto mipHeight = Math::Max(src.Height >> mipIndex, 1); + auto blocksWidth = Math::Max(Math::DivideAndRoundUp(mipWidth, 4), 1); + auto blocksHeight = Math::Max(Math::DivideAndRoundUp(mipHeight, 4), 1); + + // Allocate memory + dstMip.RowPitch = blocksWidth * bytesPerBlock; + dstMip.DepthPitch = dstMip.RowPitch * blocksHeight; + dstMip.Lines = blocksHeight; + dstMip.Data.Allocate(dstMip.DepthPitch); + + // Compress texture + for (int32 yBlock = 0; yBlock < blocksHeight; yBlock++) + { + for (int32 xBlock = 0; xBlock < blocksWidth; xBlock++) + { + // Sample source texture 4x4 block + Color32 srcBlock[16]; + for (int32 y = 0; y < 4; y++) + { + for (int32 x = 0; x < 4; x++) + { + Color color = TextureTool::SamplePoint(sampler, xBlock * 4 + x, yBlock * 4 + y, srcMip.Data.Get(), srcMip.RowPitch); + if (isDstSRGB) + color = Color::LinearToSrgb(color); + srcBlock[y * 4 + x] = Color32(color); + } + } + + // Compress block + switch (dstFormat) + { + case PixelFormat::BC1_UNorm: + case PixelFormat::BC1_UNorm_sRGB: + stb_compress_dxt_block((byte*)dstMip.Data.Get() + (yBlock * blocksWidth + xBlock) * bytesPerBlock, (byte*)&srcBlock, 0, STB_DXT_HIGHQUAL); + break; + case PixelFormat::BC3_UNorm: + case PixelFormat::BC3_UNorm_sRGB: + stb_compress_dxt_block((byte*)dstMip.Data.Get() + (yBlock * blocksWidth + xBlock) * bytesPerBlock, (byte*)&srcBlock, 1, STB_DXT_HIGHQUAL); + break; + case PixelFormat::BC4_UNorm: + for (int32 i = 1; i < 16; i++) + ((byte*)&srcBlock)[i] = srcBlock[i].R; + stb_compress_bc4_block((byte*)dstMip.Data.Get() + (yBlock * blocksWidth + xBlock) * bytesPerBlock, (byte*)&srcBlock); + break; + case PixelFormat::BC5_UNorm: + for (int32 i = 0; i < 16; i++) + ((uint16*)&srcBlock)[i] = srcBlock[i].R << 8 | srcBlock[i].G; + stb_compress_bc5_block((byte*)dstMip.Data.Get() + (yBlock * blocksWidth + xBlock) * bytesPerBlock, (byte*)&srcBlock); + break; + default: + LOG(Warning, "Cannot compress image. Unsupported format {0}", static_cast(dstFormat)); + return true; + } + } + } + } + } + } + else + { + int32 bytesPerPixel = PixelFormatExtensions::SizeInBytes(dstFormat); + auto dstSampler = TextureTool::GetSampler(dstFormat); + if (!dstSampler) + { + LOG(Warning, "Cannot convert image. Unsupported format {0}", static_cast(dstFormat)); + return true; + } + + // Convert all array slices + for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) + { + const auto& srcSlice = src.Items[arrayIndex]; + auto& dstSlice = dst.Items[arrayIndex]; + auto mipLevels = srcSlice.Mips.Count(); + dstSlice.Mips.Resize(mipLevels, false); + + // Convert all mip levels + for (int32 mipIndex = 0; mipIndex < mipLevels; mipIndex++) + { + const auto& srcMip = srcSlice.Mips[mipIndex]; + auto& dstMip = dstSlice.Mips[mipIndex]; + auto mipWidth = Math::Max(src.Width >> mipIndex, 1); + auto mipHeight = Math::Max(src.Height >> mipIndex, 1); + + // Allocate memory + dstMip.RowPitch = mipWidth * bytesPerPixel; + dstMip.DepthPitch = dstMip.RowPitch * mipHeight; + dstMip.Lines = mipHeight; + dstMip.Data.Allocate(dstMip.DepthPitch); + + // Convert texture + for (int32 y = 0; y < mipHeight; y++) + { + for (int32 x = 0; x < mipWidth; x++) + { + // Sample source texture + Color color = TextureTool::SamplePoint(sampler, x, y, srcMip.Data.Get(), srcMip.RowPitch); + + // Store destination texture + TextureTool::Store(dstSampler, x, y, dstMip.Data.Get(), dstMip.RowPitch, color); + } + } + } + } + } + + return false; +} + +bool TextureTool::ResizeStb(PixelFormat format, TextureMipData& dstMip, const TextureMipData& srcMip, int32 dstMipWidth, int32 dstMipHeight) +{ + // Setup + auto formatSize = PixelFormatExtensions::SizeInBytes(format); + auto components = PixelFormatExtensions::ComputeComponentsCount(format); + auto srcMipWidth = srcMip.RowPitch / formatSize; + auto srcMipHeight = srcMip.DepthPitch / srcMip.RowPitch; + + // Allocate memory + dstMip.RowPitch = dstMipWidth * formatSize; + dstMip.DepthPitch = dstMip.RowPitch * dstMipHeight; + dstMip.Lines = dstMipHeight; + dstMip.Data.Allocate(dstMip.DepthPitch); + + // Resize texture + switch (format) + { + case PixelFormat::R8_Typeless: + case PixelFormat::R8_SInt: + case PixelFormat::R8_SNorm: + case PixelFormat::R8G8_Typeless: + case PixelFormat::R8G8_SInt: + case PixelFormat::R8G8_SNorm: + case PixelFormat::R8G8B8A8_Typeless: + case PixelFormat::R8G8B8A8_UNorm: + case PixelFormat::R8G8B8A8_UInt: + case PixelFormat::R8G8B8A8_SNorm: + case PixelFormat::R8G8B8A8_SInt: + case PixelFormat::B8G8R8A8_UNorm: + case PixelFormat::B8G8R8X8_Typeless: + case PixelFormat::B8G8R8X8_UNorm: + { + if (!stbir_resize_uint8((const uint8*)srcMip.Data.Get(), srcMipWidth, srcMipHeight, srcMip.RowPitch, (uint8*)dstMip.Data.Get(), dstMipWidth, dstMipHeight, dstMip.RowPitch, components)) + { + LOG(Warning, "Cannot resize image."); + return true; + } + break; + } + case PixelFormat::R8G8B8A8_UNorm_sRGB: + case PixelFormat::B8G8R8A8_UNorm_sRGB: + case PixelFormat::B8G8R8X8_UNorm_sRGB: + { + auto alphaChannel = format == PixelFormat::B8G8R8X8_UNorm_sRGB ? STBIR_ALPHA_CHANNEL_NONE : 3; + if (!stbir_resize_uint8_srgb((const uint8*)srcMip.Data.Get(), srcMipWidth, srcMipHeight, srcMip.RowPitch, (uint8*)dstMip.Data.Get(), dstMipWidth, dstMipHeight, dstMip.RowPitch, components, alphaChannel, 0)) + { + LOG(Warning, "Cannot resize image."); + return true; + } + break; + } + case PixelFormat::R32_Typeless: + case PixelFormat::R32_Float: + case PixelFormat::R32G32_Float: + case PixelFormat::R32G32B32_Float: + case PixelFormat::R32G32B32A32_Float: + { + if (!stbir_resize_float((const float*)srcMip.Data.Get(), srcMipWidth, srcMipHeight, srcMip.RowPitch, (float*)dstMip.Data.Get(), dstMipWidth, dstMipHeight, dstMip.RowPitch, components)) + { + LOG(Warning, "Cannot resize image."); + return true; + } + break; + } + default: + LOG(Warning, "Cannot resize image. Unsupported format {0}", static_cast(format)); + return true; + } + + return false; +} + bool TextureTool::ResizeStb(TextureData& dst, const TextureData& src, int32 dstWidth, int32 dstHeight) { // Setup @@ -268,7 +742,7 @@ bool TextureTool::ResizeStb(TextureData& dst, const TextureData& src, int32 dstW dst.Height = dstHeight; dst.Depth = src.Depth; dst.Format = src.Format; - dst.Items.Resize(arraySize); + dst.Items.Resize(arraySize, false); auto formatSize = PixelFormatExtensions::SizeInBytes(src.Format); auto components = PixelFormatExtensions::ComputeComponentsCount(src.Format); @@ -278,7 +752,7 @@ bool TextureTool::ResizeStb(TextureData& dst, const TextureData& src, int32 dstW const auto& srcSlice = src.Items[arrayIndex]; auto& dstSlice = dst.Items[arrayIndex]; auto mipLevels = srcSlice.Mips.Count(); - dstSlice.Mips.Resize(mipLevels); + dstSlice.Mips.Resize(mipLevels, false); // Resize all mip levels for (int32 mipIndex = 0; mipIndex < mipLevels; mipIndex++) @@ -287,69 +761,10 @@ bool TextureTool::ResizeStb(TextureData& dst, const TextureData& src, int32 dstW auto& dstMip = dstSlice.Mips[mipIndex]; auto srcMipWidth = srcMip.RowPitch / formatSize; auto srcMipHeight = srcMip.DepthPitch / srcMip.RowPitch; - auto dstMipWidth = Math::Max(dstWidth << mipIndex, 1); - auto dstMipHeight = Math::Max(dstHeight << mipIndex, 1); - - // Allocate memory - dstMip.RowPitch = dstMipWidth * formatSize; - dstMip.DepthPitch = dstMip.RowPitch * dstMipHeight; - dstMip.Lines = dstMipHeight; - dstMip.Data.Allocate(dstMip.DepthPitch); - - // Resize texture - switch (src.Format) - { - case PixelFormat::R8_Typeless: - case PixelFormat::R8_SInt: - case PixelFormat::R8_SNorm: - case PixelFormat::R8G8_Typeless: - case PixelFormat::R8G8_SInt: - case PixelFormat::R8G8_SNorm: - case PixelFormat::R8G8B8A8_Typeless: - case PixelFormat::R8G8B8A8_UNorm: - case PixelFormat::R8G8B8A8_UInt: - case PixelFormat::R8G8B8A8_SNorm: - case PixelFormat::R8G8B8A8_SInt: - case PixelFormat::B8G8R8A8_UNorm: - case PixelFormat::B8G8R8X8_Typeless: - case PixelFormat::B8G8R8X8_UNorm: - { - if (!stbir_resize_uint8((const uint8*)srcMip.Data.Get(), srcMipWidth, srcMipHeight, srcMip.RowPitch, (uint8*)dstMip.Data.Get(), dstMipWidth, dstMipHeight, dstMip.RowPitch, components)) - { - LOG(Warning, "Cannot resize image."); - return true; - } - break; - } - case PixelFormat::R8G8B8A8_UNorm_sRGB: - case PixelFormat::B8G8R8A8_UNorm_sRGB: - case PixelFormat::B8G8R8X8_UNorm_sRGB: - { - auto alphaChannel = src.Format == PixelFormat::B8G8R8X8_UNorm_sRGB ? STBIR_ALPHA_CHANNEL_NONE : 3; - if (!stbir_resize_uint8_srgb((const uint8*)srcMip.Data.Get(), srcMipWidth, srcMipHeight, srcMip.RowPitch, (uint8*)dstMip.Data.Get(), dstMipWidth, dstMipHeight, dstMip.RowPitch, components, alphaChannel, 0)) - { - LOG(Warning, "Cannot resize image."); - return true; - } - break; - } - case PixelFormat::R32_Typeless: - case PixelFormat::R32_Float: - case PixelFormat::R32G32_Float: - case PixelFormat::R32G32B32_Float: - case PixelFormat::R32G32B32A32_Float: - { - if (!stbir_resize_float((const float*)srcMip.Data.Get(), srcMipWidth, srcMipHeight, srcMip.RowPitch, (float*)dstMip.Data.Get(), dstMipWidth, dstMipHeight, dstMip.RowPitch, components)) - { - LOG(Warning, "Cannot resize image."); - return true; - } - break; - } - default: - LOG(Warning, "Cannot resize image. Unsupported format {0}", static_cast(src.Format)); + auto dstMipWidth = Math::Max(dstWidth >> mipIndex, 1); + auto dstMipHeight = Math::Max(dstHeight >> mipIndex, 1); + if (ResizeStb(src.Format, dstMip, srcMip, dstMipWidth, dstMipHeight)) return true; - } } } diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs index d797c25f4..0889bad9d 100644 --- a/Source/Engine/UI/GUI/Common/Label.cs +++ b/Source/Engine/UI/GUI/Common/Label.cs @@ -192,7 +192,7 @@ namespace FlaxEngine.GUI var rect = new Rectangle(new Vector2(Margin.Left, Margin.Top), Size - Margin.Size); if (ClipText) - Render2D.PushClip(ref rect); + Render2D.PushClip(new Rectangle(Vector2.Zero, Size)); var color = IsMouseOver ? TextColorHighlighted : TextColor; diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index 6a1c4c429..5dcb25419 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -124,7 +124,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (font) { - height = font.Height; + height = font.Height / Platform.DpiScale; return textBlock.Bounds.UpperLeft; } } @@ -136,7 +136,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (font) { - height = font.Height; + height = font.Height / Platform.DpiScale; return textBlock.Bounds.UpperRight; } } @@ -151,7 +151,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (!font) break; - height = font.Height; + height = font.Height / Platform.DpiScale; return textBlock.Bounds.Location + font.GetCharPosition(_text, ref textBlock.Range, index - textBlock.Range.StartIndex); } } @@ -166,7 +166,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (!font) break; - height = font.Height; + height = font.Height / Platform.DpiScale; return textBlock.Bounds.UpperRight; } } @@ -280,10 +280,11 @@ namespace FlaxEngine.GUI { Vector2 leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : font.GetCharPosition(_text, selection.StartIndex); Vector2 rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : font.GetCharPosition(_text, selection.EndIndex); + float height = font.Height / Platform.DpiScale; float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); alpha *= alpha; Color selectionColor = Color.White * alpha; - Rectangle selectionRect = new Rectangle(leftEdge.X, leftEdge.Y, rightEdge.X - leftEdge.X, font.Height); + Rectangle selectionRect = new Rectangle(leftEdge.X, leftEdge.Y, rightEdge.X - leftEdge.X, height); textBlock.Style.BackgroundSelectedBrush.Draw(selectionRect, selectionColor); } } @@ -329,7 +330,8 @@ namespace FlaxEngine.GUI if (textBlock.Style.UnderlineBrush != null) { var underLineHeight = 2.0f; - var underlineRect = new Rectangle(textBlock.Bounds.Location.X, textBlock.Bounds.Location.Y + font.Height - underLineHeight * 0.5f, textBlock.Bounds.Width, underLineHeight); + var height = font.Height / Platform.DpiScale; + var underlineRect = new Rectangle(textBlock.Bounds.Location.X, textBlock.Bounds.Location.Y + height - underLineHeight * 0.5f, textBlock.Bounds.Width, underLineHeight); textBlock.Style.UnderlineBrush.Draw(underlineRect, textBlock.Style.Color); } } diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs index 36460130f..b1b873f34 100644 --- a/Source/Engine/UI/GUI/Common/TextBox.cs +++ b/Source/Engine/UI/GUI/Common/TextBox.cs @@ -1,7 +1,5 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. -using FlaxEngine.Assertions; - namespace FlaxEngine.GUI { /// @@ -109,7 +107,7 @@ namespace FlaxEngine.GUI return Vector2.Zero; } - height = font.Height; + height = font.Height / Platform.DpiScale; return font.GetCharPosition(_text, index, ref _layout); } @@ -161,7 +159,7 @@ namespace FlaxEngine.GUI { Vector2 leftEdge = font.GetCharPosition(_text, SelectionLeft, ref _layout); Vector2 rightEdge = font.GetCharPosition(_text, SelectionRight, ref _layout); - float fontHeight = font.Height; + float fontHeight = font.Height / Platform.DpiScale; // Draw selection background float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); diff --git a/Source/Engine/UI/GUI/Control.Bounds.cs b/Source/Engine/UI/GUI/Control.Bounds.cs index e74c73e66..11b5e677a 100644 --- a/Source/Engine/UI/GUI/Control.Bounds.cs +++ b/Source/Engine/UI/GUI/Control.Bounds.cs @@ -30,7 +30,7 @@ namespace FlaxEngine.GUI /// Gets or sets the normalized position in the parent control that the upper left corner is anchored to (range 0-1). /// [Serialize] - [ExpandGroups, Limit(0.0f, 1.0f, 0.01f), EditorDisplay("Transform"), EditorOrder(990), Tooltip("The normalized position in the parent control that the upper left corner is anchored to (range 0-1).")] + [HideInEditor, ExpandGroups, Limit(0.0f, 1.0f, 0.01f), EditorDisplay("Transform"), EditorOrder(990), Tooltip("The normalized position in the parent control that the upper left corner is anchored to (range 0-1).")] public Vector2 AnchorMin { get => _anchorMin; @@ -50,7 +50,7 @@ namespace FlaxEngine.GUI /// Gets or sets the normalized position in the parent control that the bottom right corner is anchored to (range 0-1). /// [Serialize] - [ExpandGroups, Limit(0.0f, 1.0f, 0.01f), EditorDisplay("Transform"), EditorOrder(991), Tooltip("The normalized position in the parent control that the bottom right corner is anchored to (range 0-1).")] + [HideInEditor, ExpandGroups, Limit(0.0f, 1.0f, 0.01f), EditorDisplay("Transform"), EditorOrder(991), Tooltip("The normalized position in the parent control that the bottom right corner is anchored to (range 0-1).")] public Vector2 AnchorMax { get => _anchorMax; @@ -70,7 +70,7 @@ namespace FlaxEngine.GUI /// Gets or sets the offsets of the corners of the control relative to its anchors. /// [Serialize] - [ExpandGroups, EditorDisplay("Transform"), EditorOrder(992), Tooltip("The offsets of the corners of the control relative to its anchors.")] + [HideInEditor, ExpandGroups, EditorDisplay("Transform"), EditorOrder(992), Tooltip("The offsets of the corners of the control relative to its anchors.")] public Margin Offsets { get => _offsets; @@ -84,11 +84,53 @@ namespace FlaxEngine.GUI } } +#if FLAX_EDITOR + /// + /// Helper for Editor UI (see UIControlControlEditor). + /// + [NoSerialize, HideInEditor] + internal float Proxy_Offset_Left + { + get => Offsets.Left; + set => Offsets = new Margin(value, Offsets.Right, Offsets.Top, Offsets.Bottom); + } + + /// + /// Helper for Editor UI (see UIControlControlEditor). + /// + [NoSerialize, HideInEditor] + internal float Proxy_Offset_Right + { + get => Offsets.Right; + set => Offsets = new Margin(Offsets.Left, value, Offsets.Top, Offsets.Bottom); + } + + /// + /// Helper for Editor UI (see UIControlControlEditor). + /// + [NoSerialize, HideInEditor] + internal float Proxy_Offset_Top + { + get => Offsets.Top; + set => Offsets = new Margin(Offsets.Left, Offsets.Right, value, Offsets.Bottom); + } + + /// + /// Helper for Editor UI (see UIControlControlEditor). + /// + [NoSerialize, HideInEditor] + internal float Proxy_Offset_Bottom + { + get => Offsets.Bottom; + set => Offsets = new Margin(Offsets.Left, Offsets.Right, Offsets.Top, value); + } +#endif + /// /// Gets or sets coordinates of the upper-left corner of the control relative to the upper-left corner of its container. /// [NoSerialize] - [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1000), Tooltip("The location of the upper-left corner of the control relative to he upper-left corner of its container.")] + [HideInEditor, ExpandGroups, EditorDisplay("Transform"), EditorOrder(1000), Tooltip("The location of the upper-left corner of the control relative to he upper-left corner of its container.")] public Vector2 Location { get => _bounds.Location; @@ -119,7 +161,7 @@ namespace FlaxEngine.GUI /// Gets or sets control's size. /// [NoSerialize] - [EditorDisplay("Transform"), EditorOrder(1010), Tooltip("The size of the control bounds.")] + [HideInEditor, EditorDisplay("Transform"), EditorOrder(1010), Tooltip("The size of the control bounds.")] public Vector2 Size { get => _bounds.Size; @@ -231,7 +273,7 @@ namespace FlaxEngine.GUI /// /// Gets or sets the scale. /// - [EditorDisplay("Transform"), Limit(float.MinValue, float.MaxValue, 0.1f), EditorOrder(1020), Tooltip("The control scale parameter.")] + [ExpandGroups, EditorDisplay("Transform"), Limit(float.MinValue, float.MaxValue, 0.1f), EditorOrder(1020), Tooltip("The control scale parameter.")] public Vector2 Scale { get => _scale; @@ -247,7 +289,7 @@ namespace FlaxEngine.GUI /// /// Gets or sets the normalized pivot location (used to transform control around it). Point (0,0) is upper left corner, (0.5,0.5) is center, (1,1) is bottom right corner. /// - [EditorDisplay("Transform"), Limit(0.0f, 1.0f, 0.1f), EditorOrder(1030), Tooltip("The control rotation pivot location in normalized control size. Point (0,0) is upper left corner, (0.5,0.5) is center, (1,1) is bottom right corner.")] + [ExpandGroups, EditorDisplay("Transform"), Limit(0.0f, 1.0f, 0.1f), EditorOrder(1030), Tooltip("The control rotation pivot location in normalized control size. Point (0,0) is upper left corner, (0.5,0.5) is center, (1,1) is bottom right corner.")] public Vector2 Pivot { get => _pivot; @@ -263,7 +305,7 @@ namespace FlaxEngine.GUI /// /// Gets or sets the shear transform angles (x, y). Defined in degrees. /// - [EditorDisplay("Transform"), EditorOrder(1040), Tooltip("The shear transform angles (x, y). Defined in degrees.")] + [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1040), Tooltip("The shear transform angles (x, y). Defined in degrees.")] public Vector2 Shear { get => _shear; @@ -279,7 +321,7 @@ namespace FlaxEngine.GUI /// /// Gets or sets the rotation angle (in degrees). /// - [EditorDisplay("Transform"), EditorOrder(1050), Tooltip("The control rotation angle (in degrees).")] + [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1050), Tooltip("The control rotation angle (in degrees).")] public float Rotation { get => _rotation; diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs index c2ba34f05..3062c3088 100644 --- a/Source/Engine/UI/GUI/Control.cs +++ b/Source/Engine/UI/GUI/Control.cs @@ -176,7 +176,7 @@ namespace FlaxEngine.GUI /// Gets or sets the anchor preset used by the control anchors (based on and ). /// /// To change anchor preset with current control bounds preservation use . - [NoSerialize, EditorDisplay("Transform"), EditorOrder(980), Tooltip("The anchor preset used by the control anchors.")] + [NoSerialize, EditorDisplay("Transform"), HideInEditor, EditorOrder(980), Tooltip("The anchor preset used by the control anchors.")] public AnchorPresets AnchorPreset { get @@ -310,7 +310,7 @@ namespace FlaxEngine.GUI /// /// Gets the GUI window root control which contains that control (or null if not linked to any). /// - public virtual WindowRootControl RootWindow => _parent?.RootWindow; + public virtual WindowRootControl RootWindow => _root?.RootWindow; /// /// Gets screen position of the control (upper left corner). diff --git a/Source/Engine/UI/GUI/RenderOutputControl.cs b/Source/Engine/UI/GUI/RenderOutputControl.cs index b840e0be8..c12b1844e 100644 --- a/Source/Engine/UI/GUI/RenderOutputControl.cs +++ b/Source/Engine/UI/GUI/RenderOutputControl.cs @@ -224,7 +224,7 @@ namespace FlaxEngine.GUI /// public void SyncBackbufferSize() { - float scale = ResolutionScale * Platform.DpiScale; + float scale = ResolutionScale * (RootWindow?.DpiScale ?? Platform.DpiScale); int width = Mathf.CeilToInt(Width * scale); int height = Mathf.CeilToInt(Height * scale); if (_customResolution.HasValue) diff --git a/Source/Engine/UI/GUI/Tooltip.cs b/Source/Engine/UI/GUI/Tooltip.cs index 5d03bf75c..1ccf0a5da 100644 --- a/Source/Engine/UI/GUI/Tooltip.cs +++ b/Source/Engine/UI/GUI/Tooltip.cs @@ -68,7 +68,7 @@ namespace FlaxEngine.GUI var parentWin = target.Root; if (parentWin == null) return; - float dpiScale = Platform.DpiScale; + float dpiScale = target.RootWindow.DpiScale; Vector2 dpiSize = Size * dpiScale; Vector2 locationWS = target.PointToWindow(location); Vector2 locationSS = parentWin.PointToScreen(locationWS); @@ -183,7 +183,7 @@ namespace FlaxEngine.GUI { if (_window) { - _window.ClientSize = Size * Platform.DpiScale; + _window.ClientSize = Size * _window.DpiScale; } } diff --git a/Source/Engine/UI/GUI/WindowRootControl.cs b/Source/Engine/UI/GUI/WindowRootControl.cs index 02c996b68..a8028ebe8 100644 --- a/Source/Engine/UI/GUI/WindowRootControl.cs +++ b/Source/Engine/UI/GUI/WindowRootControl.cs @@ -55,6 +55,11 @@ namespace FlaxEngine.GUI /// public bool IsMaximized => _window.IsMaximized; + /// + /// Gets the window DPI scale factor (1 is default). Includes custom DPI scale + /// + public float DpiScale => _window.DpiScale; + internal WindowRootControl(Window window) { _window = window; @@ -151,7 +156,7 @@ namespace FlaxEngine.GUI } /// - public override Vector2 TrackingMouseOffset => _window.TrackingMouseOffset / _window._dpiScale; + public override Vector2 TrackingMouseOffset => _window.TrackingMouseOffset / _window.DpiScale; /// public override WindowRootControl RootWindow => this; @@ -159,8 +164,8 @@ namespace FlaxEngine.GUI /// public override Vector2 MousePosition { - get => _window.MousePosition / _window._dpiScale; - set => _window.MousePosition = value * _window._dpiScale; + get => _window.MousePosition / _window.DpiScale; + set => _window.MousePosition = value * _window.DpiScale; } /// @@ -234,13 +239,13 @@ namespace FlaxEngine.GUI /// public override Vector2 PointFromScreen(Vector2 location) { - return _window.ScreenToClient(location) / _window._dpiScale; + return _window.ScreenToClient(location) / _window.DpiScale; } /// public override Vector2 PointToScreen(Vector2 location) { - return _window.ClientToScreen(location * _window._dpiScale); + return _window.ClientToScreen(location * _window.DpiScale); } /// diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index 8e00c2cc3..a26d3d169 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -177,8 +177,15 @@ void TextRender::UpdateLayout() // Get texture atlas that contains current character drawChunk.FontAtlasIndex = entry.TextureIndex; fontAtlas = FontManager::GetAtlas(drawChunk.FontAtlasIndex); - fontAtlas->EnsureTextureCreated(); - invAtlasSize = 1.0f / fontAtlas->GetSize(); + if (fontAtlas) + { + fontAtlas->EnsureTextureCreated(); + invAtlasSize = 1.0f / fontAtlas->GetSize(); + } + else + { + invAtlasSize = 1.0f; + } // Setup material drawChunk.Material = Content::CreateVirtualAsset(); @@ -281,6 +288,11 @@ void TextRender::UpdateLayout() #endif // Update text bounds (from build vertex positions) + if (_ib.Data.IsEmpty()) + { + // Empty + box = BoundingBox(_transform.Translation, _transform.Translation); + } _localBox = box; BoundingBox::Transform(_localBox, _world, _box); BoundingSphere::FromBox(_box, _sphere); diff --git a/Source/Engine/Utilities/StringUtils.cs b/Source/Engine/Utilities/StringUtils.cs index cb04afbfc..ff6beb4ec 100644 --- a/Source/Engine/Utilities/StringUtils.cs +++ b/Source/Engine/Utilities/StringUtils.cs @@ -232,20 +232,30 @@ namespace FlaxEngine return result; } + private static IEnumerable GraphemeClusters(this string s) + { + var enumerator = System.Globalization.StringInfo.GetTextElementEnumerator(s); + while (enumerator.MoveNext()) + { + yield return (string)enumerator.Current; + } + } + /// /// Reverses the specified input string. /// + /// Correctly handles all UTF-16 strings /// The string to reverse. /// The reversed string. public static string Reverse(this string s) { - char[] charArray = s.ToCharArray(); - Array.Reverse(charArray); - return new string(charArray); + string[] graphemes = s.GraphemeClusters().ToArray(); + Array.Reverse(graphemes); + return string.Concat(graphemes); } - private static readonly Regex IncNameRegex1 = new Regex("^(\\d+)"); - private static readonly Regex IncNameRegex2 = new Regex("^\\)(\\d+)\\("); + private static readonly Regex IncNameRegex1 = new Regex("(\\d+)$"); + private static readonly Regex IncNameRegex2 = new Regex("\\((\\d+)\\)$"); /// /// Tries to parse number in the name brackets at the end of the value and then increment it to create a new name. @@ -264,14 +274,13 @@ namespace FlaxEngine int index; int MaxChecks = 10000; string result; - string reversed = name.Reverse(); // Find '' case - var match = IncNameRegex1.Match(reversed); + var match = IncNameRegex1.Match(name); if (match.Success && match.Groups.Count == 2) { // Get result - string num = match.Groups[0].Value.Reverse(); + string num = match.Groups[0].Value; // Parse value if (int.TryParse(num, out index)) @@ -294,12 +303,12 @@ namespace FlaxEngine } // Find ' ()' case - match = IncNameRegex2.Match(reversed); + match = IncNameRegex2.Match(name); if (match.Success && match.Groups.Count == 2) { // Get result string num = match.Groups[0].Value; - num = num.Substring(1, num.Length - 2).Reverse(); + num = num.Substring(1, num.Length - 2); // Parse value if (int.TryParse(num, out index)) diff --git a/Source/Engine/Visject/ShaderGraph.cpp b/Source/Engine/Visject/ShaderGraph.cpp index b3f221617..754c1aac9 100644 --- a/Source/Engine/Visject/ShaderGraph.cpp +++ b/Source/Engine/Visject/ShaderGraph.cpp @@ -1118,7 +1118,8 @@ ShaderGenerator::Value ShaderGenerator::writeLocal(ValueType type, const String& ShaderGenerator::Value ShaderGenerator::writeOperation2(Node* caller, const Value& valueA, const Value& valueB, Char op1) { - const String value = String::Format(TEXT("{0} {1} {2}"), valueA.Value, op1, Value::Cast(valueB, valueA.Type).Value); + const Char op1Str[2] = { op1, 0}; + const String value = String::Format(TEXT("{0} {1} {2}"), valueA.Value, op1Str, Value::Cast(valueB, valueA.Type).Value); return writeLocal(valueA.Type, value, caller); } diff --git a/Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so b/Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so deleted file mode 120000 index 35c4facf6..000000000 --- a/Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so +++ /dev/null @@ -1 +0,0 @@ -libmono-native.so.0.0.0 \ No newline at end of file diff --git a/Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so b/Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so new file mode 100644 index 000000000..b2f93e404 --- /dev/null +++ b/Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c398b22f122c52e8554af5560e9788648941f0f9598df5c430fdda676413db2 +size 181240 diff --git a/Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so b/Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so deleted file mode 120000 index 35c4facf6..000000000 --- a/Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so +++ /dev/null @@ -1 +0,0 @@ -libmono-native.so.0.0.0 \ No newline at end of file diff --git a/Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so b/Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so new file mode 100644 index 000000000..b2f93e404 --- /dev/null +++ b/Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c398b22f122c52e8554af5560e9788648941f0f9598df5c430fdda676413db2 +size 181240 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so deleted file mode 120000 index 9a02130ad..000000000 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so +++ /dev/null @@ -1 +0,0 @@ -libassimp.so.4.1.0 \ No newline at end of file diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so new file mode 100755 index 000000000..08aa3b9a2 --- /dev/null +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b35cfdc2b6aa4cbdf0a2aad81d5027736f9e92b1d708e3d358c31c03e679b2d1 +size 11877400 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so.4 b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so.4 deleted file mode 120000 index 9a02130ad..000000000 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so.4 +++ /dev/null @@ -1 +0,0 @@ -libassimp.so.4.1.0 \ No newline at end of file diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so.4.1.0 b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so.4.1.0 deleted file mode 100755 index 45891b71d..000000000 Binary files a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so.4.1.0 and /dev/null differ diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so deleted file mode 120000 index eeb2a3c1c..000000000 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so +++ /dev/null @@ -1 +0,0 @@ -libmonosgen-2.0.so.1.0.0 \ No newline at end of file diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so new file mode 100755 index 000000000..578a2c79f --- /dev/null +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26d47044044a8c49c30003b8a2b73e7f01ea17ea225e25c99548ba93b826eb84 +size 19098552 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so.1 b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so.1 deleted file mode 120000 index eeb2a3c1c..000000000 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so.1 +++ /dev/null @@ -1 +0,0 @@ -libmonosgen-2.0.so.1.0.0 \ No newline at end of file diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so.1.0.0 b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so.1.0.0 deleted file mode 100755 index f6233b55d..000000000 Binary files a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so.1.0.0 and /dev/null differ diff --git a/Source/ThirdParty/assimp/assimp.Build.cs b/Source/ThirdParty/assimp/assimp.Build.cs index 4f5b1ea41..110007b7f 100644 --- a/Source/ThirdParty/assimp/assimp.Build.cs +++ b/Source/ThirdParty/assimp/assimp.Build.cs @@ -36,8 +36,6 @@ public class assimp : DepsModule break; case TargetPlatform.Linux: options.DependencyFiles.Add(Path.Combine(depsRoot, "libassimp.so")); - options.DependencyFiles.Add(Path.Combine(depsRoot, "libassimp.so.4")); - options.DependencyFiles.Add(Path.Combine(depsRoot, "libassimp.so.4.1.0")); options.Libraries.Add(Path.Combine(depsRoot, "libassimp.so")); break; default: throw new InvalidPlatformException(options.Platform.Target); diff --git a/Source/ThirdParty/detex/LICENSE b/Source/ThirdParty/detex/LICENSE new file mode 100644 index 000000000..8998ccac5 --- /dev/null +++ b/Source/ThirdParty/detex/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2015 Harm Hanemaaijer + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/Source/ThirdParty/detex/decompress-bc.cpp b/Source/ThirdParty/detex/decompress-bc.cpp new file mode 100644 index 000000000..82f89b54d --- /dev/null +++ b/Source/ThirdParty/detex/decompress-bc.cpp @@ -0,0 +1,241 @@ +/* + +Copyright (c) 2015 Harm Hanemaaijer + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#include "detex.h" + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC1 */ +/* format. */ +bool detexDecompressBlockBC1(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, +uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) + uint32_t colors = *(uint32_t *)&bitstring[0]; +#else + uint32_t colors = ((uint32_t)bitstring[0] << 24) | + ((uint32_t)bitstring[1] << 16) | + ((uint32_t)bitstring[2] << 8) | bitstring[3]; +#endif + // Decode the two 5-6-5 RGB colors. + int color_r[4], color_g[4], color_b[4]; + color_b[0] = (colors & 0x0000001F) << 3; + color_g[0] = (colors & 0x000007E0) >> (5 - 2); + color_r[0] = (colors & 0x0000F800) >> (11 - 3); + color_b[1] = (colors & 0x001F0000) >> (16 - 3); + color_g[1] = (colors & 0x07E00000) >> (21 - 2); + color_r[1] = (colors & 0xF8000000) >> (27 - 3); + if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16)) { + color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); + color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); + color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); + color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); + color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); + color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); + } + else { + color_r[2] = (color_r[0] + color_r[1]) / 2; + color_g[2] = (color_g[0] + color_g[1]) / 2; + color_b[2] = (color_b[0] + color_b[1]) / 2; + color_r[3] = color_g[3] = color_b[3] = 0; + } + uint32_t pixels = *(uint32_t *)&bitstring[4]; + for (int i = 0; i < 16; i++) { + int pixel = (pixels >> (i * 2)) & 0x3; + *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGB8Alpha0xFF( + color_r[pixel], color_g[pixel], color_b[pixel]); + } + return true; +} + +uint32_t detexGetModeBC1(const uint8_t *bitstring) { + uint32_t colors = *(uint32_t *)bitstring; + if ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16)) + return 0; + else + return 1; +} + +void detexSetModeBC1(uint8_t *bitstring, uint32_t mode, uint32_t flags, +uint32_t *colors) { + uint32_t colorbits = *(uint32_t *)bitstring; + uint32_t current_mode; + if ((colorbits & 0xFFFF) > ((colorbits & 0xFFFF0000) >> 16)) + current_mode = 0; + else + current_mode = 1; + if (current_mode != mode) { + colorbits = ((colorbits & 0xFFFF) << 16) | (colorbits >> 16); + *(uint32_t *)bitstring = colorbits; + } +} + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC1A */ +/* format. */ +bool detexDecompressBlockBC1A(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, +uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) + uint32_t colors = *(uint32_t *)&bitstring[0]; +#else + uint32_t colors = ((uint32_t)bitstring[0] << 24) | + ((uint32_t)bitstring[1] << 16) | + ((uint32_t)bitstring[2] << 8) | bitstring[3]; +#endif + bool opaque = ((colors & 0xFFFF) > ((colors & 0xFFFF0000) >> 16)); + if (opaque && (flags & DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY)) + return false; + if (!opaque && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY)) + return false; + // Decode the two 5-6-5 RGB colors. + int color_r[4], color_g[4], color_b[4], color_a[4]; + color_b[0] = (colors & 0x0000001F) << 3; + color_g[0] = (colors & 0x000007E0) >> (5 - 2); + color_r[0] = (colors & 0x0000F800) >> (11 - 3); + color_b[1] = (colors & 0x001F0000) >> (16 - 3); + color_g[1] = (colors & 0x07E00000) >> (21 - 2); + color_r[1] = (colors & 0xF8000000) >> (27 - 3); + color_a[0] = color_a[1] = color_a[2] = color_a[3] = 0xFF; + if (opaque) { + color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); + color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); + color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); + color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); + color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); + color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); + } + else { + color_r[2] = (color_r[0] + color_r[1]) / 2; + color_g[2] = (color_g[0] + color_g[1]) / 2; + color_b[2] = (color_b[0] + color_b[1]) / 2; + color_r[3] = color_g[3] = color_b[3] = color_a[3] = 0; + } + uint32_t pixels = *(uint32_t *)&bitstring[4]; + for (int i = 0; i < 16; i++) { + int pixel = (pixels >> (i * 2)) & 0x3; + *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8( + color_r[pixel], color_g[pixel], color_b[pixel], + color_a[pixel]); + } + return true; +} + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC2 */ +/* format. */ +bool detexDecompressBlockBC2(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, +uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) + uint32_t colors = *(uint32_t *)&bitstring[8]; +#else + uint32_t colors = ((uint32_t)bitstring[8] << 24) | + ((uint32_t)bitstring[9] << 16) | + ((uint32_t)bitstring[10] << 8) | bitstring[11]; +#endif + if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) && + (flags & DETEX_DECOMPRESS_FLAG_ENCODE)) + // GeForce 6 and 7 series produce wrong result in this case. + return false; + int color_r[4], color_g[4], color_b[4]; + color_b[0] = (colors & 0x0000001F) << 3; + color_g[0] = (colors & 0x000007E0) >> (5 - 2); + color_r[0] = (colors & 0x0000F800) >> (11 - 3); + color_b[1] = (colors & 0x001F0000) >> (16 - 3); + color_g[1] = (colors & 0x07E00000) >> (21 - 2); + color_r[1] = (colors & 0xF8000000) >> (27 - 3); + color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); + color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); + color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); + color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); + color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); + color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); + uint32_t pixels = *(uint32_t *)&bitstring[12]; + uint64_t alpha_pixels = *(uint64_t *)&bitstring[0]; + for (int i = 0; i < 16; i++) { + int pixel = (pixels >> (i * 2)) & 0x3; + int alpha = ((alpha_pixels >> (i * 4)) & 0xF) * 255 / 15; + *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8( + color_r[pixel], color_g[pixel], color_b[pixel], alpha); + } + return true; +} + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC3 */ +/* format. */ +bool detexDecompressBlockBC3(const uint8_t * DETEX_RESTRICT bitstring, uint32_t mode_mask, +uint32_t flags, uint8_t * DETEX_RESTRICT pixel_buffer) { + int alpha0 = bitstring[0]; + int alpha1 = bitstring[1]; + if (alpha0 > alpha1 && (flags & DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY)) + return false; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) + uint32_t colors = *(uint32_t *)&bitstring[8]; +#else + uint32_t colors = ((uint32_t)bitstring[8] << 24) | + ((uint32_t)bitstring[9] << 16) | + ((uint32_t)bitstring[10] << 8) | bitstring[11]; +#endif + if ((colors & 0xFFFF) <= ((colors & 0xFFFF0000) >> 16) && + (flags & DETEX_DECOMPRESS_FLAG_ENCODE)) + // GeForce 6 and 7 series produce wrong result in this case. + return false; + int color_r[4], color_g[4], color_b[4]; + // color_x[] has a value between 0 and 248 with the lower three bits zero. + color_b[0] = (colors & 0x0000001F) << 3; + color_g[0] = (colors & 0x000007E0) >> (5 - 2); + color_r[0] = (colors & 0x0000F800) >> (11 - 3); + color_b[1] = (colors & 0x001F0000) >> (16 - 3); + color_g[1] = (colors & 0x07E00000) >> (21 - 2); + color_r[1] = (colors & 0xF8000000) >> (27 - 3); + color_r[2] = detexDivide0To767By3(2 * color_r[0] + color_r[1]); + color_g[2] = detexDivide0To767By3(2 * color_g[0] + color_g[1]); + color_b[2] = detexDivide0To767By3(2 * color_b[0] + color_b[1]); + color_r[3] = detexDivide0To767By3(color_r[0] + 2 * color_r[1]); + color_g[3] = detexDivide0To767By3(color_g[0] + 2 * color_g[1]); + color_b[3] = detexDivide0To767By3(color_b[0] + 2 * color_b[1]); + uint32_t pixels = *(uint32_t *)&bitstring[12]; + uint64_t alpha_bits = (uint32_t)bitstring[2] | + ((uint32_t)bitstring[3] << 8) | + ((uint64_t)*(uint32_t *)&bitstring[4] << 16); + for (int i = 0; i < 16; i++) { + int pixel = (pixels >> (i * 2)) & 0x3; + int code = (alpha_bits >> (i * 3)) & 0x7; + int alpha; + if (alpha0 > alpha1) + switch (code) { + case 0 : alpha = alpha0; break; + case 1 : alpha = alpha1; break; + case 2 : alpha = detexDivide0To1791By7(6 * alpha0 + 1 * alpha1); break; + case 3 : alpha = detexDivide0To1791By7(5 * alpha0 + 2 * alpha1); break; + case 4 : alpha = detexDivide0To1791By7(4 * alpha0 + 3 * alpha1); break; + case 5 : alpha = detexDivide0To1791By7(3 * alpha0 + 4 * alpha1); break; + case 6 : alpha = detexDivide0To1791By7(2 * alpha0 + 5 * alpha1); break; + case 7 : alpha = detexDivide0To1791By7(1 * alpha0 + 6 * alpha1); break; + } + else + switch (code) { + case 0 : alpha = alpha0; break; + case 1 : alpha = alpha1; break; + case 2 : alpha = detexDivide0To1279By5(4 * alpha0 + 1 * alpha1); break; + case 3 : alpha = detexDivide0To1279By5(3 * alpha0 + 2 * alpha1); break; + case 4 : alpha = detexDivide0To1279By5(2 * alpha0 + 3 * alpha1); break; + case 5 : alpha = detexDivide0To1279By5(1 * alpha0 + 4 * alpha1); break; + case 6 : alpha = 0; break; + case 7 : alpha = 0xFF; break; + } + *(uint32_t *)(pixel_buffer + i * 4) = detexPack32RGBA8( + color_r[pixel], color_g[pixel], color_b[pixel], alpha); + } + return true; +} + diff --git a/Source/ThirdParty/detex/detex.Build.cs b/Source/ThirdParty/detex/detex.Build.cs new file mode 100644 index 000000000..18e3414f8 --- /dev/null +++ b/Source/ThirdParty/detex/detex.Build.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +using Flax.Build; + +/// +/// https://github.com/hglm/detex +/// +public class detex : ThirdPartyModule +{ + /// + public override void Init() + { + base.Init(); + + LicenseType = LicenseTypes.MIT; + LicenseFilePath = "LICENSE"; + + // Merge third-party modules into engine binary + BinaryModuleName = "FlaxEngine"; + } +} diff --git a/Source/ThirdParty/detex/detex.h b/Source/ThirdParty/detex/detex.h new file mode 100644 index 000000000..adbeac512 --- /dev/null +++ b/Source/ThirdParty/detex/detex.h @@ -0,0 +1,1194 @@ +/* + +Copyright (c) 2015 Harm Hanemaaijer + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#ifndef __DETEX_H__ +#define __DETEX_H__ + +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS /* empty */ +#define __END_DECLS /* empty */ +#endif + +/* Generic helper definitions for shared library support. */ +#if defined _WIN32 || defined __CYGWIN__ + #define DETEX_HELPER_SHARED_IMPORT __declspec(dllimport) + #define DETEX_HELPER_SHARED_EXPORT __declspec(dllexport) + #define DETEX_HELPER_SHARED_LOCAL +#else + #if __GNUC__ >= 4 + #define DETEX_HELPER_SHARED_IMPORT __attribute__ ((visibility ("default"))) + #define DETEX_HELPER_SHARED_EXPORT __attribute__ ((visibility ("default"))) + #define DETEX_HELPER_SHARED_LOCAL __attribute__ ((visibility ("hidden"))) + #else + #define DETEX_HELPER_SHARED_IMPORT + #define DETEX_HELPER_SHARED_EXPORT + #define DETEX_HELPER_SHARED_LOCAL + #endif +#endif + +/* Now we use the generic helper definitions above to define DETEX_API and DETEX_LOCAL. */ +/* DETEX_API is used for the public API symbols. It either imports or exports the symbol */ +/* for shared/DLL libraries (or does nothing for static build). DETEX_LOCAL is used for */ +/* non-API symbols. */ + +#ifdef DETEX_SHARED + /* Defined if DETEX is compiled as a shared library. */ + #ifdef DETEX_SHARED_EXPORTS + /* Defined if we are building the detex shared library (instead of using it). */ + #define DETEX_API DETEX_HELPER_SHARED_EXPORT + #else + #define DETEX_API DETEX_HELPER_SHARED_IMPORT + #endif /* DETEX_SHARED_EXPORTS */ + #define DETEX_LOCAL DETEX_HELPER_SHARED_LOCAL +#else + /* DETEX_SHARED is not defined: this means detex is a static lib. */ + #define DETEX_API + #define DETEX_LOCAL +#endif /* DETEX_SHARED */ + +__BEGIN_DECLS + +#include +#include +#include + +#define DETEX_INLINE_ONLY __attribute__((always_inline)) inline +#define DETEX_RESTRICT __restrict + +/* Maximum uncompressed block size in bytes. */ +#define DETEX_MAX_BLOCK_SIZE 256 + +/* Detex library pixel formats. */ + +enum { + /* The format has 16-bit components. */ + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT = 0x1, + /* The format has 32-bit components. */ + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT = 0x2, + /* The format has an alpha component. */ + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT = 0x4, + /* The sequential component order is RGB. */ + DETEX_PIXEL_FORMAT_RGB_COMPONENT_ORDER_BIT = 0x0, + /* The sequential component order is BGR. */ + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT = 0x8, + /* The format has one component. */ + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS = 0x0, + /* The format has two components. */ + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS = 0x10, + /* The format has three components. */ + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS = 0x20, + /* The format has four components. */ + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS = 0x30, + /* The format is stored as 8-bit pixels. */ + DETEX_PIXEL_FORMAT_8BIT_PIXEL_BITS = 0x000, + /* The format is stored as 16-bit pixels. */ + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS = 0x100, + /* The format is stored as 24-bit pixels. */ + DETEX_PIXEL_FORMAT_24BIT_PIXEL_BITS = 0x200, + /* The format is stored as 32-bit pixels. */ + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS = 0x300, + /* The format is stored as 48-bit pixels. */ + DETEX_PIXEL_FORMAT_48BIT_PIXEL_BITS = 0x500, + /* The format is stored as 64-bit pixels. */ + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS = 0x700, + /* The format is stored as 96-bit pixels. */ + DETEX_PIXEL_FORMAT_96BIT_PIXEL_BITS = 0xB00, + /* The format is stored as 128-bit pixels. */ + DETEX_PIXEL_FORMAT_128BIT_PIXEL_BITS = 0xF00, + /* The format has signed integer components. */ + DETEX_PIXEL_FORMAT_SIGNED_BIT = 0x1000, + /* The format has (half-)float components. */ + DETEX_PIXEL_FORMAT_FLOAT_BIT = 0x2000, + /* The fomat is HDR (high dynamic range). */ + DETEX_PIXEL_FORMAT_HDR_BIT = 0x4000, + + DETEX_PIXEL_FORMAT_RGBA8 = ( + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_BGRA8 = ( + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_RGBX8 = ( + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_BGRX8 = ( + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_RGB8 = ( + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_24BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_BGR8 = ( + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_24BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_R8 = ( + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_8BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_SIGNED_R8 = ( + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_8BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_SIGNED_BIT + ), + DETEX_PIXEL_FORMAT_RG8 = ( + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_SIGNED_RG8 = ( + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_SIGNED_BIT + ), + DETEX_PIXEL_FORMAT_R16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_SIGNED_R16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_SIGNED_BIT + ), + DETEX_PIXEL_FORMAT_RG16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_SIGNED_RG16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_SIGNED_BIT + ), + DETEX_PIXEL_FORMAT_RGB16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_48BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_RGBX16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_RGBA16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS + ), + DETEX_PIXEL_FORMAT_FLOAT_R16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_R16_HDR = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_16BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RG16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RG16_HDR = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBX16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBX16_HDR = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBA16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBA16_HDR = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGB16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_48BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGB16_HDR = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_48BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_BGRX16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_BGRX16_HDR = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_SIGNED_BIT | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_SIGNED_FLOAT_BGRX16 = ( + DETEX_PIXEL_FORMAT_16BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_BGR_COMPONENT_ORDER_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_SIGNED_BIT | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_R32 = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_R32_HDR = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_32BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RG32 = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RG32_HDR = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_TWO_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_64BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGB32 = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_96BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGB32_HDR = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_96BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBX32 = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_128BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBX32_HDR = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_THREE_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_128BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBA32 = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_128BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT + ), + DETEX_PIXEL_FORMAT_FLOAT_RGBA32_HDR = ( + DETEX_PIXEL_FORMAT_32BIT_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_FOUR_COMPONENTS_BITS | + DETEX_PIXEL_FORMAT_128BIT_PIXEL_BITS | + DETEX_PIXEL_FORMAT_FLOAT_BIT | + DETEX_PIXEL_FORMAT_HDR_BIT + ), + DETEX_PIXEL_FORMAT_A8 = ( + DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT | + DETEX_PIXEL_FORMAT_ONE_COMPONENT_BITS | + DETEX_PIXEL_FORMAT_8BIT_PIXEL_BITS + ), +}; + +/* Mode mask flags. */ + +enum { + DETEX_MODE_MASK_ETC_INDIVIDUAL = 0x1, + DETEX_MODE_MASK_ETC_DIFFERENTIAL = 0x2, + DETEX_MODE_MASK_ETC_T = 0x4, + DETEX_MODE_MASK_ETC_H = 0x8, + DETEX_MODE_MASK_ETC_PLANAR = 0x10, + DETEX_MODE_MASK_ALL_MODES_ETC1 = 0x3, + DETEX_MODE_MASK_ALL_MODES_ETC2 = 0x1F, + DETEX_MODE_MASK_ALL_MODES_ETC2_PUNCHTHROUGH = 0X1E, + DETEX_MODE_MASK_ALL_MODES_BPTC = 0xFF, + DETEX_MODE_MASK_ALL_MODES_BPTC_FLOAT = 0x3FFF, + DETEX_MODE_MASK_ALL = 0XFFFFFFFF, +}; + +/* Decompression function flags. */ + +enum { + /* Function returns false (invalid block) when the compressed block */ + /* is in a format not allowed to be generated by an encoder. */ + DETEX_DECOMPRESS_FLAG_ENCODE = 0x1, + /* For compression formats that have opaque and non-opaque modes, */ + /* return false (invalid block) when the compressed block is encoded */ + /* using a non-opaque mode. */ + DETEX_DECOMPRESS_FLAG_OPAQUE_ONLY = 0x2, + /* For compression formats that have opaque and non-opaque modes, */ + /* return false (invalid block) when the compressed block is encoded */ + /* using an opaque mode. */ + DETEX_DECOMPRESS_FLAG_NON_OPAQUE_ONLY = 0x4, +}; + +/* Set mode function flags. */ + +enum { + /* The block is opaque (alpha is always 0xFF). */ + DETEX_SET_MODE_FLAG_OPAQUE = 0x2, + /* The block is non-opaque (alpha is not always 0xFF). */ + DETEX_SET_MODE_FLAG_NON_OPAQUE = 0x4, + /* The block has punchthrough alpha (alpha is either 0x00 or 0xFF). */ + DETEX_SET_MODE_FLAG_PUNCHTHROUGH = 0x8, + /* The block only consists of one or two different pixel colors. */ + DETEX_SET_MODE_FLAG_MAX_TWO_COLORS = 0x10, +}; + +/* + * Decompression functions for 8-bit RGB8/RGBA8 formats. The output pixel format + * is DETEX_PIXEL_FORMAT_RGBA8 or DETEX_PIXEL_FORMAT_RGBX8 (32-bit pixels with + * optional alpha component, red component in lowest-order byte. When the + * texture format does not have alpha, alpha is set to 0xFF. + */ + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the ETC1 */ +/* format. */ +DETEX_API bool detexDecompressBlockETC1(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the ETC2 */ +/* format. */ +DETEX_API bool detexDecompressBlockETC2(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the */ +/* ETC2_PUNCHTROUGH format. */ +DETEX_API bool detexDecompressBlockETC2_PUNCHTHROUGH(const uint8_t *bitstring, + uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the ETC2_EAC */ +/* format. */ +DETEX_API bool detexDecompressBlockETC2_EAC(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); + + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC1 */ +/* format. */ +DETEX_API bool detexDecompressBlockBC1(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC1A */ +/* format. */ +DETEX_API bool detexDecompressBlockBC1A(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC2 */ +/* format. */ +DETEX_API bool detexDecompressBlockBC2(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the BC3 */ +/* format. */ +DETEX_API bool detexDecompressBlockBC3(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the BPTC */ +/* (BC7) format. */ +DETEX_API bool detexDecompressBlockBPTC(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); + +/* + * Decompression functions for 8-bit unsigned R and RG formats. The + * output format is DETEX_PIXEL_FORMAT_R8 or DETEX_PIXEL_FORMAT_RG8. + */ + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the */ +/* unsigned RGTC1 (BC4) format. */ +DETEX_API bool detexDecompressBlockRGTC1(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the */ +/* unsigned RGTC2 (BC5) format. */ +DETEX_API bool detexDecompressBlockRGTC2(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); + +/* + * Decompression functions for 16-bit unsigned/signed R and RG formats. The + * output format is DETEX_PIXEL_FORMAT_R16, DETEX_PIXEL_FORMAT_SIGNED_R16, + * DETEX_PIXEL_FORMAT_RG16, or DETEX_PIXEL_FORMAT_SIGNED_RG16. + */ + +/* Decompress a 64-bit 4x4 pixel texture block compressed using the */ +/* signed RGTC1 (signed BC4) format. */ +DETEX_API bool detexDecompressBlockSIGNED_RGTC1(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the */ +/* signed RGTC2 (signed BC5) format. */ +DETEX_API bool detexDecompressBlockSIGNED_RGTC2(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the */ +/* ETC2_R11_EAC format. */ +DETEX_API bool detexDecompressBlockEAC_R11(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 64-bit 4x4 pixel texture block compressed using the */ +/* ETC2_SIGNED_R11_EAC format. */ +DETEX_API bool detexDecompressBlockEAC_SIGNED_R11(const uint8_t *bitstring, + uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the */ +/* ETC2_RG11_EAC format. */ +DETEX_API bool detexDecompressBlockEAC_RG11(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the */ +/* ETC2_SIGNED_RG11_EAC format. */ +DETEX_API bool detexDecompressBlockEAC_SIGNED_RG11(const uint8_t *bitstring, + uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer); + +/* + * Decompression functions for 16-bit half-float formats. The output format is + * DETEX_PIXEL_FORMAT_FLOAT_RGBX16 or DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16. + */ + +/* Decompress a 128-bit 4x4 pixel texture block compressed using the */ +/* BPTC_FLOAT (BC6H) format. The output format is */ +/* DETEX_PIXEL_FORMAT_FLOAT_RGBX16. */ +DETEX_API bool detexDecompressBlockBPTC_FLOAT(const uint8_t *bitstring, uint32_t mode_mask, + uint32_t flags, uint8_t *pixel_buffer); +/* Decompress a 128-bit 4x4 pixel texture block compressed using the */ +/* BPTC_FLOAT (BC6H_FLOAT) format. The output format is */ +/* DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16. */ +DETEX_API bool detexDecompressBlockBPTC_SIGNED_FLOAT(const uint8_t *bitstring, + uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer); + + +/* + * Get mode functions. They return the internal compression format mode used + * inside the compressed block. For compressed formats that do not use a mode, + * there is no GetMode function. + */ + +DETEX_API uint32_t detexGetModeBC1(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeETC1(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeETC2(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeETC2_PUNCHTHROUGH(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeETC2_EAC(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeBPTC(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeBPTC_FLOAT(const uint8_t *bitstring); +DETEX_API uint32_t detexGetModeBPTC_SIGNED_FLOAT(const uint8_t *bitstring); + +/* + * Set mode functions. The set mode function modifies a compressed texture block + * so that the specified mode is set, making use of information about the block + * (whether it is opaque, non-opaque or punchthrough for formats with alpha, + * whether at most two different colors are used). For compressed formats + * that do not use a mode, there is no SetMode function. + */ + +DETEX_API void detexSetModeBC1(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); +DETEX_API void detexSetModeETC1(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); +DETEX_API void detexSetModeETC2(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); +DETEX_API void detexSetModeETC2_PUNCHTHROUGH(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); +DETEX_API void detexSetModeETC2_EAC(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); +DETEX_API void detexSetModeBPTC(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); +DETEX_API void detexSetModeBPTC_FLOAT(uint8_t *bitstring, uint32_t mode, uint32_t flags, + uint32_t *colors); + +/* Compressed texture format definitions for general texture decompression */ +/* functions. */ + +#define DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS(n) ((uint32_t)n << 24) + +enum { + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_UNCOMPRESSED = 0, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1 = 1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT1 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_S3TC = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT1A = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT3 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_DXT5 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC4_UNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC4_SNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC5_UNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC5_SNORM = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC6H_UF16 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC6H_SF16 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC7 = DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC1, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_PUNCHTHROUGH, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_EAC, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_R11, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_R11, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_RG11, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_RG11, + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ASTC_4X4, +}; + +enum { + DETEX_TEXTURE_FORMAT_PIXEL_FORMAT_MASK = 0x0000FFFF, + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT = 0x00800000, + DETEX_TEXTURE_FORMAT_BC1 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1) | + DETEX_PIXEL_FORMAT_RGBX8 + ), + DETEX_TEXTURE_FORMAT_BC1A = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC1A) | + DETEX_PIXEL_FORMAT_RGBA8 + ), + DETEX_TEXTURE_FORMAT_BC2 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC2) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RGBA8 + ), + DETEX_TEXTURE_FORMAT_BC3 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BC3) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RGBA8 + ), + DETEX_TEXTURE_FORMAT_RGTC1 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC1) | + DETEX_PIXEL_FORMAT_R8 + ), + DETEX_TEXTURE_FORMAT_SIGNED_RGTC1 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC1) | + DETEX_PIXEL_FORMAT_SIGNED_R16 + ), + DETEX_TEXTURE_FORMAT_RGTC2 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_RGTC2) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RG8 + ), + DETEX_TEXTURE_FORMAT_SIGNED_RGTC2 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_SIGNED_RGTC2) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_SIGNED_RG16 + ), + DETEX_TEXTURE_FORMAT_BPTC_FLOAT = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_FLOAT) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_FLOAT_RGBX16 + ), + DETEX_TEXTURE_FORMAT_BPTC_SIGNED_FLOAT = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC_SIGNED_FLOAT) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16 + ), + DETEX_TEXTURE_FORMAT_BPTC = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_BPTC) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RGBA8 + ), + DETEX_TEXTURE_FORMAT_ETC1 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC1) | + DETEX_PIXEL_FORMAT_RGBX8 + ), + DETEX_TEXTURE_FORMAT_ETC2 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2) | + DETEX_PIXEL_FORMAT_RGBX8 + ), + DETEX_TEXTURE_FORMAT_ETC2_PUNCHTHROUGH = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_PUNCHTHROUGH) | + DETEX_PIXEL_FORMAT_RGBA8 + ), + DETEX_TEXTURE_FORMAT_ETC2_EAC = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ETC2_EAC) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RGBA8 + ), + DETEX_TEXTURE_FORMAT_EAC_R11 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_R11) | + DETEX_PIXEL_FORMAT_R16 + ), + DETEX_TEXTURE_FORMAT_EAC_SIGNED_R11 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_R11) | + DETEX_PIXEL_FORMAT_SIGNED_R16 + ), + DETEX_TEXTURE_FORMAT_EAC_RG11 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_RG11) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RG16 + ), + DETEX_TEXTURE_FORMAT_EAC_SIGNED_RG11 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_EAC_SIGNED_RG11) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_SIGNED_RG16 + ), + DETEX_TEXTURE_FORMAT_ASTC_4X4 = ( + DETEX_TEXTURE_FORMAT_COMPRESSED_FORMAT_BITS( + DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_ASTC_4X4 ) | + DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT | + DETEX_PIXEL_FORMAT_RGBA8 + ), +}; + +typedef struct { + uint32_t format; + uint8_t *data; + int width; + int height; + int width_in_blocks; + int height_in_blocks; +} detexTexture; + +/* + * General texture decompression functions (tiled or linear) with specified + * compression format. + */ + +/* + * General block decompression function. Block is decompressed using the given + * compressed format, and stored in the given pixel format. + */ +DETEX_API bool detexDecompressBlock(const uint8_t *bitstring, uint32_t texture_format, + uint32_t mode_mask, uint32_t flags, uint8_t *pixel_buffer, + uint32_t pixel_format); + +/* + * Decode texture function (tiled). Decode an entire compressed texture into an + * array of image buffer tiles (corresponding to compressed blocks), converting + * into the given pixel format. + */ +DETEX_API bool detexDecompressTextureTiled(const detexTexture *texture, uint8_t *pixel_buffer, + uint32_t pixel_format); + +/* + * Decode texture function (linear). Decode an entire texture into a single + * image buffer, with pixels stored row-by-row, converting into the given pixel + * format. + */ +DETEX_API bool detexDecompressTextureLinear(const detexTexture *texture, uint8_t *pixel_buffer, + uint32_t pixel_format); + + +/* + * Miscellaneous functions. + */ + +/* + * Convert pixels between different formats. The target pixel buffer must + * be allocated with sufficient size to the hold the result. Returns true if + * succesful. + */ +DETEX_API bool detexConvertPixels(uint8_t *source_pixel_buffer, uint32_t nu_pixels, + uint32_t source_pixel_format, uint8_t *target_pixel_buffer, + uint32_t target_pixel_format); + +/* Convert in-place, modifying the source pixel buffer only. If any conversion step changes the */ +/* pixel size, the function will not be succesful and return false. */ +DETEX_API bool detexConvertPixelsInPlace(uint8_t * DETEX_RESTRICT source_pixel_buffer, + uint32_t nu_pixels, uint32_t source_pixel_format, uint32_t target_pixel_format); + +/* Return the component bitfield masks for a pixel format (pixel size must be at most 64 bits). */ +/* Return true if succesful. */ +DETEX_API bool detexGetComponentMasks(uint32_t texture_format, uint64_t *red_mask, uint64_t *green_mask, + uint64_t *blue_mask, uint64_t *alpha_mask); + +/* Return a text description/identifier of the texture type. */ +DETEX_API const char *detexGetTextureFormatText(uint32_t texture_format); + +/* Return a alternative text description of the texture type. Returns empty string */ +/* when there is no alternative description. */ +DETEX_API const char *detexGetAlternativeTextureFormatText(uint32_t texture_format); + +/* Return OpenGL TexImage2D/KTX file parameters for a texture format. */ +DETEX_API bool detexGetOpenGLParameters(uint32_t texture_format, int *gl_internal_format, + uint32_t *gl_format, uint32_t *gl_type); + +/* Return DirectX 10 format for a texture format. */ +DETEX_API bool detexGetDX10Parameters(uint32_t texture_format, uint32_t *dx10_format); + +/* Return the error message for the last encountered error. */ +DETEX_API const char *detexGetErrorMessage(); + + +/* + * HDR-related functions. + */ + +/* Set HDR gamma curve parameters. */ +DETEX_API void detexSetHDRParameters(float gamma, float range_min, float range_max); + +/* Calculate the dynamic range of a pixel buffer. Valid for float and half-float formats. */ +/* Returns true if successful. */ +DETEX_API bool detexCalculateDynamicRange(uint8_t *pixel_buffer, int nu_pixels, uint32_t pixel_format, + float *range_min_out, float *range_max_out); + + +/* + * Texture file loading. + */ + +/* Load texture from KTX file with mip-maps. Returns true if successful. */ +/* nu_levels is a return parameter that returns the number of mipmap levels found. */ +/* textures_out is a return parameter for an array of detexTexture pointers that is allocated, */ +/* free with free(). textures_out[i] are allocated textures corresponding to each level, free */ +/* with free(). */ +DETEX_API bool detexLoadKTXFileWithMipmaps(const char *filename, int max_mipmaps, detexTexture ***textures_out, + int *nu_levels_out); + +/* Load texture from KTX file (first mip-map only). Returns true if successful. */ +/* The texture is allocated, free with free(). */ +DETEX_API bool detexLoadKTXFile(const char *filename, detexTexture **texture_out); + +/* Save textures to KTX file (multiple mip-maps levels). Return true if succesful. */ +DETEX_API bool detexSaveKTXFileWithMipmaps(detexTexture **textures, int nu_levels, const char *filename); + +/* Save texture to KTX file (single mip-map level). Returns true if succesful. */ +DETEX_API bool detexSaveKTXFile(detexTexture *texture, const char *filename); + +/* Load texture from DDS file with mip-maps. Returns true if successful. */ +/* nu_levels is a return parameter that returns the number of mipmap levels found. */ +/* textures_out is a return parameter for an array of detexTexture pointers that is allocated, */ +/* free with free(). textures_out[i] are allocated textures corresponding to each level, free */ +/* with free(). */ +DETEX_API bool detexLoadDDSFileWithMipmaps(const char *filename, int max_mipmaps, detexTexture ***textures_out, + int *nu_levels_out); + +/* Load texture from DDS file (first mip-map only). Returns true if successful. */ +/* The texture is allocated, free with free(). */ +DETEX_API bool detexLoadDDSFile(const char *filename, detexTexture **texture_out); + +/* Save textures to DDS file (multiple mip-maps levels). Return true if succesful. */ +DETEX_API bool detexSaveDDSFileWithMipmaps(detexTexture **textures, int nu_levels, const char *filename); + +/* Save texture to DDS file (single mip-map level). Returns true if succesful. */ +DETEX_API bool detexSaveDDSFile(detexTexture *texture, const char *filename); + +/* Load texture file (type autodetected from extension) with mipmaps. */ +DETEX_API bool detexLoadTextureFileWithMipmaps(const char *filename, int max_mipmaps, detexTexture ***textures_out, + int *nu_levels_out); + +/* Load texture file (type autodetected from extension). */ +DETEX_API bool detexLoadTextureFile(const char *filename, detexTexture **texture_out); + +/* Load texture from raw file (first mip-map only) given the format and dimensions */ +/* in texture. Returns true if successful. */ +/* The texture->data is allocated, free with free(). */ +DETEX_API bool detexLoadRawFile(const char *filename, detexTexture *texture); + +/* Save texture to raw file (first mip-map only) given the format and dimensions */ +/* in texture. Returns true if successful. */ +DETEX_API bool detexSaveRawFile(detexTexture *texture, const char *filename); + +/* Return pixel size in bytes for pixel format or texture format (decompressed). */ +static DETEX_INLINE_ONLY int detexGetPixelSize(uint32_t pixel_format) { + return 1 + ((pixel_format & 0xF00) >> 8); +} + +/* Return the number of components of a pixel format or texture format. */ +static DETEX_INLINE_ONLY int detexGetNumberOfComponents(uint32_t pixel_format) { + return 1 + ((pixel_format & 0x30) >> 4); +} + +/* Return the component size in bytes of a pixel format or texture format. */ +static DETEX_INLINE_ONLY int detexGetComponentSize(uint32_t pixel_format) { + return 1 << (pixel_format & 0x3); +} + +/* Return the approximate precision in bits of the components of a pixel format. */ +static DETEX_INLINE_ONLY uint32_t detexGetComponentPrecision(uint32_t pixel_format) { + return detexGetComponentSize(pixel_format) * 8 - + ((pixel_format & DETEX_PIXEL_FORMAT_FLOAT_BIT) != 0) * 5 * + (1 + (detexGetComponentSize(pixel_format) == 4)); +} + +/* Return the total size of a compressed texture. */ +static DETEX_INLINE_ONLY uint32_t detexTextureSize(uint32_t width_in_blocks, +uint32_t height_in_blocks, uint32_t pixel_format) { + return width_in_blocks * height_in_blocks * detexGetPixelSize(pixel_format) * 16; +} + +/* Return whether a pixel or texture format has an alpha component. */ +static DETEX_INLINE_ONLY uint32_t detexFormatHasAlpha(uint32_t pixel_format) { + return (pixel_format & DETEX_PIXEL_FORMAT_ALPHA_COMPONENT_BIT) != 0; +} + + +/* Return the compressed texture type index of a texture format. */ +static DETEX_INLINE_ONLY uint32_t detexGetCompressedFormat(uint32_t texture_format) { + return texture_format >> 24; +} + +/* Return the block size of a compressed texture format in bytes. */ +static DETEX_INLINE_ONLY uint32_t detexGetCompressedBlockSize(uint32_t texture_format) { + return 8 + ((texture_format & DETEX_TEXTURE_FORMAT_128BIT_BLOCK_BIT) >> 20); +} + +/* Return whether a texture format is compressed. */ +static DETEX_INLINE_ONLY uint32_t detexFormatIsCompressed(uint32_t texture_format) { + return detexGetCompressedFormat(texture_format) != DETEX_COMPRESSED_TEXTURE_FORMAT_INDEX_UNCOMPRESSED; +} + +/* Return the pixel format of a texture format. */ +static DETEX_INLINE_ONLY uint32_t detexGetPixelFormat(uint32_t texture_format) { + return texture_format & DETEX_TEXTURE_FORMAT_PIXEL_FORMAT_MASK; +} + + +DETEX_API extern const uint8_t detex_clamp0to255_table[767]; + +/* Clamp an integer value in the range -255 to 511 to the the range 0 to 255. */ +static DETEX_INLINE_ONLY uint8_t detexClamp0To255(int x) { + return detex_clamp0to255_table[x + 255]; +} + +/* Clamp a float point value to the range 0.0 to 1.0f. */ +static DETEX_INLINE_ONLY float detexClamp0To1(float f) { + if (f < 0.0f) + return 0.0f; + else if (f > 1.0f) + return 1.0f; + else + return f; +} + + +/* Integer division using look-up tables, used by BC1/2/3 and RGTC (BC4/5) */ +/* decompression. */ + +DETEX_API extern const uint8_t detex_division_by_3_table[768]; + +static DETEX_INLINE_ONLY uint32_t detexDivide0To767By3(uint32_t value) { + return detex_division_by_3_table[value]; +} + +DETEX_API extern const uint8_t detex_division_by_7_table[1792]; + +static DETEX_INLINE_ONLY uint32_t detexDivide0To1791By7(uint32_t value) { + return detex_division_by_7_table[value]; +} + +static DETEX_INLINE_ONLY int8_t detexSignInt32(int v) { + return (int8_t)((v >> 31) | - (- v >> 31)); +} + +static DETEX_INLINE_ONLY int detexDivideMinus895To895By7(int value) { + return (int8_t)detex_division_by_7_table[abs(value)] * detexSignInt32(value); +} + +DETEX_API extern const uint8_t detex_division_by_5_table[1280]; + +static DETEX_INLINE_ONLY uint32_t detexDivide0To1279By5(uint32_t value) { + return detex_division_by_5_table[value]; +} + +static DETEX_INLINE_ONLY int detexDivideMinus639To639By5(int value) { + return (int8_t)detex_division_by_5_table[abs(value)] * detexSignInt32(value); +} + + +/* + * Define some short functions for pixel packing/unpacking. The compiler will + * take care of optimization by inlining and removing unused functions. + * + * The pixel format used corresponds to formats with an RGB component order, + * including: + * + * DETEX_PIXEL_FORMAT_RGB8, DETEX_PIXEL_FORMAT_RGBA8 + * detexPack32RGB8Alpha0xFF, detexPack32R8, detexPack32G8, detexPack32B8, + * detexPixel32GetR8, detexPixel32GetG8, detexPixel32GetB8 + * DETEX_PIXEL_FORMAT_RGBA8 + * detexPack32RGBA8, detexPack32A8, detexPixel32GetA8 + * DETEX_PIXEL_FORMAT_RG16, DETEX_PIXEL_FORMAT_SIGNED_RG16, + * DETEX_PIXEL_FORMAT_FLOAT_RG16 + * detexPack32RG16, detexPack32R16, detexPack32G16, detexPack32RG16, + * detexPixel32GetR16, detexPixel32GetG16 + * DETEX_PIXEL_FORMAT_FLOAT_RGBX16, DETEX_PIXEL_FORMAT_SIGNED_FLOAT_RGBX16 + * detexPack64RGB16, detexPack64R16, detexPack64G16, detexPack64B16, + * detexPixel64GetR16, detexPixel64GetG16, detexPixel64GetB16 + */ + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || !defined(__BYTE_ORDER__) + +static DETEX_INLINE_ONLY uint32_t detexPack32RGBA8(int r, int g, int b, int a) { + return (uint32_t)r | ((uint32_t)g << 8) | ((uint32_t)b << 16) | + ((uint32_t)a << 24); +} + +static DETEX_INLINE_ONLY uint32_t detexPack32RGB8Alpha0xFF(int r, int g, int b) { + return detexPack32RGBA8(r, g, b, 0xFF); +} + +static DETEX_INLINE_ONLY uint32_t detexPack32R8(int r) { + return (uint32_t)r; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32G8(int g) { + return (uint32_t)g << 8; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32B8(int b) { + return (uint32_t)b << 16; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32A8(int a) { + return (uint32_t)a << 24; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32RG8(uint32_t r8, uint32_t g8) { + return r8 | (g8 << 8); +} + +static DETEX_INLINE_ONLY uint32_t detexPack32R16(uint32_t r16) { + return r16; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32G16(uint32_t g16) { + return g16 << 16; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32RG16(uint32_t r16, uint32_t g16) { + return r16 | (g16 << 16); +} + +static DETEX_INLINE_ONLY uint64_t detexPack64R16(uint32_t r16) { + return r16; +} + +static DETEX_INLINE_ONLY uint64_t detexPack64G16(uint32_t g16) { + return g16 << 16; +} + +static DETEX_INLINE_ONLY uint64_t detexPack64B16(uint32_t b16) { + return (uint64_t)b16 << 32; +} + +static DETEX_INLINE_ONLY uint64_t detexPack64A16(uint32_t a16) { + return (uint64_t)a16 << 48; +} + +static DETEX_INLINE_ONLY uint64_t detexPack64RGB16(uint16_t r16, uint16_t g16, uint16_t b16) { + return (uint64_t)r16 | ((uint64_t)g16 << 16) | ((uint64_t)b16 << 32); +} + +static DETEX_INLINE_ONLY uint64_t detexPack64RGBA16(uint16_t r16, uint16_t g16, uint16_t b16, uint16_t a16) { + return (uint64_t)r16 | ((uint64_t)g16 << 16) | ((uint64_t)b16 << 32) | ((uint64_t)a16 << 48); +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetR8(uint32_t pixel) { + return pixel & 0xFF; +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetG8(uint32_t pixel) { + return (pixel & 0xFF00) >> 8; +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetB8(uint32_t pixel) { + return (pixel & 0xFF0000) >> 16; +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetA8(uint32_t pixel) { + return (pixel & 0xFF000000) >> 24; +} + +static DETEX_INLINE_ONLY int detexPixel32GetSignedR8(uint32_t pixel) { + return (int8_t)(pixel & 0xFF); +} + +static DETEX_INLINE_ONLY int detexPixel32GetSignedG8(uint32_t pixel) { + return (int8_t)((pixel & 0xFF00) >> 8); +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetR16(uint32_t pixel) { + return pixel & 0x0000FFFF; +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetG16(uint32_t pixel) { + return (pixel & 0xFFFF0000) >> 16; +} + +static DETEX_INLINE_ONLY int detexPixel32GetSignedR16(uint32_t pixel) { + return (int16_t)(pixel & 0x0000FFFF); +} + +static DETEX_INLINE_ONLY int detexPixel32GetSignedG16(uint32_t pixel) { + return (int16_t)((pixel & 0xFFFF0000) >> 16); +} + +static DETEX_INLINE_ONLY uint64_t detexPixel64GetR16(uint64_t pixel) { + return pixel & 0xFFFF; +} + +static DETEX_INLINE_ONLY uint64_t detexPixel64GetG16(uint64_t pixel) { + return (pixel & 0xFFFF0000) >> 16; +} + +static DETEX_INLINE_ONLY uint64_t detexPixel64GetB16(uint64_t pixel) { + return (pixel & 0xFFFF00000000) >> 32; +} + +static DETEX_INLINE_ONLY uint64_t detexPixel64GetA16(uint64_t pixel) { + return (pixel & 0xFFFF000000000000) >> 48; +} + +#define DETEX_PIXEL32_ALPHA_BYTE_OFFSET 3 + +#else + +#error Big-endian byte order not supported. + +static DETEX_INLINE_ONLY uint32_t detexPack32RGBA8(int r, int g, int b, int a) { + return a | ((uint32_t)b << 8) | ((uint32_t)g << 16) | ((uint32_t)r << 24); +} + +static DETEX_INLINE_ONLY uint32_t detexPack32RGB8Alpha0xFF(int r, int g, int b) { + return pack_rgba(r, g, b, 0xFF); +} + +static DETEX_INLINE_ONLY uint32_t detexPack32R8(int r) { + return (uint32_t)r << 24; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32G8(int g) { + return (uint32_t)g << 16; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32B8(int b) { + return (uint32_t)b << 8; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32A8(int a) { + return a; +} + +static DETEX_INLINE_ONLY uint32_t detexPack32RG16(uint32_t r16, uint32_t g16) { + return g16 | (r16 << 16); +} + +static DETEX_INLINE_ONLY int detexPixel32GetR8(uint32_t pixel) { + return (pixel & 0xFF000000) >> 24; +} + +static DETEX_INLINE_ONLY int detexPixel32GetG8(uint32_t pixel) { + return (pixel & 0xFF0000) >> 16; +} + +static DETEX_INLINE_ONLY int detexPixel32GetB8(uint32_t pixel) { + return (pixel & 0xFF00) >> 8; +} + +static DETEX_INLINE_ONLY int detexPixel32GetA8(uint32_t pixel) { + return pixel & 0xFF; +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetR16(uint32_t pixel) { + return ((pixel & 0xFF000000) >> 24) | ((pixel & 0x00FF0000) >> 8); +} + +static DETEX_INLINE_ONLY uint32_t detexPixel32GetG16(uint32_t pixel) { + return ((pixel & 0x0000FF00) >> 8) | ((pixel & 0x000000FF) << 8); +} + +#define DETEX_PIXEL32_ALPHA_BYTE_OFFSET 0 + +#endif + +__END_DECLS + +#endif + diff --git a/Source/ThirdParty/detex/division-tables.cpp b/Source/ThirdParty/detex/division-tables.cpp new file mode 100644 index 000000000..cb07c0c42 --- /dev/null +++ b/Source/ThirdParty/detex/division-tables.cpp @@ -0,0 +1,512 @@ +/* + +Copyright (c) 2015 Harm Hanemaaijer + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#include "detex.h" + +// Integer division using look-up tables, used by BC1/2/3 and RGTC (BC4/5) +// decompression. + +const uint8_t detex_division_by_3_table[768] = { + 0, 0, 0, 1, 1, 1, 2, 2, + 2, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 9, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, + 13, 13, 14, 14, 14, 15, 15, 15, + 16, 16, 16, 17, 17, 17, 18, 18, + 18, 19, 19, 19, 20, 20, 20, 21, + 21, 21, 22, 22, 22, 23, 23, 23, + 24, 24, 24, 25, 25, 25, 26, 26, + 26, 27, 27, 27, 28, 28, 28, 29, + 29, 29, 30, 30, 30, 31, 31, 31, + 32, 32, 32, 33, 33, 33, 34, 34, + 34, 35, 35, 35, 36, 36, 36, 37, + 37, 37, 38, 38, 38, 39, 39, 39, + 40, 40, 40, 41, 41, 41, 42, 42, + 42, 43, 43, 43, 44, 44, 44, 45, + 45, 45, 46, 46, 46, 47, 47, 47, + 48, 48, 48, 49, 49, 49, 50, 50, + 50, 51, 51, 51, 52, 52, 52, 53, + 53, 53, 54, 54, 54, 55, 55, 55, + 56, 56, 56, 57, 57, 57, 58, 58, + 58, 59, 59, 59, 60, 60, 60, 61, + 61, 61, 62, 62, 62, 63, 63, 63, + 64, 64, 64, 65, 65, 65, 66, 66, + 66, 67, 67, 67, 68, 68, 68, 69, + 69, 69, 70, 70, 70, 71, 71, 71, + 72, 72, 72, 73, 73, 73, 74, 74, + 74, 75, 75, 75, 76, 76, 76, 77, + 77, 77, 78, 78, 78, 79, 79, 79, + 80, 80, 80, 81, 81, 81, 82, 82, + 82, 83, 83, 83, 84, 84, 84, 85, + 85, 85, 86, 86, 86, 87, 87, 87, + 88, 88, 88, 89, 89, 89, 90, 90, + 90, 91, 91, 91, 92, 92, 92, 93, + 93, 93, 94, 94, 94, 95, 95, 95, + 96, 96, 96, 97, 97, 97, 98, 98, + 98, 99, 99, 99, 100, 100, 100, 101, + 101, 101, 102, 102, 102, 103, 103, 103, + 104, 104, 104, 105, 105, 105, 106, 106, + 106, 107, 107, 107, 108, 108, 108, 109, + 109, 109, 110, 110, 110, 111, 111, 111, + 112, 112, 112, 113, 113, 113, 114, 114, + 114, 115, 115, 115, 116, 116, 116, 117, + 117, 117, 118, 118, 118, 119, 119, 119, + 120, 120, 120, 121, 121, 121, 122, 122, + 122, 123, 123, 123, 124, 124, 124, 125, + 125, 125, 126, 126, 126, 127, 127, 127, + 128, 128, 128, 129, 129, 129, 130, 130, + 130, 131, 131, 131, 132, 132, 132, 133, + 133, 133, 134, 134, 134, 135, 135, 135, + 136, 136, 136, 137, 137, 137, 138, 138, + 138, 139, 139, 139, 140, 140, 140, 141, + 141, 141, 142, 142, 142, 143, 143, 143, + 144, 144, 144, 145, 145, 145, 146, 146, + 146, 147, 147, 147, 148, 148, 148, 149, + 149, 149, 150, 150, 150, 151, 151, 151, + 152, 152, 152, 153, 153, 153, 154, 154, + 154, 155, 155, 155, 156, 156, 156, 157, + 157, 157, 158, 158, 158, 159, 159, 159, + 160, 160, 160, 161, 161, 161, 162, 162, + 162, 163, 163, 163, 164, 164, 164, 165, + 165, 165, 166, 166, 166, 167, 167, 167, + 168, 168, 168, 169, 169, 169, 170, 170, + 170, 171, 171, 171, 172, 172, 172, 173, + 173, 173, 174, 174, 174, 175, 175, 175, + 176, 176, 176, 177, 177, 177, 178, 178, + 178, 179, 179, 179, 180, 180, 180, 181, + 181, 181, 182, 182, 182, 183, 183, 183, + 184, 184, 184, 185, 185, 185, 186, 186, + 186, 187, 187, 187, 188, 188, 188, 189, + 189, 189, 190, 190, 190, 191, 191, 191, + 192, 192, 192, 193, 193, 193, 194, 194, + 194, 195, 195, 195, 196, 196, 196, 197, + 197, 197, 198, 198, 198, 199, 199, 199, + 200, 200, 200, 201, 201, 201, 202, 202, + 202, 203, 203, 203, 204, 204, 204, 205, + 205, 205, 206, 206, 206, 207, 207, 207, + 208, 208, 208, 209, 209, 209, 210, 210, + 210, 211, 211, 211, 212, 212, 212, 213, + 213, 213, 214, 214, 214, 215, 215, 215, + 216, 216, 216, 217, 217, 217, 218, 218, + 218, 219, 219, 219, 220, 220, 220, 221, + 221, 221, 222, 222, 222, 223, 223, 223, + 224, 224, 224, 225, 225, 225, 226, 226, + 226, 227, 227, 227, 228, 228, 228, 229, + 229, 229, 230, 230, 230, 231, 231, 231, + 232, 232, 232, 233, 233, 233, 234, 234, + 234, 235, 235, 235, 236, 236, 236, 237, + 237, 237, 238, 238, 238, 239, 239, 239, + 240, 240, 240, 241, 241, 241, 242, 242, + 242, 243, 243, 243, 244, 244, 244, 245, + 245, 245, 246, 246, 246, 247, 247, 247, + 248, 248, 248, 249, 249, 249, 250, 250, + 250, 251, 251, 251, 252, 252, 252, 253, + 253, 253, 254, 254, 254, 255, 255, 255, +}; + +const uint8_t detex_division_by_7_table[1792] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, + 4, 4, 4, 5, 5, 5, 5, 5, + 5, 5, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 9, 9, 10, 10, + 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, + 12, 12, 12, 13, 13, 13, 13, 13, + 13, 13, 14, 14, 14, 14, 14, 14, + 14, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 17, 17, 18, 18, + 18, 18, 18, 18, 18, 19, 19, 19, + 19, 19, 19, 19, 20, 20, 20, 20, + 20, 20, 20, 21, 21, 21, 21, 21, + 21, 21, 22, 22, 22, 22, 22, 22, + 22, 23, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 25, + 25, 25, 25, 25, 25, 25, 26, 26, + 26, 26, 26, 26, 26, 27, 27, 27, + 27, 27, 27, 27, 28, 28, 28, 28, + 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 30, 30, 30, 30, 30, 30, + 30, 31, 31, 31, 31, 31, 31, 31, + 32, 32, 32, 32, 32, 32, 32, 33, + 33, 33, 33, 33, 33, 33, 34, 34, + 34, 34, 34, 34, 34, 35, 35, 35, + 35, 35, 35, 35, 36, 36, 36, 36, + 36, 36, 36, 37, 37, 37, 37, 37, + 37, 37, 38, 38, 38, 38, 38, 38, + 38, 39, 39, 39, 39, 39, 39, 39, + 40, 40, 40, 40, 40, 40, 40, 41, + 41, 41, 41, 41, 41, 41, 42, 42, + 42, 42, 42, 42, 42, 43, 43, 43, + 43, 43, 43, 43, 44, 44, 44, 44, + 44, 44, 44, 45, 45, 45, 45, 45, + 45, 45, 46, 46, 46, 46, 46, 46, + 46, 47, 47, 47, 47, 47, 47, 47, + 48, 48, 48, 48, 48, 48, 48, 49, + 49, 49, 49, 49, 49, 49, 50, 50, + 50, 50, 50, 50, 50, 51, 51, 51, + 51, 51, 51, 51, 52, 52, 52, 52, + 52, 52, 52, 53, 53, 53, 53, 53, + 53, 53, 54, 54, 54, 54, 54, 54, + 54, 55, 55, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 56, 56, 57, + 57, 57, 57, 57, 57, 57, 58, 58, + 58, 58, 58, 58, 58, 59, 59, 59, + 59, 59, 59, 59, 60, 60, 60, 60, + 60, 60, 60, 61, 61, 61, 61, 61, + 61, 61, 62, 62, 62, 62, 62, 62, + 62, 63, 63, 63, 63, 63, 63, 63, + 64, 64, 64, 64, 64, 64, 64, 65, + 65, 65, 65, 65, 65, 65, 66, 66, + 66, 66, 66, 66, 66, 67, 67, 67, + 67, 67, 67, 67, 68, 68, 68, 68, + 68, 68, 68, 69, 69, 69, 69, 69, + 69, 69, 70, 70, 70, 70, 70, 70, + 70, 71, 71, 71, 71, 71, 71, 71, + 72, 72, 72, 72, 72, 72, 72, 73, + 73, 73, 73, 73, 73, 73, 74, 74, + 74, 74, 74, 74, 74, 75, 75, 75, + 75, 75, 75, 75, 76, 76, 76, 76, + 76, 76, 76, 77, 77, 77, 77, 77, + 77, 77, 78, 78, 78, 78, 78, 78, + 78, 79, 79, 79, 79, 79, 79, 79, + 80, 80, 80, 80, 80, 80, 80, 81, + 81, 81, 81, 81, 81, 81, 82, 82, + 82, 82, 82, 82, 82, 83, 83, 83, + 83, 83, 83, 83, 84, 84, 84, 84, + 84, 84, 84, 85, 85, 85, 85, 85, + 85, 85, 86, 86, 86, 86, 86, 86, + 86, 87, 87, 87, 87, 87, 87, 87, + 88, 88, 88, 88, 88, 88, 88, 89, + 89, 89, 89, 89, 89, 89, 90, 90, + 90, 90, 90, 90, 90, 91, 91, 91, + 91, 91, 91, 91, 92, 92, 92, 92, + 92, 92, 92, 93, 93, 93, 93, 93, + 93, 93, 94, 94, 94, 94, 94, 94, + 94, 95, 95, 95, 95, 95, 95, 95, + 96, 96, 96, 96, 96, 96, 96, 97, + 97, 97, 97, 97, 97, 97, 98, 98, + 98, 98, 98, 98, 98, 99, 99, 99, + 99, 99, 99, 99, 100, 100, 100, 100, + 100, 100, 100, 101, 101, 101, 101, 101, + 101, 101, 102, 102, 102, 102, 102, 102, + 102, 103, 103, 103, 103, 103, 103, 103, + 104, 104, 104, 104, 104, 104, 104, 105, + 105, 105, 105, 105, 105, 105, 106, 106, + 106, 106, 106, 106, 106, 107, 107, 107, + 107, 107, 107, 107, 108, 108, 108, 108, + 108, 108, 108, 109, 109, 109, 109, 109, + 109, 109, 110, 110, 110, 110, 110, 110, + 110, 111, 111, 111, 111, 111, 111, 111, + 112, 112, 112, 112, 112, 112, 112, 113, + 113, 113, 113, 113, 113, 113, 114, 114, + 114, 114, 114, 114, 114, 115, 115, 115, + 115, 115, 115, 115, 116, 116, 116, 116, + 116, 116, 116, 117, 117, 117, 117, 117, + 117, 117, 118, 118, 118, 118, 118, 118, + 118, 119, 119, 119, 119, 119, 119, 119, + 120, 120, 120, 120, 120, 120, 120, 121, + 121, 121, 121, 121, 121, 121, 122, 122, + 122, 122, 122, 122, 122, 123, 123, 123, + 123, 123, 123, 123, 124, 124, 124, 124, + 124, 124, 124, 125, 125, 125, 125, 125, + 125, 125, 126, 126, 126, 126, 126, 126, + 126, 127, 127, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 128, 128, 129, + 129, 129, 129, 129, 129, 129, 130, 130, + 130, 130, 130, 130, 130, 131, 131, 131, + 131, 131, 131, 131, 132, 132, 132, 132, + 132, 132, 132, 133, 133, 133, 133, 133, + 133, 133, 134, 134, 134, 134, 134, 134, + 134, 135, 135, 135, 135, 135, 135, 135, + 136, 136, 136, 136, 136, 136, 136, 137, + 137, 137, 137, 137, 137, 137, 138, 138, + 138, 138, 138, 138, 138, 139, 139, 139, + 139, 139, 139, 139, 140, 140, 140, 140, + 140, 140, 140, 141, 141, 141, 141, 141, + 141, 141, 142, 142, 142, 142, 142, 142, + 142, 143, 143, 143, 143, 143, 143, 143, + 144, 144, 144, 144, 144, 144, 144, 145, + 145, 145, 145, 145, 145, 145, 146, 146, + 146, 146, 146, 146, 146, 147, 147, 147, + 147, 147, 147, 147, 148, 148, 148, 148, + 148, 148, 148, 149, 149, 149, 149, 149, + 149, 149, 150, 150, 150, 150, 150, 150, + 150, 151, 151, 151, 151, 151, 151, 151, + 152, 152, 152, 152, 152, 152, 152, 153, + 153, 153, 153, 153, 153, 153, 154, 154, + 154, 154, 154, 154, 154, 155, 155, 155, + 155, 155, 155, 155, 156, 156, 156, 156, + 156, 156, 156, 157, 157, 157, 157, 157, + 157, 157, 158, 158, 158, 158, 158, 158, + 158, 159, 159, 159, 159, 159, 159, 159, + 160, 160, 160, 160, 160, 160, 160, 161, + 161, 161, 161, 161, 161, 161, 162, 162, + 162, 162, 162, 162, 162, 163, 163, 163, + 163, 163, 163, 163, 164, 164, 164, 164, + 164, 164, 164, 165, 165, 165, 165, 165, + 165, 165, 166, 166, 166, 166, 166, 166, + 166, 167, 167, 167, 167, 167, 167, 167, + 168, 168, 168, 168, 168, 168, 168, 169, + 169, 169, 169, 169, 169, 169, 170, 170, + 170, 170, 170, 170, 170, 171, 171, 171, + 171, 171, 171, 171, 172, 172, 172, 172, + 172, 172, 172, 173, 173, 173, 173, 173, + 173, 173, 174, 174, 174, 174, 174, 174, + 174, 175, 175, 175, 175, 175, 175, 175, + 176, 176, 176, 176, 176, 176, 176, 177, + 177, 177, 177, 177, 177, 177, 178, 178, + 178, 178, 178, 178, 178, 179, 179, 179, + 179, 179, 179, 179, 180, 180, 180, 180, + 180, 180, 180, 181, 181, 181, 181, 181, + 181, 181, 182, 182, 182, 182, 182, 182, + 182, 183, 183, 183, 183, 183, 183, 183, + 184, 184, 184, 184, 184, 184, 184, 185, + 185, 185, 185, 185, 185, 185, 186, 186, + 186, 186, 186, 186, 186, 187, 187, 187, + 187, 187, 187, 187, 188, 188, 188, 188, + 188, 188, 188, 189, 189, 189, 189, 189, + 189, 189, 190, 190, 190, 190, 190, 190, + 190, 191, 191, 191, 191, 191, 191, 191, + 192, 192, 192, 192, 192, 192, 192, 193, + 193, 193, 193, 193, 193, 193, 194, 194, + 194, 194, 194, 194, 194, 195, 195, 195, + 195, 195, 195, 195, 196, 196, 196, 196, + 196, 196, 196, 197, 197, 197, 197, 197, + 197, 197, 198, 198, 198, 198, 198, 198, + 198, 199, 199, 199, 199, 199, 199, 199, + 200, 200, 200, 200, 200, 200, 200, 201, + 201, 201, 201, 201, 201, 201, 202, 202, + 202, 202, 202, 202, 202, 203, 203, 203, + 203, 203, 203, 203, 204, 204, 204, 204, + 204, 204, 204, 205, 205, 205, 205, 205, + 205, 205, 206, 206, 206, 206, 206, 206, + 206, 207, 207, 207, 207, 207, 207, 207, + 208, 208, 208, 208, 208, 208, 208, 209, + 209, 209, 209, 209, 209, 209, 210, 210, + 210, 210, 210, 210, 210, 211, 211, 211, + 211, 211, 211, 211, 212, 212, 212, 212, + 212, 212, 212, 213, 213, 213, 213, 213, + 213, 213, 214, 214, 214, 214, 214, 214, + 214, 215, 215, 215, 215, 215, 215, 215, + 216, 216, 216, 216, 216, 216, 216, 217, + 217, 217, 217, 217, 217, 217, 218, 218, + 218, 218, 218, 218, 218, 219, 219, 219, + 219, 219, 219, 219, 220, 220, 220, 220, + 220, 220, 220, 221, 221, 221, 221, 221, + 221, 221, 222, 222, 222, 222, 222, 222, + 222, 223, 223, 223, 223, 223, 223, 223, + 224, 224, 224, 224, 224, 224, 224, 225, + 225, 225, 225, 225, 225, 225, 226, 226, + 226, 226, 226, 226, 226, 227, 227, 227, + 227, 227, 227, 227, 228, 228, 228, 228, + 228, 228, 228, 229, 229, 229, 229, 229, + 229, 229, 230, 230, 230, 230, 230, 230, + 230, 231, 231, 231, 231, 231, 231, 231, + 232, 232, 232, 232, 232, 232, 232, 233, + 233, 233, 233, 233, 233, 233, 234, 234, + 234, 234, 234, 234, 234, 235, 235, 235, + 235, 235, 235, 235, 236, 236, 236, 236, + 236, 236, 236, 237, 237, 237, 237, 237, + 237, 237, 238, 238, 238, 238, 238, 238, + 238, 239, 239, 239, 239, 239, 239, 239, + 240, 240, 240, 240, 240, 240, 240, 241, + 241, 241, 241, 241, 241, 241, 242, 242, + 242, 242, 242, 242, 242, 243, 243, 243, + 243, 243, 243, 243, 244, 244, 244, 244, + 244, 244, 244, 245, 245, 245, 245, 245, + 245, 245, 246, 246, 246, 246, 246, 246, + 246, 247, 247, 247, 247, 247, 247, 247, + 248, 248, 248, 248, 248, 248, 248, 249, + 249, 249, 249, 249, 249, 249, 250, 250, + 250, 250, 250, 250, 250, 251, 251, 251, + 251, 251, 251, 251, 252, 252, 252, 252, + 252, 252, 252, 253, 253, 253, 253, 253, + 253, 253, 254, 254, 254, 254, 254, 254, + 254, 255, 255, 255, 255, 255, 255, 255, +}; + +const uint8_t detex_division_by_5_table[1280] = { + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 3, + 3, 3, 3, 3, 4, 4, 4, 4, + 4, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 9, 9, 9, + 9, 9, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 14, 14, + 14, 14, 14, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 17, 17, 17, + 17, 17, 18, 18, 18, 18, 18, 19, + 19, 19, 19, 19, 20, 20, 20, 20, + 20, 21, 21, 21, 21, 21, 22, 22, + 22, 22, 22, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 27, + 27, 27, 27, 27, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 30, 30, + 30, 30, 30, 31, 31, 31, 31, 31, + 32, 32, 32, 32, 32, 33, 33, 33, + 33, 33, 34, 34, 34, 34, 34, 35, + 35, 35, 35, 35, 36, 36, 36, 36, + 36, 37, 37, 37, 37, 37, 38, 38, + 38, 38, 38, 39, 39, 39, 39, 39, + 40, 40, 40, 40, 40, 41, 41, 41, + 41, 41, 42, 42, 42, 42, 42, 43, + 43, 43, 43, 43, 44, 44, 44, 44, + 44, 45, 45, 45, 45, 45, 46, 46, + 46, 46, 46, 47, 47, 47, 47, 47, + 48, 48, 48, 48, 48, 49, 49, 49, + 49, 49, 50, 50, 50, 50, 50, 51, + 51, 51, 51, 51, 52, 52, 52, 52, + 52, 53, 53, 53, 53, 53, 54, 54, + 54, 54, 54, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 58, 58, 58, 58, 58, 59, + 59, 59, 59, 59, 60, 60, 60, 60, + 60, 61, 61, 61, 61, 61, 62, 62, + 62, 62, 62, 63, 63, 63, 63, 63, + 64, 64, 64, 64, 64, 65, 65, 65, + 65, 65, 66, 66, 66, 66, 66, 67, + 67, 67, 67, 67, 68, 68, 68, 68, + 68, 69, 69, 69, 69, 69, 70, 70, + 70, 70, 70, 71, 71, 71, 71, 71, + 72, 72, 72, 72, 72, 73, 73, 73, + 73, 73, 74, 74, 74, 74, 74, 75, + 75, 75, 75, 75, 76, 76, 76, 76, + 76, 77, 77, 77, 77, 77, 78, 78, + 78, 78, 78, 79, 79, 79, 79, 79, + 80, 80, 80, 80, 80, 81, 81, 81, + 81, 81, 82, 82, 82, 82, 82, 83, + 83, 83, 83, 83, 84, 84, 84, 84, + 84, 85, 85, 85, 85, 85, 86, 86, + 86, 86, 86, 87, 87, 87, 87, 87, + 88, 88, 88, 88, 88, 89, 89, 89, + 89, 89, 90, 90, 90, 90, 90, 91, + 91, 91, 91, 91, 92, 92, 92, 92, + 92, 93, 93, 93, 93, 93, 94, 94, + 94, 94, 94, 95, 95, 95, 95, 95, + 96, 96, 96, 96, 96, 97, 97, 97, + 97, 97, 98, 98, 98, 98, 98, 99, + 99, 99, 99, 99, 100, 100, 100, 100, + 100, 101, 101, 101, 101, 101, 102, 102, + 102, 102, 102, 103, 103, 103, 103, 103, + 104, 104, 104, 104, 104, 105, 105, 105, + 105, 105, 106, 106, 106, 106, 106, 107, + 107, 107, 107, 107, 108, 108, 108, 108, + 108, 109, 109, 109, 109, 109, 110, 110, + 110, 110, 110, 111, 111, 111, 111, 111, + 112, 112, 112, 112, 112, 113, 113, 113, + 113, 113, 114, 114, 114, 114, 114, 115, + 115, 115, 115, 115, 116, 116, 116, 116, + 116, 117, 117, 117, 117, 117, 118, 118, + 118, 118, 118, 119, 119, 119, 119, 119, + 120, 120, 120, 120, 120, 121, 121, 121, + 121, 121, 122, 122, 122, 122, 122, 123, + 123, 123, 123, 123, 124, 124, 124, 124, + 124, 125, 125, 125, 125, 125, 126, 126, + 126, 126, 126, 127, 127, 127, 127, 127, + 128, 128, 128, 128, 128, 129, 129, 129, + 129, 129, 130, 130, 130, 130, 130, 131, + 131, 131, 131, 131, 132, 132, 132, 132, + 132, 133, 133, 133, 133, 133, 134, 134, + 134, 134, 134, 135, 135, 135, 135, 135, + 136, 136, 136, 136, 136, 137, 137, 137, + 137, 137, 138, 138, 138, 138, 138, 139, + 139, 139, 139, 139, 140, 140, 140, 140, + 140, 141, 141, 141, 141, 141, 142, 142, + 142, 142, 142, 143, 143, 143, 143, 143, + 144, 144, 144, 144, 144, 145, 145, 145, + 145, 145, 146, 146, 146, 146, 146, 147, + 147, 147, 147, 147, 148, 148, 148, 148, + 148, 149, 149, 149, 149, 149, 150, 150, + 150, 150, 150, 151, 151, 151, 151, 151, + 152, 152, 152, 152, 152, 153, 153, 153, + 153, 153, 154, 154, 154, 154, 154, 155, + 155, 155, 155, 155, 156, 156, 156, 156, + 156, 157, 157, 157, 157, 157, 158, 158, + 158, 158, 158, 159, 159, 159, 159, 159, + 160, 160, 160, 160, 160, 161, 161, 161, + 161, 161, 162, 162, 162, 162, 162, 163, + 163, 163, 163, 163, 164, 164, 164, 164, + 164, 165, 165, 165, 165, 165, 166, 166, + 166, 166, 166, 167, 167, 167, 167, 167, + 168, 168, 168, 168, 168, 169, 169, 169, + 169, 169, 170, 170, 170, 170, 170, 171, + 171, 171, 171, 171, 172, 172, 172, 172, + 172, 173, 173, 173, 173, 173, 174, 174, + 174, 174, 174, 175, 175, 175, 175, 175, + 176, 176, 176, 176, 176, 177, 177, 177, + 177, 177, 178, 178, 178, 178, 178, 179, + 179, 179, 179, 179, 180, 180, 180, 180, + 180, 181, 181, 181, 181, 181, 182, 182, + 182, 182, 182, 183, 183, 183, 183, 183, + 184, 184, 184, 184, 184, 185, 185, 185, + 185, 185, 186, 186, 186, 186, 186, 187, + 187, 187, 187, 187, 188, 188, 188, 188, + 188, 189, 189, 189, 189, 189, 190, 190, + 190, 190, 190, 191, 191, 191, 191, 191, + 192, 192, 192, 192, 192, 193, 193, 193, + 193, 193, 194, 194, 194, 194, 194, 195, + 195, 195, 195, 195, 196, 196, 196, 196, + 196, 197, 197, 197, 197, 197, 198, 198, + 198, 198, 198, 199, 199, 199, 199, 199, + 200, 200, 200, 200, 200, 201, 201, 201, + 201, 201, 202, 202, 202, 202, 202, 203, + 203, 203, 203, 203, 204, 204, 204, 204, + 204, 205, 205, 205, 205, 205, 206, 206, + 206, 206, 206, 207, 207, 207, 207, 207, + 208, 208, 208, 208, 208, 209, 209, 209, + 209, 209, 210, 210, 210, 210, 210, 211, + 211, 211, 211, 211, 212, 212, 212, 212, + 212, 213, 213, 213, 213, 213, 214, 214, + 214, 214, 214, 215, 215, 215, 215, 215, + 216, 216, 216, 216, 216, 217, 217, 217, + 217, 217, 218, 218, 218, 218, 218, 219, + 219, 219, 219, 219, 220, 220, 220, 220, + 220, 221, 221, 221, 221, 221, 222, 222, + 222, 222, 222, 223, 223, 223, 223, 223, + 224, 224, 224, 224, 224, 225, 225, 225, + 225, 225, 226, 226, 226, 226, 226, 227, + 227, 227, 227, 227, 228, 228, 228, 228, + 228, 229, 229, 229, 229, 229, 230, 230, + 230, 230, 230, 231, 231, 231, 231, 231, + 232, 232, 232, 232, 232, 233, 233, 233, + 233, 233, 234, 234, 234, 234, 234, 235, + 235, 235, 235, 235, 236, 236, 236, 236, + 236, 237, 237, 237, 237, 237, 238, 238, + 238, 238, 238, 239, 239, 239, 239, 239, + 240, 240, 240, 240, 240, 241, 241, 241, + 241, 241, 242, 242, 242, 242, 242, 243, + 243, 243, 243, 243, 244, 244, 244, 244, + 244, 245, 245, 245, 245, 245, 246, 246, + 246, 246, 246, 247, 247, 247, 247, 247, + 248, 248, 248, 248, 248, 249, 249, 249, + 249, 249, 250, 250, 250, 250, 250, 251, + 251, 251, 251, 251, 252, 252, 252, 252, + 252, 253, 253, 253, 253, 253, 254, 254, + 254, 254, 254, 255, 255, 255, 255, 255, +}; + diff --git a/Source/ThirdParty/mono-2.0/mono.Build.cs b/Source/ThirdParty/mono-2.0/mono.Build.cs index 2399b47e8..9fa592f35 100644 --- a/Source/ThirdParty/mono-2.0/mono.Build.cs +++ b/Source/ThirdParty/mono-2.0/mono.Build.cs @@ -73,8 +73,6 @@ public class mono : DepsModule case TargetPlatform.Linux: options.PublicDefinitions.Add("USE_MONO_DYNAMIC_LIB"); options.DependencyFiles.Add(Path.Combine(depsRoot, "libmonosgen-2.0.so")); - options.DependencyFiles.Add(Path.Combine(depsRoot, "libmonosgen-2.0.so.1")); - options.DependencyFiles.Add(Path.Combine(depsRoot, "libmonosgen-2.0.so.1.0.0")); options.Libraries.Add(Path.Combine(depsRoot, "libmonosgen-2.0.so")); break; case TargetPlatform.PS4: diff --git a/Source/ThirdParty/stb/stb_dxt.h b/Source/ThirdParty/stb/stb_dxt.h new file mode 100644 index 000000000..04666de99 --- /dev/null +++ b/Source/ThirdParty/stb/stb_dxt.h @@ -0,0 +1,753 @@ +// stb_dxt.h - v1.10 - DXT1/DXT5 compressor - public domain +// original by fabian "ryg" giesen - ported to C by stb +// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation +// +// USAGE: +// call stb_compress_dxt_block() for every block (you must pad) +// source should be a 4x4 block of RGBA data in row-major order; +// Alpha channel is not stored if you specify alpha=0 (but you +// must supply some constant alpha in the alpha channel). +// You can turn on dithering and "high quality" using mode. +// +// version history: +// v1.10 - (i.c) various small quality improvements +// v1.09 - (stb) update documentation re: surprising alpha channel requirement +// v1.08 - (stb) fix bug in dxt-with-alpha block +// v1.07 - (stb) bc4; allow not using libc; add STB_DXT_STATIC +// v1.06 - (stb) fix to known-broken 1.05 +// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski) +// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); +// single color match fix (allow for inexact color interpolation); +// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps. +// v1.03 - (stb) endianness support +// v1.02 - (stb) fix alpha encoding bug +// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom +// v1.00 - (stb) first release +// +// contributors: +// Rich Geldreich (more accurate index selection) +// Kevin Schmidt (#defines for "freestanding" compilation) +// github:ppiastucki (BC4 support) +// Ignacio Castano - improve DXT endpoint quantization +// +// LICENSE +// +// See end of file for license information. + +#ifndef STB_INCLUDE_STB_DXT_H +#define STB_INCLUDE_STB_DXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_DXT_STATIC +#define STBDDEF static +#else +#define STBDDEF extern +#endif + +// compression mode (bitflags) +#define STB_DXT_NORMAL 0 +#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like! +#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower. + +STBDDEF void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode); +STBDDEF void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src_r_one_byte_per_pixel); +STBDDEF void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel); + +#define STB_COMPRESS_DXT_BLOCK + +#ifdef __cplusplus +} +#endif +#endif // STB_INCLUDE_STB_DXT_H + +#ifdef STB_DXT_IMPLEMENTATION + +// configuration options for DXT encoder. set them in the project/makefile or just define +// them at the top. + +// STB_DXT_USE_ROUNDING_BIAS +// use a rounding bias during color interpolation. this is closer to what "ideal" +// interpolation would do but doesn't match the S3TC/DX10 spec. old versions (pre-1.03) +// implicitly had this turned on. +// +// in case you're targeting a specific type of hardware (e.g. console programmers): +// NVidia and Intel GPUs (as of 2010) as well as DX9 ref use DXT decoders that are closer +// to STB_DXT_USE_ROUNDING_BIAS. AMD/ATI, S3 and DX10 ref are closer to rounding with no bias. +// you also see "(a*5 + b*3) / 8" on some old GPU designs. +// #define STB_DXT_USE_ROUNDING_BIAS + +#include + +#if !defined(STBD_ABS) || !defined(STBI_FABS) +#include +#endif + +#ifndef STBD_ABS +#define STBD_ABS(i) abs(i) +#endif + +#ifndef STBD_FABS +#define STBD_FABS(x) fabs(x) +#endif + +#ifndef STBD_MEMSET +#include +#define STBD_MEMSET memset +#endif + +static unsigned char stb__Expand5[32]; +static unsigned char stb__Expand6[64]; +static unsigned char stb__OMatch5[256][2]; +static unsigned char stb__OMatch6[256][2]; +static unsigned char stb__QuantRBTab[256+16]; +static unsigned char stb__QuantGTab[256+16]; + +static int stb__Mul8Bit(int a, int b) +{ + int t = a*b + 128; + return (t + (t >> 8)) >> 8; +} + +static void stb__From16Bit(unsigned char *out, unsigned short v) +{ + int rv = (v & 0xf800) >> 11; + int gv = (v & 0x07e0) >> 5; + int bv = (v & 0x001f) >> 0; + + out[0] = stb__Expand5[rv]; + out[1] = stb__Expand6[gv]; + out[2] = stb__Expand5[bv]; + out[3] = 0; +} + +static unsigned short stb__As16Bit(int r, int g, int b) +{ + return (unsigned short)((stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31)); +} + +// linear interpolation at 1/3 point between a and b, using desired rounding type +static int stb__Lerp13(int a, int b) +{ +#ifdef STB_DXT_USE_ROUNDING_BIAS + // with rounding bias + return a + stb__Mul8Bit(b-a, 0x55); +#else + // without rounding bias + // replace "/ 3" by "* 0xaaab) >> 17" if your compiler sucks or you really need every ounce of speed. + return (2*a + b) / 3; +#endif +} + +// lerp RGB color +static void stb__Lerp13RGB(unsigned char *out, unsigned char *p1, unsigned char *p2) +{ + out[0] = (unsigned char)stb__Lerp13(p1[0], p2[0]); + out[1] = (unsigned char)stb__Lerp13(p1[1], p2[1]); + out[2] = (unsigned char)stb__Lerp13(p1[2], p2[2]); +} + +/****************************************************************************/ + +// compute table to reproduce constant colors as accurately as possible +static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expand,int size) +{ + int i,mn,mx; + for (i=0;i<256;i++) { + int bestErr = 256; + for (mn=0;mn> 4)]; + ep1[0] = bp[ 0] - dp[ 0]; + dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)]; + ep1[1] = bp[ 4] - dp[ 4]; + dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)]; + ep1[2] = bp[ 8] - dp[ 8]; + dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)]; + ep1[3] = bp[12] - dp[12]; + bp += 16; + dp += 16; + et = ep1, ep1 = ep2, ep2 = et; // swap + } + } +} + +// The color matching function +static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color,int dither) +{ + unsigned int mask = 0; + int dirr = color[0*4+0] - color[1*4+0]; + int dirg = color[0*4+1] - color[1*4+1]; + int dirb = color[0*4+2] - color[1*4+2]; + int dots[16]; + int stops[4]; + int i; + int c0Point, halfPoint, c3Point; + + for(i=0;i<16;i++) + dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb; + + for(i=0;i<4;i++) + stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb; + + // think of the colors as arranged on a line; project point onto that line, then choose + // next color out of available ones. we compute the crossover points for "best color in top + // half"/"best in bottom half" and then the same inside that subinterval. + // + // relying on this 1d approximation isn't always optimal in terms of euclidean distance, + // but it's very close and a lot faster. + // http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html + + c0Point = (stops[1] + stops[3]); + halfPoint = (stops[3] + stops[2]); + c3Point = (stops[2] + stops[0]); + + if(!dither) { + // the version without dithering is straightforward + for (i=15;i>=0;i--) { + int dot = dots[i]*2; + mask <<= 2; + + if(dot < halfPoint) + mask |= (dot < c0Point) ? 1 : 3; + else + mask |= (dot < c3Point) ? 2 : 0; + } + } else { + // with floyd-steinberg dithering + int err[8],*ep1 = err,*ep2 = err+4; + int *dp = dots, y; + + c0Point <<= 3; + halfPoint <<= 3; + c3Point <<= 3; + for(i=0;i<8;i++) + err[i] = 0; + + for(y=0;y<4;y++) + { + int dot,lmask,step; + + dot = (dp[0] << 4) + (3*ep2[1] + 5*ep2[0]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[0] = dp[0] - stops[step]; + lmask = step; + + dot = (dp[1] << 4) + (7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[1] = dp[1] - stops[step]; + lmask |= step<<2; + + dot = (dp[2] << 4) + (7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[2] = dp[2] - stops[step]; + lmask |= step<<4; + + dot = (dp[3] << 4) + (7*ep1[2] + 5*ep2[3] + ep2[2]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[3] = dp[3] - stops[step]; + lmask |= step<<6; + + dp += 4; + mask |= lmask << (y*8); + { int *et = ep1; ep1 = ep2; ep2 = et; } // swap + } + } + + return mask; +} + +// The color optimization function. (Clever code, part 1) +static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16) +{ + int mind = 0x7fffffff,maxd = -0x7fffffff; + unsigned char *minp, *maxp; + double magn; + int v_r,v_g,v_b; + static const int nIterPower = 4; + float covf[6],vfr,vfg,vfb; + + // determine color distribution + int cov[6]; + int mu[3],min[3],max[3]; + int ch,i,iter; + + for(ch=0;ch<3;ch++) + { + const unsigned char *bp = ((const unsigned char *) block) + ch; + int muv,minv,maxv; + + muv = minv = maxv = bp[0]; + for(i=4;i<64;i+=4) + { + muv += bp[i]; + if (bp[i] < minv) minv = bp[i]; + else if (bp[i] > maxv) maxv = bp[i]; + } + + mu[ch] = (muv + 8) >> 4; + min[ch] = minv; + max[ch] = maxv; + } + + // determine covariance matrix + for (i=0;i<6;i++) + cov[i] = 0; + + for (i=0;i<16;i++) + { + int r = block[i*4+0] - mu[0]; + int g = block[i*4+1] - mu[1]; + int b = block[i*4+2] - mu[2]; + + cov[0] += r*r; + cov[1] += r*g; + cov[2] += r*b; + cov[3] += g*g; + cov[4] += g*b; + cov[5] += b*b; + } + + // convert covariance matrix to float, find principal axis via power iter + for(i=0;i<6;i++) + covf[i] = cov[i] / 255.0f; + + vfr = (float) (max[0] - min[0]); + vfg = (float) (max[1] - min[1]); + vfb = (float) (max[2] - min[2]); + + for(iter=0;iter magn) magn = STBD_FABS(vfg); + if (STBD_FABS(vfb) > magn) magn = STBD_FABS(vfb); + + if(magn < 4.0f) { // too small, default to luminance + v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. + v_g = 587; + v_b = 114; + } else { + magn = 512.0 / magn; + v_r = (int) (vfr * magn); + v_g = (int) (vfg * magn); + v_b = (int) (vfb * magn); + } + + // Pick colors at extreme points + for(i=0;i<16;i++) + { + int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b; + + if (dot < mind) { + mind = dot; + minp = block+i*4; + } + + if (dot > maxd) { + maxd = dot; + maxp = block+i*4; + } + } + + *pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]); + *pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]); +} + +static const float midpoints5[32] = { + 0.015686f, 0.047059f, 0.078431f, 0.111765f, 0.145098f, 0.176471f, 0.207843f, 0.241176f, 0.274510f, 0.305882f, 0.337255f, 0.370588f, 0.403922f, 0.435294f, 0.466667f, 0.5f, + 0.533333f, 0.564706f, 0.596078f, 0.629412f, 0.662745f, 0.694118f, 0.725490f, 0.758824f, 0.792157f, 0.823529f, 0.854902f, 0.888235f, 0.921569f, 0.952941f, 0.984314f, 1.0f +}; + +static const float midpoints6[64] = { + 0.007843f, 0.023529f, 0.039216f, 0.054902f, 0.070588f, 0.086275f, 0.101961f, 0.117647f, 0.133333f, 0.149020f, 0.164706f, 0.180392f, 0.196078f, 0.211765f, 0.227451f, 0.245098f, + 0.262745f, 0.278431f, 0.294118f, 0.309804f, 0.325490f, 0.341176f, 0.356863f, 0.372549f, 0.388235f, 0.403922f, 0.419608f, 0.435294f, 0.450980f, 0.466667f, 0.482353f, 0.500000f, + 0.517647f, 0.533333f, 0.549020f, 0.564706f, 0.580392f, 0.596078f, 0.611765f, 0.627451f, 0.643137f, 0.658824f, 0.674510f, 0.690196f, 0.705882f, 0.721569f, 0.737255f, 0.754902f, + 0.772549f, 0.788235f, 0.803922f, 0.819608f, 0.835294f, 0.850980f, 0.866667f, 0.882353f, 0.898039f, 0.913725f, 0.929412f, 0.945098f, 0.960784f, 0.976471f, 0.992157f, 1.0f +}; + +static unsigned short stb__Quantize5(float x) +{ + unsigned short q; + x = x < 0 ? 0 : x > 1 ? 1 : x; // saturate + q = (unsigned short)(x * 31); + q += (x > midpoints5[q]); + return q; +} + +static unsigned short stb__Quantize6(float x) +{ + unsigned short q; + x = x < 0 ? 0 : x > 1 ? 1 : x; // saturate + q = (unsigned short)(x * 63); + q += (x > midpoints6[q]); + return q; +} + +// The refinement function. (Clever code, part 2) +// Tries to optimize colors to suit block contents better. +// (By solving a least squares system via normal equations+Cramer's rule) +static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask) +{ + static const int w1Tab[4] = { 3,0,2,1 }; + static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 }; + // ^some magic to save a lot of multiplies in the accumulating loop... + // (precomputed products of weights for least squares system, accumulated inside one 32-bit register) + + float f; + unsigned short oldMin, oldMax, min16, max16; + int i, akku = 0, xx,xy,yy; + int At1_r,At1_g,At1_b; + int At2_r,At2_g,At2_b; + unsigned int cm = mask; + + oldMin = *pmin16; + oldMax = *pmax16; + + if((mask ^ (mask<<2)) < 4) // all pixels have the same index? + { + // yes, linear system would be singular; solve using optimal + // single-color match on average color + int r = 8, g = 8, b = 8; + for (i=0;i<16;++i) { + r += block[i*4+0]; + g += block[i*4+1]; + b += block[i*4+2]; + } + + r >>= 4; g >>= 4; b >>= 4; + + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + At1_r = At1_g = At1_b = 0; + At2_r = At2_g = At2_b = 0; + for (i=0;i<16;++i,cm>>=2) { + int step = cm&3; + int w1 = w1Tab[step]; + int r = block[i*4+0]; + int g = block[i*4+1]; + int b = block[i*4+2]; + + akku += prods[step]; + At1_r += w1*r; + At1_g += w1*g; + At1_b += w1*b; + At2_r += r; + At2_g += g; + At2_b += b; + } + + At2_r = 3*At2_r - At1_r; + At2_g = 3*At2_g - At1_g; + At2_b = 3*At2_b - At1_b; + + // extract solutions and decide solvability + xx = akku >> 16; + yy = (akku >> 8) & 0xff; + xy = (akku >> 0) & 0xff; + + f = 3.0f / 255.0f / (xx*yy - xy*xy); + + max16 = stb__Quantize5((At1_r*yy - At2_r * xy) * f) << 11; + max16 |= stb__Quantize6((At1_g*yy - At2_g * xy) * f) << 5; + max16 |= stb__Quantize5((At1_b*yy - At2_b * xy) * f) << 0; + + min16 = stb__Quantize5((At2_r*xx - At1_r * xy) * f) << 11; + min16 |= stb__Quantize6((At2_g*xx - At1_g * xy) * f) << 5; + min16 |= stb__Quantize5((At2_b*xx - At1_b * xy) * f) << 0; + } + + *pmin16 = min16; + *pmax16 = max16; + return oldMin != min16 || oldMax != max16; +} + +// Color block compression +static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, int mode) +{ + unsigned int mask; + int i; + int dither; + int refinecount; + unsigned short max16, min16; + unsigned char dblock[16*4],color[4*4]; + + dither = mode & STB_DXT_DITHER; + refinecount = (mode & STB_DXT_HIGHQUAL) ? 2 : 1; + + // check if block is constant + for (i=1;i<16;i++) + if (((unsigned int *) block)[i] != ((unsigned int *) block)[0]) + break; + + if(i == 16) { // constant color + int r = block[0], g = block[1], b = block[2]; + mask = 0xaaaaaaaa; + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + // first step: compute dithered version for PCA if desired + if(dither) + stb__DitherBlock(dblock,block); + + // second step: pca+map along principal axis + stb__OptimizeColorsBlock(dither ? dblock : block,&max16,&min16); + if (max16 != min16) { + stb__EvalColors(color,max16,min16); + mask = stb__MatchColorsBlock(block,color,dither); + } else + mask = 0; + + // third step: refine (multiple times if requested) + for (i=0;i> 8); + dest[2] = (unsigned char) (min16); + dest[3] = (unsigned char) (min16 >> 8); + dest[4] = (unsigned char) (mask); + dest[5] = (unsigned char) (mask >> 8); + dest[6] = (unsigned char) (mask >> 16); + dest[7] = (unsigned char) (mask >> 24); +} + +// Alpha block compression (this is easy for a change) +static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src, int stride) +{ + int i,dist,bias,dist4,dist2,bits,mask; + + // find min/max color + int mn,mx; + mn = mx = src[0]; + + for (i=1;i<16;i++) + { + if (src[i*stride] < mn) mn = src[i*stride]; + else if (src[i*stride] > mx) mx = src[i*stride]; + } + + // encode them + dest[0] = (unsigned char)mx; + dest[1] = (unsigned char)mn; + dest += 2; + + // determine bias and emit color indices + // given the choice of mx/mn, these indices are optimal: + // http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/ + dist = mx-mn; + dist4 = dist*4; + dist2 = dist*2; + bias = (dist < 8) ? (dist - 1) : (dist/2 + 2); + bias -= mn * 7; + bits = 0,mask=0; + + for (i=0;i<16;i++) { + int a = src[i*stride]*7 + bias; + int ind,t; + + // select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max). + t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t; + t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t; + ind += (a >= dist); + + // turn linear scale into DXT index (0/1 are extremal pts) + ind = -ind & 7; + ind ^= (2 > ind); + + // write index + mask |= ind << bits; + if((bits += 3) >= 8) { + *dest++ = (unsigned char)mask; + mask >>= 8; + bits -= 8; + } + } +} + +static void stb__InitDXT() +{ + int i; + for(i=0;i<32;i++) + stb__Expand5[i] = (unsigned char)((i<<3)|(i>>2)); + + for(i=0;i<64;i++) + stb__Expand6[i] = (unsigned char)((i<<2)|(i>>4)); + + for(i=0;i<256+16;i++) + { + int v = i-8 < 0 ? 0 : i-8 > 255 ? 255 : i-8; + stb__QuantRBTab[i] = stb__Expand5[stb__Mul8Bit(v,31)]; + stb__QuantGTab[i] = stb__Expand6[stb__Mul8Bit(v,63)]; + } + + stb__PrepareOptTable(&stb__OMatch5[0][0],stb__Expand5,32); + stb__PrepareOptTable(&stb__OMatch6[0][0],stb__Expand6,64); +} + +void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode) +{ + unsigned char data[16][4]; + static int init=1; + if (init) { + stb__InitDXT(); + init=0; + } + + if (alpha) { + int i; + stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4); + dest += 8; + // make a new copy of the data in which alpha is opaque, + // because code uses a fast test for color constancy + memcpy(data, src, 4*16); + for (i=0; i < 16; ++i) + data[i][3] = 255; + src = &data[0][0]; + } + + stb__CompressColorBlock(dest,(unsigned char*) src,mode); +} + +void stb_compress_bc4_block(unsigned char *dest, const unsigned char *src) +{ + stb__CompressAlphaBlock(dest,(unsigned char*) src, 1); +} + +void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src) +{ + stb__CompressAlphaBlock(dest,(unsigned char*) src,2); + stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2); +} +#endif // STB_DXT_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/Source/Tools/Flax.Build/Build/EngineTarget.cs b/Source/Tools/Flax.Build/Build/EngineTarget.cs index 575d0cdc5..2dd00f9d2 100644 --- a/Source/Tools/Flax.Build/Build/EngineTarget.cs +++ b/Source/Tools/Flax.Build/Build/EngineTarget.cs @@ -99,6 +99,23 @@ namespace Flax.Build // Restore state from PreBuild Modules.Add("Main"); } + + // Mono on Linux is using dynamic linking and needs additional link files + if (buildOptions.Platform.Target == TargetPlatform.Linux) + { + var task = graph.Add(); + task.PrerequisiteFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so")); + task.ProducedFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so.1")); + task.WorkingDirectory = buildOptions.OutputFolder; + task.CommandPath = "ln"; + task.CommandArguments = "-s -f libmonosgen-2.0.so libmonosgen-2.0.so.1"; + task = graph.Add(); + task.PrerequisiteFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so")); + task.ProducedFiles.Add(Path.Combine(buildOptions.OutputFolder, "libmonosgen-2.0.so.1.0.0")); + task.WorkingDirectory = buildOptions.OutputFolder; + task.CommandPath = "ln"; + task.CommandArguments = "-s -f libmonosgen-2.0.so libmonosgen-2.0.so.1.0.0"; + } } private void BuildMainExecutable(TaskGraph graph, BuildOptions buildOptions) diff --git a/Source/Tools/Flax.Build/Deploy/Deployer.cs b/Source/Tools/Flax.Build/Deploy/Deployer.cs index 472a94c22..9b6ac7657 100644 --- a/Source/Tools/Flax.Build/Deploy/Deployer.cs +++ b/Source/Tools/Flax.Build/Deploy/Deployer.cs @@ -103,9 +103,10 @@ namespace Flax.Deploy private static void BuildEditor() { - FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", TargetPlatform.Windows, TargetArchitecture.x64, TargetConfiguration.Debug); - FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", TargetPlatform.Windows, TargetArchitecture.x64, TargetConfiguration.Development); - FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", TargetPlatform.Windows, TargetArchitecture.x64, TargetConfiguration.Release); + var targetPlatform = Platform.BuildPlatform.Target; + FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Debug); + FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Development); + FlaxBuild.Build(Globals.EngineRoot, "FlaxEditor", targetPlatform, TargetArchitecture.x64, TargetConfiguration.Release); } private static bool CannotBuildPlatform(TargetPlatform platform) diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs index b545f844d..8164214cc 100644 --- a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs +++ b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs @@ -50,6 +50,10 @@ namespace Flax.Deploy { DeployFolder(RootPath, OutputPath, "Source/Platforms/Editor/Windows/Mono"); } + else if (Platform.BuildPlatform.Target == TargetPlatform.Linux) + { + DeployFolder(RootPath, OutputPath, "Source/Platforms/Editor/Linux/Mono"); + } else { throw new NotImplementedException(); @@ -120,18 +124,21 @@ namespace Flax.Deploy } Log.Info("Compressed editor package size: " + Utilities.GetFileSize(editorPackageZipPath)); - Log.Info("Compressing editor debug symbols files..."); - editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols.zip"); - using (ZipFile zip = new ZipFile()) + if (Platform.BuildPlatform.Target == TargetPlatform.Windows) { - zip.AddDirectory(Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols")); + Log.Info("Compressing editor debug symbols files..."); + editorPackageZipPath = Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols.zip"); + using (ZipFile zip = new ZipFile()) + { + zip.AddDirectory(Path.Combine(Deployer.PackageOutputPath, "EditorDebugSymbols")); - zip.CompressionLevel = CompressionLevel.BestCompression; - zip.Comment = string.Format("Flax Editor {0}.{1}.{2}\nDate: {3}", Deployer.VersionMajor, Deployer.VersionMinor, Deployer.VersionBuild, DateTime.UtcNow); + zip.CompressionLevel = CompressionLevel.BestCompression; + zip.Comment = string.Format("Flax Editor {0}.{1}.{2}\nDate: {3}", Deployer.VersionMajor, Deployer.VersionMinor, Deployer.VersionBuild, DateTime.UtcNow); - zip.Save(editorPackageZipPath); + zip.Save(editorPackageZipPath); + } + Log.Info("Compressed editor debug symbols package size: " + Utilities.GetFileSize(editorPackageZipPath)); } - Log.Info("Compressed editor debug symbols package size: " + Utilities.GetFileSize(editorPackageZipPath)); // Cleanup Utilities.DirectoryDelete(OutputPath); @@ -171,6 +178,25 @@ namespace Flax.Deploy File.Delete(Path.Combine(dstDebug, "FlaxEngine.CSharp.pdb")); File.Delete(Path.Combine(dstDebug, "Newtonsoft.Json.pdb")); } + else if (Platform.BuildPlatform.Target == TargetPlatform.Linux) + { + var binariesSubDir = "Binaries/Editor/Linux/" + configuration; + var src = Path.Combine(RootPath, binariesSubDir); + var dst = Path.Combine(OutputPath, binariesSubDir); + Directory.CreateDirectory(dst); + + // Deploy binaries + DeployFile(src, dst, "FlaxEditor"); + DeployFile(src, dst, "FlaxEditor.Build.json"); + DeployFile(src, dst, "FlaxEngine.CSharp.pdb"); + DeployFile(src, dst, "FlaxEngine.CSharp.xml"); + DeployFile(src, dst, "Newtonsoft.Json.pdb"); + DeployFiles(src, dst, "*.dll"); + DeployFiles(src, dst, "*.so"); + DeployFile(src, dst, "libmonosgen-2.0.so.1"); + DeployFile(src, dst, "libmonosgen-2.0.so.1.0.0"); + DeployFile(src, dst, "Logo.png"); + } else { throw new NotImplementedException(); diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs index 5e8346fe3..abb8b47f0 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs @@ -76,9 +76,10 @@ namespace Flax.Deps.Dependencies RunCmake(root, TargetPlatform.Linux, TargetArchitecture.x64, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DASSIMP_NO_EXPORT=ON -DASSIMP_BUILD_ASSIMP_TOOLS=OFF -DASSIMP_BUILD_TESTS=OFF"); Utilities.Run("make", null, null, root, Utilities.RunOptions.None); var depsFolder = GetThirdPartyFolder(options, TargetPlatform.Linux, TargetArchitecture.x64); - var libName = "libassimp.so.4.1.0"; - Utilities.FileCopy(Path.Combine(root, "lib", libName), Path.Combine(depsFolder, libName)); - Utilities.Run("strip", libName, null, depsFolder, Utilities.RunOptions.None); + var srcName = "libassimp.so.4.1.0"; + var dstName = "libassimp.so"; + Utilities.FileCopy(Path.Combine(root, "lib", srcName), Path.Combine(depsFolder, dstName)); + Utilities.Run("strip", dstName, null, depsFolder, Utilities.RunOptions.None); break; } }