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.
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.
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;
}
}
}
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -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.

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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;

View File

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

View File

@@ -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());

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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)
{

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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];
}

View File

@@ -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)

View File

@@ -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>

View File

@@ -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()

View File

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

View File

@@ -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();
}