Merge remote-tracking branch 'origin/1.1' into 1.2
# Conflicts: # Source/Editor/Editor.Build.cs
This commit is contained in:
12
PackageEditor.sh
Executable file
12
PackageEditor.sh
Executable file
@@ -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" "$@"
|
||||
@@ -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" "$@"
|
||||
|
||||
@@ -75,6 +75,8 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
}
|
||||
|
||||
public int MetadataToken => 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAttribute(Type attributeType, bool inherit)
|
||||
{
|
||||
@@ -195,6 +197,8 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public ScriptType ValueType => _returnType;
|
||||
|
||||
public int MetadataToken => 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAttribute(Type attributeType, bool inherit)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -101,7 +101,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
// Deploy files
|
||||
Array<String> 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<UniformGridPanel> UniformGridTwoByOne(LayoutElementsContainer cont)
|
||||
{
|
||||
var horUp = cont.CustomContainer<UniformGridPanel>();
|
||||
horUp.CustomControl.SlotsHorizontally = 2;
|
||||
horUp.CustomControl.SlotsVertically = 1;
|
||||
horUp.CustomControl.SlotPadding = Margin.Zero;
|
||||
horUp.CustomControl.ClipChildren = false;
|
||||
return horUp;
|
||||
}
|
||||
|
||||
private CustomElementsContainer<UniformGridPanel> UniformPanelCapsuleForObjectWithText(LayoutElementsContainer el, string text, ValueContainer values)
|
||||
{
|
||||
CustomElementsContainer<UniformGridPanel> 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;
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes if equality of anchors does not correspond to the cached equality
|
||||
/// </summary>
|
||||
public void RefreshBaseOnAnchorsEquality()
|
||||
{
|
||||
if (Values.HasNull)
|
||||
return;
|
||||
|
||||
GetAnchorEquality(out bool xEq, out bool yEq, ValuesTypes);
|
||||
if (xEq != _cachedXEq || yEq != _cachedYEq)
|
||||
{
|
||||
RebuildLayout();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -68,6 +68,24 @@ namespace FlaxEditor.Options
|
||||
CompileScripts,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Order of script members show in editor
|
||||
/// </summary>
|
||||
public enum MembersOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows properties/fields in alphabetical order
|
||||
/// </summary>
|
||||
[Tooltip("Shows properties/fields in alphabetical order")]
|
||||
Alphabetical,
|
||||
|
||||
/// <summary>
|
||||
/// Shows properties/fields in declaration order
|
||||
/// </summary>
|
||||
[Tooltip("Shows properties/fields in declaration order")]
|
||||
Declaration
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the scene to load on editor startup.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an order of script properties/fields in properties panel.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether automatically save the Visual Script asset editors when starting the play mode in editor.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the mouse wheel sensitivity applied to zoom in orthographic mode.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default movement speed for the viewport camera (must match the dropdown menu values in the viewport).
|
||||
/// </summary>
|
||||
|
||||
@@ -40,6 +40,27 @@ namespace FlaxEditor.Scripting
|
||||
/// </summary>
|
||||
public string Name => _managed?.Name ?? _custom?.Name;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a metadata token for sorting so it may not be the actual token.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is declared public.
|
||||
/// </summary>
|
||||
@@ -1444,6 +1465,11 @@ namespace FlaxEditor.Scripting
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a metadata token for sorting so it may not be the actual token.
|
||||
/// </summary>
|
||||
int MetadataToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is declared public.
|
||||
/// </summary>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -1646,8 +1646,8 @@ namespace FlaxEditor.Utilities
|
||||
/// </summary>
|
||||
/// <param name="source">The source code.</param>
|
||||
/// <param name="title">The window title.</param>
|
||||
/// <param name="control">The context control used to show source code window popup in a proper location.</param>
|
||||
public static void ShowSourceCodeWindow(string source, string title, Control control = null)
|
||||
/// <param name="parentWindow">The optional parent window.</param>
|
||||
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);
|
||||
|
||||
|
||||
@@ -88,6 +88,17 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
Editor.GetActorEditorSphere(actor, out BoundingSphere sphere);
|
||||
ShowSphere(ref sphere);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the viewport to visualize selected actors.
|
||||
/// </summary>
|
||||
/// <param name="actor">The actors to show.</param>
|
||||
/// <param name="orientation">The used orientation.</param>
|
||||
public void ShowActor(Actor actor, ref Quaternion orientation)
|
||||
{
|
||||
Editor.GetActorEditorSphere(actor, out BoundingSphere sphere);
|
||||
ShowSphere(ref sphere, ref orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the viewport to visualize selected actors.
|
||||
@@ -111,17 +122,50 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
ShowSphere(ref mergesSphere);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the viewport to visualize selected actors.
|
||||
/// </summary>
|
||||
/// <param name="actors">The actors to show.</param>
|
||||
/// <param name="orientation">The used orientation.</param>
|
||||
public void ShowActors(List<SceneGraphNode> 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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -371,7 +371,7 @@ namespace FlaxEditor.Windows
|
||||
|
||||
// Focus content window
|
||||
Focus();
|
||||
RootWindow?.Window.Focus();
|
||||
RootWindow?.Focus();
|
||||
}
|
||||
|
||||
// Refresh database and view now
|
||||
|
||||
@@ -243,7 +243,13 @@ namespace FlaxEditor.Windows
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -156,9 +156,9 @@ void Log::Logger::Dispose()
|
||||
WriteFloor();
|
||||
|
||||
// Close
|
||||
LogAfterInit = false;
|
||||
if (LogAfterInit)
|
||||
{
|
||||
LogAfterInit = false;
|
||||
LogFile->Close();
|
||||
Delete(LogFile);
|
||||
LogFile = nullptr;
|
||||
|
||||
@@ -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<IUnknown*>(_windowHandle), &swapChainDesc, nullptr, &_swapChain));
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -6,10 +6,14 @@
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include <Engine/Main/Android/android_native_app_glue.h>
|
||||
|
||||
#define DefaultDPI 96
|
||||
|
||||
AndroidWindow::AndroidWindow(const CreateWindowSettings& settings)
|
||||
: WindowBase(settings)
|
||||
{
|
||||
_clientSize = settings.Size;
|
||||
_dpi = DefaultDPI;
|
||||
_dpiScale = (float)_dpi / (float)DefaultDPI;
|
||||
}
|
||||
|
||||
AndroidWindow::~AndroidWindow()
|
||||
|
||||
@@ -569,17 +569,17 @@ public:
|
||||
API_PROPERTY() static BatteryInfo GetBatteryInfo();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the screen DPI setting.
|
||||
/// Gets the primary monitor's DPI setting.
|
||||
/// </summary>
|
||||
API_PROPERTY() static int32 GetDpi();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
API_PROPERTY() static float GetDpiScale();
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
API_FIELD() static float CustomDpiScale;
|
||||
|
||||
|
||||
@@ -281,6 +281,8 @@ protected:
|
||||
String _title;
|
||||
CursorType _cursor;
|
||||
Vector2 _clientSize;
|
||||
int _dpi;
|
||||
float _dpiScale;
|
||||
|
||||
Vector2 _trackingMouseOffset;
|
||||
bool _isUsingMouseOffset;
|
||||
@@ -542,6 +544,21 @@ public:
|
||||
/// <returns>The screen space position.</returns>
|
||||
API_FUNCTION() virtual Vector2 ClientToScreen(const Vector2& clientPos) const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window DPI setting.
|
||||
/// </summary>
|
||||
API_PROPERTY() int GetDpi() const
|
||||
{
|
||||
return _dpi;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window DPI scale factor (1 is default). Includes custom DPI scale
|
||||
/// </summary>
|
||||
API_PROPERTY() float GetDpiScale() const
|
||||
{
|
||||
return Platform::CustomDpiScale * _dpiScale;
|
||||
}
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -100,7 +100,6 @@ private:
|
||||
|
||||
UWPWindowImpl* _impl;
|
||||
|
||||
float _dpi, _dpiScale;
|
||||
Vector2 _logicalSize;
|
||||
|
||||
public:
|
||||
|
||||
@@ -7,8 +7,6 @@ namespace FlaxEngine
|
||||
{
|
||||
partial class Window
|
||||
{
|
||||
internal float _dpiScale;
|
||||
|
||||
/// <summary>
|
||||
/// Window closing delegate.
|
||||
/// </summary>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "../Win32/IncludeWindowsHeaders.h"
|
||||
#include <propidl.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -508,8 +508,9 @@ bool MCore::LoadEngine()
|
||||
Thread::ThreadExiting.Bind<OnThreadExiting>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
/// <param name="input">The object.</param>
|
||||
/// <param name="jsonBuffer">The input json data buffer (raw, fixed memory buffer).</param>
|
||||
/// <param name="jsonLength">The input json data buffer length (characters count).</param>
|
||||
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)
|
||||
|
||||
157
Source/Engine/Serialization/UnmanagedMemoryStream.cs
Normal file
157
Source/Engine/Serialization/UnmanagedMemoryStream.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements a <see cref="T:System.IO.Stream" /> that reads from unmanaged buffer (provided as raw pointer and length).
|
||||
/// </summary>
|
||||
internal class UnmanagedMemoryStream : Stream
|
||||
{
|
||||
private unsafe byte* _ptr;
|
||||
private int _length;
|
||||
private int _pos;
|
||||
private FileAccess _access;
|
||||
internal bool _isOpen;
|
||||
private Task<int> _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<int> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -218,7 +218,7 @@ public:
|
||||
/// <param name="y">The Y texture coordinates (normalized to range 0-height).</param>
|
||||
/// <param name="data">The data pointer for the texture slice (1D or 2D image).</param>
|
||||
/// <param name="rowPitch">The row pitch (in bytes). The offset between each image rows.</param>
|
||||
/// <param name="color">The color to store.</param>
|
||||
/// <param name="color">The color to store (linear).</param>
|
||||
static void Store(const PixelFormatSampler* sampler, int32 x, int32 y, const void* data, int32 rowPitch, const Color& color);
|
||||
|
||||
/// <summary>
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
/// <param name="data">The data pointer for the texture slice (1D or 2D image).</param>
|
||||
/// <param name="size">The size of the input texture (in pixels).</param>
|
||||
/// <param name="rowPitch">The row pitch (in bytes). The offset between each image rows.</param>
|
||||
/// <returns>The sampled color.</returns>
|
||||
/// <returns>The sampled color (linear).</returns>
|
||||
static Color SamplePoint(const PixelFormatSampler* sampler, const Vector2& uv, const void* data, const Int2& size, int32 rowPitch);
|
||||
|
||||
/// <summary>
|
||||
@@ -246,7 +246,7 @@ public:
|
||||
/// <param name="y">The Y texture coordinates (normalized to range 0-height).</param>
|
||||
/// <param name="data">The data pointer for the texture slice (1D or 2D image).</param>
|
||||
/// <param name="rowPitch">The row pitch (in bytes). The offset between each image rows.</param>
|
||||
/// <returns>The sampled color.</returns>
|
||||
/// <returns>The sampled color (linear).</returns>
|
||||
static Color SamplePoint(const PixelFormatSampler* sampler, int32 x, int32 y, const void* data, int32 rowPitch);
|
||||
|
||||
/// <summary>
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
/// <param name="data">The data pointer for the texture slice (1D or 2D image).</param>
|
||||
/// <param name="size">The size of the input texture (in pixels).</param>
|
||||
/// <param name="rowPitch">The row pitch (in bytes). The offset between each image rows.</param>
|
||||
/// <returns>The sampled color.</returns>
|
||||
/// <returns>The sampled color (linear).</returns>
|
||||
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
|
||||
};
|
||||
|
||||
@@ -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 <ThirdParty/stb/stb_image_resize.h>
|
||||
|
||||
#define STBD_ABS(i) Math::Abs(i)
|
||||
#define STBD_FABS(x) Math::Abs(x)
|
||||
#define STB_DXT_IMPLEMENTATION
|
||||
#include <ThirdParty/stb/stb_dxt.h>
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include <ThirdParty/detex/detex.h>
|
||||
|
||||
#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<byte> 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<int32>(sourceWidth * options.Scale), 1, options.MaxSize);
|
||||
int32 height = Math::Clamp(options.Resize ? options.SizeY : static_cast<int32>(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<float>(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<int32>(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<int32>(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<int32>(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<int32>(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<int32>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine.Assertions;
|
||||
|
||||
namespace FlaxEngine.GUI
|
||||
{
|
||||
/// <summary>
|
||||
@@ -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);
|
||||
|
||||
@@ -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).
|
||||
/// </summary>
|
||||
[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).
|
||||
/// </summary>
|
||||
[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.
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// Helper for Editor UI (see UIControlControlEditor).
|
||||
/// </summary>
|
||||
[NoSerialize, HideInEditor]
|
||||
internal float Proxy_Offset_Left
|
||||
{
|
||||
get => Offsets.Left;
|
||||
set => Offsets = new Margin(value, Offsets.Right, Offsets.Top, Offsets.Bottom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for Editor UI (see UIControlControlEditor).
|
||||
/// </summary>
|
||||
[NoSerialize, HideInEditor]
|
||||
internal float Proxy_Offset_Right
|
||||
{
|
||||
get => Offsets.Right;
|
||||
set => Offsets = new Margin(Offsets.Left, value, Offsets.Top, Offsets.Bottom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for Editor UI (see UIControlControlEditor).
|
||||
/// </summary>
|
||||
[NoSerialize, HideInEditor]
|
||||
internal float Proxy_Offset_Top
|
||||
{
|
||||
get => Offsets.Top;
|
||||
set => Offsets = new Margin(Offsets.Left, Offsets.Right, value, Offsets.Bottom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for Editor UI (see UIControlControlEditor).
|
||||
/// </summary>
|
||||
[NoSerialize, HideInEditor]
|
||||
internal float Proxy_Offset_Bottom
|
||||
{
|
||||
get => Offsets.Bottom;
|
||||
set => Offsets = new Margin(Offsets.Left, Offsets.Right, Offsets.Top, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets coordinates of the upper-left corner of the control relative to the upper-left corner of its container.
|
||||
/// </summary>
|
||||
[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.
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// Gets or sets the scale.
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// Gets or sets the shear transform angles (x, y). Defined in degrees.
|
||||
/// </summary>
|
||||
[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
|
||||
/// <summary>
|
||||
/// Gets or sets the rotation angle (in degrees).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
@@ -176,7 +176,7 @@ namespace FlaxEngine.GUI
|
||||
/// Gets or sets the anchor preset used by the control anchors (based on <see cref="AnchorMin"/> and <see cref="AnchorMax"/>).
|
||||
/// </summary>
|
||||
/// <remarks>To change anchor preset with current control bounds preservation use <see cref="SetAnchorPreset"/>.</remarks>
|
||||
[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
|
||||
/// <summary>
|
||||
/// Gets the GUI window root control which contains that control (or null if not linked to any).
|
||||
/// </summary>
|
||||
public virtual WindowRootControl RootWindow => _parent?.RootWindow;
|
||||
public virtual WindowRootControl RootWindow => _root?.RootWindow;
|
||||
|
||||
/// <summary>
|
||||
/// Gets screen position of the control (upper left corner).
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace FlaxEngine.GUI
|
||||
/// </summary>
|
||||
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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@ namespace FlaxEngine.GUI
|
||||
/// </summary>
|
||||
public bool IsMaximized => _window.IsMaximized;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window DPI scale factor (1 is default). Includes custom DPI scale
|
||||
/// </summary>
|
||||
public float DpiScale => _window.DpiScale;
|
||||
|
||||
internal WindowRootControl(Window window)
|
||||
{
|
||||
_window = window;
|
||||
@@ -151,7 +156,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Vector2 TrackingMouseOffset => _window.TrackingMouseOffset / _window._dpiScale;
|
||||
public override Vector2 TrackingMouseOffset => _window.TrackingMouseOffset / _window.DpiScale;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override WindowRootControl RootWindow => this;
|
||||
@@ -159,8 +164,8 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -234,13 +239,13 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override Vector2 PointFromScreen(Vector2 location)
|
||||
{
|
||||
return _window.ScreenToClient(location) / _window._dpiScale;
|
||||
return _window.ScreenToClient(location) / _window.DpiScale;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Vector2 PointToScreen(Vector2 location)
|
||||
{
|
||||
return _window.ClientToScreen(location * _window._dpiScale);
|
||||
return _window.ClientToScreen(location * _window.DpiScale);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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<MaterialInstance>();
|
||||
@@ -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);
|
||||
|
||||
@@ -232,20 +232,30 @@ namespace FlaxEngine
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GraphemeClusters(this string s)
|
||||
{
|
||||
var enumerator = System.Globalization.StringInfo.GetTextElementEnumerator(s);
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
yield return (string)enumerator.Current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverses the specified input string.
|
||||
/// </summary>
|
||||
/// <remarks>Correctly handles all UTF-16 strings</remarks>
|
||||
/// <param name="s">The string to reverse.</param>
|
||||
/// <returns>The reversed string.</returns>
|
||||
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+)\\)$");
|
||||
|
||||
/// <summary>
|
||||
/// 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 '<name><num>' 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 '<name> (<num>)' 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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
libmono-native.so.0.0.0
|
||||
BIN
Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so
(Stored with Git LFS)
Normal file
BIN
Source/Platforms/Editor/Linux/Mono/lib/libmono-native.so
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
libmono-native.so.0.0.0
|
||||
BIN
Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so
(Stored with Git LFS)
Normal file
BIN
Source/Platforms/Linux/Binaries/Mono/lib/libmono-native.so
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
libassimp.so.4.1.0
|
||||
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so
(Stored with Git LFS)
vendored
Executable file
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so
(Stored with Git LFS)
vendored
Executable file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
libassimp.so.4.1.0
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
libmonosgen-2.0.so.1.0.0
|
||||
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so
(Stored with Git LFS)
vendored
Executable file
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libmonosgen-2.0.so
(Stored with Git LFS)
vendored
Executable file
Binary file not shown.
@@ -1 +0,0 @@
|
||||
libmonosgen-2.0.so.1.0.0
|
||||
Binary file not shown.
2
Source/ThirdParty/assimp/assimp.Build.cs
vendored
2
Source/ThirdParty/assimp/assimp.Build.cs
vendored
@@ -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);
|
||||
|
||||
14
Source/ThirdParty/detex/LICENSE
vendored
Normal file
14
Source/ThirdParty/detex/LICENSE
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
|
||||
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.
|
||||
|
||||
241
Source/ThirdParty/detex/decompress-bc.cpp
vendored
Normal file
241
Source/ThirdParty/detex/decompress-bc.cpp
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
21
Source/ThirdParty/detex/detex.Build.cs
vendored
Normal file
21
Source/ThirdParty/detex/detex.Build.cs
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using Flax.Build;
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/hglm/detex
|
||||
/// </summary>
|
||||
public class detex : ThirdPartyModule
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
LicenseType = LicenseTypes.MIT;
|
||||
LicenseFilePath = "LICENSE";
|
||||
|
||||
// Merge third-party modules into engine binary
|
||||
BinaryModuleName = "FlaxEngine";
|
||||
}
|
||||
}
|
||||
1194
Source/ThirdParty/detex/detex.h
vendored
Normal file
1194
Source/ThirdParty/detex/detex.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
512
Source/ThirdParty/detex/division-tables.cpp
vendored
Normal file
512
Source/ThirdParty/detex/division-tables.cpp
vendored
Normal file
@@ -0,0 +1,512 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015 Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
2
Source/ThirdParty/mono-2.0/mono.Build.cs
vendored
2
Source/ThirdParty/mono-2.0/mono.Build.cs
vendored
@@ -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:
|
||||
|
||||
753
Source/ThirdParty/stb/stb_dxt.h
vendored
Normal file
753
Source/ThirdParty/stb/stb_dxt.h
vendored
Normal file
@@ -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 <stdlib.h>
|
||||
|
||||
#if !defined(STBD_ABS) || !defined(STBI_FABS)
|
||||
#include <math.h>
|
||||
#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 <string.h>
|
||||
#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<size;mn++) {
|
||||
for (mx=0;mx<size;mx++) {
|
||||
int mine = expand[mn];
|
||||
int maxe = expand[mx];
|
||||
int err = STBD_ABS(stb__Lerp13(maxe, mine) - i);
|
||||
|
||||
// DX10 spec says that interpolation must be within 3% of "correct" result,
|
||||
// add this as error term. (normally we'd expect a random distribution of
|
||||
// +-1.5% error, but nowhere in the spec does it say that the error has to be
|
||||
// unbiased - better safe than sorry).
|
||||
err += STBD_ABS(maxe - mine) * 3 / 100;
|
||||
|
||||
if(err < bestErr)
|
||||
{
|
||||
Table[i*2+0] = (unsigned char)mx;
|
||||
Table[i*2+1] = (unsigned char)mn;
|
||||
bestErr = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stb__EvalColors(unsigned char *color,unsigned short c0,unsigned short c1)
|
||||
{
|
||||
stb__From16Bit(color+ 0, c0);
|
||||
stb__From16Bit(color+ 4, c1);
|
||||
stb__Lerp13RGB(color+ 8, color+0, color+4);
|
||||
stb__Lerp13RGB(color+12, color+4, color+0);
|
||||
}
|
||||
|
||||
// Block dithering function. Simply dithers a block to 565 RGB.
|
||||
// (Floyd-Steinberg)
|
||||
static void stb__DitherBlock(unsigned char *dest, unsigned char *block)
|
||||
{
|
||||
int err[8],*ep1 = err,*ep2 = err+4, *et;
|
||||
int ch,y;
|
||||
|
||||
// process channels separately
|
||||
for (ch=0; ch<3; ++ch) {
|
||||
unsigned char *bp = block+ch, *dp = dest+ch;
|
||||
unsigned char *quant = (ch == 1) ? stb__QuantGTab+8 : stb__QuantRBTab+8;
|
||||
STBD_MEMSET(err, 0, sizeof(err));
|
||||
for(y=0; y<4; ++y) {
|
||||
dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 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<nIterPower;iter++)
|
||||
{
|
||||
float r = vfr*covf[0] + vfg*covf[1] + vfb*covf[2];
|
||||
float g = vfr*covf[1] + vfg*covf[3] + vfb*covf[4];
|
||||
float b = vfr*covf[2] + vfg*covf[4] + vfb*covf[5];
|
||||
|
||||
vfr = r;
|
||||
vfg = g;
|
||||
vfb = b;
|
||||
}
|
||||
|
||||
magn = STBD_FABS(vfr);
|
||||
if (STBD_FABS(vfg) > 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<refinecount;i++) {
|
||||
unsigned int lastmask = mask;
|
||||
|
||||
if (stb__RefineBlock(dither ? dblock : block,&max16,&min16,mask)) {
|
||||
if (max16 != min16) {
|
||||
stb__EvalColors(color,max16,min16);
|
||||
mask = stb__MatchColorsBlock(block,color,dither);
|
||||
} else {
|
||||
mask = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(mask == lastmask)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the color block
|
||||
if(max16 < min16)
|
||||
{
|
||||
unsigned short t = min16;
|
||||
min16 = max16;
|
||||
max16 = t;
|
||||
mask ^= 0x55555555;
|
||||
}
|
||||
|
||||
dest[0] = (unsigned char) (max16);
|
||||
dest[1] = (unsigned char) (max16 >> 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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -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>();
|
||||
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>();
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user