Merge remote-tracking branch 'origin/1.1' into 1.2

# Conflicts:
#	Source/Editor/Editor.Build.cs
This commit is contained in:
Wojtek Figat
2021-03-15 09:38:58 +01:00
86 changed files with 4242 additions and 317 deletions

12
PackageEditor.sh Executable file
View 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" "$@"

View File

@@ -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" "$@"

View File

@@ -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)
{

View File

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

View File

@@ -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))

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)

View File

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

View File

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

View File

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

View File

@@ -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>

View File

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

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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 =

View File

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

View File

@@ -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>

View File

@@ -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 />

View File

@@ -371,7 +371,7 @@ namespace FlaxEditor.Windows
// Focus content window
Focus();
RootWindow?.Window.Focus();
RootWindow?.Focus();
}
// Refresh database and view now

View File

@@ -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>

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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

View File

@@ -156,9 +156,9 @@ void Log::Logger::Dispose()
WriteFloor();
// Close
LogAfterInit = false;
if (LogAfterInit)
{
LogAfterInit = false;
LogFile->Close();
Delete(LogFile);
LogFile = nullptr;

View File

@@ -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));

View File

@@ -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
{

View File

@@ -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()

View File

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

View File

@@ -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>

View File

@@ -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 |

View File

@@ -100,7 +100,6 @@ private:
UWPWindowImpl* _impl;
float _dpi, _dpiScale;
Vector2 _logicalSize;
public:

View File

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

View File

@@ -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();

View File

@@ -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);

View File

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

View File

@@ -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);

View File

@@ -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

View File

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

View File

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

View File

@@ -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

View File

@@ -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)

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

View File

@@ -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

View File

@@ -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");

View File

@@ -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);
},
},
{

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);

View File

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

View File

@@ -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).

View File

@@ -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)

View File

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

View File

@@ -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 />

View File

@@ -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);

View File

@@ -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))

View File

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

View File

@@ -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

Binary file not shown.

View File

@@ -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

Binary file not shown.

View File

@@ -1 +0,0 @@
libassimp.so.4.1.0

BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.so (Stored with Git LFS) vendored Executable file

Binary file not shown.

View File

@@ -1 +0,0 @@
libassimp.so.4.1.0

View File

@@ -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

Binary file not shown.

View File

@@ -1 +0,0 @@
libmonosgen-2.0.so.1.0.0

View File

@@ -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
View 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.

View 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
View 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

File diff suppressed because it is too large Load Diff

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

View File

@@ -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
View 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.
------------------------------------------------------------------------------
*/

View File

@@ -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)

View File

@@ -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)

View File

@@ -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();

View File

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