Merge remote-tracking branch 'origin/master' into 1.10

# Conflicts:
#	Flax.flaxproj
This commit is contained in:
Wojtek Figat
2025-03-26 19:48:47 +01:00
16 changed files with 152 additions and 68 deletions

View File

@@ -4,7 +4,7 @@
"Major": 1,
"Minor": 10,
"Revision": 0,
"Build": 6702
"Build": 6703
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.",

View File

@@ -18,32 +18,32 @@ namespace FlaxEditor.Content.Create
public enum Templates
{
/// <summary>
/// The empty asset.
/// An empty emitter.
/// </summary>
Empty,
/// <summary>
/// The simple particle system that uses constant emission rate.
/// An emitter that emits particles at a constant emission rate.
/// </summary>
ConstantBurst,
/// <summary>
/// The simple periodic burst particle system.
/// An emitter that produces simple, periodic bursts of particles.
/// </summary>
PeriodicBurst,
/// <summary>
/// The layers and tags settings.
/// An emitter that uses a blended spritesheet to produce a smooth, thick cloud of smoke.
/// </summary>
Smoke,
/// <summary>
/// The GPU sparks with depth-buffer collisions.
/// A GPU emitter that produces sparks that can collide, thanks to depth-buffer based collisions.
/// </summary>
Sparks,
/// <summary>
/// The ribbon spiral particles.
/// An emitter that produces a spiral shaped ribbon.
/// </summary>
RibbonSpiral,
}

View File

@@ -2,6 +2,7 @@
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
@@ -33,8 +34,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
totalSize.X / Units.Meters2Units * 0.001f,
totalSize.Z / Units.Meters2Units * 0.001f
);
var label = layout.Label(text);
var group = layout.Group("Info");
var label = group.Label(text);
label.Label.AutoHeight = true;
// Add a bit of padding to make it look nicer
label.Label.Margin = new Margin(3);
}
}
}

View File

@@ -81,7 +81,7 @@ namespace FlaxEditor.CustomEditors.Editors
b.Enabled = Index + 1 < Editor.Count && !Editor._readOnly;
b = menu.AddButton("Remove", OnRemoveClicked);
b.Enabled = !Editor._readOnly;
b.Enabled = !Editor._readOnly && Editor._canResize;
}
/// <inheritdoc />

View File

@@ -50,30 +50,31 @@ bool Editor::CheckProjectUpgrade()
const auto versionFilePath = Globals::ProjectCacheFolder / TEXT("version");
// Load version cache file
int32 lastMajor = FLAXENGINE_VERSION_MAJOR;
int32 lastMinor = FLAXENGINE_VERSION_MINOR;
int32 lastBuild = FLAXENGINE_VERSION_BUILD;
struct VersionCache
{
int32 Major = FLAXENGINE_VERSION_MAJOR;
int32 Minor = FLAXENGINE_VERSION_MINOR;
int32 Build = FLAXENGINE_VERSION_BUILD;
int32 RealSize = sizeof(Real); // Rebuild when changing between Large Worlds
};
VersionCache lastVersion;
if (FileSystem::FileExists(versionFilePath))
{
auto file = FileReadStream::Open(versionFilePath);
if (file)
{
file->ReadInt32(&lastMajor);
file->ReadInt32(&lastMinor);
file->ReadInt32(&lastBuild);
file->ReadBytes(&lastVersion, sizeof(lastVersion));
// Invalidate results if data has issues
if (file->HasError() || lastMajor < 0 || lastMinor < 0 || lastMajor > 100 || lastMinor > 1000)
if (file->HasError() || lastVersion.Major < 0 || lastVersion.Minor < 0 || lastVersion.Major > 100 || lastVersion.Minor > 1000)
{
lastMajor = FLAXENGINE_VERSION_MAJOR;
lastMinor = FLAXENGINE_VERSION_MINOR;
lastBuild = FLAXENGINE_VERSION_BUILD;
lastVersion = VersionCache();
LOG(Warning, "Invalid version cache data");
}
else
{
LOG(Info, "Last project open version: {0}.{1}.{2}", lastMajor, lastMinor, lastBuild);
LastProjectOpenedEngineBuild = lastBuild;
LOG(Info, "Last project open version: {0}.{1}.{2}", lastVersion.Major, lastVersion.Minor, lastVersion.Build);
LastProjectOpenedEngineBuild = lastVersion.Build;
}
Delete(file);
@@ -256,13 +257,13 @@ bool Editor::CheckProjectUpgrade()
LOG(Warning, "Project layout upgraded!");
}
// Check if last version was the same
else if (lastMajor == FLAXENGINE_VERSION_MAJOR && lastMinor == FLAXENGINE_VERSION_MINOR)
else if (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor == FLAXENGINE_VERSION_MINOR)
{
// Do nothing
IsOldProjectOpened = false;
}
// Check if last version was older
else if (lastMajor < FLAXENGINE_VERSION_MAJOR || (lastMajor == FLAXENGINE_VERSION_MAJOR && lastMinor < FLAXENGINE_VERSION_MINOR))
else if (lastVersion.Major < FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor < FLAXENGINE_VERSION_MINOR))
{
LOG(Warning, "The project was opened with the older editor version last time");
const auto result = MessageBox::Show(TEXT("The project was opened with the older editor version last time. Loading it may modify existing data so older editor version won't open it. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question);
@@ -285,7 +286,7 @@ bool Editor::CheckProjectUpgrade()
}
}
// Check if last version was newer
else if (lastMajor > FLAXENGINE_VERSION_MAJOR || (lastMajor == FLAXENGINE_VERSION_MAJOR && lastMinor > FLAXENGINE_VERSION_MINOR))
else if (lastVersion.Major > FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor > FLAXENGINE_VERSION_MINOR))
{
LOG(Warning, "The project was opened with the newer editor version last time");
const auto result = MessageBox::Show(TEXT("The project was opened with the newer editor version last time. Loading it may fail and corrupt existing data. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning);
@@ -309,7 +310,7 @@ bool Editor::CheckProjectUpgrade()
}
// When changing between major/minor version clear some caches to prevent possible issues
if (lastMajor != FLAXENGINE_VERSION_MAJOR || lastMinor != FLAXENGINE_VERSION_MINOR)
if (lastVersion.Major != FLAXENGINE_VERSION_MAJOR || lastVersion.Minor != FLAXENGINE_VERSION_MINOR || lastVersion.RealSize != sizeof(Real))
{
LOG(Info, "Cleaning cache files from different engine version");
FileSystem::DeleteDirectory(Globals::ProjectFolder / TEXT("Cache/Cooker"));
@@ -318,7 +319,7 @@ bool Editor::CheckProjectUpgrade()
// Upgrade old 0.7 projects
// [Deprecated: 01.11.2020, expires 01.11.2021]
if (lastMajor == 0 && lastMinor == 7 && lastBuild <= 6197)
if (lastVersion.Major == 0 && lastVersion.Minor == 7 && lastVersion.Build <= 6197)
{
Array<String> files;
FileSystem::DirectoryGetFiles(files, Globals::ProjectSourceFolder, TEXT("*.Gen.cs"));
@@ -331,9 +332,8 @@ bool Editor::CheckProjectUpgrade()
auto file = FileWriteStream::Open(versionFilePath);
if (file)
{
file->WriteInt32(FLAXENGINE_VERSION_MAJOR);
file->WriteInt32(FLAXENGINE_VERSION_MINOR);
file->WriteInt32(FLAXENGINE_VERSION_BUILD);
lastVersion = VersionCache();
file->WriteBytes(&lastVersion, sizeof(lastVersion));
Delete(file);
}
else

View File

@@ -74,8 +74,7 @@ public sealed class ViewportRubberBandSelector
/// </summary>
/// <param name="canStart">Whether the creation can start.</param>
/// <param name="mousePosition">The current mouse position.</param>
/// <param name="viewFrustum">The view frustum.</param>
public void TryCreateRubberBand(bool canStart, Float2 mousePosition, BoundingFrustum viewFrustum)
public void TryCreateRubberBand(bool canStart, Float2 mousePosition)
{
if (_isRubberBandSpanning && !canStart)
{
@@ -101,32 +100,43 @@ public sealed class ViewportRubberBandSelector
_isMosueCaptured = true;
_owner.Viewport.StartMouseCapture();
}
UpdateRubberBand(ref viewFrustum);
UpdateRubberBand();
}
}
}
private struct ViewportProjection
{
private Viewport _viewport;
private Matrix _viewProjection;
private BoundingFrustum _frustum;
private Viewport _viewport;
private Vector3 _origin;
public void Init(EditorViewport editorViewport)
{
// Inline EditorViewport.ProjectPoint to save on calculation for large set of points
_viewport = new Viewport(0, 0, editorViewport.Width, editorViewport.Height);
var frustum = editorViewport.ViewFrustum;
_viewProjection = frustum.Matrix;
_frustum = editorViewport.ViewFrustum;
_viewProjection = _frustum.Matrix;
_origin = editorViewport.Task.View.Origin;
}
public void ProjectPoint(ref Vector3 worldSpaceLocation, out Float2 viewportSpaceLocation)
public void ProjectPoint(Vector3 worldSpaceLocation, out Float2 viewportSpaceLocation)
{
worldSpaceLocation -= _origin;
_viewport.Project(ref worldSpaceLocation, ref _viewProjection, out var projected);
viewportSpaceLocation = new Float2((float)projected.X, (float)projected.Y);
}
public ContainmentType FrustumCull(ref BoundingBox bounds)
{
bounds.Minimum -= _origin;
bounds.Maximum -= _origin;
return _frustum.Contains(ref bounds);
}
}
private void UpdateRubberBand(ref BoundingFrustum viewFrustum)
private void UpdateRubberBand()
{
Profiler.BeginEvent("UpdateRubberBand");
@@ -169,7 +179,7 @@ public sealed class ViewportRubberBandSelector
// Skip actor if outside of view frustum
var actorBox = a.EditorBox;
if (viewFrustum.Contains(actorBox) == ContainmentType.Disjoint)
if (projection.FrustumCull(ref actorBox) == ContainmentType.Disjoint)
continue;
// Get valid selection points
@@ -220,7 +230,7 @@ public sealed class ViewportRubberBandSelector
bool containsAllPoints = points.Length != 0;
for (int i = 0; i < points.Length; i++)
{
projection.ProjectPoint(ref points[i], out var loc);
projection.ProjectPoint(points[i], out var loc);
if (!adjustedRect.Contains(loc))
{
containsAllPoints = false;

View File

@@ -164,21 +164,10 @@ namespace FlaxEditor.States
{
Assert.AreEqual(Guid.Empty, _lastSceneFromRequest, "Invalid state.");
// Bind events, only bind loading event and error if re-loading the same scene to avoid issues.
if (_scenesToUnload.Count == 1 && _scenesToLoad.Count == 1)
{
if (_scenesToLoad[0] == _scenesToUnload[0].ID)
{
Level.SceneLoaded += OnSceneEvent;
Level.SceneLoadError += OnSceneEvent;
}
}
else
{
Level.SceneLoaded += OnSceneEvent;
Level.SceneLoadError += OnSceneEvent;
Level.SceneUnloaded += OnSceneEvent;
}
// Bind events
Level.SceneLoaded += OnSceneEvent;
Level.SceneLoadError += OnSceneEvent;
Level.SceneUnloaded += OnSceneEvent;
// Push scenes changing requests
for (int i = 0; i < _scenesToUnload.Count; i++)

View File

@@ -114,6 +114,18 @@ namespace FlaxEditor.Surface.Elements
{
result = (arch.BoxID == 0 ? asFloat4.X : arch.BoxID == 1 ? asFloat4.Y : arch.BoxID == 2 ? asFloat4.Z : asFloat4.W);
}
else if (value is Double2 asDouble2)
{
result = (float)(arch.BoxID == 0 ? asDouble2.X : asDouble2.Y);
}
else if (value is Double3 asDouble3)
{
result = (float)(arch.BoxID == 0 ? asDouble3.X : arch.BoxID == 1 ? asDouble3.Y : asDouble3.Z);
}
else if (value is Double4 asDouble4)
{
result = (float)(arch.BoxID == 0 ? asDouble4.X : arch.BoxID == 1 ? asDouble4.Y : arch.BoxID == 2 ? asDouble4.Z : asDouble4.W);
}
else
{
result = 0;
@@ -212,6 +224,36 @@ namespace FlaxEditor.Surface.Elements
asFloat4.W = toSet;
value = asFloat4;
}
else if (value is Double2 asDouble2)
{
if (arch.BoxID == 0)
asDouble2.X = toSet;
else
asDouble2.Y = toSet;
value = asDouble2;
}
else if (value is Double3 asDouble3)
{
if (arch.BoxID == 0)
asDouble3.X = toSet;
else if (arch.BoxID == 1)
asDouble3.Y = toSet;
else
asDouble3.Z = toSet;
value = asDouble3;
}
else if (value is Double4 asDouble4)
{
if (arch.BoxID == 0)
asDouble4.X = toSet;
else if (arch.BoxID == 1)
asDouble4.Y = toSet;
else if (arch.BoxID == 2)
asDouble4.Z = toSet;
else
asDouble4.W = toSet;
value = asDouble4;
}
else
{
value = 0;
@@ -269,6 +311,18 @@ namespace FlaxEditor.Surface.Elements
{
value = new Float4(toSet);
}
else if (value is Double2)
{
value = new Double2(toSet);
}
else if (value is Double3)
{
value = new Double3(toSet);
}
else if (value is Double4)
{
value = new Double4(toSet);
}
else
{
value = 0;

View File

@@ -611,8 +611,8 @@ namespace FlaxEditor.Viewport
// Don't allow rubber band selection when gizmo is controlling mouse, vertex painting mode, or cloth painting is enabled
bool canStart = !(IsControllingMouse || IsRightMouseButtonDown || IsAltKeyDown) &&
Gizmos.Active is TransformGizmo && !Gizmos.Active.IsControllingMouse;
_rubberBandSelector.TryCreateRubberBand(canStart, _viewMousePos, ViewFrustum);
Gizmos?.Active is TransformGizmo && !Gizmos.Active.IsControllingMouse;
_rubberBandSelector.TryCreateRubberBand(canStart, _viewMousePos);
}
/// <inheritdoc />

View File

@@ -149,6 +149,10 @@ namespace FlaxEditor.Windows.Assets
(instance, parameter, tag) => ((AnimationGraphWindow)instance).PreviewActor.GetParameterValue(parameter.Identifier),
(instance, value, parameter, tag) => ((AnimationGraphWindow)instance).PreviewActor.SetParameterValue(parameter.Identifier, value),
Values);
// Parameters will always have one element
if (parameters.Length < 2)
layout.Label("No parameters", TextAlignment.Center);
}
}
}

View File

@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.CustomEditors;
using FlaxEditor.Scripting;
@@ -104,6 +105,9 @@ namespace FlaxEditor.Windows.Assets
(instance, parameter, tag) => ((ParticleEmitterWindow)instance).Preview.PreviewActor.GetParameterValue(string.Empty, parameter.Name),
(instance, value, parameter, tag) => ((ParticleEmitterWindow)instance).Preview.PreviewActor.SetParameterValue(string.Empty, parameter.Name, value),
Values);
if (!parameters.Any())
layout.Label("No parameters", TextAlignment.Center);
}
}
}

View File

@@ -62,6 +62,7 @@ namespace FlaxEditor.Windows
AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
Parent = headerPanel,
Bounds = new Rectangle(4, 4, headerPanel.Width - 8, 18),
TooltipText = "Search the scene tree.\n\nYou can prefix your search with different search operators:\ns: -> Actor with script of type\na: -> Actor type\nc: -> Control type",
};
_searchBox.TextChanged += OnSearchBoxTextChanged;

View File

@@ -223,7 +223,7 @@ bool AnimGraphBase::onNodeLoaded(Node* n)
// Store triangles vertices indices (map the back to the anim node slots)
n->Data.MultiBlend2D.TrianglesCount = triangles.Count();
n->Data.MultiBlend2D.Triangles = (ANIM_GRAPH_MULTI_BLEND_INDEX*)Allocator::Allocate(triangles.Count() * 3 - sizeof(ANIM_GRAPH_MULTI_BLEND_INDEX));
n->Data.MultiBlend2D.Triangles = (ANIM_GRAPH_MULTI_BLEND_INDEX*)Allocator::Allocate(triangles.Count() * 3 * sizeof(ANIM_GRAPH_MULTI_BLEND_INDEX));
for (int32 i = 0, t = 0; i < triangles.Count(); i++)
{
n->Data.MultiBlend2D.Triangles[t++] = vertexToAnim[triangles[i].Indices[0]];

View File

@@ -888,9 +888,9 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
if (!CommandLine::Options.Headless.IsTrue())
{
if (ScriptsBuilder::LastCompilationFailed())
MessageBox::Show(TEXT("Scripts compilation failed. Cannot load scene without game script modules. Please fix the compilation issues. See logs for more info."), TEXT("Failed to compile scripts"), MessageBoxButtons::OK, MessageBoxIcon::Error);
MessageBox::Show(TEXT("Script compilation failed.\n\nCannot load scene without game script modules. Please fix any compilation issues.\n\nSee Output Log or logs for more info."), TEXT("Failed to compile scripts"), MessageBoxButtons::OK, MessageBoxIcon::Error);
else
MessageBox::Show(TEXT("Failed to load scripts. Cannot load scene without game script modules. See logs for more info."), TEXT("Missing game modules"), MessageBoxButtons::OK, MessageBoxIcon::Error);
MessageBox::Show(TEXT("Failed to load scripts.\n\nCannot load scene without game script modules.\n\nSee logs for more info."), TEXT("Missing game modules"), MessageBoxButtons::OK, MessageBoxIcon::Error);
}
#endif
return true;

View File

@@ -258,10 +258,10 @@ public:
API_FIELD(Attributes="EditorOrder(1100), EditorDisplay(\"Level Of Detail\", \"Generate LODs\"), VisibleIf(nameof(ShowGeometry))")
bool GenerateLODs = false;
// The index of the LOD from the source model data to use as a reference for following LODs generation.
API_FIELD(Attributes="EditorOrder(1110), EditorDisplay(\"Level Of Detail\", \"Base LOD\"), VisibleIf(nameof(ShowGeometry)), Limit(0, 5)")
API_FIELD(Attributes="EditorOrder(1110), EditorDisplay(\"Level Of Detail\", \"Base LOD\"), VisibleIf(nameof(ShowGeometry)), Limit(0, 5, 0.065f)")
int32 BaseLOD = 0;
// The amount of LODs to include in the model (all remaining ones starting from Base LOD will be generated).
API_FIELD(Attributes="EditorOrder(1120), EditorDisplay(\"Level Of Detail\", \"LOD Count\"), VisibleIf(nameof(ShowGeometry)), Limit(1, 6)")
API_FIELD(Attributes="EditorOrder(1120), EditorDisplay(\"Level Of Detail\", \"LOD Count\"), VisibleIf(nameof(ShowGeometry)), Limit(1, 6, 0.065f)")
int32 LODCount = 4;
// The target amount of triangles for the generated LOD (based on the higher LOD). Normalized to range 0-1. For instance 0.4 cuts the triangle count to 40%.
API_FIELD(Attributes="EditorOrder(1130), EditorDisplay(\"Level Of Detail\"), VisibleIf(nameof(ShowGeometry)), Limit(0, 1, 0.001f)")
@@ -309,7 +309,7 @@ public:
API_FIELD(Attributes="EditorOrder(2000), EditorDisplay(\"Splitting\"), VisibleIf(nameof(ShowSplitting))")
bool SplitObjects = false;
// The zero-based index for the mesh/animation clip to import. If the source file has more than one mesh/animation it can be used to pick a desired object. Default -1 imports all objects.
API_FIELD(Attributes="EditorOrder(2010), EditorDisplay(\"Splitting\"), VisibleIf(nameof(ShowSplitting))")
API_FIELD(Attributes="EditorOrder(2010), EditorDisplay(\"Splitting\"), VisibleIf(nameof(ShowSplitting)), Limit(int.MinValue, int.MaxValue, 0.065f)")
int32 ObjectIndex = -1;
public: // Other

View File

@@ -230,7 +230,8 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
case VariantType::Double4:
value = Double3(v1.AsDouble4()).Length();
break;
default: CRASH;
default:
value = 0.0f;
break;
}
break;
@@ -265,7 +266,8 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
case VariantType::Double4:
value = Double4(Double3::Normalize(Double3(v1.AsDouble3())), 0.0f);
break;
default: CRASH;
default:
value = 0.0f;
break;
}
break;
@@ -290,13 +292,25 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
case VariantType::Double3:
value = Double3::Cross(v1.AsDouble3(), v2.AsDouble3());
break;
default: CRASH;
default:
value = 0.0f;
break;
}
break;
case 19:
switch (v1.Type.Type)
{
case VariantType::Bool:
case VariantType::Int16:
case VariantType::Uint16:
case VariantType::Int:
case VariantType::Uint:
case VariantType::Int64:
case VariantType::Uint64:
case VariantType::Float:
case VariantType::Double:
value = Math::Abs((float)v1 - (float)v2);
break;
case VariantType::Float2:
value = Float2::Distance(v1.AsFloat2(), v2.AsFloat2());
break;
@@ -316,7 +330,8 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
case VariantType::Double4:
value = Double3::Distance((Double3)v1, (Double3)v2);
break;
default: CRASH;
default:
value = 0.0f;
break;
}
break;
@@ -342,7 +357,8 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
case VariantType::Double4:
value = Double3::Dot((Double3)v1, (Double3)v2);
break;
default: CRASH;
default:
value = 0.0f;
break;
}
break;
@@ -386,7 +402,8 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
case VariantType::Float4:
value = Float4(v1.AsFloat4() - 2.0f * v2.AsFloat4() * Float3::Dot((Float3)v1, (Float3)v2));
break;
default: CRASH;
default:
value = 0.0f;
break;
}
break;