Merge branch 'master' into ImprovementSlider
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Repo Purpose
|
||||
|
||||
Flax Engine is a modern 3D game engine written in C++ and C#.
|
||||
This repository contains the engine, editor, tooling, shaders, tests, assets, and platform-specific sources, excluding NDA-protected platform support.
|
||||
|
||||
## High-Level Structure
|
||||
|
||||
- `Source/Engine/`: engine runtime code and managed/runtime integration.
|
||||
- `Source/Editor/`: editor code in both C++ and C#.
|
||||
- `Source/Tools/`: build system and developer tooling, including `Flax.Build`.
|
||||
- `Source/Platforms/`: platform-specific code, dependencies, and binaries.
|
||||
- `Source/ThirdParty/`: vendored third-party code. Avoid changes here unless the task explicitly requires it.
|
||||
- `Source/Engine/Tests/`: native and managed engine tests.
|
||||
- `Source/Tools/Flax.Build.Tests/`: .NET tests for the build tool.
|
||||
- `Content/`: engine/editor assets.
|
||||
- `Development/Scripts/`: helper scripts for project generation and builds.
|
||||
|
||||
## Working Assumptions
|
||||
|
||||
- Generated solutions and project files are not committed. On a clean clone, generate them first.
|
||||
- Git LFS is required. The Windows build scripts explicitly check for LFS-populated files.
|
||||
- On Windows, the main entry points are `GenerateProjectFiles.bat` and `Development\Scripts\Windows\CallBuildTool.bat`.
|
||||
- Prefer edits in `Source/Engine`, `Source/Editor`, `Source/Tools`, or docs. Do not modify `Binaries/`, `Cache/`, or generated project files unless the task explicitly targets generated output.
|
||||
|
||||
## Windows Setup And Build
|
||||
|
||||
Use these commands from the repo root.
|
||||
|
||||
Generate project files:
|
||||
|
||||
```powershell
|
||||
.\GenerateProjectFiles.bat -vs2022 -log -verbose -printSDKs -dotnet=8
|
||||
```
|
||||
|
||||
Alternative default generation:
|
||||
|
||||
```powershell
|
||||
.\GenerateProjectFiles.bat
|
||||
```
|
||||
|
||||
Build the editor target:
|
||||
|
||||
```powershell
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
|
||||
```
|
||||
|
||||
Run the editor:
|
||||
|
||||
```powershell
|
||||
.\Binaries\Editor\Win64\Development\FlaxEditor.exe
|
||||
```
|
||||
|
||||
Visual Studio workflow after generation:
|
||||
|
||||
- Open `Flax.sln`.
|
||||
- Use solution configuration `Editor.Development` and platform `Win64`.
|
||||
- Set `Flax` or `FlaxEngine` as the startup project.
|
||||
|
||||
## Tests And Validation
|
||||
|
||||
The checked-in CI workflow in `.github/workflows/tests.yml` is the most reliable source for current validation commands.
|
||||
|
||||
Build native tests:
|
||||
|
||||
```powershell
|
||||
.\Development\Scripts\Windows\CallBuildTool.bat -build -log -dotnet=8 -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxTestsTarget
|
||||
```
|
||||
|
||||
Run native tests:
|
||||
|
||||
```powershell
|
||||
.\Binaries\Editor\Win64\Development\FlaxTests.exe -headless
|
||||
```
|
||||
|
||||
Build Flax.Build tests:
|
||||
|
||||
```powershell
|
||||
dotnet msbuild Source\Tools\Flax.Build.Tests\Flax.Build.Tests.csproj /m /t:Restore,Build /p:Configuration=Debug /p:Platform=AnyCPU /nologo
|
||||
```
|
||||
|
||||
Run Flax.Build tests:
|
||||
|
||||
```powershell
|
||||
dotnet test -f net8.0 Binaries\Tests\Flax.Build.Tests.dll
|
||||
```
|
||||
|
||||
Run managed engine tests after copying runtime dependencies:
|
||||
|
||||
```powershell
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.dll Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\FlaxEngine.CSharp.runtimeconfig.json Binaries\Tests
|
||||
xcopy /y Binaries\Editor\Win64\Development\Newtonsoft.Json.dll Binaries\Tests
|
||||
dotnet test -f net8.0 Binaries\Tests\FlaxEngine.CSharp.dll
|
||||
```
|
||||
|
||||
If a change is localized, prefer the narrowest possible target build and only run the relevant tests for that area.
|
||||
|
||||
## Style And Conventions
|
||||
|
||||
- The root `Source/.editorconfig` sets CRLF line endings, UTF-8, final newline, and spaces for indentation.
|
||||
- Use 4 spaces for C++, C#, shaders, and Python. Use 2 spaces for XAML and MSBuild files.
|
||||
- Keep the existing copyright header in source files.
|
||||
- Public APIs in both C++ headers and C# commonly use XML-style documentation comments such as `/// <summary>`.
|
||||
- Preserve local file style instead of mass-normalizing. The C# codebase mixes block namespaces and file-scoped namespaces.
|
||||
- Follow existing naming patterns: PascalCase for types and public members; private C# fields often use `_camelCase`.
|
||||
- In C++ headers, prefer forward declarations where practical and keep includes minimal.
|
||||
|
||||
## Build System Notes
|
||||
|
||||
- `FlaxEditor` is the main standalone editor target.
|
||||
- `FlaxGame` is the standalone game target.
|
||||
- `FlaxTestsTarget` builds the native test executable.
|
||||
- `Flax.Build` supports project generation switches such as `-vs2022`, `-vs2026`, `-vscode`, and `-rider`.
|
||||
- `GenerateProjectFiles.bat` also builds C# bindings for `FlaxEditor` on Windows.
|
||||
|
||||
## Agent Guidance
|
||||
|
||||
- Treat `.github/workflows/tests.yml` as the source of truth for CI-backed validation.
|
||||
- Do not assume generated artifacts already exist in the repo.
|
||||
- Avoid broad style-only rewrites.
|
||||
- Avoid touching `Source/ThirdParty/` unless explicitly requested.
|
||||
- If a change affects developer workflow or build/test steps, update the relevant root docs as part of the task.
|
||||
- No dedicated repo-wide formatter or linter command is checked in. Prefer build and test validation over inventing formatting steps.
|
||||
- PVS-Studio is mentioned in `README.md`, but it is not wired here as a standard local validation command.
|
||||
@@ -239,7 +239,7 @@ String CookingData::GetGameBinariesPath() const
|
||||
archDir = TEXT("ARM64");
|
||||
break;
|
||||
default:
|
||||
CRASH;
|
||||
CRASH;
|
||||
return String::Empty;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,6 @@ bool ValidateStep::Perform(CookingData& data)
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: validate version
|
||||
|
||||
AssetInfo info;
|
||||
if (!Content::GetAssetInfo(gameSettings->FirstScene, info))
|
||||
{
|
||||
@@ -79,9 +77,5 @@ bool ValidateStep::Perform(CookingData& data)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: validate more game config
|
||||
|
||||
// TODO: validate all input scenes?
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -654,7 +654,7 @@ Window* Editor::CreateMainWindow()
|
||||
PROFILE_MEM(Editor);
|
||||
Window* window = Managed->GetMainWindow();
|
||||
|
||||
#if PLATFORM_LINUX || (PLATFORM_MAC && PLATFORM_SDL)
|
||||
#if PLATFORM_LINUX || PLATFORM_MAC
|
||||
// Set window icon
|
||||
const String iconPath = Globals::BinariesFolder / TEXT("Logo.png");
|
||||
if (FileSystem::FileExists(iconPath))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL || PLATFORM_MAC
|
||||
#define USE_IS_FOREGROUND
|
||||
#else
|
||||
#endif
|
||||
#if PLATFORM_SDL
|
||||
#if PLATFORM_SDL || PLATFORM_MAC
|
||||
#define USE_SDL_WORKAROUNDS
|
||||
#endif
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
@@ -189,12 +189,18 @@ namespace FlaxEditor.Options
|
||||
/// <summary>
|
||||
/// Determined automatically based on the system and any known compatibility issues with native decorations.
|
||||
/// </summary>
|
||||
#if PLATFORM_MAC && !PLATFORM_SDL
|
||||
[HideInEditor]
|
||||
#endif
|
||||
Auto,
|
||||
|
||||
/// <summary>
|
||||
/// Automatically choose most compatible window decorations for child windows, prefer custom decorations on main window.
|
||||
/// </summary>
|
||||
[EditorDisplay(Name = "Auto (Child Only)")]
|
||||
#if PLATFORM_MAC && !PLATFORM_SDL
|
||||
[HideInEditor]
|
||||
#endif
|
||||
AutoChildOnly,
|
||||
|
||||
/// <summary>
|
||||
@@ -307,18 +313,18 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Interface"), EditorOrder(322)]
|
||||
public bool ScrollToScriptOnAdd { get; set; } = true;
|
||||
|
||||
#if PLATFORM_SDL
|
||||
#if PLATFORM_SDL || PLATFORM_MAC
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether use native window title bar decorations in child windows. Editor restart required.
|
||||
/// </summary>
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_MAC
|
||||
[DefaultValue(WindowDecorationsType.ClientSide)]
|
||||
#else
|
||||
[DefaultValue(WindowDecorationsType.AutoChildOnly)]
|
||||
#endif
|
||||
[EditorDisplay("Tabs & Windows"), EditorOrder(70), Tooltip("Determines whether use native window title bar decorations. Editor restart required.")]
|
||||
public WindowDecorationsType WindowDecorations { get; set; } =
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_MAC
|
||||
WindowDecorationsType.ClientSide;
|
||||
#else
|
||||
WindowDecorationsType.AutoChildOnly;
|
||||
|
||||
@@ -651,10 +651,16 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
foreach (var e in values)
|
||||
{
|
||||
_combobox.AddItem(e.Key);
|
||||
tooltips[i++] = "Type: " + CustomEditorsUtil.GetTypeNameUI(e.Value.GetType()) + ", default value: " + e.Value;
|
||||
var value = e.Value;
|
||||
if (value == null)
|
||||
{
|
||||
tooltips[i++] = "null";
|
||||
continue;
|
||||
}
|
||||
tooltips[i++] = "Type: " + CustomEditorsUtil.GetTypeNameUI(value.GetType()) + ", default value: " + value;
|
||||
if (toSelect == e.Key)
|
||||
{
|
||||
type = e.Value.GetType();
|
||||
type = value.GetType();
|
||||
}
|
||||
}
|
||||
_combobox.Tooltips = tooltips;
|
||||
|
||||
@@ -1293,6 +1293,12 @@ namespace FlaxEditor.Utilities
|
||||
};
|
||||
#elif PLATFORM_WINDOWS
|
||||
return !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem;
|
||||
#elif PLATFORM_MAC
|
||||
return Editor.Instance.Options.Options.Interface.WindowDecorations switch
|
||||
{
|
||||
Options.InterfaceOptions.WindowDecorationsType.ClientSide => true,
|
||||
_ => false
|
||||
};
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@@ -157,6 +157,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
private void Setter(object instance, int index, object value)
|
||||
{
|
||||
CheckForNullValue(ref value, _proxy.DefaultValues[_name].GetType());
|
||||
if (_isDefault)
|
||||
_proxy.DefaultValues[_name] = value;
|
||||
else
|
||||
@@ -251,6 +252,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
typeof(Rectangle),
|
||||
typeof(Matrix),
|
||||
typeof(string),
|
||||
typeof(Texture),
|
||||
typeof(CubeTexture),
|
||||
};
|
||||
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -272,7 +275,6 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
var name = e.Key;
|
||||
var value = _proxy.Asset.GetValue(name);
|
||||
var valueContainer = new VariableValueContainer(_proxy, name, value, false);
|
||||
var propertyLabel = new PropertyNameLabel(name)
|
||||
{
|
||||
Tag = name,
|
||||
@@ -280,7 +282,15 @@ namespace FlaxEditor.Windows.Assets
|
||||
string tooltip = null;
|
||||
if (_proxy.DefaultValues.TryGetValue(name, out var defaultValue))
|
||||
tooltip = "Default value: " + defaultValue;
|
||||
layout.Object(propertyLabel, valueContainer, null, tooltip);
|
||||
var property = layout.AddPropertyItem(propertyLabel, tooltip);
|
||||
if (value == null)
|
||||
{
|
||||
property.Label("null").Label.TextColor = Color.Red;
|
||||
continue;
|
||||
}
|
||||
var valueContainer = new VariableValueContainer(_proxy, name, value, false);
|
||||
valueContainer.SetDefaultValue(defaultValue);
|
||||
property.Object(valueContainer);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -289,19 +299,37 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
var name = e.Key;
|
||||
var value = e.Value;
|
||||
var valueContainer = new VariableValueContainer(_proxy, name, value, true);
|
||||
var propertyLabel = new ClickablePropertyNameLabel(name)
|
||||
{
|
||||
Tag = name,
|
||||
};
|
||||
propertyLabel.MouseLeftDoubleClick += (label, location) => StartParameterRenaming(name, label);
|
||||
propertyLabel.SetupContextMenu += OnPropertyLabelSetupContextMenu;
|
||||
layout.Object(propertyLabel, valueContainer, null, "Type: " + CustomEditorsUtil.GetTypeNameUI(value.GetType()));
|
||||
var tooltip = value != null ? "Type: " + CustomEditorsUtil.GetTypeNameUI(value.GetType()) : string.Empty;
|
||||
var property = layout.AddPropertyItem(propertyLabel, tooltip);
|
||||
if (value == null)
|
||||
{
|
||||
property.Label("null").Label.TextColor = Color.Red;
|
||||
continue;
|
||||
}
|
||||
var valueContainer = new VariableValueContainer(_proxy, name, value, true);
|
||||
property.Object(valueContainer);
|
||||
}
|
||||
if (_proxy.DefaultValues.Count == 0)
|
||||
{
|
||||
var emptyLabel = layout.Label("Empty", TextAlignment.Center).Label;
|
||||
emptyLabel.TextColor = emptyLabel.TextColorHighlighted = FlaxEngine.GUI.Style.Current.ForegroundDisabled;
|
||||
}
|
||||
|
||||
// TODO: improve the UI
|
||||
layout.Space(40);
|
||||
var addParamType = layout.ComboBox().ComboBox;
|
||||
var addPanel = layout.HorizontalPanel();
|
||||
addPanel.Panel.Size = new Float2(0, TextBox.DefaultHeight);
|
||||
addPanel.Panel.Margin = Margin.Zero;
|
||||
addPanel.Panel.Spacing = Utilities.Constants.UIMargin;
|
||||
|
||||
addPanel.Label("New value type:");
|
||||
|
||||
var addParamType = addPanel.ComboBox().ComboBox;
|
||||
object lastValue = null;
|
||||
foreach (var e in _proxy.DefaultValues)
|
||||
lastValue = e.Value;
|
||||
@@ -314,7 +342,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
addParamType.Items = allowedTypes;
|
||||
addParamType.SelectedIndex = index;
|
||||
_addParamType = addParamType;
|
||||
var addParamButton = layout.Button("Add").Button;
|
||||
var addParamButton = addPanel.Button("Add").Button;
|
||||
addParamButton.Clicked += OnAddParamButtonClicked;
|
||||
}
|
||||
}
|
||||
@@ -344,6 +372,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)),
|
||||
DefaultValue = TypeUtils.GetDefaultValue(new ScriptType(type)),
|
||||
};
|
||||
CheckForNullValue(ref action.DefaultValue, type);
|
||||
_proxy.Window.Undo.AddAction(action);
|
||||
action.Do();
|
||||
}
|
||||
@@ -387,6 +416,26 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckForNullValue(ref object value, Type type)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
// Default values are invalid as Variant type is used in C++ to properly bind the value
|
||||
if (typeof(CubeTexture).IsAssignableFrom(type))
|
||||
{
|
||||
// Default cube texture
|
||||
value = FlaxEngine.Content.LoadAsyncInternal<CubeTexture>(EditorAssets.DefaultSkyCubeTexture);
|
||||
}
|
||||
else if (typeof(Texture).IsAssignableFrom(type))
|
||||
{
|
||||
// Default texture
|
||||
value = FlaxEngine.Content.LoadAsyncInternal<Texture>("Engine/Textures/BlackTexture");
|
||||
}
|
||||
else
|
||||
throw new Exception("Null values are not allowed in Gameplay Globals");
|
||||
}
|
||||
}
|
||||
|
||||
private CustomEditorPresenter _propertiesEditor;
|
||||
private PropertiesProxy _proxy;
|
||||
private ToolStripButton _saveButton;
|
||||
|
||||
@@ -85,21 +85,31 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
||||
LOG(Info, "Audio: {0}kHz, channels: {1}, Bit depth: {2}, Length: {3}s", info.SampleRate / 1000.0f, info.NumChannels, info.BitDepth, info.GetLength());
|
||||
|
||||
// Load the whole audio data
|
||||
uint32 bytesPerSample = info.BitDepth / 8;
|
||||
uint32 bufferSize = info.NumSamples * bytesPerSample;
|
||||
DataContainer<byte> sampleBuffer;
|
||||
sampleBuffer.Link(audioData.Get());
|
||||
sampleBuffer.Link(audioData.Get(), info.NumSamples * (info.BitDepth / 8));
|
||||
|
||||
if (!Math::IsOne(options.Volume))
|
||||
{
|
||||
// Scale PCM signal
|
||||
Array<float> pcm;
|
||||
pcm.Resize(info.NumSamples);
|
||||
AudioTool::ConvertToFloat(sampleBuffer.Get(), info.BitDepth, pcm.Get(), info.NumSamples);
|
||||
for (float& e : pcm)
|
||||
e *= options.Volume;
|
||||
sampleBuffer.Allocate(info.NumSamples * sizeof(int32));
|
||||
AudioTool::ConvertFromFloat(pcm.Get(), (int32*)sampleBuffer.Get(), info.NumSamples);
|
||||
info.BitDepth = 32;
|
||||
}
|
||||
|
||||
// Convert bit depth if need to
|
||||
uint32 outputBitDepth = (uint32)options.BitDepth;
|
||||
if (outputBitDepth != info.BitDepth)
|
||||
{
|
||||
DataContainer<byte> sampleBufferPrev = MoveTemp(sampleBuffer);
|
||||
const uint32 outBufferSize = info.NumSamples * (outputBitDepth / 8);
|
||||
sampleBuffer.Allocate(outBufferSize);
|
||||
AudioTool::ConvertBitDepth(audioData.Get(), info.BitDepth, sampleBuffer.Get(), outputBitDepth, info.NumSamples);
|
||||
AudioTool::ConvertBitDepth(sampleBufferPrev.Get(), info.BitDepth, sampleBuffer.Get(), outputBitDepth, info.NumSamples);
|
||||
info.BitDepth = outputBitDepth;
|
||||
bytesPerSample = info.BitDepth / 8;
|
||||
bufferSize = outBufferSize;
|
||||
}
|
||||
|
||||
// Base
|
||||
@@ -157,13 +167,14 @@ CreateAssetResult ImportAudio::Import(CreateAssetContext& context, AudioDecoder&
|
||||
if (context.AllocateChunk(0))
|
||||
return CreateAssetResult::CannotAllocateChunk;
|
||||
|
||||
WRITE_DATA(0, sampleBuffer.Get(), bufferSize);
|
||||
WRITE_DATA(0, sampleBuffer.Get(), sampleBuffer.Length());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split audio data into a several chunks (uniform data spread)
|
||||
const uint32 minChunkSize = 1 * 1024 * 1024; // 1 MB
|
||||
const uint32 dataAlignment = info.NumChannels * bytesPerSample * ASSET_FILE_DATA_CHUNKS; // Ensure to never split samples in-between (eg. 24-bit that uses 3 bytes)
|
||||
const uint32 bufferSize = sampleBuffer.Length();
|
||||
const uint32 dataAlignment = info.NumChannels * (info.BitDepth / 8) * ASSET_FILE_DATA_CHUNKS; // Ensure to never split samples in-between (eg. 24-bit that uses 3 bytes)
|
||||
const uint32 chunkSize = Math::AlignUp(Math::Max(minChunkSize, bufferSize / ASSET_FILE_DATA_CHUNKS), dataAlignment);
|
||||
const int32 chunksCount = Math::CeilToInt((float)bufferSize / (float)chunkSize);
|
||||
ASSERT(chunksCount > 0 && chunksCount <= ASSET_FILE_DATA_CHUNKS);
|
||||
|
||||
@@ -259,29 +259,29 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new frustum relaying on perspective camera parameters
|
||||
/// Creates a new frustum based on a perspective camera parameters.
|
||||
/// </summary>
|
||||
/// <param name="cameraPos">The camera pos.</param>
|
||||
/// <param name="lookDir">The look dir.</param>
|
||||
/// <param name="upDir">Up dir.</param>
|
||||
/// <param name="fov">The fov.</param>
|
||||
/// <param name="znear">The Z near.</param>
|
||||
/// <param name="zfar">The Z far.</param>
|
||||
/// <param name="aspect">The aspect.</param>
|
||||
/// <returns>The bounding frustum calculated from perspective camera</returns>
|
||||
public static BoundingFrustum FromCamera(Vector3 cameraPos, Vector3 lookDir, Vector3 upDir, float fov, float znear, float zfar, float aspect)
|
||||
/// <param name="cameraPos">The camera position.</param>
|
||||
/// <param name="lookDir">The look direction.</param>
|
||||
/// <param name="upDir">Up direction.</param>
|
||||
/// <param name="fov">The fov in radians.</param>
|
||||
/// <param name="zNear">The Z near plane.</param>
|
||||
/// <param name="zFar">The Z far plane.</param>
|
||||
/// <param name="aspectRatio">The aspect ratio.</param>
|
||||
/// <returns>The bounding frustum calculated from the perspective camera</returns>
|
||||
public static BoundingFrustum FromCamera(Vector3 cameraPos, Vector3 lookDir, Vector3 upDir, float fov, float zNear, float zFar, float aspectRatio)
|
||||
{
|
||||
//http://knol.google.com/k/view-frustum
|
||||
|
||||
lookDir = Vector3.Normalize(lookDir);
|
||||
upDir = Vector3.Normalize(upDir);
|
||||
|
||||
Vector3 nearCenter = cameraPos + lookDir * znear;
|
||||
Vector3 farCenter = cameraPos + lookDir * zfar;
|
||||
var nearHalfHeight = (float)(znear * Math.Tan(fov / 2f));
|
||||
var farHalfHeight = (float)(zfar * Math.Tan(fov / 2f));
|
||||
float nearHalfWidth = nearHalfHeight * aspect;
|
||||
float farHalfWidth = farHalfHeight * aspect;
|
||||
Vector3 nearCenter = cameraPos + lookDir * zNear;
|
||||
Vector3 farCenter = cameraPos + lookDir * zFar;
|
||||
var nearHalfHeight = (float)(zNear * Math.Tan(fov / 2f));
|
||||
var farHalfHeight = (float)(zFar * Math.Tan(fov / 2f));
|
||||
float nearHalfWidth = nearHalfHeight * aspectRatio;
|
||||
float farHalfWidth = farHalfHeight * aspectRatio;
|
||||
|
||||
Vector3 rightDir = Vector3.Normalize(Vector3.Cross(upDir, lookDir));
|
||||
Vector3 near1 = nearCenter - nearHalfHeight * upDir + nearHalfWidth * rightDir;
|
||||
@@ -310,20 +310,21 @@ namespace FlaxEngine
|
||||
result.pTop.Normalize();
|
||||
result.pBottom.Normalize();
|
||||
|
||||
result.pMatrix = Matrix.LookAt(cameraPos, cameraPos + lookDir * 10, upDir) * Matrix.PerspectiveFov(fov, aspect, znear, zfar);
|
||||
result.pMatrix = Matrix.LookAt(cameraPos, cameraPos + lookDir * 10, upDir) * Matrix.PerspectiveFov(fov, aspectRatio, zNear, zFar);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the 8 corners of the frustum, element0 is Near1 (near right down corner)
|
||||
/// , element1 is Near2 (near right top corner)
|
||||
/// , element2 is Near3 (near Left top corner)
|
||||
/// , element3 is Near4 (near Left down corner)
|
||||
/// , element4 is Far1 (far right down corner)
|
||||
/// , element5 is Far2 (far right top corner)
|
||||
/// , element6 is Far3 (far left top corner)
|
||||
/// , element7 is Far4 (far left down corner)
|
||||
/// Returns the 8 corners of the frustum:
|
||||
/// <para>[0] is Near1 (Near right down corner)</para>
|
||||
/// <para>[1] is Near2 (Near right top corner)</para>
|
||||
/// <para>[2] is Near3 (Near left top corner)</para>
|
||||
/// <para>[3] is Near4 (Near left down corner)</para>
|
||||
/// <para>[4] is Far1 (Far right down corner)</para>
|
||||
/// <para>[5] is Far2 (Far right top corner)</para>
|
||||
/// <para>[6] is Far3 (Far left top corner)</para>
|
||||
/// <para>[7] is Far4 (Far left down corner)</para>
|
||||
/// </summary>
|
||||
/// <returns>The 8 corners of the frustum</returns>
|
||||
public Vector3[] GetCorners()
|
||||
@@ -334,16 +335,16 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the 8 corners of the frustum, element0 is Near1 (near right down corner)
|
||||
/// , element1 is Near2 (near right top corner)
|
||||
/// , element2 is Near3 (near Left top corner)
|
||||
/// , element3 is Near4 (near Left down corner)
|
||||
/// , element4 is Far1 (far right down corner)
|
||||
/// , element5 is Far2 (far right top corner)
|
||||
/// , element6 is Far3 (far left top corner)
|
||||
/// , element7 is Far4 (far left down corner)
|
||||
/// Populates the array with the 8 corners of the frustum:
|
||||
/// <para>[0] is Near1 (Near right down corner)</para>
|
||||
/// <para>[1] is Near2 (Near right top corner)</para>
|
||||
/// <para>[2] is Near3 (Near left top corner)</para>
|
||||
/// <para>[3] is Near4 (Near left down corner)</para>
|
||||
/// <para>[4] is Far1 (Far right down corner)</para>
|
||||
/// <para>[5] is Far2 (Far right top corner)</para>
|
||||
/// <para>[6] is Far3 (Far left top corner)</para>
|
||||
/// <para>[7] is Far4 (Far left down corner)</para>
|
||||
/// </summary>
|
||||
/// <returns>The 8 corners of the frustum</returns>
|
||||
public void GetCorners(Vector3[] corners)
|
||||
{
|
||||
corners[0] = Get3PlanesInterPoint(ref pNear, ref pBottom, ref pRight); //Near1
|
||||
@@ -357,7 +358,7 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a point lay inside, intersects or lay outside the frustum.
|
||||
/// Checks whether a point lays inside, intersects or lays outside the frustum.
|
||||
/// </summary>
|
||||
/// <param name="point">The point.</param>
|
||||
/// <returns>Type of the containment</returns>
|
||||
@@ -664,15 +665,15 @@ namespace FlaxEngine
|
||||
{
|
||||
if (Contains(ray.Position) != ContainmentType.Disjoint)
|
||||
{
|
||||
Real nearstPlaneDistance = Real.MaxValue;
|
||||
Real nearestPlaneDistance = Real.MaxValue;
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
Plane plane = GetPlane(i);
|
||||
if (CollisionsHelper.RayIntersectsPlane(ref ray, ref plane, out Real distance) && (distance < nearstPlaneDistance))
|
||||
nearstPlaneDistance = distance;
|
||||
if (CollisionsHelper.RayIntersectsPlane(ref ray, ref plane, out Real distance) && (distance < nearestPlaneDistance))
|
||||
nearestPlaneDistance = distance;
|
||||
}
|
||||
|
||||
inDistance = nearstPlaneDistance;
|
||||
inDistance = nearestPlaneDistance;
|
||||
outDistance = null;
|
||||
return true;
|
||||
}
|
||||
@@ -706,9 +707,9 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the distance which when added to camera position along the lookat direction will do the effect of zoom to extents (zoom to fit) operation, so all the passed points will fit in the current view.
|
||||
/// if the returned value is positive, the camera will move toward the lookat direction (ZoomIn).
|
||||
/// if the returned value is negative, the camera will move in the reverse direction of the lookat direction (ZoomOut).
|
||||
/// Get the distance which when added to camera position along the look-at direction will do the effect of zoom to extents (zoom to fit) operation, so all the passed points will fit in the current view.
|
||||
/// if the returned value is positive, the camera will move toward the look-at direction (ZoomIn).
|
||||
/// if the returned value is negative, the camera will move in the reverse direction of the look-at direction (ZoomOut).
|
||||
/// </summary>
|
||||
/// <param name="points">The points.</param>
|
||||
/// <returns>The zoom to fit distance</returns>
|
||||
@@ -735,9 +736,9 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the distance which when added to camera position along the lookat direction will do the effect of zoom to extents (zoom to fit) operation, so all the passed points will fit in the current view.
|
||||
/// if the returned value is positive, the camera will move toward the lookat direction (ZoomIn).
|
||||
/// if the returned value is negative, the camera will move in the reverse direction of the lookat direction (ZoomOut).
|
||||
/// Get the distance which when added to camera position along the look-at direction will do the effect of zoom to extents (zoom to fit) operation, so all the passed points will fit in the current view.
|
||||
/// if the returned value is positive, the camera will move toward the look-at direction (ZoomIn).
|
||||
/// if the returned value is negative, the camera will move in the reverse direction of the look-at direction (ZoomOut).
|
||||
/// </summary>
|
||||
/// <param name="boundingBox">The bounding box.</param>
|
||||
/// <returns>The zoom to fit distance</returns>
|
||||
|
||||
@@ -10,6 +10,7 @@ struct Transform;
|
||||
template<typename T>
|
||||
class AssetReference;
|
||||
struct ScriptingTypeHandle;
|
||||
template<typename Type> ScriptingTypeHandle StaticType();
|
||||
|
||||
/// <summary>
|
||||
/// Represents an object type that can be interpreted as more than one type.
|
||||
|
||||
@@ -149,6 +149,18 @@ bool GameplayGlobals::Save(const StringView& path)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameplayGlobals::GetReferences(Array<Guid>& assets, Array<String>& files) const
|
||||
{
|
||||
BinaryAsset::GetReferences(assets, files);
|
||||
|
||||
for (auto& e : Variables)
|
||||
{
|
||||
auto asset = (Asset*)e.Value.DefaultValue;
|
||||
if (asset)
|
||||
assets.Add(asset->GetID());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GameplayGlobals::InitAsVirtual()
|
||||
|
||||
@@ -85,6 +85,7 @@ public:
|
||||
void InitAsVirtual() override;
|
||||
#if USE_EDITOR
|
||||
bool Save(const StringView& path = StringView::Empty) override;
|
||||
void GetReferences(Array<Guid>& assets, Array<String>& files) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@@ -472,7 +472,17 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Int4)));
|
||||
*((Int4*)(meta.Constants.Get() + _offset)) = (Int4)e->Value.AsInt4();
|
||||
break;
|
||||
default: ;
|
||||
case VariantType::Asset:
|
||||
{
|
||||
auto texture = Cast<TextureBase>(e->Value.AsAsset);
|
||||
meta.Context->BindSR(_registerIndex, texture ? texture->GetTexture() : nullptr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
#if !BUILD_RELEASE
|
||||
LOG(Warning, "Invalid Gameplay Global '{}' ({}) value type '{}' to bind to material", _name, _asAsset->GetPath(), e->Value.Type.ToString());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,7 +489,9 @@ public:
|
||||
ModelBase* GetModel() override;
|
||||
bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override;
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
|
||||
bool GetMeshData(const MeshReference& ref, MeshBufferType type, BytesContainer& result, int32& count, GPUVertexLayout** layout) const override;
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
|
||||
MeshBase* GetMesh(const MeshReference& ref) const override;
|
||||
void UpdateBounds() override;
|
||||
MeshDeformation* GetMeshDeformation() const override;
|
||||
|
||||
@@ -181,7 +181,9 @@ public:
|
||||
ModelBase* GetModel() override;
|
||||
bool IntersectsEntry(int32 entryIndex, const Ray& ray, Real& distance, Vector3& normal) override;
|
||||
bool IntersectsEntry(const Ray& ray, Real& distance, Vector3& normal, int32& entryIndex) override;
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
|
||||
bool GetMeshData(const MeshReference& ref, MeshBufferType type, BytesContainer& result, int32& count, GPUVertexLayout** layout) const override;
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
|
||||
MeshBase* GetMesh(const MeshReference& ref) const override;
|
||||
MeshDeformation* GetMeshDeformation() const override;
|
||||
void UpdateBounds() override;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "ParticleEmitterGraph.GPU.h"
|
||||
#include "Engine/Graphics/Materials/MaterialInfo.h"
|
||||
|
||||
bool ParticleEmitterGPUGenerator::loadTexture(Node* caller, Box* box, const SerializedMaterialParam& texture, Value& result)
|
||||
bool ParticleEmitterGPUGenerator::loadTexture(Node* caller, Box* box, const SerializedMaterialParam& texture, const Value& textureValue, Value& result)
|
||||
{
|
||||
ASSERT(caller && box && texture.ID.IsValid());
|
||||
|
||||
@@ -22,7 +22,8 @@ bool ParticleEmitterGPUGenerator::loadTexture(Node* caller, Box* box, const Seri
|
||||
&& texture.Type != MaterialParameterType::GPUTextureVolume
|
||||
&& texture.Type != MaterialParameterType::GPUTextureCube
|
||||
&& texture.Type != MaterialParameterType::GPUTextureArray
|
||||
&& texture.Type != MaterialParameterType::CubeTexture)
|
||||
&& texture.Type != MaterialParameterType::CubeTexture
|
||||
&& textureValue.Type != VariantType::Object)
|
||||
{
|
||||
result = Value::Zero;
|
||||
OnError(caller, box, TEXT("No parameter for texture load or invalid type."));
|
||||
@@ -41,7 +42,8 @@ bool ParticleEmitterGPUGenerator::loadTexture(Node* caller, Box* box, const Seri
|
||||
|
||||
// Load texture
|
||||
const Char* format = TEXT("{0}.Load({1})");
|
||||
const String sampledValue = String::Format(format, texture.ShaderName, location.Value);
|
||||
auto& shaderName = textureValue.Type == VariantType::Object ? textureValue.Value : texture.ShaderName;
|
||||
const String sampledValue = String::Format(format, shaderName, location.Value);
|
||||
result = writeLocal(VariantType::Float4, sampledValue, parent);
|
||||
|
||||
return false;
|
||||
@@ -300,7 +302,7 @@ void ParticleEmitterGPUGenerator::ProcessGroupTextures(Box* box, Node* node, Val
|
||||
const auto copy = *textureParam;
|
||||
|
||||
// Load texture
|
||||
loadTexture(node, box, copy, value);
|
||||
loadTexture(node, box, copy, texture, value);
|
||||
break;
|
||||
}
|
||||
// Sample Global SDF
|
||||
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
|
||||
Parameter* findGraphParam(const Guid& id);
|
||||
bool sampleSceneTexture(Node* caller, Box* box, const SerializedMaterialParam& texture, Value& result);
|
||||
bool loadTexture(Node* caller, Box* box, const SerializedMaterialParam& texture, Value& result);
|
||||
bool loadTexture(Node* caller, Box* box, const SerializedMaterialParam& texture, const Value& textureValue, Value& result);
|
||||
void sampleSceneDepth(Node* caller, Value& value, Box* box);
|
||||
void linearizeSceneDepth(Node* caller, const Value& depth, Value& value);
|
||||
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
#include "Engine/Platform/Base/DragDropHelper.h"
|
||||
#endif
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Input/Input.h"
|
||||
#include "Engine/Input/Mouse.h"
|
||||
#include "Engine/Input/Keyboard.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
@@ -200,6 +202,19 @@ Float2 GetMousePosition(MacWindow* window, NSEvent* event)
|
||||
return Float2(point.x, frame.size.height - point.y) * MacPlatform::ScreenScale - GetWindowTitleSize(window);
|
||||
}
|
||||
|
||||
NSRect GetFrameRectForClientBounds(MacWindow* macWindow, NSWindow* window, const Rectangle& clientArea)
|
||||
{
|
||||
const float screenScale = MacPlatform::ScreenScale;
|
||||
NSRect rect = NSMakeRect(0, 0, clientArea.Size.X / screenScale, clientArea.Size.Y / screenScale);
|
||||
rect = [window frameRectForContentRect:rect];
|
||||
|
||||
Float2 pos = AppleUtils::PosToCoca(clientArea.Location) / screenScale;
|
||||
Float2 titleSize = GetWindowTitleSize(macWindow);
|
||||
rect.origin.x = pos.X + titleSize.X;
|
||||
rect.origin.y = pos.Y - rect.size.height + titleSize.Y;
|
||||
return rect;
|
||||
}
|
||||
|
||||
class MacDropData : public IGuiData
|
||||
{
|
||||
public:
|
||||
@@ -310,6 +325,12 @@ NSDragOperation GetDragDropOperation(DragDropEffect dragDropEffect)
|
||||
Window->OnLostFocus();
|
||||
}
|
||||
|
||||
- (void)windowDidMove:(NSNotification*)notification
|
||||
{
|
||||
if (IsWindowInvalid(Window)) return;
|
||||
Window->SyncWindowState();
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification
|
||||
{
|
||||
[self setDelegate: nil];
|
||||
@@ -518,6 +539,28 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
||||
if (IsWindowInvalid(Window)) return;
|
||||
Float2 mousePos = GetMousePosition(Window, event);
|
||||
mousePos = Window->ClientToScreen(mousePos);
|
||||
|
||||
if ([event clickCount] == 1 && !Input::Mouse->IsRelative())
|
||||
{
|
||||
WindowHitCodes hit = WindowHitCodes::Client;
|
||||
bool handled = false;
|
||||
Window->OnHitTest(mousePos, hit, handled);
|
||||
|
||||
if (hit == WindowHitCodes::Caption)
|
||||
{
|
||||
bool consumed = false;
|
||||
Window->OnLeftButtonHit(hit, consumed);
|
||||
|
||||
if (!consumed)
|
||||
{
|
||||
[(NSWindow*)Window->GetNativePtr() performWindowDragWithEvent:event];
|
||||
Window->SyncWindowState();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MouseButton mouseButton = MouseButton::Left;
|
||||
if ([event clickCount] == 2 && !Input::Mouse->IsRelative())
|
||||
Input::Mouse->OnMouseDoubleClick(mousePos, mouseButton, Window);
|
||||
@@ -835,15 +878,28 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||
|
||||
MacWindow::~MacWindow()
|
||||
{
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window close];
|
||||
[window release];
|
||||
if (NSWindow* window = (NSWindow*)_window)
|
||||
{
|
||||
[window close];
|
||||
[window release];
|
||||
}
|
||||
_window = nullptr;
|
||||
_view = nullptr;
|
||||
}
|
||||
|
||||
void MacWindow::SyncWindowState()
|
||||
{
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (window)
|
||||
{
|
||||
_minimized = window.miniaturized;
|
||||
_maximized = window.zoomed;
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::CheckForResize(float width, float height)
|
||||
{
|
||||
SyncWindowState();
|
||||
const Float2 clientSize(width, height);
|
||||
if (clientSize != _clientSize)
|
||||
{
|
||||
@@ -940,7 +996,7 @@ void MacWindow::Hide()
|
||||
[window orderOut:nil];
|
||||
|
||||
// Transfer focus back to the parent when hiding popup
|
||||
if (_settings.Parent && wasKey)
|
||||
if (_settings.Parent && wasKey && _settings.Type != WindowType::Popup && _settings.Type != WindowType::Tooltip)
|
||||
{
|
||||
NSWindow* parent = (NSWindow*)_settings.Parent->GetNativePtr();
|
||||
[parent makeKeyAndOrderFront:nil];
|
||||
@@ -951,6 +1007,27 @@ void MacWindow::Hide()
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::Close(ClosingReason reason)
|
||||
{
|
||||
const BOOL wasKey = _window && [(NSWindow*)_window isKeyWindow];
|
||||
WindowBase::Close(reason);
|
||||
|
||||
// Closing can be cancelled by managed Window.Closing handlers.
|
||||
if (!IsClosed())
|
||||
return;
|
||||
|
||||
if (NSWindow* window = (NSWindow*)_window)
|
||||
{
|
||||
[window close];
|
||||
}
|
||||
|
||||
if (_settings.Parent && wasKey && _settings.Type != WindowType::Popup && _settings.Type != WindowType::Tooltip)
|
||||
{
|
||||
NSWindow* parent = (NSWindow*)_settings.Parent->GetNativePtr();
|
||||
[parent makeKeyAndOrderFront:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::Minimize()
|
||||
{
|
||||
if (!_settings.AllowMinimize)
|
||||
@@ -967,17 +1044,43 @@ void MacWindow::Maximize()
|
||||
if (!_settings.AllowMaximize)
|
||||
return;
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window)
|
||||
return;
|
||||
if (!window.zoomed)
|
||||
{
|
||||
if (!_maximized)
|
||||
{
|
||||
_restoreClientBounds = GetClientBounds();
|
||||
_hasRestoreClientBounds = true;
|
||||
}
|
||||
[window zoom:nil];
|
||||
}
|
||||
SyncWindowState();
|
||||
}
|
||||
|
||||
void MacWindow::Restore()
|
||||
{
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window)
|
||||
return;
|
||||
if (window.miniaturized)
|
||||
{
|
||||
[window deminiaturize:nil];
|
||||
SyncWindowState();
|
||||
}
|
||||
else if (_maximized && _hasRestoreClientBounds)
|
||||
{
|
||||
const Rectangle restoreClientBounds = _restoreClientBounds;
|
||||
_hasRestoreClientBounds = false;
|
||||
NSRect restoreFrame = GetFrameRectForClientBounds(this, window, restoreClientBounds);
|
||||
[window setFrame:restoreFrame display:YES animate:YES];
|
||||
_maximized = false;
|
||||
}
|
||||
else if (window.zoomed)
|
||||
{
|
||||
[window zoom:nil];
|
||||
SyncWindowState();
|
||||
}
|
||||
}
|
||||
|
||||
bool MacWindow::IsForegroundWindow() const
|
||||
@@ -1001,17 +1104,7 @@ void MacWindow::SetClientBounds(const Rectangle& clientArea)
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window)
|
||||
return;
|
||||
const float screenScale = MacPlatform::ScreenScale;
|
||||
|
||||
NSRect oldRect = [window frame];
|
||||
NSRect newRect = NSMakeRect(0, 0, clientArea.Size.X / screenScale, clientArea.Size.Y / screenScale);
|
||||
newRect = [window frameRectForContentRect:newRect];
|
||||
|
||||
Float2 pos = AppleUtils::PosToCoca(clientArea.Location) / screenScale;
|
||||
Float2 titleSize = GetWindowTitleSize(this);
|
||||
newRect.origin.x = pos.X + titleSize.X;
|
||||
newRect.origin.y = pos.Y - newRect.size.height + titleSize.Y;
|
||||
|
||||
NSRect newRect = GetFrameRectForClientBounds(this, window, clientArea);
|
||||
[window setFrame:newRect display:YES];
|
||||
}
|
||||
|
||||
@@ -1211,4 +1304,37 @@ void MacWindow::SetCursor(CursorType type)
|
||||
}
|
||||
}
|
||||
|
||||
void MacWindow::SetIcon(TextureData& icon)
|
||||
{
|
||||
// Get pixels
|
||||
Array<Color32> colorData;
|
||||
icon.GetPixels(colorData);
|
||||
|
||||
// Convert to Cocoa image
|
||||
NSImage* image = [[NSImage alloc] initWithSize:NSMakeSize(icon.Width, icon.Height)];
|
||||
if (image == nil)
|
||||
return;
|
||||
NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:icon.Width
|
||||
pixelsHigh:icon.Height
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSDeviceRGBColorSpace
|
||||
bytesPerRow:icon.Width * 4
|
||||
bitsPerPixel:32];
|
||||
if (rep == nil)
|
||||
return;
|
||||
|
||||
// Copy the pixels
|
||||
Platform::MemoryCopy([rep bitmapData], colorData.Get(), colorData.Count() * sizeof(Color32));
|
||||
|
||||
// Add the image representation
|
||||
[image addRepresentation:rep];
|
||||
|
||||
// Set app icon
|
||||
[NSApp setApplicationIconImage:image];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,13 +17,16 @@ private:
|
||||
void* _window = nullptr;
|
||||
void* _view = nullptr;
|
||||
bool _isMouseOver = false;
|
||||
bool _hasRestoreClientBounds = false;
|
||||
Rectangle _restoreClientBounds;
|
||||
Float2 _mouseTrackPos = Float2::Minimum;
|
||||
String _dragText;
|
||||
|
||||
public:
|
||||
MacWindow(const CreateWindowSettings& settings);
|
||||
~MacWindow();
|
||||
~MacWindow() override;
|
||||
|
||||
void SyncWindowState();
|
||||
void CheckForResize(float width, float height);
|
||||
void SetIsMouseOver(bool value);
|
||||
const String& GetDragText() const
|
||||
@@ -37,6 +40,7 @@ public:
|
||||
void OnUpdate(float dt) override;
|
||||
void Show() override;
|
||||
void Hide() override;
|
||||
void Close(ClosingReason reason) override;
|
||||
void Minimize() override;
|
||||
void Maximize() override;
|
||||
void Restore() override;
|
||||
@@ -59,6 +63,7 @@ public:
|
||||
void StartTrackingMouse(bool useMouseScreenOffset) override;
|
||||
void EndTrackingMouse() override;
|
||||
void SetCursor(CursorType type) override;
|
||||
void SetIcon(TextureData& icon) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,27 +21,7 @@
|
||||
|
||||
String AudioTool::Options::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("Format:{}, DisableStreaming:{}, Is3D:{}, Quality:{}, BitDepth:{}"), ScriptingEnum::ToString(Format), DisableStreaming, Is3D, Quality, (int32)BitDepth);
|
||||
}
|
||||
|
||||
void AudioTool::Options::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
{
|
||||
SERIALIZE_GET_OTHER_OBJ(AudioTool::Options);
|
||||
|
||||
SERIALIZE(Format);
|
||||
SERIALIZE(DisableStreaming);
|
||||
SERIALIZE(Is3D);
|
||||
SERIALIZE(Quality);
|
||||
SERIALIZE(BitDepth);
|
||||
}
|
||||
|
||||
void AudioTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
{
|
||||
DESERIALIZE(Format);
|
||||
DESERIALIZE(DisableStreaming);
|
||||
DESERIALIZE(Is3D);
|
||||
DESERIALIZE(Quality);
|
||||
DESERIALIZE(BitDepth);
|
||||
return String::Format(TEXT("Volume: {}, Format:{}, DisableStreaming:{}, Is3D:{}, Quality:{}, BitDepth:{}"), Volume, ScriptingEnum::ToString(Format), DisableStreaming, Is3D, Quality, (int32)BitDepth);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,13 @@ public:
|
||||
API_STRUCT(Attributes="HideInEditor") struct FLAXENGINE_API Options : public ISerializable
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(Options);
|
||||
API_AUTO_SERIALIZATION();
|
||||
|
||||
/// <summary>
|
||||
/// The audio volume. Can be used to scale source audio data at import time.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(5), Limit(0, 10, 0.01f)")
|
||||
float Volume = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The audio data format to import the audio clip as.
|
||||
@@ -74,10 +81,6 @@ public:
|
||||
BitDepth BitDepth = BitDepth::_16;
|
||||
|
||||
String ToString() const;
|
||||
|
||||
// [ISerializable]
|
||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "ShaderGraph.h"
|
||||
#include "GraphUtilities.h"
|
||||
#include "ShaderGraphUtilities.h"
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Content/Assets/CubeTexture.h"
|
||||
#include "Engine/Engine/GameplayGlobals.h"
|
||||
|
||||
const Char* ShaderGenerator::_mathFunctions[] =
|
||||
@@ -742,6 +744,37 @@ void ShaderGenerator::ProcessGroupTools(Box* box, Node* node, Value& value)
|
||||
// Get param value
|
||||
value.Type = variable.DefaultValue.Type.Type;
|
||||
value.Value = param->ShaderName;
|
||||
switch (variable.DefaultValue.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
case VariantType::Int:
|
||||
case VariantType::Uint:
|
||||
case VariantType::Float:
|
||||
case VariantType::Float2:
|
||||
case VariantType::Float3:
|
||||
case VariantType::Float4:
|
||||
case VariantType::Color:
|
||||
case VariantType::Double2:
|
||||
case VariantType::Double3:
|
||||
case VariantType::Double4:
|
||||
case VariantType::Int2:
|
||||
case VariantType::Int3:
|
||||
case VariantType::Int4:
|
||||
// POD value types
|
||||
break;
|
||||
case VariantType::Asset:
|
||||
if (Texture::GetStaticType().Fullname == variable.DefaultValue.Type.TypeName ||
|
||||
CubeTexture::GetStaticType().Fullname == variable.DefaultValue.Type.TypeName)
|
||||
{
|
||||
// Texture or Cube Texture
|
||||
value.Type = VariantType::Object;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(Warning, "Invalid Gameplay Global '{}' ({}) value type '{}' to bind to material", name, asset->GetPath(), variable.DefaultValue.Type.ToString());
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Platform Switch
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Core/Math/Vector4.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/Texture.h"
|
||||
#include "Engine/Content/Assets/CubeTexture.h"
|
||||
#include "Engine/Engine/GameplayGlobals.h"
|
||||
#include "Engine/Graphics/Config.h"
|
||||
#include "Engine/Renderer/GlobalSignDistanceFieldPass.h"
|
||||
@@ -172,6 +174,26 @@ const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& wri
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
format = TEXT("Texture3D {0} : register(t{1});");
|
||||
break;
|
||||
case MaterialParameterType::GameplayGlobal:
|
||||
{
|
||||
auto asset = Content::LoadAsync<GameplayGlobals>(param.AsGuid);
|
||||
if (!asset || asset->WaitForLoaded())
|
||||
break;
|
||||
GameplayGlobals::Variable variable;
|
||||
if (!asset->Variables.TryGet(param.Name, variable))
|
||||
break;
|
||||
if (Texture::GetStaticType().Fullname == variable.DefaultValue.Type.TypeName)
|
||||
{
|
||||
// Texture
|
||||
format = TEXT("Texture2D {0} : register(t{1});");
|
||||
}
|
||||
else if (CubeTexture::GetStaticType().Fullname == variable.DefaultValue.Type.TypeName)
|
||||
{
|
||||
// Cube Texture
|
||||
format = TEXT("TextureCube {0} : register(t{1});");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MaterialParameterType::GlobalSDF:
|
||||
format = TEXT("Texture3D<snorm float> {0}_Tex : register(t{1});\nTexture3D<snorm float> {0}_Mip : register(t{2});");
|
||||
zeroOffset = false;
|
||||
|
||||
@@ -71,8 +71,7 @@ public class FlaxEditor : EngineTarget
|
||||
break;
|
||||
case TargetPlatform.Mac:
|
||||
options.OutputFolder = Path.Combine(options.WorkingDirectory, "Binaries", "Editor", "Mac", options.Configuration.ToString());
|
||||
if (EngineConfiguration.WithSDL(options))
|
||||
options.DependencyFiles.Add(Path.Combine(Globals.EngineRoot, "Source", "Logo.png"));
|
||||
options.DependencyFiles.Add(Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Mac", "Logo.png"));
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target, "Not supported Editor platform.");
|
||||
}
|
||||
|
||||
Binary file not shown.
Vendored
+4
-1
@@ -37,7 +37,6 @@
|
||||
#include <stdint.h>
|
||||
#include <limits>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
@@ -464,10 +463,12 @@ FMT_INLINE void assume(bool condition) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FMT_USE_ITERATOR
|
||||
// An approximation of iterator_t for pre-C++20 systems.
|
||||
template <typename T>
|
||||
using iterator_t = decltype(std::begin(std::declval<T&>()));
|
||||
template <typename T> using sentinel_t = decltype(std::end(std::declval<T&>()));
|
||||
#endif
|
||||
|
||||
#if FMT_USE_STRING
|
||||
// A workaround for std::string not having mutable data() until C++17.
|
||||
@@ -3407,6 +3408,7 @@ auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
|
||||
return {begin, end, sep};
|
||||
}
|
||||
|
||||
#if FMT_USE_ITERATOR
|
||||
/**
|
||||
\rst
|
||||
Returns a view that formats `range` with elements separated by `sep`.
|
||||
@@ -3428,6 +3430,7 @@ auto join(Range&& range, string_view sep)
|
||||
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>> {
|
||||
return join(std::begin(range), std::end(range), sep);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_USE_STRING
|
||||
/**
|
||||
|
||||
@@ -357,8 +357,7 @@ namespace Flax.Deploy
|
||||
DeployFile(src, dst, "MoltenVK_icd.json");
|
||||
DeployFiles(src, dst, "*.dll");
|
||||
DeployFiles(src, dst, "*.dylib");
|
||||
if (EngineConfiguration.UseSDL && MacConfiguration.UseSDL)
|
||||
DeployFile(src, dst, "Logo.png");
|
||||
DeployFile(src, dst, "Logo.png");
|
||||
|
||||
// Optimize package size
|
||||
Utilities.Run("strip", "FlaxEditor", null, dst, Utilities.RunOptions.None);
|
||||
|
||||
Reference in New Issue
Block a user