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;
}
}