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

This commit is contained in:
Wojtek Figat
2024-08-16 14:52:57 +02:00
47 changed files with 345 additions and 96 deletions

View File

@@ -80,7 +80,7 @@ namespace FlaxEditor.Content
// Translate asset type name // Translate asset type name
var typeName = TypeName; var typeName = TypeName;
string[] typeNamespaces = typeName.Split('.'); string[] typeNamespaces = typeName.Split('.');
if (typeNamespaces.Length != 0 && typeNamespaces.Length != 0) if (typeNamespaces.Length != 0 && typeNamespaces[typeNamespaces.Length - 1].Length != 0)
{ {
typeName = Utilities.Utils.GetPropertyNameUI(typeNamespaces[typeNamespaces.Length - 1]); typeName = Utilities.Utils.GetPropertyNameUI(typeNamespaces[typeNamespaces.Length - 1]);
} }

View File

@@ -208,7 +208,7 @@ namespace FlaxEditor.CustomEditors.Editors
else else
{ {
// Draw info // Draw info
Render2D.DrawText(style.FontMedium, Type != null ? $"None ({Utilities.Utils.GetPropertyNameUI(Type.ToString())})" : "-", nameRect, isEnabled ? Color.OrangeRed : Color.DarkOrange, TextAlignment.Near, TextAlignment.Center); Render2D.DrawText(style.FontMedium, Type != null ? $"None ({Utilities.Utils.GetPropertyNameUI(Type.ToString())})" : "-", nameRect, isEnabled ? style.ForegroundGrey : style.ForegroundGrey.AlphaMultiplied(0.75f), TextAlignment.Near, TextAlignment.Center);
} }
// Draw picker button // Draw picker button

View File

@@ -22,7 +22,7 @@ namespace FlaxEditor.GUI.Dialogs
/// <summary> /// <summary>
/// The parent window. /// The parent window.
/// </summary> /// </summary>
protected Window _window; protected volatile Window _window;
/// <summary> /// <summary>
/// The dialog result. /// The dialog result.

View File

@@ -89,6 +89,9 @@ namespace FlaxEditor.Surface
private static NodesCache _nodesCache = new NodesCache(IterateNodesCache); private static NodesCache _nodesCache = new NodesCache(IterateNodesCache);
/// <inheritdoc />
public override bool UseContextMenuDescriptionPanel => true;
/// <summary> /// <summary>
/// The state machine editing context menu. /// The state machine editing context menu.
/// </summary> /// </summary>

View File

@@ -156,7 +156,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Lerp", Title = "Lerp",
Description = "Performs a linear interpolation", Description = "Performs a linear interpolation",
Flags = NodeFlags.AllGraphs, Flags = NodeFlags.AllGraphs,
Size = new Float2(110, 60), Size = new Float2(150, 60),
ConnectionsHints = ConnectionsHint.Numeric, ConnectionsHints = ConnectionsHint.Numeric,
IndependentBoxes = new[] { 0, 1 }, IndependentBoxes = new[] { 0, 1 },
DependentBoxes = new[] { 3 }, DependentBoxes = new[] { 3 },

View File

@@ -25,6 +25,9 @@ namespace FlaxEditor.Surface
/// <inheritdoc /> /// <inheritdoc />
public override bool CanLivePreviewValueChanges => false; public override bool CanLivePreviewValueChanges => false;
/// <inheritdoc />
public override bool UseContextMenuDescriptionPanel => true;
/// <inheritdoc /> /// <inheritdoc />
public override string GetTypeName(ScriptType type) public override string GetTypeName(ScriptType type)
{ {

View File

@@ -24,6 +24,9 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
public FlaxEditor.Surface.Archetypes.Particles.ParticleEmitterNode RootNode => _rootNode; public FlaxEditor.Surface.Archetypes.Particles.ParticleEmitterNode RootNode => _rootNode;
/// <inheritdoc />
public override bool UseContextMenuDescriptionPanel => true;
/// <inheritdoc /> /// <inheritdoc />
public ParticleEmitterSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo) public ParticleEmitterSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
: base(owner, onSave, undo) : base(owner, onSave, undo)

View File

@@ -8,6 +8,7 @@ using System.Reflection;
using System.Text; using System.Text;
using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Elements; using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.Options;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Utilities; using FlaxEditor.Utilities;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
@@ -71,7 +72,12 @@ namespace FlaxEditor.Surface
} }
// By name // By name
return string.Compare(x.DisplayName, y.DisplayName, StringComparison.InvariantCulture); if (Editor.Instance.Options.Options.General.ScriptMembersOrder == GeneralOptions.MembersOrder.Alphabetical)
{
return string.Compare(x.DisplayName, y.DisplayName, StringComparison.InvariantCulture);
}
// Keep same order
return 0;
} }
} }

View File

@@ -492,7 +492,7 @@ namespace FlaxEditor.Surface
Focus(); Focus();
return true; return true;
} }
if (_rightMouseDown || (_middleMouseDown && _middleMouseDown)) if (_rightMouseDown || _middleMouseDown)
{ {
// Start navigating // Start navigating
StartMouseCapture(); StartMouseCapture();

View File

@@ -197,6 +197,12 @@ namespace FlaxEditor.Tools.Foliage
{ {
PaintEnd(); PaintEnd();
} }
// Increase or decrease brush size with scroll
if (Input.GetKey(KeyboardKeys.Shift) && !Input.GetMouseButton(MouseButton.Right))
{
Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f;
}
// Perform detailed tracing to find cursor location for the foliage placement // Perform detailed tracing to find cursor location for the foliage placement
var mouseRay = Owner.MouseRay; var mouseRay = Owner.MouseRay;

View File

@@ -113,6 +113,7 @@ namespace FlaxEditor.Tools.Terrain
} }
_createTerrainButton.Clicked += OnCreateNewTerrainClicked; _createTerrainButton.Clicked += OnCreateNewTerrainClicked;
OnSelectionChanged();
} }
private void OnSceneLoaded(Scene arg1, Guid arg2) private void OnSceneLoaded(Scene arg1, Guid arg2)
@@ -159,6 +160,7 @@ namespace FlaxEditor.Tools.Terrain
} }
_noTerrainPanel.Visible = terrain == null; _noTerrainPanel.Visible = terrain == null;
_modes.Visible = !_noTerrainPanel.Visible;
} }
private void InitSculptMode() private void InitSculptMode()

View File

@@ -151,7 +151,7 @@ namespace FlaxEditor.Tools.Terrain
} }
// Increase or decrease brush size with scroll // Increase or decrease brush size with scroll
if (Input.GetKey(KeyboardKeys.Shift)) if (Input.GetKey(KeyboardKeys.Shift) && !Input.GetMouseButton(MouseButton.Right))
{ {
Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f; Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f;
} }

View File

@@ -159,7 +159,7 @@ namespace FlaxEditor.Tools.Terrain
} }
// Increase or decrease brush size with scroll // Increase or decrease brush size with scroll
if (Input.GetKey(KeyboardKeys.Shift)) if (Input.GetKey(KeyboardKeys.Shift) && !Input.GetMouseButton(MouseButton.Right))
{ {
Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f; Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f;
} }

View File

@@ -79,7 +79,7 @@ namespace FlaxEditor.Utilities
value = Convert.ToInt32(value); value = Convert.ToInt32(value);
else if (type.Type == typeof(long)) else if (type.Type == typeof(long))
value = Convert.ToInt64(value); value = Convert.ToInt64(value);
else if (type.Type == typeof(int)) else if (type.Type == typeof(ushort))
value = Convert.ToUInt16(value); value = Convert.ToUInt16(value);
else if (type.Type == typeof(uint)) else if (type.Type == typeof(uint))
value = Convert.ToUInt32(value); value = Convert.ToUInt32(value);

View File

@@ -1612,7 +1612,7 @@ namespace FlaxEditor.Viewport
_input.IsPanning = !isAltDown && mbDown && !rbDown; _input.IsPanning = !isAltDown && mbDown && !rbDown;
_input.IsRotating = !isAltDown && !mbDown && rbDown; _input.IsRotating = !isAltDown && !mbDown && rbDown;
_input.IsMoving = !isAltDown && mbDown && rbDown; _input.IsMoving = !isAltDown && mbDown && rbDown;
_input.IsZooming = wheelInUse && !_input.IsShiftDown; _input.IsZooming = wheelInUse && !(_input.IsShiftDown || (!ContainsFocus && FlaxEngine.Input.GetKey(KeyboardKeys.Shift)));
_input.IsOrbiting = isAltDown && lbDown && !mbDown && !rbDown; _input.IsOrbiting = isAltDown && lbDown && !mbDown && !rbDown;
// Control move speed with RMB+Wheel // Control move speed with RMB+Wheel

View File

@@ -12,6 +12,7 @@ using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.Viewport namespace FlaxEditor.Viewport
{ {
@@ -62,6 +63,7 @@ namespace FlaxEditor.Viewport
private UpdateDelegate _update; private UpdateDelegate _update;
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
private readonly List<Actor> _debugDrawActors = new List<Actor>();
private PrefabSpritesRenderer _spritesRenderer; private PrefabSpritesRenderer _spritesRenderer;
private IntPtr _tempDebugDrawContext; private IntPtr _tempDebugDrawContext;
@@ -623,14 +625,44 @@ namespace FlaxEditor.Viewport
DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, false); DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, false);
} }
} }
// Debug draw all actors in prefab // Debug draw all actors in prefab and collect actors
var viewFlags = Task.ViewFlags;
var collectActors = (viewFlags & ViewFlags.PhysicsDebug) != 0 || (viewFlags & ViewFlags.LightsDebug) != 0;
_debugDrawActors.Clear();
foreach (var child in SceneGraphRoot.ChildNodes) foreach (var child in SceneGraphRoot.ChildNodes)
{ {
if (child is not ActorNode actorNode || !actorNode.Actor) if (child is not ActorNode actorNode || !actorNode.Actor)
continue; continue;
DebugDraw.DrawActorsTree(actorNode.Actor); var actor = actorNode.Actor;
if (collectActors)
Utils.GetActorsTree(_debugDrawActors, actor);
DebugDraw.DrawActorsTree(actor);
} }
// Draw physics debug
if ((viewFlags & ViewFlags.PhysicsDebug) != 0)
{
foreach (var actor in _debugDrawActors)
{
if (actor is Collider c && c.IsActiveInHierarchy)
{
DebugDraw.DrawColliderDebugPhysics(c, renderContext.View);
}
}
}
// Draw lights debug
if ((viewFlags & ViewFlags.LightsDebug) != 0)
{
foreach (var actor in _debugDrawActors)
{
if (actor is Light l && l.IsActiveInHierarchy)
DebugDraw.DrawLightDebug(l, renderContext.View);
}
}
_debugDrawActors.Clear();
} }
} }
} }

View File

@@ -1,11 +1,13 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Xml; using System.Xml;
using FlaxEditor.CustomEditors; using FlaxEditor.CustomEditors;
using FlaxEditor.SceneGraph; using FlaxEditor.SceneGraph;
using FlaxEditor.Viewport; using FlaxEditor.Viewport;
using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
namespace FlaxEditor.Windows namespace FlaxEditor.Windows
@@ -19,6 +21,8 @@ namespace FlaxEditor.Windows
{ {
private IEnumerable<object> undoRecordObjects; private IEnumerable<object> undoRecordObjects;
private readonly Dictionary<Guid, float> _actorScrollValues = new Dictionary<Guid, float>();
/// <inheritdoc /> /// <inheritdoc />
public override bool UseLayoutData => true; public override bool UseLayoutData => true;
@@ -57,9 +61,42 @@ namespace FlaxEditor.Windows
Presenter.GetUndoObjects += GetUndoObjects; Presenter.GetUndoObjects += GetUndoObjects;
Presenter.Features |= FeatureFlags.CacheExpandedGroups; Presenter.Features |= FeatureFlags.CacheExpandedGroups;
VScrollBar.ValueChanged += OnScrollValueChanged;
Editor.SceneEditing.SelectionChanged += OnSelectionChanged; Editor.SceneEditing.SelectionChanged += OnSelectionChanged;
} }
/// <inheritdoc />
public override void OnSceneLoaded(Scene scene, Guid sceneId)
{
base.OnSceneLoaded(scene, sceneId);
// Clear scroll values if new scene is loaded non additively
if (Level.ScenesCount > 1)
return;
_actorScrollValues.Clear();
}
private void OnScrollValueChanged()
{
if (Editor.SceneEditing.SelectionCount > 1)
return;
// Clear first 10 scroll values to keep the memory down. Dont need to cache very single value in a scene. We could expose this as a editor setting in the future.
if (_actorScrollValues.Count >= 20)
{
int i = 0;
foreach (var e in _actorScrollValues)
{
if (i >= 10)
break;
_actorScrollValues.Remove(e.Key);
i += 1;
}
}
_actorScrollValues[Editor.SceneEditing.Selection[0].ID] = VScrollBar.TargetValue;
}
private IEnumerable<object> GetUndoObjects(CustomEditorPresenter customEditorPresenter) private IEnumerable<object> GetUndoObjects(CustomEditorPresenter customEditorPresenter)
{ {
return undoRecordObjects; return undoRecordObjects;
@@ -75,6 +112,10 @@ namespace FlaxEditor.Windows
undoRecordObjects = Editor.SceneEditing.Selection.ConvertAll(x => x.UndoRecordObject).Distinct(); undoRecordObjects = Editor.SceneEditing.Selection.ConvertAll(x => x.UndoRecordObject).Distinct();
var objects = Editor.SceneEditing.Selection.ConvertAll(x => x.EditableObject).Distinct(); var objects = Editor.SceneEditing.Selection.ConvertAll(x => x.EditableObject).Distinct();
Presenter.Select(objects); Presenter.Select(objects);
// Set scroll value of window if it exists
if (Editor.SceneEditing.SelectionCount == 1)
VScrollBar.TargetValue = _actorScrollValues.GetValueOrDefault(Editor.SceneEditing.Selection[0].ID, 0);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -2237,8 +2237,9 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
{ {
// Start playing animation // Start playing animation
bucket.Index = i; bucket.Index = i;
bucket.TimePosition = 0.0f; // Keep bucket time position and blend in time for if blending between two anims in the same slot.
bucket.BlendInPosition = 0.0f; bucket.TimePosition = bucket.TimePosition;
bucket.BlendInPosition = bucket.BlendInPosition;
bucket.BlendOutPosition = 0.0f; bucket.BlendOutPosition = 0.0f;
bucket.LoopsDone = 0; bucket.LoopsDone = 0;
bucket.LoopsLeft = slot.LoopCount; bucket.LoopsLeft = slot.LoopCount;
@@ -2248,6 +2249,12 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
if (bucket.Index == -1 || !slots[bucket.Index].Animation->IsLoaded()) if (bucket.Index == -1 || !slots[bucket.Index].Animation->IsLoaded())
{ {
value = tryGetValue(node->GetBox(1), Value::Null); value = tryGetValue(node->GetBox(1), Value::Null);
// Reset times if time is left over from playing between different anims in the same slot.
if (bucket.BlendInPosition > 0)
{
bucket.TimePosition = 0;
bucket.BlendInPosition = 0;
}
return; return;
} }
} }
@@ -2256,12 +2263,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
auto& slot = slots[bucket.Index]; auto& slot = slots[bucket.Index];
Animation* anim = slot.Animation; Animation* anim = slot.Animation;
ASSERT(slot.Animation && slot.Animation->IsLoaded()); ASSERT(slot.Animation && slot.Animation->IsLoaded());
if (slot.Reset)
{
// Start from the begining
slot.Reset = false;
bucket.TimePosition = 0.0f;
}
const float deltaTime = slot.Pause ? 0.0f : context.DeltaTime * slot.Speed; const float deltaTime = slot.Pause ? 0.0f : context.DeltaTime * slot.Speed;
const float length = anim->GetLength(); const float length = anim->GetLength();
const bool loop = bucket.LoopsLeft != 0; const bool loop = bucket.LoopsLeft != 0;
@@ -2285,6 +2286,57 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
// Speed is accounted for in the new time pos, so keep sample speed at 1 // Speed is accounted for in the new time pos, so keep sample speed at 1
value = SampleAnimation(node, loop, length, 0.0f, bucket.TimePosition, newTimePos, anim, 1); value = SampleAnimation(node, loop, length, 0.0f, bucket.TimePosition, newTimePos, anim, 1);
bucket.TimePosition = newTimePos; bucket.TimePosition = newTimePos;
// On animation slot stop
if (slot.Reset)
{
// Blend between last anim and new anim if found, otherwise blend back to input.
Animation* sAnim = nullptr;
for (int32 i = 0; i < slots.Count(); i++)
{
if (bucket.Index == i)
continue;
auto& s = slots[i];
if (s.Animation && s.Name == slotName)
{
sAnim = s.Animation;
}
}
float oldTimePos = bucket.BlendOutPosition;
bucket.BlendOutPosition += deltaTime;
bucket.BlendInPosition = bucket.BlendOutPosition;
const float alpha = bucket.BlendOutPosition / slot.BlendOutTime;
if (sAnim != nullptr)
{
auto sValue = SampleAnimation(node, false, sAnim->GetLength(), 0.0f, oldTimePos, bucket.BlendInPosition, sAnim, 1);
//value = SampleAnimationsWithBlend(node, false, length, 0.0f, bucket.TimePosition, newTimePos, anim, sAnim, 1, 1, alpha);
value = Blend(node, value, sValue, alpha, AlphaBlendMode::HermiteCubic);
}
else
{
auto input = tryGetValue(node->GetBox(1), Value::Null);
value = Blend(node, value, input, alpha, AlphaBlendMode::HermiteCubic);
}
if (bucket.BlendOutPosition >= slot.BlendOutTime)
{
// Start from the beginning or the blend in position if next anim found.
slot.Animation = nullptr;
slot.Reset = false;
if (!sAnim)
{
bucket.TimePosition = 0;
bucket.BlendInPosition = 0;
}
else
{
bucket.TimePosition = bucket.BlendInPosition;
}
}
break;
}
if (bucket.LoopsLeft == 0 && slot.BlendOutTime > 0.0f && length - slot.BlendOutTime < bucket.TimePosition) if (bucket.LoopsLeft == 0 && slot.BlendOutTime > 0.0f && length - slot.BlendOutTime < bucket.TimePosition)
{ {
// Blend out // Blend out

View File

@@ -196,6 +196,7 @@ bool AudioService::Init()
LOG(Info, "Audio system initialization... (backend: {0})", AudioBackend::Name()); LOG(Info, "Audio system initialization... (backend: {0})", AudioBackend::Name());
EnableHRTF = settings->EnableHRTF;
if (AudioBackend::Init()) if (AudioBackend::Init())
{ {
LOG(Warning, "Failed to initialize audio backend."); LOG(Warning, "Failed to initialize audio backend.");

View File

@@ -313,6 +313,7 @@ void AudioSource::PlayInternal()
{ {
AudioBackend::Source::Play(SourceID); AudioBackend::Source::Play(SourceID);
_isActuallyPlayingSth = true; _isActuallyPlayingSth = true;
_startingToPlay = true;
} }
#if USE_EDITOR #if USE_EDITOR
@@ -394,6 +395,30 @@ void AudioSource::Update()
AudioBackend::Source::VelocityChanged(SourceID, _velocity); AudioBackend::Source::VelocityChanged(SourceID, _velocity);
} }
// Reset starting to play value once time is greater than zero
if (_startingToPlay && GetTime() > 0.0f)
{
_startingToPlay = false;
}
if (!UseStreaming() && Math::NearEqual(GetTime(), 0.0f) && _isActuallyPlayingSth && !_startingToPlay)
{
int32 queuedBuffers;
AudioBackend::Source::GetQueuedBuffersCount(this, queuedBuffers);
if (queuedBuffers)
{
if (GetIsLooping())
{
Stop();
Play();
}
else
{
Stop();
}
}
}
// Skip other update logic if it's not valid streamable source // Skip other update logic if it's not valid streamable source
if (!UseStreaming() || SourceID == 0) if (!UseStreaming() || SourceID == 0)
return; return;

View File

@@ -56,6 +56,7 @@ private:
bool _allowSpatialization; bool _allowSpatialization;
bool _isActuallyPlayingSth = false; bool _isActuallyPlayingSth = false;
bool _startingToPlay = false;
bool _needToUpdateStreamingBuffers = false; bool _needToUpdateStreamingBuffers = false;
States _state = States::Stopped; States _state = States::Stopped;

View File

@@ -662,13 +662,13 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
if (!failed) if (!failed)
{ {
stream->SetPosition(chunk->LocationInFile.Address); stream->SetPosition(chunk->LocationInFile.Address);
if (!stream->HasError())
break;
} }
if (!stream->HasError())
break;
} }
} }
if (stream->HasError()) if (!stream || stream->HasError())
{ {
failed = true; failed = true;
UnlockChunks(); UnlockChunks();

View File

@@ -94,8 +94,8 @@ namespace FlaxEngine
throw new ArgumentOutOfRangeException(nameof(values), "There must be sixteen and only four input values for Matrix2x2."); throw new ArgumentOutOfRangeException(nameof(values), "There must be sixteen and only four input values for Matrix2x2.");
M11 = values[0]; M11 = values[0];
M12 = values[1]; M12 = values[1];
M21 = values[3]; M21 = values[2];
M22 = values[4]; M22 = values[3];
} }
/// <summary> /// <summary>

View File

@@ -289,7 +289,7 @@ void Quaternion::Billboard(const Float3& objectPosition, const Float3& cameraPos
Quaternion Quaternion::FromDirection(const Float3& direction) Quaternion Quaternion::FromDirection(const Float3& direction)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), Quaternion::Identity);
Quaternion orientation; Quaternion orientation;
if (Float3::Dot(direction, Float3::Up) >= 0.999f) if (Float3::Dot(direction, Float3::Up) >= 0.999f)
{ {

View File

@@ -57,6 +57,7 @@ using Real = System.Single;
using System; using System;
using System.Globalization; using System.Globalization;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using FlaxEngine.Assertions;
namespace FlaxEngine namespace FlaxEngine
{ {
@@ -77,6 +78,7 @@ namespace FlaxEngine
{ {
Position = position; Position = position;
Direction = direction; Direction = direction;
Assert.IsTrue(Direction.IsNormalized, "The Ray Direction was not normalized");
} }
/// <summary> /// <summary>

View File

@@ -46,7 +46,7 @@ public:
: Position(position) : Position(position)
, Direction(direction) , Direction(direction)
{ {
ASSERT(Direction.IsNormalized()); CHECK_DEBUG(Direction.IsNormalized());
} }
public: public:

View File

@@ -324,15 +324,14 @@ public:
{ {
if (length <= 0) if (length <= 0)
return; return;
if (Base::Length() == 0) auto prev = Base::_data;
const auto prevLength = Base::_length;
if (prevLength == 0 || prev == nullptr)
{ {
Copy(data, length); Copy(data, length);
return; return;
} }
auto prev = Base::_data;
const auto prevLength = Base::_length;
Base::_length = prevLength + length; Base::_length = prevLength + length;
Base::_data = (T*)Allocator::Allocate(Base::_length * sizeof(T)); Base::_data = (T*)Allocator::Allocate(Base::_length * sizeof(T));

View File

@@ -2702,8 +2702,8 @@ void Variant::SetAsset(Asset* asset)
SetType(VariantType(VariantType::Asset)); SetType(VariantType(VariantType::Asset));
if (AsAsset) if (AsAsset)
{ {
asset->OnUnloaded.Unbind<Variant, &Variant::OnAssetUnloaded>(this); AsAsset->OnUnloaded.Unbind<Variant, &Variant::OnAssetUnloaded>(this);
asset->RemoveReference(); AsAsset->RemoveReference();
} }
AsAsset = asset; AsAsset = asset;
if (asset) if (asset)

View File

@@ -27,6 +27,8 @@
#include "Engine/Render2D/FontAsset.h" #include "Engine/Render2D/FontAsset.h"
#if USE_EDITOR #if USE_EDITOR
#include "Editor/Editor.h" #include "Editor/Editor.h"
#include "Engine/Level/Actors/Light.h"
#include "Engine/Physics/Colliders/Collider.h"
#endif #endif
// Debug draw service configuration // Debug draw service configuration
@@ -950,9 +952,26 @@ void DebugDraw::DrawActorsTree(Actor* actor)
actor->TreeExecute(function); actor->TreeExecute(function);
} }
#if USE_EDITOR
void DebugDraw::DrawColliderDebugPhysics(Collider* collider, RenderView& view)
{
if (!collider)
return;
collider->DrawPhysicsDebug(view);
}
void DebugDraw::DrawLightDebug(Light* light, RenderView& view)
{
if (!light)
return;
light->DrawLightsDebug(view);
}
#endif
void DebugDraw::DrawAxisFromDirection(const Vector3& origin, const Vector3& direction, float size, float duration, bool depthTest) void DebugDraw::DrawAxisFromDirection(const Vector3& origin, const Vector3& direction, float size, float duration, bool depthTest)
{ {
ASSERT(direction.IsNormalized()); CHECK_DEBUG(direction.IsNormalized());
const auto rot = Quaternion::FromDirection(direction); const auto rot = Quaternion::FromDirection(direction);
const Vector3 up = (rot * Vector3::Up); const Vector3 up = (rot * Vector3::Up);
const Vector3 forward = (rot * Vector3::Forward); const Vector3 forward = (rot * Vector3::Forward);
@@ -978,7 +997,7 @@ void DebugDraw::DrawRay(const Vector3& origin, const Vector3& direction, const C
void DebugDraw::DrawRay(const Vector3& origin, const Vector3& direction, const Color& color, float length, float duration, bool depthTest) void DebugDraw::DrawRay(const Vector3& origin, const Vector3& direction, const Color& color, float length, float duration, bool depthTest)
{ {
ASSERT(direction.IsNormalized()); CHECK_DEBUG(direction.IsNormalized());
if (isnan(length) || isinf(length)) if (isnan(length) || isinf(length))
return; return;
DrawLine(origin, origin + (direction * length), color, duration, depthTest); DrawLine(origin, origin + (direction * length), color, duration, depthTest);

View File

@@ -8,6 +8,9 @@
#include "Engine/Core/Math/Color.h" #include "Engine/Core/Math/Color.h"
#include "Engine/Core/Types/Span.h" #include "Engine/Core/Types/Span.h"
struct RenderView;
class Collider;
class Light;
struct RenderContext; struct RenderContext;
class GPUTextureView; class GPUTextureView;
class GPUContext; class GPUContext;
@@ -70,9 +73,23 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// <summary> /// <summary>
/// Draws the debug shapes for the given actor and the actor's children /// Draws the debug shapes for the given actor and the actor's children
/// </summary> /// </summary>
/// /// <param name="actor">The actor to start drawing at.</param> /// <param name="actor">The actor to start drawing at.</param>
API_FUNCTION() static void DrawActorsTree(Actor* actor); API_FUNCTION() static void DrawActorsTree(Actor* actor);
#if USE_EDITOR
/// <summary>
/// Draws the physics debug shapes for the given collider. Editor Only
/// </summary>
/// <param name="collider">The collider to draw.</param>
/// <param name="view">The render view to draw in.</param>
API_FUNCTION() static void DrawColliderDebugPhysics(Collider* collider, RenderView& view);
/// <summary>
/// Draws the light debug shapes for the given light. Editor Only
/// </summary>
/// <param name="light">The light debug to draw.</param>
/// <param name="view">The render view to draw in.</param>
API_FUNCTION() static void DrawLightDebug(Light* light, RenderView& view);
#endif
/// <summary> /// <summary>
/// Draws the lines axis from direction. /// Draws the lines axis from direction.
/// </summary> /// </summary>

View File

@@ -199,6 +199,7 @@ void GameBaseImpl::OnMainWindowClosed()
// Request engine exit // Request engine exit
Globals::IsRequestingExit = true; Globals::IsRequestingExit = true;
Engine::RequestingExit();
} }
void GameBaseImpl::OnPostRender(GPUContext* context, RenderContext& renderContext) void GameBaseImpl::OnPostRender(GPUContext* context, RenderContext& renderContext)

View File

@@ -70,6 +70,7 @@ Action Engine::LateFixedUpdate;
Action Engine::Draw; Action Engine::Draw;
Action Engine::Pause; Action Engine::Pause;
Action Engine::Unpause; Action Engine::Unpause;
Action Engine::RequestingExit;
Window* Engine::MainWindow = nullptr; Window* Engine::MainWindow = nullptr;
int32 Engine::Main(const Char* cmdLine) int32 Engine::Main(const Char* cmdLine)
@@ -259,10 +260,12 @@ void Engine::RequestExit(int32 exitCode)
{ {
Globals::IsRequestingExit = true; Globals::IsRequestingExit = true;
Globals::ExitCode = exitCode; Globals::ExitCode = exitCode;
RequestingExit();
} }
#else #else
Globals::IsRequestingExit = true; Globals::IsRequestingExit = true;
Globals::ExitCode = exitCode; Globals::ExitCode = exitCode;
RequestingExit();
#endif #endif
} }

View File

@@ -79,6 +79,11 @@ public:
/// </summary> /// </summary>
static Action Unpause; static Action Unpause;
/// <summary>
/// Event called when the engine is requesting exit.
/// </summary>
API_EVENT() static Action RequestingExit;
public: public:
/// <summary> /// <summary>

View File

@@ -59,9 +59,19 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
// True if fatal error occurred (engine is exiting) // True if fatal error occurred (engine is exiting)
static bool FatalErrorOccurred; static bool FatalErrorOccurred;
// True if engine need to be closed // True if engine needs to be closed
static bool IsRequestingExit; static bool IsRequestingExit;
/// <summary>
/// True if engine needs to be closed
/// </summary>
API_PROPERTY() FORCE_INLINE static bool GetIsRequestingExit() { return IsRequestingExit; }
/// <summary>
/// True if fatal error occurred (engine is exiting)
/// </summary>
API_PROPERTY() FORCE_INLINE static bool GetFatalErrorOccurred() { return FatalErrorOccurred; }
// Exit code // Exit code
static int32 ExitCode; static int32 ExitCode;

View File

@@ -996,37 +996,37 @@ public:
/// <summary> /// <summary>
/// Called when actor parent gets changed. /// Called when actor parent gets changed.
/// </summary> /// </summary>
virtual void OnParentChanged(); API_FUNCTION() virtual void OnParentChanged();
/// <summary> /// <summary>
/// Called when actor transform gets changed. /// Called when actor transform gets changed.
/// </summary> /// </summary>
virtual void OnTransformChanged(); API_FUNCTION() virtual void OnTransformChanged();
/// <summary> /// <summary>
/// Called when actor active state gets changed. /// Called when actor active state gets changed.
/// </summary> /// </summary>
virtual void OnActiveChanged(); API_FUNCTION() virtual void OnActiveChanged();
/// <summary> /// <summary>
/// Called when actor active in tree state gets changed. /// Called when actor active in tree state gets changed.
/// </summary> /// </summary>
virtual void OnActiveInTreeChanged(); API_FUNCTION() virtual void OnActiveInTreeChanged();
/// <summary> /// <summary>
/// Called when order in parent children array gets changed. /// Called when order in parent children array gets changed.
/// </summary> /// </summary>
virtual void OnOrderInParentChanged(); API_FUNCTION() virtual void OnOrderInParentChanged();
/// <summary> /// <summary>
/// Called when actor static flag gets changed. /// Called when actor static flag gets changed.
/// </summary> /// </summary>
virtual void OnStaticFlagsChanged(); API_FUNCTION() virtual void OnStaticFlagsChanged();
/// <summary> /// <summary>
/// Called when layer gets changed. /// Called when layer gets changed.
/// </summary> /// </summary>
virtual void OnLayerChanged(); API_FUNCTION() virtual void OnLayerChanged();
/// <summary> /// <summary>
/// Called when adding object to the game. /// Called when adding object to the game.

View File

@@ -506,7 +506,7 @@ void AnimatedModel::StopSlotAnimation(const StringView& slotName, Animation* ani
{ {
if (slot.Animation == anim && slot.Name == slotName) if (slot.Animation == anim && slot.Name == slotName)
{ {
slot.Animation = nullptr; //slot.Animation = nullptr; // TODO: make an immediate version of this method and set the animation to nullptr.
slot.Reset = true; slot.Reset = true;
break; break;
} }

View File

@@ -71,7 +71,7 @@ void Collider::SetContactOffset(float value)
bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) const bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) const
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
resultHitDistance = MAX_float; resultHitDistance = MAX_float;
if (_shape == nullptr) if (_shape == nullptr)
return false; return false;
@@ -80,7 +80,7 @@ bool Collider::RayCast(const Vector3& origin, const Vector3& direction, float& r
bool Collider::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) const bool Collider::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) const
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
if (_shape == nullptr) if (_shape == nullptr)
return false; return false;
return PhysicsBackend::RayCastShape(_shape, _transform.Translation, _transform.Orientation, origin, direction, hitInfo, maxDistance); return PhysicsBackend::RayCastShape(_shape, _transform.Translation, _transform.Orientation, origin, direction, hitInfo, maxDistance);

View File

@@ -154,10 +154,6 @@ protected:
/// </summary> /// </summary>
void RemoveStaticActor(); void RemoveStaticActor();
#if USE_EDITOR
virtual void DrawPhysicsDebug(RenderView& view);
#endif
private: private:
void OnMaterialChanged(); void OnMaterialChanged();
@@ -169,6 +165,10 @@ public:
void ClosestPoint(const Vector3& point, Vector3& result) const final; void ClosestPoint(const Vector3& point, Vector3& result) const final;
bool ContainsPoint(const Vector3& point) const final; bool ContainsPoint(const Vector3& point) const final;
#if USE_EDITOR
virtual void DrawPhysicsDebug(RenderView& view);
#endif
protected: protected:
// [PhysicsColliderActor] // [PhysicsColliderActor]
void OnEnable() override; void OnEnable() override;

View File

@@ -235,91 +235,91 @@ bool Physics::LineCastAll(const Vector3& start, const Vector3& end, Array<RayCas
bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers); return DefaultScene->RayCast(origin, direction, maxDistance, layerMask, hitTriggers);
} }
bool Physics::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->RayCast(origin, direction, hitInfo, maxDistance, layerMask, hitTriggers); return DefaultScene->RayCast(origin, direction, hitInfo, maxDistance, layerMask, hitTriggers);
} }
bool Physics::RayCastAll(const Vector3& origin, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::RayCastAll(const Vector3& origin, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->RayCastAll(origin, direction, results, maxDistance, layerMask, hitTriggers); return DefaultScene->RayCastAll(origin, direction, results, maxDistance, layerMask, hitTriggers);
} }
bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->BoxCast(center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->BoxCast(center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->BoxCast(center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->BoxCast(center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->BoxCastAll(center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->BoxCastAll(center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->SphereCast(center, radius, direction, maxDistance, layerMask, hitTriggers); return DefaultScene->SphereCast(center, radius, direction, maxDistance, layerMask, hitTriggers);
} }
bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->SphereCast(center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers); return DefaultScene->SphereCast(center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers);
} }
bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->SphereCastAll(center, radius, direction, results, maxDistance, layerMask, hitTriggers); return DefaultScene->SphereCastAll(center, radius, direction, results, maxDistance, layerMask, hitTriggers);
} }
bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->CapsuleCast(center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->CapsuleCast(center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->CapsuleCast(center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->CapsuleCast(center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->CapsuleCastAll(center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->CapsuleCastAll(center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->ConvexCast(center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->ConvexCast(center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->ConvexCast(center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->ConvexCast(center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
} }
bool Physics::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool Physics::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return DefaultScene->ConvexCastAll(center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers); return DefaultScene->ConvexCastAll(center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers);
} }
@@ -520,91 +520,91 @@ bool PhysicsScene::LineCastAll(const Vector3& start, const Vector3& end, Array<R
bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::RayCast(_scene, origin, direction, maxDistance, layerMask, hitTriggers); return PhysicsBackend::RayCast(_scene, origin, direction, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::RayCast(_scene, origin, direction, hitInfo, maxDistance, layerMask, hitTriggers); return PhysicsBackend::RayCast(_scene, origin, direction, hitInfo, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::RayCastAll(const Vector3& origin, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::RayCastAll(const Vector3& origin, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::RayCastAll(_scene, origin, direction, results, maxDistance, layerMask, hitTriggers); return PhysicsBackend::RayCastAll(_scene, origin, direction, results, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::BoxCast(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::BoxCast(_scene, center, halfExtents, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::BoxCastAll(const Vector3& center, const Vector3& halfExtents, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::BoxCastAll(_scene, center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::BoxCastAll(_scene, center, halfExtents, direction, results, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::SphereCast(_scene, center, radius, direction, maxDistance, layerMask, hitTriggers); return PhysicsBackend::SphereCast(_scene, center, radius, direction, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::SphereCast(const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::SphereCast(_scene, center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers); return PhysicsBackend::SphereCast(_scene, center, radius, direction, hitInfo, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::SphereCastAll(const Vector3& center, const float radius, const Vector3& direction, Array<RayCastHit>& results, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::SphereCastAll(_scene, center, radius, direction, results, maxDistance, layerMask, hitTriggers); return PhysicsBackend::SphereCastAll(_scene, center, radius, direction, results, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::CapsuleCast(_scene, center, radius, height, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::CapsuleCastAll(_scene, center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::CapsuleCastAll(_scene, center, radius, height, direction, results, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::ConvexCast(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::ConvexCast(_scene, center, convexMesh, scale, direction, hitInfo, rotation, maxDistance, layerMask, hitTriggers);
} }
bool PhysicsScene::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers) bool PhysicsScene::ConvexCastAll(const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
return PhysicsBackend::ConvexCastAll(_scene, center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers); return PhysicsBackend::ConvexCastAll(_scene, center, convexMesh, scale, direction, results, rotation, maxDistance, layerMask, hitTriggers);
} }

View File

@@ -271,6 +271,7 @@ void PlatformBase::Fatal(const Char* msg, void* context)
Globals::FatalErrorOccurred = true; Globals::FatalErrorOccurred = true;
Globals::IsRequestingExit = true; Globals::IsRequestingExit = true;
Globals::ExitCode = -1; Globals::ExitCode = -1;
Engine::RequestingExit();
// Collect crash info (platform-dependant implementation that might collect stack trace and/or create memory dump) // Collect crash info (platform-dependant implementation that might collect stack trace and/or create memory dump)
{ {

View File

@@ -35,7 +35,7 @@
#endif #endif
#if ENABLE_ASSERTION #if ENABLE_ASSERTION
// Performs hard assertion of the expression. Crashes the engine and inserts debugger break in case of expression fail. // Performs a hard assertion of the expression. Crashes the engine and triggers a debugger break if the expression fails.
#define ASSERT(expression) \ #define ASSERT(expression) \
if (!(expression)) \ if (!(expression)) \
{ \ { \
@@ -46,24 +46,40 @@
Platform::Assert(#expression, __FILE__, __LINE__); \ Platform::Assert(#expression, __FILE__, __LINE__); \
} }
#else #else
// Performs a hard assertion of the expression. Crashes the engine and triggers a debugger break if the expression fails.
#define ASSERT(expression) ((void)0) #define ASSERT(expression) ((void)0)
#endif #endif
#if ENABLE_ASSERTION_LOW_LAYERS #if ENABLE_ASSERTION_LOW_LAYERS
// Performs a hard assertion of the expression. Crashes the engine and triggers a debugger break if the expression fails.
#define ASSERT_LOW_LAYER(x) ASSERT(x) #define ASSERT_LOW_LAYER(x) ASSERT(x)
#else #else
// Performs a hard assertion of the expression. Crashes the engine and triggers a debugger break if the expression fails.
#define ASSERT_LOW_LAYER(x) #define ASSERT_LOW_LAYER(x)
#endif #endif
// Performs soft check of the expression. Logs the expression fail to log and returns the function call. // Performs a soft check of the expression. Logs the expression failure and returns from the function call.
#define CHECK(expression) \ #define CHECK(expression) \
if (!(expression)) \ if (!(expression)) \
{ \ { \
Platform::CheckFailed(#expression, __FILE__, __LINE__); \ Platform::CheckFailed(#expression, __FILE__, __LINE__); \
return; \ return; \
} }
// Performs a soft check of the expression. Logs the expression failure and returns from the function call using the given return value.
#define CHECK_RETURN(expression, returnValue) \ #define CHECK_RETURN(expression, returnValue) \
if (!(expression)) \ if (!(expression)) \
{ \ { \
Platform::CheckFailed(#expression, __FILE__, __LINE__); \ Platform::CheckFailed(#expression, __FILE__, __LINE__); \
return returnValue; \ return returnValue; \
} }
#if ENABLE_ASSERTION
// Performs a soft check of the expression. Logs the expression failure and returns from the function call.
#define CHECK_DEBUG(expression) CHECK(expression)
// Performs a soft check of the expression. Logs the expression failure and returns from the function call using the given return value.
#define CHECK_RETURN_DEBUG(expression, returnValue) CHECK_RETURN(expression, returnValue)
#else
// Performs a soft check of the expression. Logs the expression failure and returns from the function call.
#define CHECK_DEBUG(expression) ((void)0)
// Performs a soft check of the expression. Logs the expression failure and returns from the function call using the given return value.
#define CHECK_RETURN_DEBUG(expression, returnValue) ((void)0)
#endif

View File

@@ -130,7 +130,7 @@ public:
} }
/// <summary> /// <summary>
/// Gets the terrain LODs distribution parameter. Adjusts terrain chunks transitions distances. Use lower value to increase terrain quality or higher value to increase performance. Default value is 0.75. /// Gets the terrain LODs distribution parameter. Adjusts terrain chunks transitions distances. Use lower value to increase terrain quality or higher value to increase performance.
/// </summary> /// </summary>
API_PROPERTY(Attributes="EditorOrder(70), DefaultValue(0.6f), Limit(0, 5, 0.01f), EditorDisplay(\"Terrain\", \"LOD Distribution\")") API_PROPERTY(Attributes="EditorOrder(70), DefaultValue(0.6f), Limit(0, 5, 0.01f), EditorDisplay(\"Terrain\", \"LOD Distribution\")")
FORCE_INLINE float GetLODDistribution() const FORCE_INLINE float GetLODDistribution() const
@@ -139,7 +139,7 @@ public:
} }
/// <summary> /// <summary>
/// Sets the terrain LODs distribution parameter. Adjusts terrain chunks transitions distances. Use lower value to increase terrain quality or higher value to increase performance. Default value is 0.75. /// Sets the terrain LODs distribution parameter. Adjusts terrain chunks transitions distances. Use lower value to increase terrain quality or higher value to increase performance.
/// </summary> /// </summary>
API_PROPERTY() void SetLODDistribution(float value); API_PROPERTY() void SetLODDistribution(float value);

View File

@@ -1963,7 +1963,7 @@ bool TerrainPatch::UpdateCollision()
bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) const bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance) const
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
if (_physicsShape == nullptr) if (_physicsShape == nullptr)
return false; return false;
Vector3 shapePos; Vector3 shapePos;
@@ -1974,7 +1974,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance) const bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance) const
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
if (_physicsShape == nullptr) if (_physicsShape == nullptr)
return false; return false;
Vector3 shapePos; Vector3 shapePos;
@@ -1992,7 +1992,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance) const bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance) const
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
if (_physicsShape == nullptr) if (_physicsShape == nullptr)
return false; return false;
Vector3 shapePos; Vector3 shapePos;
@@ -2030,7 +2030,7 @@ bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, floa
bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) const bool TerrainPatch::RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance) const
{ {
ASSERT(direction.IsNormalized()); CHECK_RETURN_DEBUG(direction.IsNormalized(), false);
if (_physicsShape == nullptr) if (_physicsShape == nullptr)
return false; return false;
Vector3 shapePos; Vector3 shapePos;

View File

@@ -77,7 +77,7 @@ namespace FlaxEngine.GUI
/// </summary> /// </summary>
public void Hide() public void Hide()
{ {
_window.Show(); _window.Hide();
} }
/// <summary> /// <summary>

View File

@@ -17,7 +17,7 @@ MMethod* UICanvas_PostDeserialize = nullptr;
MMethod* UICanvas_Enable = nullptr; MMethod* UICanvas_Enable = nullptr;
MMethod* UICanvas_Disable = nullptr; MMethod* UICanvas_Disable = nullptr;
#if USE_EDITOR #if USE_EDITOR
MMethod* UICanvas_OnActiveInTreeChanged = nullptr; MMethod* UICanvas_ActiveInTreeChanged = nullptr;
#endif #endif
MMethod* UICanvas_EndPlay = nullptr; MMethod* UICanvas_EndPlay = nullptr;
MMethod* UICanvas_ParentChanged = nullptr; MMethod* UICanvas_ParentChanged = nullptr;
@@ -49,7 +49,7 @@ UICanvas::UICanvas(const SpawnParams& params)
UICanvas_Enable = mclass->GetMethod("Enable"); UICanvas_Enable = mclass->GetMethod("Enable");
UICanvas_Disable = mclass->GetMethod("Disable"); UICanvas_Disable = mclass->GetMethod("Disable");
#if USE_EDITOR #if USE_EDITOR
UICanvas_OnActiveInTreeChanged = mclass->GetMethod("OnActiveInTreeChanged"); UICanvas_ActiveInTreeChanged = mclass->GetMethod("ActiveInTreeChanged");
#endif #endif
UICanvas_EndPlay = mclass->GetMethod("EndPlay"); UICanvas_EndPlay = mclass->GetMethod("EndPlay");
UICanvas_ParentChanged = mclass->GetMethod("ParentChanged"); UICanvas_ParentChanged = mclass->GetMethod("ParentChanged");
@@ -182,7 +182,7 @@ void UICanvas::OnTransformChanged()
void UICanvas::OnActiveInTreeChanged() void UICanvas::OnActiveInTreeChanged()
{ {
UICANVAS_INVOKE(OnActiveInTreeChanged); UICANVAS_INVOKE(ActiveInTreeChanged);
// Base // Base
Actor::OnActiveInTreeChanged(); Actor::OnActiveInTreeChanged();

View File

@@ -777,7 +777,7 @@ namespace FlaxEngine
} }
#if FLAX_EDITOR #if FLAX_EDITOR
internal void OnActiveInTreeChanged() internal void ActiveInTreeChanged()
{ {
if (RenderMode == CanvasRenderMode.ScreenSpace && _editorRoot != null && _guiRoot != null) if (RenderMode == CanvasRenderMode.ScreenSpace && _editorRoot != null && _guiRoot != null)
{ {

View File

@@ -156,6 +156,7 @@ namespace Flax.Build.Bindings
// Numbers // Numbers
if (float.TryParse(value, out _) || (value[value.Length - 1] == 'f' && float.TryParse(value.Substring(0, value.Length - 1), out _))) if (float.TryParse(value, out _) || (value[value.Length - 1] == 'f' && float.TryParse(value.Substring(0, value.Length - 1), out _)))
{ {
value = value.Replace(".f", ".0f");
// If the value type is different than the value (eg. value is int but the field is float) then cast it for the [DefaultValue] attribute // If the value type is different than the value (eg. value is int but the field is float) then cast it for the [DefaultValue] attribute
if (valueType != null && attribute) if (valueType != null && attribute)
return $"({GenerateCSharpNativeToManaged(buildData, valueType, caller)}){value}"; return $"({GenerateCSharpNativeToManaged(buildData, valueType, caller)}){value}";
@@ -179,7 +180,7 @@ namespace Flax.Build.Bindings
foreach (var vectorType in CSharpVectorTypes) foreach (var vectorType in CSharpVectorTypes)
{ {
if (value.Length > vectorType.Length + 4 && value.StartsWith(vectorType) && value[vectorType.Length] == '(') if (value.Length > vectorType.Length + 4 && value.StartsWith(vectorType) && value[vectorType.Length] == '(')
return $"typeof({vectorType}), \"{value.Substring(vectorType.Length + 1, value.Length - vectorType.Length - 2).Replace("f", "")}\""; return $"typeof({vectorType}), \"{value.Substring(vectorType.Length + 1, value.Length - vectorType.Length - 2).Replace(".f", ".0").Replace("f", "")}\"";
} }
return null; return null;