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

This commit is contained in:
Wojtek Figat
2024-08-22 17:33:20 +02:00
24 changed files with 269 additions and 88 deletions

View File

@@ -124,3 +124,7 @@ Install `.NET SDK`, `NuGet package manager` and `NuGet targets and build tasks`
Using Flax source code is strictly governed by the Flax Engine End User License Agreement. If you don't agree to those terms, as amended from time to time, you are not permitted to access or use Flax Engine. Using Flax source code is strictly governed by the Flax Engine End User License Agreement. If you don't agree to those terms, as amended from time to time, you are not permitted to access or use Flax Engine.
We welcome any contributions to Flax Engine development through pull requests on GitHub. Most of our active development is in the master branch, so we prefer to take pull requests there (particularly for new features). We try to make sure that all new code adheres to the Flax coding standards. All contributions are governed by the terms of the [EULA](https://flaxengine.com/licensing/). We welcome any contributions to Flax Engine development through pull requests on GitHub. Most of our active development is in the master branch, so we prefer to take pull requests there (particularly for new features). We try to make sure that all new code adheres to the Flax coding standards. All contributions are governed by the terms of the [EULA](https://flaxengine.com/licensing/).
## SAST Tools
[PVS-Studio](https://pvs-studio.com/en/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.

View File

@@ -1,5 +1,7 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.Surface; using FlaxEditor.Surface;
using FlaxEngine; using FlaxEngine;
@@ -12,6 +14,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
[CustomEditor(typeof(AnimatedModel)), DefaultEditor] [CustomEditor(typeof(AnimatedModel)), DefaultEditor]
public class AnimatedModelEditor : ActorEditor public class AnimatedModelEditor : ActorEditor
{ {
private bool _parametersAdded = false;
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
@@ -31,6 +35,24 @@ namespace FlaxEditor.CustomEditors.Dedicated
(instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier), (instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier),
(instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value), (instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value),
Values); Values);
_parametersAdded = true;
}
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
// Check if parameters group is still showing if not in play mode and hide it.
if (!Editor.Instance.StateMachine.IsPlayMode && _parametersAdded)
{
var group = Layout.Children.Find(x => x is GroupElement g && g.Panel.HeaderText.Equals("Parameters", StringComparison.Ordinal));
if (group != null)
{
RebuildLayout();
_parametersAdded = false;
}
} }
} }
} }

View File

@@ -178,6 +178,8 @@ namespace FlaxEditor.CustomEditors.Editors
return 1; return 1;
if (Info.MetadataToken < other.Info.MetadataToken) if (Info.MetadataToken < other.Info.MetadataToken)
return -1; return -1;
// Keep declaration order if same metadata token.
return 0;
} }
// By name // By name

View File

@@ -138,18 +138,17 @@ namespace FlaxEditor.Gizmo
private void UpdateGizmoPosition() private void UpdateGizmoPosition()
{ {
var position = Vector3.Zero;
// Get gizmo pivot // Get gizmo pivot
switch (_activePivotType) switch (_activePivotType)
{ {
case PivotType.ObjectCenter: case PivotType.ObjectCenter:
if (SelectionCount > 0) if (SelectionCount > 0)
Position = GetSelectedTransform(0).Translation; position = GetSelectedTransform(0).Translation;
break; break;
case PivotType.SelectionCenter: case PivotType.SelectionCenter:
Position = GetSelectionCenter(); position = GetSelectionCenter();
break;
case PivotType.WorldOrigin:
Position = Vector3.Zero;
break; break;
} }
@@ -157,11 +156,13 @@ namespace FlaxEditor.Gizmo
if (_vertexSnapObject != null) if (_vertexSnapObject != null)
{ {
Vector3 vertexSnapPoint = _vertexSnapObject.Transform.LocalToWorld(_vertexSnapPoint); Vector3 vertexSnapPoint = _vertexSnapObject.Transform.LocalToWorld(_vertexSnapPoint);
Position += vertexSnapPoint - Position; position += vertexSnapPoint - position;
} }
// Apply current movement // Apply current movement
Position += _translationDelta; position += _translationDelta;
Position = position;
} }
private void UpdateMatrices() private void UpdateMatrices()
@@ -213,10 +214,11 @@ namespace FlaxEditor.Gizmo
ray.Position = Vector3.Transform(ray.Position, invRotationMatrix); ray.Position = Vector3.Transform(ray.Position, invRotationMatrix);
Vector3.TransformNormal(ref ray.Direction, ref invRotationMatrix, out ray.Direction); Vector3.TransformNormal(ref ray.Direction, ref invRotationMatrix, out ray.Direction);
var planeXY = new Plane(Vector3.Backward, Vector3.Transform(Position, invRotationMatrix).Z); var position = Position;
var planeYZ = new Plane(Vector3.Left, Vector3.Transform(Position, invRotationMatrix).X); var planeXY = new Plane(Vector3.Backward, Vector3.Transform(position, invRotationMatrix).Z);
var planeZX = new Plane(Vector3.Down, Vector3.Transform(Position, invRotationMatrix).Y); var planeYZ = new Plane(Vector3.Left, Vector3.Transform(position, invRotationMatrix).X);
var dir = Vector3.Normalize(ray.Position - Position); var planeZX = new Plane(Vector3.Down, Vector3.Transform(position, invRotationMatrix).Y);
var dir = Vector3.Normalize(ray.Position - position);
var planeDotXY = Mathf.Abs(Vector3.Dot(planeXY.Normal, dir)); var planeDotXY = Mathf.Abs(Vector3.Dot(planeXY.Normal, dir));
var planeDotYZ = Mathf.Abs(Vector3.Dot(planeYZ.Normal, dir)); var planeDotYZ = Mathf.Abs(Vector3.Dot(planeYZ.Normal, dir));
var planeDotZX = Mathf.Abs(Vector3.Dot(planeZX.Normal, dir)); var planeDotZX = Mathf.Abs(Vector3.Dot(planeZX.Normal, dir));
@@ -229,8 +231,8 @@ namespace FlaxEditor.Gizmo
var plane = planeDotXY > planeDotZX ? planeXY : planeZX; var plane = planeDotXY > planeDotZX ? planeXY : planeZX;
if (ray.Intersects(ref plane, out intersection)) if (ray.Intersects(ref plane, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(_tDelta.X, 0, 0); delta = new Vector3(_tDelta.X, 0, 0);
} }
@@ -241,8 +243,8 @@ namespace FlaxEditor.Gizmo
var plane = planeDotXY > planeDotYZ ? planeXY : planeYZ; var plane = planeDotXY > planeDotYZ ? planeXY : planeYZ;
if (ray.Intersects(ref plane, out intersection)) if (ray.Intersects(ref plane, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(0, _tDelta.Y, 0); delta = new Vector3(0, _tDelta.Y, 0);
} }
@@ -253,8 +255,8 @@ namespace FlaxEditor.Gizmo
var plane = planeDotZX > planeDotYZ ? planeZX : planeYZ; var plane = planeDotZX > planeDotYZ ? planeZX : planeYZ;
if (ray.Intersects(ref plane, out intersection)) if (ray.Intersects(ref plane, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(0, 0, _tDelta.Z); delta = new Vector3(0, 0, _tDelta.Z);
} }
@@ -264,8 +266,8 @@ namespace FlaxEditor.Gizmo
{ {
if (ray.Intersects(ref planeYZ, out intersection)) if (ray.Intersects(ref planeYZ, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(0, _tDelta.Y, _tDelta.Z); delta = new Vector3(0, _tDelta.Y, _tDelta.Z);
} }
@@ -275,8 +277,8 @@ namespace FlaxEditor.Gizmo
{ {
if (ray.Intersects(ref planeXY, out intersection)) if (ray.Intersects(ref planeXY, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(_tDelta.X, _tDelta.Y, 0); delta = new Vector3(_tDelta.X, _tDelta.Y, 0);
} }
@@ -286,8 +288,8 @@ namespace FlaxEditor.Gizmo
{ {
if (ray.Intersects(ref planeZX, out intersection)) if (ray.Intersects(ref planeZX, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(_tDelta.X, 0, _tDelta.Z); delta = new Vector3(_tDelta.X, 0, _tDelta.Z);
} }
@@ -299,8 +301,8 @@ namespace FlaxEditor.Gizmo
var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length); var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length);
if (ray.Intersects(ref plane, out intersection)) if (ray.Intersects(ref plane, out intersection))
{ {
_intersectPosition = ray.Position + ray.Direction * intersection; _intersectPosition = ray.GetPoint(intersection);
if (_lastIntersectionPosition != Vector3.Zero) if (!_lastIntersectionPosition.IsZero)
_tDelta = _intersectPosition - _lastIntersectionPosition; _tDelta = _intersectPosition - _lastIntersectionPosition;
} }
delta = _tDelta; delta = _tDelta;
@@ -412,10 +414,8 @@ namespace FlaxEditor.Gizmo
public override void Update(float dt) public override void Update(float dt)
{ {
LastDelta = Transform.Identity; LastDelta = Transform.Identity;
if (!IsActive) if (!IsActive)
return; return;
bool isLeftBtnDown = Owner.IsLeftMouseButtonDown; bool isLeftBtnDown = Owner.IsLeftMouseButtonDown;
// Snap to ground // Snap to ground
@@ -516,6 +516,7 @@ namespace FlaxEditor.Gizmo
{ {
// Clear cache // Clear cache
_accMoveDelta = Vector3.Zero; _accMoveDelta = Vector3.Zero;
_lastIntersectionPosition = _intersectPosition = Vector3.Zero;
EndTransforming(); EndTransforming();
} }
} }

View File

@@ -717,6 +717,9 @@ namespace FlaxEditor.Modules
/// <param name="rebuild">Should rebuild entire database after addition.</param> /// <param name="rebuild">Should rebuild entire database after addition.</param>
public void AddProxy(ContentProxy proxy, bool rebuild = false) public void AddProxy(ContentProxy proxy, bool rebuild = false)
{ {
var oldProxy = Proxy.Find(x => x.GetType().ToString().Equals(proxy.GetType().ToString(), StringComparison.Ordinal));
if (oldProxy != null)
RemoveProxy(oldProxy);
Proxy.Insert(0, proxy); Proxy.Insert(0, proxy);
if (rebuild) if (rebuild)
Rebuild(true); Rebuild(true);

View File

@@ -24,6 +24,13 @@ namespace FlaxEditor.Options
[DefaultValue(1.0f), Limit(0.01f, 100.0f)] [DefaultValue(1.0f), Limit(0.01f, 100.0f)]
[EditorDisplay("General"), EditorOrder(101), Tooltip("The mouse wheel sensitivity applied to zoom in orthographic mode.")] [EditorDisplay("General"), EditorOrder(101), Tooltip("The mouse wheel sensitivity applied to zoom in orthographic mode.")]
public float MouseWheelSensitivity { get; set; } = 1.0f; public float MouseWheelSensitivity { get; set; } = 1.0f;
/// <summary>
/// Gets or sets whether to invert the Y rotation of the mouse in the editor viewport.
/// </summary>
[DefaultValue(false)]
[EditorDisplay("General"), EditorOrder(102), Tooltip("Whether to invert the Y rotation of the mouse in the editor viewport.")]
public bool InvertMouseYAxisRotation { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets the total amount of steps the camera needs to go from minimum to maximum speed. /// Gets or sets the total amount of steps the camera needs to go from minimum to maximum speed.

View File

@@ -111,6 +111,9 @@ namespace FlaxEditor.Viewport
IsMouseRightDown = useMouse && window.GetMouseButton(MouseButton.Right); IsMouseRightDown = useMouse && window.GetMouseButton(MouseButton.Right);
IsMouseMiddleDown = useMouse && window.GetMouseButton(MouseButton.Middle); IsMouseMiddleDown = useMouse && window.GetMouseButton(MouseButton.Middle);
IsMouseLeftDown = useMouse && window.GetMouseButton(MouseButton.Left); IsMouseLeftDown = useMouse && window.GetMouseButton(MouseButton.Left);
if (WasAltDownBefore && !IsMouseLeftDown && !IsAltDown)
WasAltDownBefore = false;
} }
/// <summary> /// <summary>
@@ -1385,15 +1388,32 @@ namespace FlaxEditor.Viewport
/// <summary> /// <summary>
/// Converts the mouse position to the ray (in world space of the viewport). /// Converts the mouse position to the ray (in world space of the viewport).
/// </summary> /// </summary>
/// <param name="mousePosition">The mouse position.</param> /// <param name="mousePosition">The mouse position (in UI space of the viewport [0; Size]).</param>
/// <returns>The result ray.</returns> /// <returns>The result ray.</returns>
public Ray ConvertMouseToRay(ref Float2 mousePosition) public Ray ConvertMouseToRay(ref Float2 mousePosition)
{ {
// Prepare
var viewport = new FlaxEngine.Viewport(0, 0, Width, Height); var viewport = new FlaxEngine.Viewport(0, 0, Width, Height);
CreateProjectionMatrix(out var p); if (viewport.Width < Mathf.Epsilon || viewport.Height < Mathf.Epsilon)
return ViewRay;
Vector3 viewOrigin = Task.View.Origin; Vector3 viewOrigin = Task.View.Origin;
Float3 position = ViewPosition - viewOrigin; Float3 position = ViewPosition - viewOrigin;
// Use different logic in orthographic projection
if (_isOrtho)
{
var screenPosition = new Float2(mousePosition.X / viewport.Width - 0.5f, -mousePosition.Y / viewport.Height + 0.5f);
var orientation = ViewOrientation;
var direction = Float3.Forward * orientation;
var rayOrigin = new Vector3(screenPosition.X * viewport.Width * _orthoSize, screenPosition.Y * viewport.Height * _orthoSize, 0);
rayOrigin = position + Vector3.Transform(rayOrigin, orientation);
rayOrigin += direction * _nearPlane;
rayOrigin += viewOrigin;
return new Ray(rayOrigin, direction);
}
// Create view frustum
CreateProjectionMatrix(out var p);
CreateViewMatrix(position, out var v); CreateViewMatrix(position, out var v);
Matrix.Multiply(ref v, ref p, out var ivp); Matrix.Multiply(ref v, ref p, out var ivp);
ivp.Invert(); ivp.Invert();
@@ -1404,11 +1424,7 @@ namespace FlaxEditor.Viewport
viewport.Unproject(ref nearPoint, ref ivp, out nearPoint); viewport.Unproject(ref nearPoint, ref ivp, out nearPoint);
viewport.Unproject(ref farPoint, ref ivp, out farPoint); viewport.Unproject(ref farPoint, ref ivp, out farPoint);
// Create direction vector return new Ray(nearPoint + viewOrigin, Vector3.Normalize(farPoint - nearPoint));
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
return new Ray(nearPoint + viewOrigin, direction);
} }
/// <summary> /// <summary>
@@ -1704,6 +1720,8 @@ namespace FlaxEditor.Viewport
// Update // Update
moveDelta *= dt * (60.0f * 4.0f); moveDelta *= dt * (60.0f * 4.0f);
mouseDelta *= 0.1833f * MouseSpeed * _mouseSensitivity; mouseDelta *= 0.1833f * MouseSpeed * _mouseSensitivity;
if (options.Viewport.InvertMouseYAxisRotation)
mouseDelta *= new Float2(1, -1);
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse); UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
// Move mouse back to the root position // Move mouse back to the root position

View File

@@ -627,8 +627,8 @@ namespace FlaxEditor.Viewport
} }
// Debug draw all actors in prefab and collect actors // Debug draw all actors in prefab and collect actors
var viewFlags = Task.ViewFlags; var view = Task.View;
var collectActors = (viewFlags & ViewFlags.PhysicsDebug) != 0 || (viewFlags & ViewFlags.LightsDebug) != 0; var collectActors = (view.Flags & ViewFlags.PhysicsDebug) != 0 || view.Mode == ViewMode.PhysicsColliders || (view.Flags & ViewFlags.LightsDebug) != 0;
_debugDrawActors.Clear(); _debugDrawActors.Clear();
foreach (var child in SceneGraphRoot.ChildNodes) foreach (var child in SceneGraphRoot.ChildNodes)
{ {
@@ -641,19 +641,17 @@ namespace FlaxEditor.Viewport
} }
// Draw physics debug // Draw physics debug
if ((viewFlags & ViewFlags.PhysicsDebug) != 0) if ((view.Flags & ViewFlags.PhysicsDebug) != 0 || view.Mode == ViewMode.PhysicsColliders)
{ {
foreach (var actor in _debugDrawActors) foreach (var actor in _debugDrawActors)
{ {
if (actor is Collider c && c.IsActiveInHierarchy) if (actor is Collider c && c.IsActiveInHierarchy)
{
DebugDraw.DrawColliderDebugPhysics(c, renderContext.View); DebugDraw.DrawColliderDebugPhysics(c, renderContext.View);
}
} }
} }
// Draw lights debug // Draw lights debug
if ((viewFlags & ViewFlags.LightsDebug) != 0) if ((view.Flags & ViewFlags.LightsDebug) != 0)
{ {
foreach (var actor in _debugDrawActors) foreach (var actor in _debugDrawActors)
{ {

View File

@@ -80,6 +80,7 @@ namespace FlaxEditor.Windows.Assets
private AnimationWindow Window; private AnimationWindow Window;
private Animation Asset; private Animation Asset;
private ModelImportSettings ImportSettings = new ModelImportSettings(); private ModelImportSettings ImportSettings = new ModelImportSettings();
private bool EnablePreviewModelCache = true;
[EditorDisplay("Preview"), NoSerialize, AssetReference(true), Tooltip("The skinned model to preview the animation playback.")] [EditorDisplay("Preview"), NoSerialize, AssetReference(true), Tooltip("The skinned model to preview the animation playback.")]
public SkinnedModel PreviewModel public SkinnedModel PreviewModel
@@ -134,6 +135,15 @@ namespace FlaxEditor.Windows.Assets
value.WaitForLoaded(500); value.WaitForLoaded(500);
Window._preview.ViewportCamera.SetArcBallView(Window._preview.PreviewActor.Sphere); Window._preview.ViewportCamera.SetArcBallView(Window._preview.PreviewActor.Sphere);
} }
if (EnablePreviewModelCache)
{
var customDataName = Window.GetPreviewModelCacheName();
if (value)
Window.Editor.ProjectCache.SetCustomData(customDataName, value.ID.ToString());
else
Window.Editor.ProjectCache.RemoveCustomData(customDataName);
}
} }
} }
@@ -142,6 +152,7 @@ namespace FlaxEditor.Windows.Assets
// Link // Link
Window = window; Window = window;
Asset = window.Asset; Asset = window.Asset;
EnablePreviewModelCache = true;
// Try to restore target asset import options (useful for fast reimport) // Try to restore target asset import options (useful for fast reimport)
Editor.TryRestoreImportOptions(ref ImportSettings.Settings, window.Item.Path); Editor.TryRestoreImportOptions(ref ImportSettings.Settings, window.Item.Path);
@@ -150,6 +161,7 @@ namespace FlaxEditor.Windows.Assets
public void OnClean() public void OnClean()
{ {
// Unlink // Unlink
EnablePreviewModelCache = false;
PreviewModel = null; PreviewModel = null;
Window = null; Window = null;
Asset = null; Asset = null;
@@ -287,12 +299,23 @@ namespace FlaxEditor.Windows.Assets
UpdateToolstrip(); UpdateToolstrip();
} }
private string GetPreviewModelCacheName()
{
return _asset.ID + ".PreviewModel";
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnAssetLoaded() protected override void OnAssetLoaded()
{ {
_properties.OnLoad(this); _properties.OnLoad(this);
_propertiesPresenter.BuildLayout(); _propertiesPresenter.BuildLayout();
ClearEditedFlag(); ClearEditedFlag();
if (!_initialPreviewModel &&
Editor.ProjectCache.TryGetCustomData(GetPreviewModelCacheName(), out string str) &&
Guid.TryParse(str, out var id))
{
_initialPreviewModel = FlaxEngine.Content.LoadAsync<SkinnedModel>(id);
}
if (_initialPreviewModel) if (_initialPreviewModel)
{ {
_properties.PreviewModel = _initialPreviewModel; _properties.PreviewModel = _initialPreviewModel;

View File

@@ -396,6 +396,7 @@ void AudioClip::unload(bool isReloading)
} }
StopStreaming(); StopStreaming();
CancelStreamingTasks();
StreamingQueue.Clear(); StreamingQueue.Clear();
if (hasAnyBuffer && AudioBackend::Instance) if (hasAnyBuffer && AudioBackend::Instance)
{ {

View File

@@ -788,7 +788,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
Matrix vp; Matrix vp;
Matrix::Multiply(view.View, view.Projection, vp); Matrix::Multiply(view.View, view.Projection, vp);
Matrix::Transpose(vp, data.ViewProjection); Matrix::Transpose(vp, data.ViewProjection);
data.ClipPosZBias = -0.2f; // Reduce Z-fighting artifacts (eg. editor grid) data.ClipPosZBias = view.IsPerspectiveProjection() ? -0.2f : 0.0f; // Reduce Z-fighting artifacts (eg. editor grid)
data.EnableDepthTest = enableDepthTest; data.EnableDepthTest = enableDepthTest;
context->UpdateCB(cb, &data); context->UpdateCB(cb, &data);
context->BindCB(0, cb); context->BindCB(0, cb);
@@ -953,11 +953,11 @@ void DebugDraw::DrawActorsTree(Actor* actor)
} }
#if USE_EDITOR #if USE_EDITOR
void DebugDraw::DrawColliderDebugPhysics(Collider* collider, RenderView& view) void DebugDraw::DrawColliderDebugPhysics(Collider* collider, RenderView& view)
{ {
if (!collider) if (!collider)
return; return;
collider->DrawPhysicsDebug(view); collider->DrawPhysicsDebug(view);
} }
@@ -965,10 +965,11 @@ void DebugDraw::DrawLightDebug(Light* light, RenderView& view)
{ {
if (!light) if (!light)
return; return;
light->DrawLightsDebug(view); light->DrawLightsDebug(view);
} }
#endif #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)
{ {
CHECK_DEBUG(direction.IsNormalized()); CHECK_DEBUG(direction.IsNormalized());

View File

@@ -75,6 +75,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// </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 #if USE_EDITOR
/// <summary> /// <summary>
/// Draws the physics debug shapes for the given collider. Editor Only /// Draws the physics debug shapes for the given collider. Editor Only
@@ -90,6 +91,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
/// <param name="view">The render view to draw in.</param> /// <param name="view">The render view to draw in.</param>
API_FUNCTION() static void DrawLightDebug(Light* light, RenderView& view); API_FUNCTION() static void DrawLightDebug(Light* light, RenderView& view);
#endif #endif
/// <summary> /// <summary>
/// Draws the lines axis from direction. /// Draws the lines axis from direction.
/// </summary> /// </summary>

View File

@@ -60,6 +60,7 @@ namespace FlaxEngine
~InputAxis() ~InputAxis()
{ {
Input.AxisValueChanged -= Handler; Input.AxisValueChanged -= Handler;
ValueChanged = null;
} }
/// <summary> /// <summary>
@@ -68,6 +69,7 @@ namespace FlaxEngine
public void Dispose() public void Dispose()
{ {
Input.AxisValueChanged -= Handler; Input.AxisValueChanged -= Handler;
ValueChanged = null;
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }

View File

@@ -70,6 +70,10 @@ namespace FlaxEngine
~InputEvent() ~InputEvent()
{ {
Input.ActionTriggered -= Handler; Input.ActionTriggered -= Handler;
Triggered = null;
Pressed = null;
Pressing = null;
Released = null;
} }
private void Handler(string name, InputActionState state) private void Handler(string name, InputActionState state)
@@ -100,6 +104,10 @@ namespace FlaxEngine
public void Dispose() public void Dispose()
{ {
Input.ActionTriggered -= Handler; Input.ActionTriggered -= Handler;
Triggered = null;
Pressed = null;
Pressing = null;
Released = null;
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }

View File

@@ -157,6 +157,8 @@ void InputSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* m
config.Gamepad = JsonTools::GetEnum(v, "Gamepad", InputGamepadIndex::All); config.Gamepad = JsonTools::GetEnum(v, "Gamepad", InputGamepadIndex::All);
config.PositiveButton = JsonTools::GetEnum(v, "PositiveButton", KeyboardKeys::None); config.PositiveButton = JsonTools::GetEnum(v, "PositiveButton", KeyboardKeys::None);
config.NegativeButton = JsonTools::GetEnum(v, "NegativeButton", KeyboardKeys::None); config.NegativeButton = JsonTools::GetEnum(v, "NegativeButton", KeyboardKeys::None);
config.GamepadPositiveButton = JsonTools::GetEnum(v, "GamepadPositiveButton", GamepadButton::None);
config.GamepadNegativeButton = JsonTools::GetEnum(v, "GamepadNegativeButton", GamepadButton::None);
config.DeadZone = JsonTools::GetFloat(v, "DeadZone", 0.1f); config.DeadZone = JsonTools::GetFloat(v, "DeadZone", 0.1f);
config.Sensitivity = JsonTools::GetFloat(v, "Sensitivity", 0.4f); config.Sensitivity = JsonTools::GetFloat(v, "Sensitivity", 0.4f);
config.Gravity = JsonTools::GetFloat(v, "Gravity", 1.0f); config.Gravity = JsonTools::GetFloat(v, "Gravity", 1.0f);
@@ -873,8 +875,8 @@ void InputService::Update()
const AxisData& data = Axes[name]; const AxisData& data = Axes[name];
// Get key raw value // Get key raw value
const bool isPositiveKey = Input::GetKey(config.PositiveButton); const bool isPositiveKey = Input::GetKey(config.PositiveButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadPositiveButton);
const bool isNegativeKey = Input::GetKey(config.NegativeButton); const bool isNegativeKey = Input::GetKey(config.NegativeButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadNegativeButton);
float keyRawValue = 0; float keyRawValue = 0;
if (isPositiveKey && !isNegativeKey) if (isPositiveKey && !isNegativeKey)
{ {

View File

@@ -87,6 +87,18 @@ API_STRUCT() struct AxisConfig
API_FIELD(Attributes="EditorOrder(40)") API_FIELD(Attributes="EditorOrder(40)")
KeyboardKeys NegativeButton; KeyboardKeys NegativeButton;
/// <summary>
/// The button to be pressed for movement in positive direction. Use <see cref="GamepadButton.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(45)")
GamepadButton GamepadPositiveButton;
/// <summary>
/// The button to be pressed for movement in negative direction. Use <see cref="GamepadButton.None"/> to ignore it.
/// </summary>
API_FIELD(Attributes="EditorOrder(46)")
GamepadButton GamepadNegativeButton;
/// <summary> /// <summary>
/// Any positive or negative values that are less than this number will register as zero. Useful for gamepads to specify the deadzone. /// Any positive or negative values that are less than this number will register as zero. Useful for gamepads to specify the deadzone.
/// </summary> /// </summary>

View File

@@ -39,6 +39,7 @@ Camera::Camera(const SpawnParams& params)
, _customAspectRatio(0.0f) , _customAspectRatio(0.0f)
, _near(10.0f) , _near(10.0f)
, _far(40000.0f) , _far(40000.0f)
, _orthoSize(0.0f)
, _orthoScale(1.0f) , _orthoScale(1.0f)
{ {
#if USE_EDITOR #if USE_EDITOR
@@ -120,6 +121,21 @@ void Camera::SetFarPlane(float value)
} }
} }
float Camera::GetOrthographicSize() const
{
return _orthoSize;
}
void Camera::SetOrthographicSize(float value)
{
value = Math::Clamp(value, 0.0f, 1000000.0f);
if (Math::NotNearEqual(_orthoSize, value))
{
_orthoSize = value;
UpdateCache();
}
}
float Camera::GetOrthographicScale() const float Camera::GetOrthographicScale() const
{ {
return _orthoScale; return _orthoScale;
@@ -191,39 +207,37 @@ Ray Camera::ConvertMouseToRay(const Float2& mousePosition) const
Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewport) const Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewport) const
{ {
#if 1 Vector3 position = GetPosition();
// Gather camera properties if (viewport.Width < ZeroTolerance || viewport.Height < ZeroTolerance)
return Ray(position, GetDirection());
// Use different logic in orthographic projection
if (!_usePerspective)
{
Float2 screenPosition(mousePosition.X / viewport.Width - 0.5f, -mousePosition.Y / viewport.Height + 0.5f);
Quaternion orientation = GetOrientation();
Float3 direction = orientation * Float3::Forward;
const float orthoSize = (_orthoSize > 0.0f ? _orthoSize : viewport.Height) * _orthoScale;
const float aspect = _customAspectRatio <= 0.0f ? viewport.GetAspectRatio() : _customAspectRatio;
Vector3 rayOrigin(screenPosition.X * orthoSize * aspect, screenPosition.Y * orthoSize, 0);
rayOrigin = position + Vector3::Transform(rayOrigin, orientation);
rayOrigin += direction * _near;
return Ray(rayOrigin, direction);
}
// Create view frustum
Matrix v, p, ivp; Matrix v, p, ivp;
GetMatrices(v, p, viewport); GetMatrices(v, p, viewport);
Matrix::Multiply(v, p, ivp); Matrix::Multiply(v, p, ivp);
ivp.Invert(); ivp.Invert();
// Create near and far points // Create near and far points
Vector3 nearPoint(mousePosition, 0.0f); Vector3 nearPoint(mousePosition, _near);
Vector3 farPoint(mousePosition, 1.0f); Vector3 farPoint(mousePosition, _far);
viewport.Unproject(nearPoint, ivp, nearPoint); viewport.Unproject(nearPoint, ivp, nearPoint);
viewport.Unproject(farPoint, ivp, farPoint); viewport.Unproject(farPoint, ivp, farPoint);
// Create direction vector return Ray(nearPoint, Vector3::Normalize(farPoint - nearPoint));
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
return Ray(nearPoint, direction);
#else
// Create near and far points
Vector3 nearPoint, farPoint;
Matrix ivp;
_frustum.GetInvMatrix(&ivp);
viewport.Unproject(Vector3(mousePosition, 0.0f), ivp, nearPoint);
viewport.Unproject(Vector3(mousePosition, 1.0f), ivp, farPoint);
// Create direction vector
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
// Return result
return Ray(nearPoint, direction);
#endif
} }
Viewport Camera::GetViewport() const Viewport Camera::GetViewport() const
@@ -264,14 +278,15 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp
void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewport, const Vector3& origin) const void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewport, const Vector3& origin) const
{ {
// Create projection matrix // Create projection matrix
const float aspect = _customAspectRatio <= 0.0f ? viewport.GetAspectRatio() : _customAspectRatio;
if (_usePerspective) if (_usePerspective)
{ {
const float aspect = _customAspectRatio <= 0.0f ? viewport.GetAspectRatio() : _customAspectRatio;
Matrix::PerspectiveFov(_fov * DegreesToRadians, aspect, _near, _far, projection); Matrix::PerspectiveFov(_fov * DegreesToRadians, aspect, _near, _far, projection);
} }
else else
{ {
Matrix::Ortho(viewport.Width * _orthoScale, viewport.Height * _orthoScale, _near, _far, projection); const float orthoSize = (_orthoSize > 0.0f ? _orthoSize : viewport.Height) * _orthoScale;
Matrix::Ortho(orthoSize * aspect, orthoSize, _near, _far, projection);
} }
// Create view matrix // Create view matrix

View File

@@ -44,6 +44,7 @@ private:
float _customAspectRatio; float _customAspectRatio;
float _near; float _near;
float _far; float _far;
float _orthoSize;
float _orthoScale; float _orthoScale;
#if USE_EDITOR #if USE_EDITOR
@@ -88,7 +89,7 @@ public:
/// <summary> /// <summary>
/// Gets the custom aspect ratio. 0 if not use custom value. /// Gets the custom aspect ratio. 0 if not use custom value.
/// </summary> /// </summary>
API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(0.0f), Limit(0, 10, 0.01f), EditorDisplay(\"Camera\"), VisibleIf(nameof(UsePerspective))") API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(0.0f), Limit(0, 10, 0.01f), EditorDisplay(\"Camera\")")
float GetCustomAspectRatio() const; float GetCustomAspectRatio() const;
/// <summary> /// <summary>
@@ -118,6 +119,17 @@ public:
/// </summary> /// </summary>
API_PROPERTY() void SetFarPlane(float value); API_PROPERTY() void SetFarPlane(float value);
/// <summary>
/// Gets the orthographic projection view height (width is based on the aspect ratio). Use `0` for size to be based on the viewport size.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(59), DefaultValue(0.0f), Limit(0.0f), EditorDisplay(\"Camera\"), VisibleIf(nameof(UsePerspective), true)")
float GetOrthographicSize() const;
/// <summary>
/// Sets the orthographic projection view height (width is based on the aspect ratio). Use `0` for size to be based on the viewport size.
/// </summary>
API_PROPERTY() void SetOrthographicSize(float value);
/// <summary> /// <summary>
/// Gets the orthographic projection scale. /// Gets the orthographic projection scale.
/// </summary> /// </summary>

View File

@@ -123,6 +123,7 @@ public:
/// <returns>The scene object (loaded).</returns> /// <returns>The scene object (loaded).</returns>
API_FUNCTION() static Scene* GetScene(int32 index) API_FUNCTION() static Scene* GetScene(int32 index)
{ {
CHECK_RETURN(index < GetScenesCount(), nullptr);
return Scenes[index]; return Scenes[index];
} }

View File

@@ -219,7 +219,7 @@ Asset::LoadResult ParticleEmitter::load()
ClearDependencies(); ClearDependencies();
for (const auto& node : Graph.Nodes) for (const auto& node : Graph.Nodes)
{ {
if (node.Type == GRAPH_NODE_MAKE_TYPE(14, 300)) if (node.Type == GRAPH_NODE_MAKE_TYPE(14, 300) && node.Assets.Count() > 0)
{ {
const auto function = node.Assets[0].As<ParticleEmitterFunction>(); const auto function = node.Assets[0].As<ParticleEmitterFunction>();
if (function) if (function)

View File

@@ -143,9 +143,11 @@ namespace FlaxEngine.GUI
if (!Mathf.NearEqual(value, _value)) if (!Mathf.NearEqual(value, _value))
{ {
_value = value; _value = value;
if (!UseSmoothing) if (!UseSmoothing || _firstUpdate)
{ {
_current = _value; _current = _value;
if (_firstUpdate)
_firstUpdate = false;
} }
} }
} }
@@ -169,6 +171,9 @@ namespace FlaxEngine.GUI
[EditorDisplay("Bar Style"), EditorOrder(2012), Tooltip("The brush used for progress bar drawing.")] [EditorDisplay("Bar Style"), EditorOrder(2012), Tooltip("The brush used for progress bar drawing.")]
public IBrush BarBrush { get; set; } public IBrush BarBrush { get; set; }
// Used to remove initial lerp from the value on play.
private bool _firstUpdate = true;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ProgressBar"/> class. /// Initializes a new instance of the <see cref="ProgressBar"/> class.
/// </summary> /// </summary>

View File

@@ -18,7 +18,7 @@ SpriteRender::SpriteRender(const SpawnParams& params)
{ {
_quadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad")); _quadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad"));
Material.Loaded.Bind<SpriteRender, &SpriteRender::OnMaterialLoaded>(this); Material.Loaded.Bind<SpriteRender, &SpriteRender::OnMaterialLoaded>(this);
Image.Changed.Bind<SpriteRender, &SpriteRender::SetImage>(this); Image.Changed.Bind<SpriteRender, &SpriteRender::SetImageParam>(this);
} }
Float2 SpriteRender::GetSize() const Float2 SpriteRender::GetSize() const
@@ -42,8 +42,7 @@ Color SpriteRender::GetColor() const
void SpriteRender::SetColor(const Color& value) void SpriteRender::SetColor(const Color& value)
{ {
_color = value; _color = value;
if (_paramColor) SetColorParam();
_paramColor->SetValue(value);
} }
SpriteHandle SpriteRender::GetSprite() const SpriteHandle SpriteRender::GetSprite() const
@@ -54,7 +53,7 @@ SpriteHandle SpriteRender::GetSprite() const
void SpriteRender::SetSprite(const SpriteHandle& value) void SpriteRender::SetSprite(const SpriteHandle& value)
{ {
_sprite = value; _sprite = value;
SetImage(); SetImageParam();
} }
void SpriteRender::OnMaterialLoaded() void SpriteRender::OnMaterialLoaded()
@@ -66,6 +65,7 @@ void SpriteRender::OnMaterialLoaded()
_materialInstance->AddReference(); _materialInstance->AddReference();
} }
_materialInstance->SetBaseMaterial(Material); _materialInstance->SetBaseMaterial(Material);
_materialInstance->ResetParameters();
// Cache parameters // Cache parameters
_paramImageMAD = _materialInstance->GetParameter(TEXT("ImageMAD")); _paramImageMAD = _materialInstance->GetParameter(TEXT("ImageMAD"));
@@ -75,15 +75,15 @@ void SpriteRender::OnMaterialLoaded()
if (_paramImage && _paramImage->GetParameterType() != MaterialParameterType::Texture) if (_paramImage && _paramImage->GetParameterType() != MaterialParameterType::Texture)
_paramImage = nullptr; _paramImage = nullptr;
else if (_paramImage) else if (_paramImage)
SetImage(); SetImageParam();
_paramColor = _materialInstance->GetParameter(TEXT("Color")); _paramColor = _materialInstance->GetParameter(TEXT("Color"));
if (_paramColor && _paramColor->GetParameterType() != MaterialParameterType::Color && _paramColor->GetParameterType() != MaterialParameterType::Vector4 && _paramColor->GetParameterType() != MaterialParameterType::Vector3) if (_paramColor && _paramColor->GetParameterType() != MaterialParameterType::Color && _paramColor->GetParameterType() != MaterialParameterType::Vector4 && _paramColor->GetParameterType() != MaterialParameterType::Vector3)
_paramColor = nullptr; _paramColor = nullptr;
else if (_paramColor) else if (_paramColor)
_paramColor->SetValue(_color); SetColorParam();
} }
void SpriteRender::SetImage() void SpriteRender::SetImageParam()
{ {
TextureBase* image = Image.Get(); TextureBase* image = Image.Get();
Vector4 imageMAD(Vector2::One, Vector2::Zero); Vector4 imageMAD(Vector2::One, Vector2::Zero);
@@ -94,9 +94,24 @@ void SpriteRender::SetImage()
imageMAD = Vector4(sprite->Area.Size, sprite->Area.Location); imageMAD = Vector4(sprite->Area.Size, sprite->Area.Location);
} }
if (_paramImage) if (_paramImage)
{
_paramImage->SetValue(image); _paramImage->SetValue(image);
_paramImage->SetIsOverride(true);
}
if (_paramImageMAD) if (_paramImageMAD)
{
_paramImageMAD->SetValue(imageMAD); _paramImageMAD->SetValue(imageMAD);
_paramImageMAD->SetIsOverride(true);
}
}
void SpriteRender::SetColorParam()
{
if (_paramColor)
{
_paramColor->SetValue(_color);
_paramColor->SetIsOverride(true);
}
} }
bool SpriteRender::HasContentLoaded() const bool SpriteRender::HasContentLoaded() const
@@ -164,9 +179,8 @@ void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
DESERIALIZE(DrawModes); DESERIALIZE(DrawModes);
DESERIALIZE(SortOrder); DESERIALIZE(SortOrder);
SetImage(); SetImageParam();
if (_paramColor) SetColorParam();
_paramColor->SetValue(_color);
} }
void SpriteRender::OnLayerChanged() void SpriteRender::OnLayerChanged()

View File

@@ -92,7 +92,8 @@ public:
private: private:
void OnMaterialLoaded(); void OnMaterialLoaded();
void SetImage(); void SetImageParam();
void SetColorParam();
public: public:
// [Actor] // [Actor]

View File

@@ -2064,13 +2064,18 @@ namespace Flax.Build.Bindings
GenerateCSharpAttributes(buildData, contents, indent, enumInfo, true); GenerateCSharpAttributes(buildData, contents, indent, enumInfo, true);
contents.Append(indent).Append(GenerateCSharpAccessLevel(enumInfo.Access)); contents.Append(indent).Append(GenerateCSharpAccessLevel(enumInfo.Access));
contents.Append("enum ").Append(enumInfo.Name); contents.Append("enum ").Append(enumInfo.Name);
string managedType = string.Empty;
if (enumInfo.UnderlyingType != null) if (enumInfo.UnderlyingType != null)
contents.Append(" : ").Append(GenerateCSharpNativeToManaged(buildData, enumInfo.UnderlyingType, enumInfo)); {
managedType = GenerateCSharpNativeToManaged(buildData, enumInfo.UnderlyingType, enumInfo);
contents.Append(" : ").Append(managedType);
}
contents.AppendLine(); contents.AppendLine();
contents.Append(indent + "{"); contents.Append(indent + "{");
indent += " "; indent += " ";
// Entries // Entries
bool usedMax = false;
foreach (var entryInfo in enumInfo.Entries) foreach (var entryInfo in enumInfo.Entries)
{ {
contents.AppendLine(); contents.AppendLine();
@@ -2078,7 +2083,29 @@ namespace Flax.Build.Bindings
GenerateCSharpAttributes(buildData, contents, indent, enumInfo, entryInfo.Attributes, entryInfo.Comment, true, false); GenerateCSharpAttributes(buildData, contents, indent, enumInfo, entryInfo.Attributes, entryInfo.Comment, true, false);
contents.Append(indent).Append(entryInfo.Name); contents.Append(indent).Append(entryInfo.Name);
if (!string.IsNullOrEmpty(entryInfo.Value)) if (!string.IsNullOrEmpty(entryInfo.Value))
contents.Append(" = ").Append(entryInfo.Value); {
if (usedMax)
usedMax = false;
string value;
if (enumInfo.UnderlyingType != null)
{
value = GenerateCSharpDefaultValueNativeToManaged(buildData, entryInfo.Value, enumInfo, enumInfo.UnderlyingType, false, managedType);
if (value.Contains($"{managedType}.MaxValue", StringComparison.Ordinal))
usedMax = true;
}
else
{
value = entryInfo.Value;
}
contents.Append(" = ").Append(value);
}
// Handle case of next value after Max value being zero if a value is not defined.
else if (string.IsNullOrEmpty(entryInfo.Value) && usedMax)
{
contents.Append(" = ").Append('0');
usedMax = false;
}
contents.Append(','); contents.Append(',');
contents.AppendLine(); contents.AppendLine();
} }