Merge remote-tracking branch 'origin/master' into 1.9
This commit is contained in:
@@ -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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.Surface;
|
||||
using FlaxEngine;
|
||||
|
||||
@@ -12,6 +14,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
[CustomEditor(typeof(AnimatedModel)), DefaultEditor]
|
||||
public class AnimatedModelEditor : ActorEditor
|
||||
{
|
||||
private bool _parametersAdded = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
@@ -31,6 +35,24 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
(instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier),
|
||||
(instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value),
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +178,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return 1;
|
||||
if (Info.MetadataToken < other.Info.MetadataToken)
|
||||
return -1;
|
||||
// Keep declaration order if same metadata token.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// By name
|
||||
|
||||
@@ -138,18 +138,17 @@ namespace FlaxEditor.Gizmo
|
||||
|
||||
private void UpdateGizmoPosition()
|
||||
{
|
||||
var position = Vector3.Zero;
|
||||
|
||||
// Get gizmo pivot
|
||||
switch (_activePivotType)
|
||||
{
|
||||
case PivotType.ObjectCenter:
|
||||
if (SelectionCount > 0)
|
||||
Position = GetSelectedTransform(0).Translation;
|
||||
position = GetSelectedTransform(0).Translation;
|
||||
break;
|
||||
case PivotType.SelectionCenter:
|
||||
Position = GetSelectionCenter();
|
||||
break;
|
||||
case PivotType.WorldOrigin:
|
||||
Position = Vector3.Zero;
|
||||
position = GetSelectionCenter();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -157,11 +156,13 @@ namespace FlaxEditor.Gizmo
|
||||
if (_vertexSnapObject != null)
|
||||
{
|
||||
Vector3 vertexSnapPoint = _vertexSnapObject.Transform.LocalToWorld(_vertexSnapPoint);
|
||||
Position += vertexSnapPoint - Position;
|
||||
position += vertexSnapPoint - position;
|
||||
}
|
||||
|
||||
// Apply current movement
|
||||
Position += _translationDelta;
|
||||
position += _translationDelta;
|
||||
|
||||
Position = position;
|
||||
}
|
||||
|
||||
private void UpdateMatrices()
|
||||
@@ -213,10 +214,11 @@ namespace FlaxEditor.Gizmo
|
||||
ray.Position = Vector3.Transform(ray.Position, invRotationMatrix);
|
||||
Vector3.TransformNormal(ref ray.Direction, ref invRotationMatrix, out ray.Direction);
|
||||
|
||||
var planeXY = new Plane(Vector3.Backward, Vector3.Transform(Position, invRotationMatrix).Z);
|
||||
var planeYZ = new Plane(Vector3.Left, Vector3.Transform(Position, invRotationMatrix).X);
|
||||
var planeZX = new Plane(Vector3.Down, Vector3.Transform(Position, invRotationMatrix).Y);
|
||||
var dir = Vector3.Normalize(ray.Position - Position);
|
||||
var position = Position;
|
||||
var planeXY = new Plane(Vector3.Backward, Vector3.Transform(position, invRotationMatrix).Z);
|
||||
var planeYZ = new Plane(Vector3.Left, Vector3.Transform(position, invRotationMatrix).X);
|
||||
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 planeDotYZ = Mathf.Abs(Vector3.Dot(planeYZ.Normal, dir));
|
||||
var planeDotZX = Mathf.Abs(Vector3.Dot(planeZX.Normal, dir));
|
||||
@@ -229,8 +231,8 @@ namespace FlaxEditor.Gizmo
|
||||
var plane = planeDotXY > planeDotZX ? planeXY : planeZX;
|
||||
if (ray.Intersects(ref plane, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(_tDelta.X, 0, 0);
|
||||
}
|
||||
@@ -241,8 +243,8 @@ namespace FlaxEditor.Gizmo
|
||||
var plane = planeDotXY > planeDotYZ ? planeXY : planeYZ;
|
||||
if (ray.Intersects(ref plane, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(0, _tDelta.Y, 0);
|
||||
}
|
||||
@@ -253,8 +255,8 @@ namespace FlaxEditor.Gizmo
|
||||
var plane = planeDotZX > planeDotYZ ? planeZX : planeYZ;
|
||||
if (ray.Intersects(ref plane, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(0, 0, _tDelta.Z);
|
||||
}
|
||||
@@ -264,8 +266,8 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
if (ray.Intersects(ref planeYZ, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(0, _tDelta.Y, _tDelta.Z);
|
||||
}
|
||||
@@ -275,8 +277,8 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
if (ray.Intersects(ref planeXY, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(_tDelta.X, _tDelta.Y, 0);
|
||||
}
|
||||
@@ -286,8 +288,8 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
if (ray.Intersects(ref planeZX, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(_tDelta.X, 0, _tDelta.Z);
|
||||
}
|
||||
@@ -299,8 +301,8 @@ namespace FlaxEditor.Gizmo
|
||||
var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length);
|
||||
if (ray.Intersects(ref plane, out intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_intersectPosition = ray.GetPoint(intersection);
|
||||
if (!_lastIntersectionPosition.IsZero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
}
|
||||
delta = _tDelta;
|
||||
@@ -412,10 +414,8 @@ namespace FlaxEditor.Gizmo
|
||||
public override void Update(float dt)
|
||||
{
|
||||
LastDelta = Transform.Identity;
|
||||
|
||||
if (!IsActive)
|
||||
return;
|
||||
|
||||
bool isLeftBtnDown = Owner.IsLeftMouseButtonDown;
|
||||
|
||||
// Snap to ground
|
||||
@@ -516,6 +516,7 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
// Clear cache
|
||||
_accMoveDelta = Vector3.Zero;
|
||||
_lastIntersectionPosition = _intersectPosition = Vector3.Zero;
|
||||
EndTransforming();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,6 +717,9 @@ namespace FlaxEditor.Modules
|
||||
/// <param name="rebuild">Should rebuild entire database after addition.</param>
|
||||
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);
|
||||
if (rebuild)
|
||||
Rebuild(true);
|
||||
|
||||
@@ -24,6 +24,13 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(1.0f), Limit(0.01f, 100.0f)]
|
||||
[EditorDisplay("General"), EditorOrder(101), Tooltip("The mouse wheel sensitivity applied to zoom in orthographic mode.")]
|
||||
public float MouseWheelSensitivity { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets 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>
|
||||
/// Gets or sets the total amount of steps the camera needs to go from minimum to maximum speed.
|
||||
|
||||
@@ -111,6 +111,9 @@ namespace FlaxEditor.Viewport
|
||||
IsMouseRightDown = useMouse && window.GetMouseButton(MouseButton.Right);
|
||||
IsMouseMiddleDown = useMouse && window.GetMouseButton(MouseButton.Middle);
|
||||
IsMouseLeftDown = useMouse && window.GetMouseButton(MouseButton.Left);
|
||||
|
||||
if (WasAltDownBefore && !IsMouseLeftDown && !IsAltDown)
|
||||
WasAltDownBefore = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1385,15 +1388,32 @@ namespace FlaxEditor.Viewport
|
||||
/// <summary>
|
||||
/// Converts the mouse position to the ray (in world space of the viewport).
|
||||
/// </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>
|
||||
public Ray ConvertMouseToRay(ref Float2 mousePosition)
|
||||
{
|
||||
// Prepare
|
||||
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;
|
||||
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);
|
||||
Matrix.Multiply(ref v, ref p, out var ivp);
|
||||
ivp.Invert();
|
||||
@@ -1404,11 +1424,7 @@ namespace FlaxEditor.Viewport
|
||||
viewport.Unproject(ref nearPoint, ref ivp, out nearPoint);
|
||||
viewport.Unproject(ref farPoint, ref ivp, out farPoint);
|
||||
|
||||
// Create direction vector
|
||||
Vector3 direction = farPoint - nearPoint;
|
||||
direction.Normalize();
|
||||
|
||||
return new Ray(nearPoint + viewOrigin, direction);
|
||||
return new Ray(nearPoint + viewOrigin, Vector3.Normalize(farPoint - nearPoint));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1704,6 +1720,8 @@ namespace FlaxEditor.Viewport
|
||||
// Update
|
||||
moveDelta *= dt * (60.0f * 4.0f);
|
||||
mouseDelta *= 0.1833f * MouseSpeed * _mouseSensitivity;
|
||||
if (options.Viewport.InvertMouseYAxisRotation)
|
||||
mouseDelta *= new Float2(1, -1);
|
||||
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
|
||||
|
||||
// Move mouse back to the root position
|
||||
|
||||
@@ -627,8 +627,8 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
|
||||
// Debug draw all actors in prefab and collect actors
|
||||
var viewFlags = Task.ViewFlags;
|
||||
var collectActors = (viewFlags & ViewFlags.PhysicsDebug) != 0 || (viewFlags & ViewFlags.LightsDebug) != 0;
|
||||
var view = Task.View;
|
||||
var collectActors = (view.Flags & ViewFlags.PhysicsDebug) != 0 || view.Mode == ViewMode.PhysicsColliders || (view.Flags & ViewFlags.LightsDebug) != 0;
|
||||
_debugDrawActors.Clear();
|
||||
foreach (var child in SceneGraphRoot.ChildNodes)
|
||||
{
|
||||
@@ -641,19 +641,17 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
|
||||
// Draw physics debug
|
||||
if ((viewFlags & ViewFlags.PhysicsDebug) != 0)
|
||||
if ((view.Flags & ViewFlags.PhysicsDebug) != 0 || view.Mode == ViewMode.PhysicsColliders)
|
||||
{
|
||||
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)
|
||||
if ((view.Flags & ViewFlags.LightsDebug) != 0)
|
||||
{
|
||||
foreach (var actor in _debugDrawActors)
|
||||
{
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
private AnimationWindow Window;
|
||||
private Animation Asset;
|
||||
private ModelImportSettings ImportSettings = new ModelImportSettings();
|
||||
private bool EnablePreviewModelCache = true;
|
||||
|
||||
[EditorDisplay("Preview"), NoSerialize, AssetReference(true), Tooltip("The skinned model to preview the animation playback.")]
|
||||
public SkinnedModel PreviewModel
|
||||
@@ -134,6 +135,15 @@ namespace FlaxEditor.Windows.Assets
|
||||
value.WaitForLoaded(500);
|
||||
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
|
||||
Window = window;
|
||||
Asset = window.Asset;
|
||||
EnablePreviewModelCache = true;
|
||||
|
||||
// Try to restore target asset import options (useful for fast reimport)
|
||||
Editor.TryRestoreImportOptions(ref ImportSettings.Settings, window.Item.Path);
|
||||
@@ -150,6 +161,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
public void OnClean()
|
||||
{
|
||||
// Unlink
|
||||
EnablePreviewModelCache = false;
|
||||
PreviewModel = null;
|
||||
Window = null;
|
||||
Asset = null;
|
||||
@@ -287,12 +299,23 @@ namespace FlaxEditor.Windows.Assets
|
||||
UpdateToolstrip();
|
||||
}
|
||||
|
||||
private string GetPreviewModelCacheName()
|
||||
{
|
||||
return _asset.ID + ".PreviewModel";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnAssetLoaded()
|
||||
{
|
||||
_properties.OnLoad(this);
|
||||
_propertiesPresenter.BuildLayout();
|
||||
ClearEditedFlag();
|
||||
if (!_initialPreviewModel &&
|
||||
Editor.ProjectCache.TryGetCustomData(GetPreviewModelCacheName(), out string str) &&
|
||||
Guid.TryParse(str, out var id))
|
||||
{
|
||||
_initialPreviewModel = FlaxEngine.Content.LoadAsync<SkinnedModel>(id);
|
||||
}
|
||||
if (_initialPreviewModel)
|
||||
{
|
||||
_properties.PreviewModel = _initialPreviewModel;
|
||||
|
||||
@@ -396,6 +396,7 @@ void AudioClip::unload(bool isReloading)
|
||||
}
|
||||
|
||||
StopStreaming();
|
||||
CancelStreamingTasks();
|
||||
StreamingQueue.Clear();
|
||||
if (hasAnyBuffer && AudioBackend::Instance)
|
||||
{
|
||||
|
||||
@@ -788,7 +788,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
Matrix vp;
|
||||
Matrix::Multiply(view.View, view.Projection, vp);
|
||||
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;
|
||||
context->UpdateCB(cb, &data);
|
||||
context->BindCB(0, cb);
|
||||
@@ -953,11 +953,11 @@ void DebugDraw::DrawActorsTree(Actor* actor)
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void DebugDraw::DrawColliderDebugPhysics(Collider* collider, RenderView& view)
|
||||
{
|
||||
if (!collider)
|
||||
return;
|
||||
|
||||
collider->DrawPhysicsDebug(view);
|
||||
}
|
||||
|
||||
@@ -965,10 +965,11 @@ 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)
|
||||
{
|
||||
CHECK_DEBUG(direction.IsNormalized());
|
||||
|
||||
@@ -75,6 +75,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor to start drawing at.</param>
|
||||
API_FUNCTION() static void DrawActorsTree(Actor* actor);
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// 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>
|
||||
API_FUNCTION() static void DrawLightDebug(Light* light, RenderView& view);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Draws the lines axis from direction.
|
||||
/// </summary>
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace FlaxEngine
|
||||
~InputAxis()
|
||||
{
|
||||
Input.AxisValueChanged -= Handler;
|
||||
ValueChanged = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,6 +69,7 @@ namespace FlaxEngine
|
||||
public void Dispose()
|
||||
{
|
||||
Input.AxisValueChanged -= Handler;
|
||||
ValueChanged = null;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,10 @@ namespace FlaxEngine
|
||||
~InputEvent()
|
||||
{
|
||||
Input.ActionTriggered -= Handler;
|
||||
Triggered = null;
|
||||
Pressed = null;
|
||||
Pressing = null;
|
||||
Released = null;
|
||||
}
|
||||
|
||||
private void Handler(string name, InputActionState state)
|
||||
@@ -100,6 +104,10 @@ namespace FlaxEngine
|
||||
public void Dispose()
|
||||
{
|
||||
Input.ActionTriggered -= Handler;
|
||||
Triggered = null;
|
||||
Pressed = null;
|
||||
Pressing = null;
|
||||
Released = null;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,6 +157,8 @@ void InputSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* m
|
||||
config.Gamepad = JsonTools::GetEnum(v, "Gamepad", InputGamepadIndex::All);
|
||||
config.PositiveButton = JsonTools::GetEnum(v, "PositiveButton", 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.Sensitivity = JsonTools::GetFloat(v, "Sensitivity", 0.4f);
|
||||
config.Gravity = JsonTools::GetFloat(v, "Gravity", 1.0f);
|
||||
@@ -873,8 +875,8 @@ void InputService::Update()
|
||||
const AxisData& data = Axes[name];
|
||||
|
||||
// Get key raw value
|
||||
const bool isPositiveKey = Input::GetKey(config.PositiveButton);
|
||||
const bool isNegativeKey = Input::GetKey(config.NegativeButton);
|
||||
const bool isPositiveKey = Input::GetKey(config.PositiveButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadPositiveButton);
|
||||
const bool isNegativeKey = Input::GetKey(config.NegativeButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadNegativeButton);
|
||||
float keyRawValue = 0;
|
||||
if (isPositiveKey && !isNegativeKey)
|
||||
{
|
||||
|
||||
@@ -87,6 +87,18 @@ API_STRUCT() struct AxisConfig
|
||||
API_FIELD(Attributes="EditorOrder(40)")
|
||||
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>
|
||||
/// Any positive or negative values that are less than this number will register as zero. Useful for gamepads to specify the deadzone.
|
||||
/// </summary>
|
||||
|
||||
@@ -39,6 +39,7 @@ Camera::Camera(const SpawnParams& params)
|
||||
, _customAspectRatio(0.0f)
|
||||
, _near(10.0f)
|
||||
, _far(40000.0f)
|
||||
, _orthoSize(0.0f)
|
||||
, _orthoScale(1.0f)
|
||||
{
|
||||
#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
|
||||
{
|
||||
return _orthoScale;
|
||||
@@ -191,39 +207,37 @@ Ray Camera::ConvertMouseToRay(const Float2& mousePosition) const
|
||||
|
||||
Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewport) const
|
||||
{
|
||||
#if 1
|
||||
// Gather camera properties
|
||||
Vector3 position = GetPosition();
|
||||
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;
|
||||
GetMatrices(v, p, viewport);
|
||||
Matrix::Multiply(v, p, ivp);
|
||||
ivp.Invert();
|
||||
|
||||
// Create near and far points
|
||||
Vector3 nearPoint(mousePosition, 0.0f);
|
||||
Vector3 farPoint(mousePosition, 1.0f);
|
||||
Vector3 nearPoint(mousePosition, _near);
|
||||
Vector3 farPoint(mousePosition, _far);
|
||||
viewport.Unproject(nearPoint, ivp, nearPoint);
|
||||
viewport.Unproject(farPoint, ivp, farPoint);
|
||||
|
||||
// Create direction vector
|
||||
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
|
||||
return Ray(nearPoint, Vector3::Normalize(farPoint - nearPoint));
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// Create projection matrix
|
||||
const float aspect = _customAspectRatio <= 0.0f ? viewport.GetAspectRatio() : _customAspectRatio;
|
||||
if (_usePerspective)
|
||||
{
|
||||
const float aspect = _customAspectRatio <= 0.0f ? viewport.GetAspectRatio() : _customAspectRatio;
|
||||
Matrix::PerspectiveFov(_fov * DegreesToRadians, aspect, _near, _far, projection);
|
||||
}
|
||||
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
|
||||
|
||||
@@ -44,6 +44,7 @@ private:
|
||||
float _customAspectRatio;
|
||||
float _near;
|
||||
float _far;
|
||||
float _orthoSize;
|
||||
float _orthoScale;
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -88,7 +89,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the custom aspect ratio. 0 if not use custom value.
|
||||
/// </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;
|
||||
|
||||
/// <summary>
|
||||
@@ -118,6 +119,17 @@ public:
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets the orthographic projection scale.
|
||||
/// </summary>
|
||||
|
||||
@@ -123,6 +123,7 @@ public:
|
||||
/// <returns>The scene object (loaded).</returns>
|
||||
API_FUNCTION() static Scene* GetScene(int32 index)
|
||||
{
|
||||
CHECK_RETURN(index < GetScenesCount(), nullptr);
|
||||
return Scenes[index];
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ Asset::LoadResult ParticleEmitter::load()
|
||||
ClearDependencies();
|
||||
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>();
|
||||
if (function)
|
||||
|
||||
@@ -143,9 +143,11 @@ namespace FlaxEngine.GUI
|
||||
if (!Mathf.NearEqual(value, _value))
|
||||
{
|
||||
_value = value;
|
||||
if (!UseSmoothing)
|
||||
if (!UseSmoothing || _firstUpdate)
|
||||
{
|
||||
_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.")]
|
||||
public IBrush BarBrush { get; set; }
|
||||
|
||||
// Used to remove initial lerp from the value on play.
|
||||
private bool _firstUpdate = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProgressBar"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -18,7 +18,7 @@ SpriteRender::SpriteRender(const SpawnParams& params)
|
||||
{
|
||||
_quadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad"));
|
||||
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
|
||||
@@ -42,8 +42,7 @@ Color SpriteRender::GetColor() const
|
||||
void SpriteRender::SetColor(const Color& value)
|
||||
{
|
||||
_color = value;
|
||||
if (_paramColor)
|
||||
_paramColor->SetValue(value);
|
||||
SetColorParam();
|
||||
}
|
||||
|
||||
SpriteHandle SpriteRender::GetSprite() const
|
||||
@@ -54,7 +53,7 @@ SpriteHandle SpriteRender::GetSprite() const
|
||||
void SpriteRender::SetSprite(const SpriteHandle& value)
|
||||
{
|
||||
_sprite = value;
|
||||
SetImage();
|
||||
SetImageParam();
|
||||
}
|
||||
|
||||
void SpriteRender::OnMaterialLoaded()
|
||||
@@ -66,6 +65,7 @@ void SpriteRender::OnMaterialLoaded()
|
||||
_materialInstance->AddReference();
|
||||
}
|
||||
_materialInstance->SetBaseMaterial(Material);
|
||||
_materialInstance->ResetParameters();
|
||||
|
||||
// Cache parameters
|
||||
_paramImageMAD = _materialInstance->GetParameter(TEXT("ImageMAD"));
|
||||
@@ -75,15 +75,15 @@ void SpriteRender::OnMaterialLoaded()
|
||||
if (_paramImage && _paramImage->GetParameterType() != MaterialParameterType::Texture)
|
||||
_paramImage = nullptr;
|
||||
else if (_paramImage)
|
||||
SetImage();
|
||||
SetImageParam();
|
||||
_paramColor = _materialInstance->GetParameter(TEXT("Color"));
|
||||
if (_paramColor && _paramColor->GetParameterType() != MaterialParameterType::Color && _paramColor->GetParameterType() != MaterialParameterType::Vector4 && _paramColor->GetParameterType() != MaterialParameterType::Vector3)
|
||||
_paramColor = nullptr;
|
||||
else if (_paramColor)
|
||||
_paramColor->SetValue(_color);
|
||||
SetColorParam();
|
||||
}
|
||||
|
||||
void SpriteRender::SetImage()
|
||||
void SpriteRender::SetImageParam()
|
||||
{
|
||||
TextureBase* image = Image.Get();
|
||||
Vector4 imageMAD(Vector2::One, Vector2::Zero);
|
||||
@@ -94,9 +94,24 @@ void SpriteRender::SetImage()
|
||||
imageMAD = Vector4(sprite->Area.Size, sprite->Area.Location);
|
||||
}
|
||||
if (_paramImage)
|
||||
{
|
||||
_paramImage->SetValue(image);
|
||||
_paramImage->SetIsOverride(true);
|
||||
}
|
||||
if (_paramImageMAD)
|
||||
{
|
||||
_paramImageMAD->SetValue(imageMAD);
|
||||
_paramImageMAD->SetIsOverride(true);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteRender::SetColorParam()
|
||||
{
|
||||
if (_paramColor)
|
||||
{
|
||||
_paramColor->SetValue(_color);
|
||||
_paramColor->SetIsOverride(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool SpriteRender::HasContentLoaded() const
|
||||
@@ -164,9 +179,8 @@ void SpriteRender::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
|
||||
DESERIALIZE(DrawModes);
|
||||
DESERIALIZE(SortOrder);
|
||||
|
||||
SetImage();
|
||||
if (_paramColor)
|
||||
_paramColor->SetValue(_color);
|
||||
SetImageParam();
|
||||
SetColorParam();
|
||||
}
|
||||
|
||||
void SpriteRender::OnLayerChanged()
|
||||
|
||||
@@ -92,7 +92,8 @@ public:
|
||||
|
||||
private:
|
||||
void OnMaterialLoaded();
|
||||
void SetImage();
|
||||
void SetImageParam();
|
||||
void SetColorParam();
|
||||
|
||||
public:
|
||||
// [Actor]
|
||||
|
||||
@@ -2064,13 +2064,18 @@ namespace Flax.Build.Bindings
|
||||
GenerateCSharpAttributes(buildData, contents, indent, enumInfo, true);
|
||||
contents.Append(indent).Append(GenerateCSharpAccessLevel(enumInfo.Access));
|
||||
contents.Append("enum ").Append(enumInfo.Name);
|
||||
string managedType = string.Empty;
|
||||
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.Append(indent + "{");
|
||||
indent += " ";
|
||||
|
||||
// Entries
|
||||
bool usedMax = false;
|
||||
foreach (var entryInfo in enumInfo.Entries)
|
||||
{
|
||||
contents.AppendLine();
|
||||
@@ -2078,7 +2083,29 @@ namespace Flax.Build.Bindings
|
||||
GenerateCSharpAttributes(buildData, contents, indent, enumInfo, entryInfo.Attributes, entryInfo.Comment, true, false);
|
||||
contents.Append(indent).Append(entryInfo.Name);
|
||||
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.AppendLine();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user