diff --git a/Content/Editor/Particles/Smoke.flax b/Content/Editor/Particles/Smoke.flax
index 1335a84f4..b42c2f325 100644
--- a/Content/Editor/Particles/Smoke.flax
+++ b/Content/Editor/Particles/Smoke.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c3dc51e7805056006ca6cbb481ba202583a9b2287c152fc04e28e1d07747d6ce
-size 14706
+oid sha256:334ac0d00495fc88b10839061ff0c3f45323d4f75ab6176b19005199a7324a19
+size 14569
diff --git a/Content/Editor/Particles/Sparks.flax b/Content/Editor/Particles/Sparks.flax
index 7977e231b..7ee0ed6e9 100644
--- a/Content/Editor/Particles/Sparks.flax
+++ b/Content/Editor/Particles/Sparks.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:77d902ab5f79426cc66dc5f19a3b8280136a58aa3c6fd317554d1a032357c65a
-size 15275
+oid sha256:87046a9bfe275cac290b4764de8a512c222ccc386d01af9026d57c3e4b7773b6
+size 13625
diff --git a/Content/Editor/Scripting/ScriptTemplate.cs b/Content/Editor/Scripting/ScriptTemplate.cs
index 663acf05f..30fbe9d86 100644
--- a/Content/Editor/Scripting/ScriptTemplate.cs
+++ b/Content/Editor/Scripting/ScriptTemplate.cs
@@ -33,4 +33,3 @@ public class %class% : Script
// Here you can add code that needs to be called every frame
}
}
-
diff --git a/Flax.flaxproj b/Flax.flaxproj
index 6b3014e94..a3157a032 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -3,7 +3,8 @@
"Version": {
"Major": 1,
"Minor": 7,
- "Build": 6402
+ "Revision": 0,
+ "Build": 6404
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
diff --git a/Source/Editor/Options/InputBinding.cs b/Source/Editor/Options/InputBinding.cs
index eb61c0f68..95c3c1d6f 100644
--- a/Source/Editor/Options/InputBinding.cs
+++ b/Source/Editor/Options/InputBinding.cs
@@ -259,10 +259,7 @@ namespace FlaxEditor.Options
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
- {
return true;
- }
-
return base.CanConvertFrom(context, sourceType);
}
@@ -270,9 +267,7 @@ namespace FlaxEditor.Options
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
- {
return false;
- }
return base.CanConvertTo(context, destinationType);
}
@@ -284,7 +279,6 @@ namespace FlaxEditor.Options
InputBinding.TryParse(str, out var result);
return result;
}
-
return base.ConvertFrom(context, culture, value);
}
@@ -295,7 +289,6 @@ namespace FlaxEditor.Options
{
return ((InputBinding)value).ToString();
}
-
return base.ConvertTo(context, culture, value, destinationType);
}
}
diff --git a/Source/Editor/Options/ViewportOptions.cs b/Source/Editor/Options/ViewportOptions.cs
index cee63a562..0fd018cbc 100644
--- a/Source/Editor/Options/ViewportOptions.cs
+++ b/Source/Editor/Options/ViewportOptions.cs
@@ -26,45 +26,108 @@ namespace FlaxEditor.Options
public float MouseWheelSensitivity { get; set; } = 1.0f;
///
- /// Gets or sets the default movement speed for the viewport camera (must match the dropdown menu values in the viewport).
+ /// Gets or sets the total amount of steps the camera needs to go from minimum to maximum speed.
///
- [DefaultValue(1.0f), Limit(0.01f, 100.0f)]
- [EditorDisplay("Defaults"), EditorOrder(110), Tooltip("The default movement speed for the viewport camera (must match the dropdown menu values in the viewport).")]
- public float DefaultMovementSpeed { get; set; } = 1.0f;
+ [DefaultValue(64), Limit(1, 128)]
+ [EditorDisplay("Camera"), EditorOrder(110), Tooltip("The total amount of steps the camera needs to go from minimum to maximum speed.")]
+ public int TotalCameraSpeedSteps { get; set; } = 64;
+
+ ///
+ /// Gets or sets the degree to which the camera will be eased when using camera flight in the editor window.
+ ///
+ [DefaultValue(3.0f), Limit(1.0f, 8.0f)]
+ [EditorDisplay("Camera"), EditorOrder(111), Tooltip("The degree to which the camera will be eased when using camera flight in the editor window (ignored if camera easing degree is enabled).")]
+ public float CameraEasingDegree { get; set; } = 3.0f;
+
+ ///
+ /// Gets or sets the default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).
+ ///
+ [DefaultValue(1.0f), Limit(0.05f, 32.0f)]
+ [EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).")]
+ public float MovementSpeed { get; set; } = 1.0f;
+
+ ///
+ /// Gets or sets the default minimum camera movement speed.
+ ///
+ [DefaultValue(0.05f), Limit(0.05f, 32.0f)]
+ [EditorDisplay("Defaults"), EditorOrder(121), Tooltip("The default minimum movement speed for the viewport camera.")]
+ public float MinMovementSpeed { get; set; } = 0.05f;
+
+ ///
+ /// Gets or sets the default maximum camera movement speed.
+ ///
+ [DefaultValue(32.0f), Limit(16.0f, 1000.0f)]
+ [EditorDisplay("Defaults"), EditorOrder(122), Tooltip("The default maximum movement speed for the viewport camera.")]
+ public float MaxMovementSpeed { get; set; } = 32f;
+
+ ///
+ /// Gets or sets the default camera easing mode.
+ ///
+ [DefaultValue(true)]
+ [EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default camera easing mode.")]
+ public bool UseCameraEasing { get; set; } = true;
///
/// Gets or sets the default near clipping plane distance for the viewport camera.
///
[DefaultValue(10.0f), Limit(0.001f, 1000.0f)]
- [EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default near clipping plane distance for the viewport camera.")]
- public float DefaultNearPlane { get; set; } = 10.0f;
+ [EditorDisplay("Defaults"), EditorOrder(140), Tooltip("The default near clipping plane distance for the viewport camera.")]
+ public float NearPlane { get; set; } = 10.0f;
///
/// Gets or sets the default far clipping plane distance for the viewport camera.
///
[DefaultValue(40000.0f), Limit(10.0f)]
- [EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default far clipping plane distance for the viewport camera.")]
- public float DefaultFarPlane { get; set; } = 40000.0f;
+ [EditorDisplay("Defaults"), EditorOrder(150), Tooltip("The default far clipping plane distance for the viewport camera.")]
+ public float FarPlane { get; set; } = 40000.0f;
///
/// Gets or sets the default field of view angle (in degrees) for the viewport camera.
///
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)]
- [EditorDisplay("Defaults", "Default Field Of View"), EditorOrder(140), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
- public float DefaultFieldOfView { get; set; } = 60.0f;
+ [EditorDisplay("Defaults"), EditorOrder(160), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
+ public float FieldOfView { get; set; } = 60.0f;
///
- /// Gets or sets if the panning direction is inverted for the viewport camera.
+ /// Gets or sets the default camera orthographic mode.
///
[DefaultValue(false)]
- [EditorDisplay("Defaults"), EditorOrder(150), Tooltip("Invert the panning direction for the viewport camera.")]
- public bool DefaultInvertPanning { get; set; } = false;
+ [EditorDisplay("Defaults"), EditorOrder(170), Tooltip("The default camera orthographic mode.")]
+ public bool UseOrthographicProjection { get; set; } = false;
///
- /// Scales editor viewport grid.
+ /// Gets or sets the default camera orthographic scale (if camera uses orthographic mode).
+ ///
+ [DefaultValue(5.0f), Limit(0.001f, 100000.0f, 0.1f)]
+ [EditorDisplay("Defaults"), EditorOrder(180), Tooltip("The default camera orthographic scale (if camera uses orthographic mode).")]
+ public float OrthographicScale { get; set; } = 5.0f;
+
+ ///
+ /// Gets or sets the default panning direction for the viewport camera.
+ ///
+ [DefaultValue(false)]
+ [EditorDisplay("Defaults"), EditorOrder(190), Tooltip("The default panning direction for the viewport camera.")]
+ public bool InvertPanning { get; set; } = false;
+
+ ///
+ /// Gets or sets the default relative panning mode.
+ ///
+ [DefaultValue(true)]
+ [EditorDisplay("Defaults"), EditorOrder(200), Tooltip("The default relative panning mode. Uses distance between camera and target to determine panning speed.")]
+ public bool UseRelativePanning { get; set; } = true;
+
+ ///
+ /// Gets or sets the default panning speed (ignored if relative panning is speed enabled).
+ ///
+ [DefaultValue(0.8f), Limit(0.01f, 128.0f, 0.1f)]
+ [EditorDisplay("Defaults"), EditorOrder(210), Tooltip("The default camera panning speed (ignored if relative panning is enabled).")]
+ public float PanningSpeed { get; set; } = 0.8f;
+
+ ///
+ /// Gets or sets the default editor viewport grid scale.
///
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)]
- [EditorDisplay("Defaults"), EditorOrder(160), Tooltip("Scales editor viewport grid.")]
+ [EditorDisplay("Defaults"), EditorOrder(220), Tooltip("The default editor viewport grid scale.")]
public float ViewportGridScale { get; set; } = 50.0f;
}
}
diff --git a/Source/Editor/ProjectInfo.cpp b/Source/Editor/ProjectInfo.cpp
index 4e7ee4483..30c558b5d 100644
--- a/Source/Editor/ProjectInfo.cpp
+++ b/Source/Editor/ProjectInfo.cpp
@@ -154,7 +154,8 @@ bool ProjectInfo::LoadProject(const String& projectPath)
Version = ::Version(
JsonTools::GetInt(version, "Major", 0),
JsonTools::GetInt(version, "Minor", 0),
- JsonTools::GetInt(version, "Build", 0));
+ JsonTools::GetInt(version, "Build", -1),
+ JsonTools::GetInt(version, "Revision", -1));
}
}
if (Version.Revision() == 0)
diff --git a/Source/Editor/ProjectInfo.cs b/Source/Editor/ProjectInfo.cs
index b00c4e042..083665f0f 100644
--- a/Source/Editor/ProjectInfo.cs
+++ b/Source/Editor/ProjectInfo.cs
@@ -23,17 +23,11 @@ namespace FlaxEditor
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
- {
writer.WriteNull();
- }
else if (value is Version)
- {
writer.WriteValue(value.ToString());
- }
else
- {
throw new JsonSerializationException("Expected Version object value");
- }
}
///
@@ -47,65 +41,60 @@ namespace FlaxEditor
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
- {
return null;
- }
- else
+
+ if (reader.TokenType == JsonToken.StartObject)
{
- if (reader.TokenType == JsonToken.StartObject)
+ try
{
- try
+ reader.Read();
+ var values = new Dictionary();
+ while (reader.TokenType == JsonToken.PropertyName)
{
+ var key = reader.Value as string;
reader.Read();
- Dictionary values = new Dictionary();
- while (reader.TokenType == JsonToken.PropertyName)
- {
- var key = reader.Value as string;
- reader.Read();
- var val = (long)reader.Value;
- reader.Read();
- values.Add(key, (int)val);
- }
+ var val = (long)reader.Value;
+ reader.Read();
+ values.Add(key, (int)val);
+ }
- int major = 0, minor = 0, build = 0;
- values.TryGetValue("Major", out major);
- values.TryGetValue("Minor", out minor);
- values.TryGetValue("Build", out build);
+ values.TryGetValue("Major", out var major);
+ values.TryGetValue("Minor", out var minor);
+ if (!values.TryGetValue("Build", out var build))
+ build = -1;
+ if (!values.TryGetValue("Revision", out var revision))
+ revision = -1;
- Version v = new Version(major, minor, build);
- return v;
- }
- catch (Exception ex)
- {
- throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
- }
+ if (build <= 0)
+ return new Version(major, minor);
+ if (revision <= 0)
+ return new Version(major, minor, build);
+ return new Version(major, minor, build, revision);
}
- else if (reader.TokenType == JsonToken.String)
+ catch (Exception ex)
{
- try
- {
- Version v = new Version((string)reader.Value!);
- return v;
- }
- catch (Exception ex)
- {
- throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
- }
- }
- else
- {
- throw new Exception(String.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
+ throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
}
}
+ if (reader.TokenType == JsonToken.String)
+ {
+ try
+ {
+ return new Version((string)reader.Value!);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
+ }
+ }
+ throw new Exception(String.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
}
///
/// Determines whether this instance can convert the specified object type.
///
/// Type of the object.
- ///
- /// true if this instance can convert the specified object type; otherwise, false.
- ///
+ /// true if this instance can convert the specified object type; otherwise, false.
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Version);
diff --git a/Source/Editor/Viewport/Cameras/FPSCamera.cs b/Source/Editor/Viewport/Cameras/FPSCamera.cs
index e578933cf..bf2e840ea 100644
--- a/Source/Editor/Viewport/Cameras/FPSCamera.cs
+++ b/Source/Editor/Viewport/Cameras/FPSCamera.cs
@@ -259,7 +259,10 @@ namespace FlaxEditor.Viewport.Cameras
// Pan
if (input.IsPanning)
{
- var panningSpeed = 0.8f;
+ var panningSpeed = (Viewport.RelativePanning)
+ ? Mathf.Abs((position - TargetPoint).Length) * 0.005f
+ : Viewport.PanningSpeed;
+
if (Viewport.InvertPanning)
{
position += up * (mouseDelta.Y * panningSpeed);
diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index 9a444f2da..c49392d01 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -128,12 +128,26 @@ namespace FlaxEditor.Viewport
public const int FpsCameraFilteringFrames = 3;
///
- /// The speed widget button.
+ /// The camera settings widget.
///
- protected ViewportWidgetButton _speedWidget;
+ protected ViewportWidgetsContainer _cameraWidget;
+
+ ///
+ /// The camera settings widget button.
+ ///
+ protected ViewportWidgetButton _cameraButton;
+
+ ///
+ /// The orthographic mode widget button.
+ ///
+ protected ViewportWidgetButton _orthographicModeButton;
+
+ private readonly Editor _editor;
private float _mouseSensitivity;
private float _movementSpeed;
+ private float _minMovementSpeed;
+ private float _maxMovementSpeed;
private float _mouseAccelerationScale;
private bool _useMouseFiltering;
private bool _useMouseAcceleration;
@@ -174,11 +188,17 @@ namespace FlaxEditor.Viewport
private float _fieldOfView;
private float _nearPlane;
private float _farPlane;
- private float _orthoSize = 1.0f;
- private bool _isOrtho = false;
- private float _wheelMovementChangeDeltaSum = 0;
+ private float _orthoSize;
+ private bool _isOrtho;
+ private bool _useCameraEasing;
+ private float _cameraEasingDegree;
+ private float _panningSpeed;
+ private bool _relativePanning;
private bool _invertPanning;
+ private int _speedStep;
+ private int _maxSpeedSteps;
+
///
/// Speed of the mouse.
///
@@ -189,6 +209,25 @@ namespace FlaxEditor.Viewport
///
public float MouseWheelZoomSpeedFactor = 1;
+ ///
+ /// Format of the text for the camera move speed.
+ ///
+ private string MovementSpeedTextFormat
+ {
+ get
+ {
+ if (Mathf.Abs(_movementSpeed - _maxMovementSpeed) < Mathf.Epsilon || Mathf.Abs(_movementSpeed - _minMovementSpeed) < Mathf.Epsilon)
+ return "{0:0.##}";
+
+ if (_movementSpeed < 10.0f)
+ return "{0:0.00}";
+ else if (_movementSpeed < 100.0f)
+ return "{0:0.0}";
+ else
+ return "{0:#}";
+ }
+ }
+
///
/// Gets or sets the camera movement speed.
///
@@ -197,19 +236,40 @@ namespace FlaxEditor.Viewport
get => _movementSpeed;
set
{
- for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
- {
- if (Math.Abs(value - EditorViewportCameraSpeedValues[i]) < 0.001f)
- {
- _movementSpeed = EditorViewportCameraSpeedValues[i];
- if (_speedWidget != null)
- _speedWidget.Text = _movementSpeed.ToString();
- break;
- }
- }
+ _movementSpeed = value;
+
+ if (_cameraButton != null)
+ _cameraButton.Text = string.Format(MovementSpeedTextFormat, _movementSpeed);
}
}
+ ///
+ /// Gets or sets the minimum camera movement speed.
+ ///
+ public float MinMovementSpeed
+ {
+ get => _minMovementSpeed;
+ set => _minMovementSpeed = value;
+ }
+
+ ///
+ /// Gets or sets the maximum camera movement speed.
+ ///
+ public float MaxMovementSpeed
+ {
+ get => _maxMovementSpeed;
+ set => _maxMovementSpeed = value;
+ }
+
+ ///
+ /// Gets or sets the camera easing mode.
+ ///
+ public bool UseCameraEasing
+ {
+ get => _useCameraEasing;
+ set => _useCameraEasing = value;
+ }
+
///
/// Gets the mouse movement position delta (user press and move).
///
@@ -396,6 +456,15 @@ namespace FlaxEditor.Viewport
set => _isOrtho = value;
}
+ ///
+ /// Gets or sets if the panning speed should be relative to the camera target.
+ ///
+ public bool RelativePanning
+ {
+ get => _relativePanning;
+ set => _relativePanning = value;
+ }
+
///
/// Gets or sets if the panning direction is inverted.
///
@@ -405,6 +474,15 @@ namespace FlaxEditor.Viewport
set => _invertPanning = value;
}
+ ///
+ /// Gets or sets the camera panning speed.
+ ///
+ public float PanningSpeed
+ {
+ get => _panningSpeed;
+ set => _panningSpeed = value;
+ }
+
///
/// The input actions collection to processed during user input.
///
@@ -419,6 +497,8 @@ namespace FlaxEditor.Viewport
public EditorViewport(SceneRenderTask task, ViewportCamera camera, bool useWidgets)
: base(task)
{
+ _editor = Editor.Instance;
+
_mouseAccelerationScale = 0.1f;
_useMouseFiltering = false;
_useMouseAcceleration = false;
@@ -431,43 +511,299 @@ namespace FlaxEditor.Viewport
// Setup options
{
- var options = Editor.Instance.Options.Options;
- _movementSpeed = options.Viewport.DefaultMovementSpeed;
- _nearPlane = options.Viewport.DefaultNearPlane;
- _farPlane = options.Viewport.DefaultFarPlane;
- _fieldOfView = options.Viewport.DefaultFieldOfView;
- _invertPanning = options.Viewport.DefaultInvertPanning;
-
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
- OnEditorOptionsChanged(options);
+ SetupViewportOptions();
}
+ // Initialize camera values from cache
+ if (_editor.ProjectCache.TryGetCustomData("CameraMovementSpeedValue", out var cachedState))
+ MovementSpeed = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraMinMovementSpeedValue", out cachedState))
+ _minMovementSpeed = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraMaxMovementSpeedValue", out cachedState))
+ _maxMovementSpeed = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("UseCameraEasingState", out cachedState))
+ _useCameraEasing = bool.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraPanningSpeedValue", out cachedState))
+ _panningSpeed = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraInvertPanningState", out cachedState))
+ _invertPanning = bool.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraRelativePanningState", out cachedState))
+ _relativePanning = bool.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicState", out cachedState))
+ _isOrtho = bool.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicSizeValue", out cachedState))
+ _orthoSize = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraFieldOfViewValue", out cachedState))
+ _fieldOfView = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraNearPlaneValue", out cachedState))
+ _nearPlane = float.Parse(cachedState);
+ if (_editor.ProjectCache.TryGetCustomData("CameraFarPlaneValue", out cachedState))
+ _farPlane = float.Parse(cachedState);
+
+ OnCameraMovementProgressChanged();
+
if (useWidgets)
{
- var largestText = "Invert Panning";
+ #region Camera settings widget
+
+ var largestText = "Relative Panning";
var textSize = Style.Current.FontMedium.MeasureText(largestText);
var xLocationForExtras = textSize.X + 5;
- // Camera speed widget
- var camSpeed = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var camSpeedCM = new ContextMenu();
- var camSpeedButton = new ViewportWidgetButton(_movementSpeed.ToString(), Editor.Instance.Icons.CamSpeed32, camSpeedCM)
+ var cameraSpeedTextWidth = Style.Current.FontMedium.MeasureText("0.00").X;
+
+ // Camera Settings Widget
+ _cameraWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
+
+ // Camera Settings Menu
+ var cameraCM = new ContextMenu();
+ _cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth)
{
Tag = this,
- TooltipText = "Camera speed scale"
+ TooltipText = "Camera Settings",
+ Parent = _cameraWidget
};
- _speedWidget = camSpeedButton;
- for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
- {
- var v = EditorViewportCameraSpeedValues[i];
- var button = camSpeedCM.AddButton(v.ToString());
- button.Tag = v;
- }
- camSpeedCM.ButtonClicked += button => MovementSpeed = (float)button.Tag;
- camSpeedCM.VisibleChanged += WidgetCamSpeedShowHide;
- camSpeedButton.Parent = camSpeed;
- camSpeed.Parent = this;
+ _cameraWidget.Parent = this;
+
+ // Orthographic/Perspective Mode Widget
+ _orthographicModeButton = new ViewportWidgetButton(string.Empty, Editor.Instance.Icons.CamSpeed32, null, true)
+ {
+ Checked = !_isOrtho,
+ TooltipText = "Toggle Orthographic/Perspective Mode",
+ Parent = _cameraWidget
+ };
+ _orthographicModeButton.Toggled += OnOrthographicModeToggled;
+
+ // Camera Speed
+ var camSpeedButton = cameraCM.AddButton("Camera Speed");
+ camSpeedButton.CloseMenuOnClick = false;
+ var camSpeedValue = new FloatValueBox(_movementSpeed, xLocationForExtras, 2, 70.0f, _minMovementSpeed, _maxMovementSpeed, 0.5f)
+ {
+ Parent = camSpeedButton
+ };
+
+ camSpeedValue.ValueChanged += () => OnMovementSpeedChanged(camSpeedValue);
+ cameraCM.VisibleChanged += control => camSpeedValue.Value = _movementSpeed;
+
+ // Minimum & Maximum Camera Speed
+ var minCamSpeedButton = cameraCM.AddButton("Min Cam Speed");
+ minCamSpeedButton.CloseMenuOnClick = false;
+ var minCamSpeedValue = new FloatValueBox(_minMovementSpeed, xLocationForExtras, 2, 70.0f, 0.05f, _maxMovementSpeed, 0.5f)
+ {
+ Parent = minCamSpeedButton
+ };
+ var maxCamSpeedButton = cameraCM.AddButton("Max Cam Speed");
+ maxCamSpeedButton.CloseMenuOnClick = false;
+ var maxCamSpeedValue = new FloatValueBox(_maxMovementSpeed, xLocationForExtras, 2, 70.0f, _minMovementSpeed, 1000.0f, 0.5f)
+ {
+ Parent = maxCamSpeedButton
+ };
+
+ minCamSpeedValue.ValueChanged += () =>
+ {
+ OnMinMovementSpeedChanged(minCamSpeedValue);
+
+ maxCamSpeedValue.MinValue = minCamSpeedValue.Value;
+
+ if (Math.Abs(camSpeedValue.MinValue - minCamSpeedValue.Value) > Mathf.Epsilon)
+ camSpeedValue.MinValue = minCamSpeedValue.Value;
+ };
+ cameraCM.VisibleChanged += control => minCamSpeedValue.Value = _minMovementSpeed;
+ maxCamSpeedValue.ValueChanged += () =>
+ {
+ OnMaxMovementSpeedChanged(maxCamSpeedValue);
+
+ minCamSpeedValue.MaxValue = maxCamSpeedValue.Value;
+
+ if (Math.Abs(camSpeedValue.MaxValue - maxCamSpeedValue.Value) > Mathf.Epsilon)
+ camSpeedValue.MaxValue = maxCamSpeedValue.Value;
+ };
+ cameraCM.VisibleChanged += control => maxCamSpeedValue.Value = _maxMovementSpeed;
+
+ // Camera Easing
+ {
+ var useCameraEasing = cameraCM.AddButton("Camera Easing");
+ useCameraEasing.CloseMenuOnClick = false;
+ var useCameraEasingValue = new CheckBox(xLocationForExtras, 2, _useCameraEasing)
+ {
+ Parent = useCameraEasing
+ };
+
+ useCameraEasingValue.StateChanged += OnCameraEasingToggled;
+ cameraCM.VisibleChanged += control => useCameraEasingValue.Checked = _useCameraEasing;
+ }
+
+ // Panning Speed
+ {
+ var panningSpeed = cameraCM.AddButton("Panning Speed");
+ panningSpeed.CloseMenuOnClick = false;
+ var panningSpeedValue = new FloatValueBox(_panningSpeed, xLocationForExtras, 2, 70.0f, 0.01f, 128.0f, 0.1f)
+ {
+ Parent = panningSpeed
+ };
+
+ panningSpeedValue.ValueChanged += () => OnPanningSpeedChanged(panningSpeedValue);
+ cameraCM.VisibleChanged += control =>
+ {
+ panningSpeed.Visible = !_relativePanning;
+ panningSpeedValue.Value = _panningSpeed;
+ };
+ }
+
+ // Relative Panning
+ {
+ var relativePanning = cameraCM.AddButton("Relative Panning");
+ relativePanning.CloseMenuOnClick = false;
+ var relativePanningValue = new CheckBox(xLocationForExtras, 2, _relativePanning)
+ {
+ Parent = relativePanning
+ };
+
+ relativePanningValue.StateChanged += checkBox =>
+ {
+ if (checkBox.Checked != _relativePanning)
+ {
+ OnRelativePanningToggled(checkBox);
+ cameraCM.Hide();
+ }
+ };
+ cameraCM.VisibleChanged += control => relativePanningValue.Checked = _relativePanning;
+ }
+
+ // Invert Panning
+ {
+ var invertPanning = cameraCM.AddButton("Invert Panning");
+ invertPanning.CloseMenuOnClick = false;
+ var invertPanningValue = new CheckBox(xLocationForExtras, 2, _invertPanning)
+ {
+ Parent = invertPanning
+ };
+
+ invertPanningValue.StateChanged += OnInvertPanningToggled;
+ cameraCM.VisibleChanged += control => invertPanningValue.Checked = _invertPanning;
+ }
+
+ cameraCM.AddSeparator();
+
+ // Camera Viewpoints
+ {
+ var cameraView = cameraCM.AddChildMenu("Viewpoints").ContextMenu;
+ for (int i = 0; i < EditorViewportCameraViewpointValues.Length; i++)
+ {
+ var co = EditorViewportCameraViewpointValues[i];
+ var button = cameraView.AddButton(co.Name);
+ button.Tag = co.Orientation;
+ }
+
+ cameraView.ButtonClicked += OnViewpointChanged;
+ }
+
+ // Orthographic Mode
+ {
+ var ortho = cameraCM.AddButton("Orthographic");
+ ortho.CloseMenuOnClick = false;
+ var orthoValue = new CheckBox(xLocationForExtras, 2, _isOrtho)
+ {
+ Parent = ortho
+ };
+
+ orthoValue.StateChanged += checkBox =>
+ {
+ if (checkBox.Checked != _isOrtho)
+ {
+ OnOrthographicModeToggled(checkBox);
+ cameraCM.Hide();
+ }
+ };
+ cameraCM.VisibleChanged += control => orthoValue.Checked = _isOrtho;
+ }
+
+ // Field of View
+ {
+ var fov = cameraCM.AddButton("Field Of View");
+ fov.CloseMenuOnClick = false;
+ var fovValue = new FloatValueBox(_fieldOfView, xLocationForExtras, 2, 70.0f, 35.0f, 160.0f, 0.1f)
+ {
+ Parent = fov
+ };
+
+ fovValue.ValueChanged += () => OnFieldOfViewChanged(fovValue);
+ cameraCM.VisibleChanged += control =>
+ {
+ fov.Visible = !_isOrtho;
+ fovValue.Value = _fieldOfView;
+ };
+ }
+
+ // Orthographic Scale
+ {
+ var orthoSize = cameraCM.AddButton("Ortho Scale");
+ orthoSize.CloseMenuOnClick = false;
+ var orthoSizeValue = new FloatValueBox(_orthoSize, xLocationForExtras, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
+ {
+ Parent = orthoSize
+ };
+
+ orthoSizeValue.ValueChanged += () => OnOrthographicSizeChanged(orthoSizeValue);
+ cameraCM.VisibleChanged += control =>
+ {
+ orthoSize.Visible = _isOrtho;
+ orthoSizeValue.Value = _orthoSize;
+ };
+ }
+
+ // Near Plane
+ {
+ var nearPlane = cameraCM.AddButton("Near Plane");
+ nearPlane.CloseMenuOnClick = false;
+ var nearPlaneValue = new FloatValueBox(_nearPlane, xLocationForExtras, 2, 70.0f, 0.001f, 1000.0f)
+ {
+ Parent = nearPlane
+ };
+
+ nearPlaneValue.ValueChanged += () => OnNearPlaneChanged(nearPlaneValue);
+ cameraCM.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
+ }
+
+ // Far Plane
+ {
+ var farPlane = cameraCM.AddButton("Far Plane");
+ farPlane.CloseMenuOnClick = false;
+ var farPlaneValue = new FloatValueBox(_farPlane, xLocationForExtras, 2, 70.0f, 10.0f)
+ {
+ Parent = farPlane
+ };
+
+ farPlaneValue.ValueChanged += () => OnFarPlaneChanged(farPlaneValue);
+ cameraCM.VisibleChanged += control => farPlaneValue.Value = _farPlane;
+ }
+
+ cameraCM.AddSeparator();
+
+ // Reset Button
+ {
+ var reset = cameraCM.AddButton("Reset to default");
+ reset.ButtonClicked += button =>
+ {
+ SetupViewportOptions();
+
+ // if the context menu is opened without triggering the value changes beforehand,
+ // the movement speed will not be correctly reset to its default value in certain cases
+ // therefore, a UI update needs to be triggered here
+ minCamSpeedValue.Value = _minMovementSpeed;
+ camSpeedValue.Value = _movementSpeed;
+ maxCamSpeedValue.Value = _maxMovementSpeed;
+ };
+ }
+
+ #endregion Camera settings widget
+
+ #region View mode widget
+
+ largestText = "Brightness";
+ textSize = Style.Current.FontMedium.MeasureText(largestText);
+ xLocationForExtras = textSize.X + 5;
- // View mode widget
var viewMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperLeft);
ViewWidgetButtonMenu = new ContextMenu();
var viewModeButton = new ViewportWidgetButton("View", SpriteHandle.Invalid, ViewWidgetButtonMenu)
@@ -484,8 +820,8 @@ namespace FlaxEditor.Viewport
// Show FPS
{
InitFpsCounter();
- _showFpsButon = ViewWidgetShowMenu.AddButton("FPS Counter", () => ShowFpsCounter = !ShowFpsCounter);
- _showFpsButon.CloseMenuOnClick = false;
+ _showFpsButton = ViewWidgetShowMenu.AddButton("FPS Counter", () => ShowFpsCounter = !ShowFpsCounter);
+ _showFpsButton.CloseMenuOnClick = false;
}
}
@@ -610,104 +946,6 @@ namespace FlaxEditor.Viewport
ViewWidgetButtonMenu.AddSeparator();
- // Orthographic
- {
- var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
- ortho.CloseMenuOnClick = false;
- var orthoValue = new CheckBox(xLocationForExtras, 2, _isOrtho)
- {
- Parent = ortho
- };
- orthoValue.StateChanged += checkBox =>
- {
- if (checkBox.Checked != _isOrtho)
- {
- _isOrtho = checkBox.Checked;
- ViewWidgetButtonMenu.Hide();
- if (_isOrtho)
- {
- var orient = ViewOrientation;
- OrientViewport(ref orient);
- }
- }
- };
- ViewWidgetButtonMenu.VisibleChanged += control => orthoValue.Checked = _isOrtho;
- }
-
- // Camera Viewpoints
- {
- var cameraView = ViewWidgetButtonMenu.AddChildMenu("Viewpoints").ContextMenu;
- for (int i = 0; i < EditorViewportCameraViewpointValues.Length; i++)
- {
- var co = EditorViewportCameraViewpointValues[i];
- var button = cameraView.AddButton(co.Name);
- button.Tag = co.Orientation;
- }
- cameraView.ButtonClicked += button =>
- {
- var orient = Quaternion.Euler((Float3)button.Tag);
- OrientViewport(ref orient);
- };
- }
-
- // Field of View
- {
- var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
- fov.CloseMenuOnClick = false;
- var fovValue = new FloatValueBox(1, xLocationForExtras, 2, 70.0f, 35.0f, 160.0f, 0.1f)
- {
- Parent = fov
- };
-
- fovValue.ValueChanged += () => _fieldOfView = fovValue.Value;
- ViewWidgetButtonMenu.VisibleChanged += control =>
- {
- fov.Visible = !_isOrtho;
- fovValue.Value = _fieldOfView;
- };
- }
-
- // Ortho Scale
- {
- var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
- orthoSize.CloseMenuOnClick = false;
- var orthoSizeValue = new FloatValueBox(_orthoSize, xLocationForExtras, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
- {
- Parent = orthoSize
- };
-
- orthoSizeValue.ValueChanged += () => _orthoSize = orthoSizeValue.Value;
- ViewWidgetButtonMenu.VisibleChanged += control =>
- {
- orthoSize.Visible = _isOrtho;
- orthoSizeValue.Value = _orthoSize;
- };
- }
-
- // Near Plane
- {
- var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
- nearPlane.CloseMenuOnClick = false;
- var nearPlaneValue = new FloatValueBox(2.0f, xLocationForExtras, 2, 70.0f, 0.001f, 1000.0f)
- {
- Parent = nearPlane
- };
- nearPlaneValue.ValueChanged += () => _nearPlane = nearPlaneValue.Value;
- ViewWidgetButtonMenu.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
- }
-
- // Far Plane
- {
- var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
- farPlane.CloseMenuOnClick = false;
- var farPlaneValue = new FloatValueBox(1000, xLocationForExtras, 2, 70.0f, 10.0f)
- {
- Parent = farPlane
- };
- farPlaneValue.ValueChanged += () => _farPlane = farPlaneValue.Value;
- ViewWidgetButtonMenu.VisibleChanged += control => farPlaneValue.Value = _farPlane;
- }
-
// Brightness
{
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
@@ -732,24 +970,7 @@ namespace FlaxEditor.Viewport
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
}
- // Invert Panning
- {
- var invert = ViewWidgetButtonMenu.AddButton("Invert Panning");
- invert.CloseMenuOnClick = false;
- var invertValue = new CheckBox(xLocationForExtras, 2, _invertPanning)
- {
- Parent = invert
- };
-
- invertValue.StateChanged += checkBox =>
- {
- if (checkBox.Checked != _invertPanning)
- {
- _invertPanning = checkBox.Checked;
- }
- };
- ViewWidgetButtonMenu.VisibleChanged += control => invertValue.Checked = _invertPanning;
- }
+ #endregion View mode widget
}
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Top").Orientation)));
@@ -766,6 +987,135 @@ namespace FlaxEditor.Viewport
task.Begin += OnRenderBegin;
}
+ ///
+ /// Sets the viewport options to the default values.
+ ///
+ private void SetupViewportOptions()
+ {
+ var options = Editor.Instance.Options.Options;
+ _minMovementSpeed = options.Viewport.MinMovementSpeed;
+ MovementSpeed = options.Viewport.MovementSpeed;
+ _maxMovementSpeed = options.Viewport.MaxMovementSpeed;
+ _useCameraEasing = options.Viewport.UseCameraEasing;
+ _panningSpeed = options.Viewport.PanningSpeed;
+ _invertPanning = options.Viewport.InvertPanning;
+ _relativePanning = options.Viewport.UseRelativePanning;
+
+ _isOrtho = options.Viewport.UseOrthographicProjection;
+ _orthoSize = options.Viewport.OrthographicScale;
+ _fieldOfView = options.Viewport.FieldOfView;
+ _nearPlane = options.Viewport.NearPlane;
+ _farPlane = options.Viewport.FarPlane;
+
+ OnEditorOptionsChanged(options);
+ }
+
+ private void OnMovementSpeedChanged(FloatValueBox control)
+ {
+ var value = Mathf.Clamp(control.Value, _minMovementSpeed, _maxMovementSpeed);
+ MovementSpeed = value;
+
+ OnCameraMovementProgressChanged();
+ _editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed.ToString());
+ }
+
+ private void OnMinMovementSpeedChanged(FloatValueBox control)
+ {
+ var value = Mathf.Clamp(control.Value, 0.05f, _maxMovementSpeed);
+ _minMovementSpeed = value;
+
+ if (_movementSpeed < value)
+ MovementSpeed = value;
+
+ OnCameraMovementProgressChanged();
+ _editor.ProjectCache.SetCustomData("CameraMinMovementSpeedValue", _minMovementSpeed.ToString());
+ }
+
+ private void OnMaxMovementSpeedChanged(FloatValueBox control)
+ {
+ var value = Mathf.Clamp(control.Value, _minMovementSpeed, 1000.0f);
+ _maxMovementSpeed = value;
+
+ if (_movementSpeed > value)
+ MovementSpeed = value;
+
+ OnCameraMovementProgressChanged();
+ _editor.ProjectCache.SetCustomData("CameraMaxMovementSpeedValue", _maxMovementSpeed.ToString());
+ }
+
+ private void OnCameraEasingToggled(Control control)
+ {
+ _useCameraEasing = !_useCameraEasing;
+
+ OnCameraMovementProgressChanged();
+ _editor.ProjectCache.SetCustomData("UseCameraEasingState", _useCameraEasing.ToString());
+ }
+
+ private void OnPanningSpeedChanged(FloatValueBox control)
+ {
+ _panningSpeed = control.Value;
+ _editor.ProjectCache.SetCustomData("CameraPanningSpeedValue", _panningSpeed.ToString());
+ }
+
+ private void OnRelativePanningToggled(Control control)
+ {
+ _relativePanning = !_relativePanning;
+ _editor.ProjectCache.SetCustomData("CameraRelativePanningState", _relativePanning.ToString());
+ }
+
+ private void OnInvertPanningToggled(Control control)
+ {
+ _invertPanning = !_invertPanning;
+ _editor.ProjectCache.SetCustomData("CameraInvertPanningState", _invertPanning.ToString());
+ }
+
+
+ private void OnViewpointChanged(ContextMenuButton button)
+ {
+ var orient = Quaternion.Euler((Float3)button.Tag);
+ OrientViewport(ref orient);
+ }
+
+ private void OnFieldOfViewChanged(FloatValueBox control)
+ {
+ _fieldOfView = control.Value;
+ _editor.ProjectCache.SetCustomData("CameraFieldOfViewValue", _fieldOfView.ToString());
+ }
+
+ private void OnOrthographicModeToggled(Control control)
+ {
+ _isOrtho = !_isOrtho;
+
+ if (_orthographicModeButton != null)
+ _orthographicModeButton.Checked = !_isOrtho;
+
+ if (_isOrtho)
+ {
+ var orient = ViewOrientation;
+ OrientViewport(ref orient);
+ }
+
+ _editor.ProjectCache.SetCustomData("CameraOrthographicState", _isOrtho.ToString());
+ }
+
+ private void OnOrthographicSizeChanged(FloatValueBox control)
+ {
+ _orthoSize = control.Value;
+ _editor.ProjectCache.SetCustomData("CameraOrthographicSizeValue", _orthoSize.ToString());
+ }
+
+ private void OnNearPlaneChanged(FloatValueBox control)
+ {
+ _nearPlane = control.Value;
+ _editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _nearPlane.ToString());
+ }
+
+ private void OnFarPlaneChanged(FloatValueBox control)
+ {
+ _farPlane = control.Value;
+ _editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _farPlane.ToString());
+ }
+
///
/// Gets a value indicating whether this viewport is using mouse currently (eg. user moving objects).
///
@@ -798,33 +1148,59 @@ namespace FlaxEditor.Viewport
}
}
+ private void OnCameraMovementProgressChanged()
+ {
+ // prevent NaN
+ if (Math.Abs(_minMovementSpeed - _maxMovementSpeed) < Mathf.Epsilon)
+ {
+ _speedStep = 0;
+ return;
+ }
+
+ if (Math.Abs(_movementSpeed - _maxMovementSpeed) < Mathf.Epsilon)
+ {
+ _speedStep = _maxSpeedSteps;
+ return;
+ }
+ else if (Math.Abs(_movementSpeed - _minMovementSpeed) < Mathf.Epsilon)
+ {
+ _speedStep = 0;
+ return;
+ }
+
+ // calculate current linear/eased progress
+ var progress = Mathf.Remap(_movementSpeed, _minMovementSpeed, _maxMovementSpeed, 0.0f, 1.0f);
+
+ if (_useCameraEasing)
+ progress = Mathf.Pow(progress, 1.0f / _cameraEasingDegree);
+
+ _speedStep = Mathf.RoundToInt(progress * _maxSpeedSteps);
+ }
+
///
/// Increases or decreases the camera movement speed.
///
/// The stepping direction for speed adjustment.
protected void AdjustCameraMoveSpeed(int step)
{
- int camValueIndex = -1;
- for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
- {
- if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
- {
- camValueIndex = i;
- break;
- }
- }
- if (camValueIndex == -1)
- return;
+ _speedStep = Mathf.Clamp(_speedStep + step, 0, _maxSpeedSteps);
- if (step > 0)
- MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
- else if (step < 0)
- MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
+ // calculate new linear/eased progress
+ var progress = _useCameraEasing
+ ? Mathf.Pow((float)_speedStep / _maxSpeedSteps, _cameraEasingDegree)
+ : (float)_speedStep / _maxSpeedSteps;
+
+ var speed = Mathf.Lerp(_minMovementSpeed, _maxMovementSpeed, progress);
+ MovementSpeed = (float)Math.Round(speed, 3);
+ _editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed.ToString());
}
private void OnEditorOptionsChanged(EditorOptions options)
{
_mouseSensitivity = options.Viewport.MouseSensitivity;
+ _maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps;
+ _cameraEasingDegree = options.Viewport.CameraEasingDegree;
+ OnCameraMovementProgressChanged();
}
private void OnRenderBegin(RenderTask task, GPUContext context)
@@ -863,7 +1239,7 @@ namespace FlaxEditor.Viewport
}
private FpsCounter _fpsCounter;
- private ContextMenuButton _showFpsButon;
+ private ContextMenuButton _showFpsButton;
///
/// Gets or sets a value indicating whether show or hide FPS counter.
@@ -875,7 +1251,7 @@ namespace FlaxEditor.Viewport
{
_fpsCounter.Visible = value;
_fpsCounter.Enabled = value;
- _showFpsButon.Icon = value ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
+ _showFpsButton.Icon = value ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
}
}
@@ -1016,8 +1392,6 @@ namespace FlaxEditor.Viewport
/// The parent window.
protected virtual void OnControlMouseBegin(Window win)
{
- _wheelMovementChangeDeltaSum = 0;
-
// Hide cursor and start tracking mouse movement
win.StartTrackingMouse(false);
win.Cursor = CursorType.Hidden;
@@ -1113,8 +1487,8 @@ namespace FlaxEditor.Viewport
_camera.Update(deltaTime);
useMovementSpeed = _camera.UseMovementSpeed;
- if (_speedWidget != null)
- _speedWidget.Parent.Visible = useMovementSpeed;
+ if (_cameraButton != null)
+ _cameraButton.Parent.Visible = useMovementSpeed;
}
// Get parent window
@@ -1217,18 +1591,8 @@ namespace FlaxEditor.Viewport
rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse;
if (rmbWheel)
{
- const float step = 4.0f;
- _wheelMovementChangeDeltaSum += _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
- if (_wheelMovementChangeDeltaSum >= step)
- {
- _wheelMovementChangeDeltaSum -= step;
- AdjustCameraMoveSpeed(1);
- }
- else if (_wheelMovementChangeDeltaSum <= -step)
- {
- _wheelMovementChangeDeltaSum += step;
- AdjustCameraMoveSpeed(-1);
- }
+ var step = _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
+ AdjustCameraMoveSpeed(step > 0.0f ? 1 : -1);
}
}
@@ -1497,22 +1861,6 @@ namespace FlaxEditor.Viewport
new CameraViewpoint("Bottom", new Float3(-90, 0, 0))
};
- private readonly float[] EditorViewportCameraSpeedValues =
- {
- 0.05f,
- 0.1f,
- 0.25f,
- 0.5f,
- 1.0f,
- 2.0f,
- 4.0f,
- 6.0f,
- 8.0f,
- 16.0f,
- 32.0f,
- 64.0f,
- };
-
private struct ViewModeOptions
{
public readonly string Name;
@@ -1568,24 +1916,6 @@ namespace FlaxEditor.Viewport
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"),
};
- private void WidgetCamSpeedShowHide(Control cm)
- {
- if (cm.Visible == false)
- return;
-
- var ccm = (ContextMenu)cm;
- foreach (var e in ccm.Items)
- {
- if (e is ContextMenuButton b)
- {
- var v = (float)b.Tag;
- b.Icon = Mathf.Abs(MovementSpeed - v) < 0.001f
- ? Style.Current.CheckBoxTick
- : SpriteHandle.Invalid;
- }
- }
- }
-
private void WidgetViewModeShowHideClicked(ContextMenuButton button)
{
if (button.Tag is ViewMode v)
diff --git a/Source/Editor/Viewport/Widgets/ViewportWidgetButton.cs b/Source/Editor/Viewport/Widgets/ViewportWidgetButton.cs
index 481bc3f1b..5ff5cdb6d 100644
--- a/Source/Editor/Viewport/Widgets/ViewportWidgetButton.cs
+++ b/Source/Editor/Viewport/Widgets/ViewportWidgetButton.cs
@@ -19,6 +19,7 @@ namespace FlaxEditor.Viewport.Widgets
private bool _checked;
private bool _autoCheck;
private bool _isMosueDown;
+ private float _forcedTextWidth;
///
/// Event fired when user toggles checked state.
@@ -63,14 +64,16 @@ namespace FlaxEditor.Viewport.Widgets
/// The text.
/// The icon.
/// The context menu.
- /// if set to true will be automatic checked on mouse click.
- public ViewportWidgetButton(string text, SpriteHandle icon, ContextMenu contextMenu = null, bool autoCheck = false)
- : base(0, 0, CalculateButtonWidth(0, icon.IsValid), ViewportWidgetsContainer.WidgetsHeight)
+ /// If set to true will be automatic checked on mouse click.
+ /// Forces the text to be drawn with the specified width.
+ public ViewportWidgetButton(string text, SpriteHandle icon, ContextMenu contextMenu = null, bool autoCheck = false, float textWidth = 0.0f)
+ : base(0, 0, CalculateButtonWidth(textWidth, icon.IsValid), ViewportWidgetsContainer.WidgetsHeight)
{
_text = text;
Icon = icon;
_cm = contextMenu;
_autoCheck = autoCheck;
+ _forcedTextWidth = textWidth;
if (_cm != null)
_cm.VisibleChanged += CmOnVisibleChanged;
@@ -160,7 +163,7 @@ namespace FlaxEditor.Viewport.Widgets
var style = Style.Current;
if (style != null && style.FontMedium)
- Width = CalculateButtonWidth(style.FontMedium.MeasureText(_text).X, Icon.IsValid);
+ Width = CalculateButtonWidth(_forcedTextWidth > 0.0f ? _forcedTextWidth : style.FontMedium.MeasureText(_text).X, Icon.IsValid);
}
}
}
diff --git a/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs b/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs
index afd34bbfd..65377acaa 100644
--- a/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/ColorConverter.cs
@@ -13,9 +13,7 @@ namespace FlaxEngine.TypeConverters
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
- {
return true;
- }
return base.CanConvertFrom(context, sourceType);
}
@@ -23,9 +21,7 @@ namespace FlaxEngine.TypeConverters
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
- {
return false;
- }
return base.CanConvertTo(context, destinationType);
}
diff --git a/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs
index 4eebbfce4..e0670df05 100644
--- a/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Double2Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Double2Converter : TypeConverter
+ internal class Double2Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Double2(double.Parse(v[0], culture), double.Parse(v[1], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs
index 420e0016c..a66892ecb 100644
--- a/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Double3Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Double3Converter : TypeConverter
+ internal class Double3Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Double3(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs
index fc1d9a7fe..d085217ef 100644
--- a/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Double4Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Double4Converter : TypeConverter
+ internal class Double4Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Double4(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture), double.Parse(v[3], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs
index a41a0f4d5..4b2ffadf5 100644
--- a/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Float2Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Float2Converter : TypeConverter
+ internal class Float2Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Float2(float.Parse(v[0], culture), float.Parse(v[1], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs
index aded4117e..3739c44ef 100644
--- a/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Float3Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Float3Converter : TypeConverter
+ internal class Float3Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Float3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs
index 58c76ac65..620f2c838 100644
--- a/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Float4Converter.cs
@@ -7,15 +7,13 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Float4Converter : TypeConverter
+ internal class VectorConverter : TypeConverter
{
///
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
- {
return true;
- }
return base.CanConvertFrom(context, sourceType);
}
@@ -23,18 +21,32 @@ namespace FlaxEngine.TypeConverters
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
- {
return false;
- }
return base.CanConvertTo(context, destinationType);
}
+ internal static string[] GetParts(string str)
+ {
+ string[] v = str.Split(',');
+ if (v.Length == 1)
+ {
+ // When converting from ToString()
+ v = str.Split(' ');
+ for (int i = 0; i < v.Length; i++)
+ v[i] = v[i].Substring(v[i].IndexOf(':') + 1);
+ }
+ return v;
+ }
+ }
+
+ internal class Float4Converter : VectorConverter
+ {
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Float4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs
index c4989c085..f528aa46b 100644
--- a/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Int2Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Int2Converter : TypeConverter
+ internal class Int2Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Int2(int.Parse(v[0], culture), int.Parse(v[1], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs
index fe01f91fd..520f806d0 100644
--- a/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Int3Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Int3Converter : TypeConverter
+ internal class Int3Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Int3(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs
index 2ce0fc202..e9a27dfda 100644
--- a/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Int4Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Int4Converter : TypeConverter
+ internal class Int4Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Int4(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture), int.Parse(v[3], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs b/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs
index 23bb901be..5d9aa206b 100644
--- a/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/QuaternionConverter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class QuaternionConverter : TypeConverter
+ internal class QuaternionConverter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Quaternion(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs b/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs
index 96d6beadc..acb5b5817 100644
--- a/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Vector2Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Vector2Converter : TypeConverter
+ internal class Vector2Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Vector2(float.Parse(v[0], culture), float.Parse(v[1], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs b/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs
index 23ee4df11..66ec831f0 100644
--- a/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Vector3Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Vector3Converter : TypeConverter
+ internal class Vector3Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Vector3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs b/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs
index c3b4d074b..f4781f45b 100644
--- a/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs
+++ b/Source/Engine/Core/Math/TypeConverters/Vector4Converter.cs
@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters
{
- internal class Vector4Converter : TypeConverter
+ internal class Vector4Converter : VectorConverter
{
- ///
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
-
- ///
- public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
- {
- if (destinationType == typeof(string))
- {
- return false;
- }
- return base.CanConvertTo(context, destinationType);
- }
-
///
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string str)
{
- string[] v = str.Split(',');
+ string[] v = GetParts(str);
return new Vector4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
}
return base.ConvertFrom(context, culture, value);
diff --git a/Source/Engine/Core/Math/Vector2.h b/Source/Engine/Core/Math/Vector2.h
index 83deb009a..cea03ec10 100644
--- a/Source/Engine/Core/Math/Vector2.h
+++ b/Source/Engine/Core/Math/Vector2.h
@@ -646,6 +646,12 @@ inline Vector2Base operator/(typename TOtherFloat::Type a, const Vector2Ba
return Vector2Base(a) / b;
}
+template
+inline uint32 GetHash(const Vector2Base& key)
+{
+ return (*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y;
+}
+
namespace Math
{
template
diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h
index c0ebdf01d..01b55e9bd 100644
--- a/Source/Engine/Core/Math/Vector3.h
+++ b/Source/Engine/Core/Math/Vector3.h
@@ -977,6 +977,12 @@ inline Vector3Base operator/(typename TOtherFloat::Type a, const Vector3Ba
return Vector3Base(a) / b;
}
+template
+inline uint32 GetHash(const Vector3Base& key)
+{
+ return (((*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y) * 397) ^ *(uint32*)&key.Z;
+}
+
namespace Math
{
template
diff --git a/Source/Engine/Core/Math/Vector4.h b/Source/Engine/Core/Math/Vector4.h
index 5c7b24c4a..1cc6d4db8 100644
--- a/Source/Engine/Core/Math/Vector4.h
+++ b/Source/Engine/Core/Math/Vector4.h
@@ -552,6 +552,12 @@ inline Vector4Base operator/(typename TOtherFloat::Type a, const Vector4Ba
return Vector4Base(a) / b;
}
+template
+inline uint32 GetHash(const Vector4Base& key)
+{
+ return (((((*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y) * 397) ^ *(uint32*)&key.Z) * 397) ^*(uint32*)&key.W;
+}
+
namespace Math
{
template
diff --git a/Source/Engine/Core/Types/Version.cpp b/Source/Engine/Core/Types/Version.cpp
index 4a11a0af6..c0410d1cb 100644
--- a/Source/Engine/Core/Types/Version.cpp
+++ b/Source/Engine/Core/Types/Version.cpp
@@ -7,15 +7,15 @@ Version::Version(int32 major, int32 minor, int32 build, int32 revision)
{
_major = Math::Max(major, 0);
_minor = Math::Max(minor, 0);
- _build = Math::Max(build, 0);
- _revision = Math::Max(revision, 0);
+ _build = Math::Max(build, -1);
+ _revision = Math::Max(revision, -1);
}
Version::Version(int32 major, int32 minor, int32 build)
{
_major = Math::Max(major, 0);
_minor = Math::Max(minor, 0);
- _build = Math::Max(build, 0);
+ _build = Math::Max(build, -1);
_revision = -1;
}
diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs
index 2f74e421c..fea1fadda 100644
--- a/Source/Engine/Engine/NativeInterop.cs
+++ b/Source/Engine/Engine/NativeInterop.cs
@@ -1302,7 +1302,8 @@ namespace FlaxEngine.Interop
#if !USE_AOT
internal bool TryGetDelegate(out Invoker.MarshalAndInvokeDelegate outDeleg, out object outDelegInvoke)
{
- if (invokeDelegate == null)
+ // Skip using in-built delegate for value types (eg. Transform) to properly handle instance value passing to method
+ if (invokeDelegate == null && !method.DeclaringType.IsValueType)
{
List methodTypes = new List();
if (!method.IsStatic)
diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp
index 34d8e7661..f0056e26c 100644
--- a/Source/Engine/Graphics/GPUDevice.cpp
+++ b/Source/Engine/Graphics/GPUDevice.cpp
@@ -313,6 +313,8 @@ bool GPUDevice::Init()
_res->TasksManager.SetExecutor(CreateTasksExecutor());
LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory));
+ if (!Limits.HasCompute)
+ LOG(Warning, "Compute Shaders are not supported");
return false;
}
diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp
index e76ee9996..86d983fd8 100644
--- a/Source/Engine/Graphics/Shaders/GPUShader.cpp
+++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp
@@ -87,7 +87,11 @@ bool GPUShader::Create(MemoryReadStream& stream)
GPUShaderProgramInitializer initializer;
#if !BUILD_RELEASE
initializer.Owner = this;
+ const StringView name = GetName();
+#else
+ const StringView name;
#endif
+ const bool hasCompute = GPUDevice::Instance->Limits.HasCompute;
for (int32 i = 0; i < shadersCount; i++)
{
const ShaderStage type = static_cast(stream.ReadByte());
@@ -117,10 +121,15 @@ bool GPUShader::Create(MemoryReadStream& stream)
stream.ReadBytes(&initializer.Bindings, sizeof(ShaderBindings));
// Create shader program
+ if (type == ShaderStage::Compute && !hasCompute)
+ {
+ LOG(Warning, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name);
+ continue;
+ }
GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream);
if (shader == nullptr)
{
- LOG(Error, "Failed to create {} Shader program '{}'.", ::ToString(type), String(initializer.Name));
+ LOG(Error, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name);
return true;
}
diff --git a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h
index 09c45506f..31f6638dc 100644
--- a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h
+++ b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h
@@ -122,6 +122,19 @@ public:
///
class GPUShaderProgramVS : public GPUShaderProgram
{
+public:
+ // Input element run-time data (see VertexShaderMeta::InputElement for compile-time data)
+ PACK_STRUCT(struct InputElement
+ {
+ byte Type; // VertexShaderMeta::InputType
+ byte Index;
+ byte Format; // PixelFormat
+ byte InputSlot;
+ uint32 AlignedByteOffset; // Fixed value or INPUT_LAYOUT_ELEMENT_ALIGN if auto
+ byte InputSlotClass; // INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA or INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA
+ uint32 InstanceDataStepRate; // 0 if per-vertex
+ });
+
public:
///
/// Gets input layout description handle (platform dependent).
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp
index b58684a4e..52192c634 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUShaderDX11.cpp
@@ -15,32 +15,21 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
case ShaderStage::Vertex:
{
- D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
-
- // Temporary variables
- byte Type, Format, Index, InputSlot, InputSlotClass;
- uint32 AlignedByteOffset, InstanceDataStepRate;
-
- // Load Input Layout (it may be empty)
+ // Load Input Layout
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
+ D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
- // TODO: maybe use struct and load at once?
- stream.ReadByte(&Type);
- stream.ReadByte(&Index);
- stream.ReadByte(&Format);
- stream.ReadByte(&InputSlot);
- stream.ReadUint32(&AlignedByteOffset);
- stream.ReadByte(&InputSlotClass);
- stream.ReadUint32(&InstanceDataStepRate);
+ GPUShaderProgramVS::InputElement inputElement;
+ stream.Read(inputElement);
// Get semantic name
const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ?
- switch (Type)
+ switch (inputElement.Type)
{
case 1:
semanticName = "POSITION";
@@ -70,7 +59,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
semanticName = "BLENDWEIGHT";
break;
default:
- LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type);
+ LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
break;
}
@@ -78,12 +67,12 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
inputLayoutDesc[a] =
{
semanticName,
- static_cast(Index),
- static_cast(Format),
- static_cast(InputSlot),
- static_cast(AlignedByteOffset),
- static_cast(InputSlotClass),
- static_cast(InstanceDataStepRate)
+ static_cast(inputElement.Index),
+ static_cast(inputElement.Format),
+ static_cast(inputElement.InputSlot),
+ static_cast(inputElement.AlignedByteOffset),
+ static_cast(inputElement.InputSlotClass),
+ static_cast(inputElement.InstanceDataStepRate)
};
}
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp
index e1e716853..07352b674 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp
@@ -20,32 +20,21 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
{
case ShaderStage::Vertex:
{
- D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
-
- // Temporary variables
- byte Type, Format, Index, InputSlot, InputSlotClass;
- uint32 AlignedByteOffset, InstanceDataStepRate;
-
// Load Input Layout (it may be empty)
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
+ D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
- // TODO: maybe use struct and load at once?
- stream.ReadByte(&Type);
- stream.ReadByte(&Index);
- stream.ReadByte(&Format);
- stream.ReadByte(&InputSlot);
- stream.ReadUint32(&AlignedByteOffset);
- stream.ReadByte(&InputSlotClass);
- stream.ReadUint32(&InstanceDataStepRate);
+ GPUShaderProgramVS::InputElement inputElement;
+ stream.Read(inputElement);
// Get semantic name
const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ?
- switch (Type)
+ switch (inputElement.Type)
{
case 1:
semanticName = "POSITION";
@@ -75,7 +64,7 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
semanticName = "BLENDWEIGHT";
break;
default:
- LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type);
+ LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
break;
}
@@ -83,12 +72,12 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
inputLayout[a] =
{
semanticName,
- static_cast(Index),
- static_cast(Format),
- static_cast(InputSlot),
- static_cast(AlignedByteOffset),
- static_cast(InputSlotClass),
- static_cast(InstanceDataStepRate)
+ static_cast(inputElement.Index),
+ static_cast(inputElement.Format),
+ static_cast(inputElement.InputSlot),
+ static_cast(inputElement.AlignedByteOffset),
+ static_cast(inputElement.InputSlotClass),
+ static_cast(inputElement.InstanceDataStepRate)
};
}
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp
index 5e583d713..852ce5bad 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUShaderVulkan.cpp
@@ -14,9 +14,9 @@
#include "Engine/Graphics/PixelFormatExtensions.h"
#if PLATFORM_DESKTOP
-#define VULKAN_UNIFORM_RING_BUFFER_SIZE 24 * 1024 * 1024
+#define VULKAN_UNIFORM_RING_BUFFER_SIZE (24 * 1024 * 1024)
#else
-#define VULKAN_UNIFORM_RING_BUFFER_SIZE 8 * 1024 * 1024
+#define VULKAN_UNIFORM_RING_BUFFER_SIZE (8 * 1024 * 1024)
#endif
UniformBufferUploaderVulkan::UniformBufferUploaderVulkan(GPUDeviceVulkan* device)
@@ -153,10 +153,6 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
vertexBindingDescriptions[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
}
- // Temporary variables
- byte Type, Format, Index, InputSlot, InputSlotClass;
- uint32 AlignedByteOffset, InstanceDataStepRate;
-
// Load Input Layout (it may be empty)
byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize);
@@ -167,32 +163,26 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
for (int32 a = 0; a < inputLayoutSize; a++)
{
// Read description
- // TODO: maybe use struct and load at once?
- stream.ReadByte(&Type);
- stream.ReadByte(&Index);
- stream.ReadByte(&Format);
- stream.ReadByte(&InputSlot);
- stream.ReadUint32(&AlignedByteOffset);
- stream.ReadByte(&InputSlotClass);
- stream.ReadUint32(&InstanceDataStepRate);
+ GPUShaderProgramVS::InputElement inputElement;
+ stream.Read(inputElement);
- const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)Format);
- if (AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN)
- offset = AlignedByteOffset;
+ const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)inputElement.Format);
+ if (inputElement.AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN)
+ offset = inputElement.AlignedByteOffset;
- auto& vertexBindingDescription = vertexBindingDescriptions[InputSlot];
- vertexBindingDescription.binding = InputSlot;
+ auto& vertexBindingDescription = vertexBindingDescriptions[inputElement.InputSlot];
+ vertexBindingDescription.binding = inputElement.InputSlot;
vertexBindingDescription.stride = Math::Max(vertexBindingDescription.stride, (uint32_t)(offset + size));
- vertexBindingDescription.inputRate = InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
- ASSERT(InstanceDataStepRate == 0 || InstanceDataStepRate == 1);
+ vertexBindingDescription.inputRate = inputElement.InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
+ ASSERT(inputElement.InstanceDataStepRate == 0 || inputElement.InstanceDataStepRate == 1);
auto& vertexAttributeDescription = vertexAttributeDescriptions[a];
vertexAttributeDescription.location = a;
- vertexAttributeDescription.binding = InputSlot;
- vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)Format);
+ vertexAttributeDescription.binding = inputElement.InputSlot;
+ vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)inputElement.Format);
vertexAttributeDescription.offset = offset;
- bindingsCount = Math::Max(bindingsCount, (uint32)InputSlot + 1);
+ bindingsCount = Math::Max(bindingsCount, (uint32)inputElement.InputSlot + 1);
offset += size;
}
diff --git a/Source/Engine/Level/Prefabs/PrefabManager.cpp b/Source/Engine/Level/Prefabs/PrefabManager.cpp
index cd9d893ec..de164343b 100644
--- a/Source/Engine/Level/Prefabs/PrefabManager.cpp
+++ b/Source/Engine/Level/Prefabs/PrefabManager.cpp
@@ -39,7 +39,7 @@ PrefabManagerService PrefabManagerServiceInstance;
Actor* PrefabManager::SpawnPrefab(Prefab* prefab)
{
Actor* parent = Level::Scenes.Count() != 0 ? Level::Scenes.Get()[0] : nullptr;
- return SpawnPrefab(prefab, Transform::Identity, parent, nullptr);
+ return SpawnPrefab(prefab, Transform(Vector3::Minimum), parent, nullptr);
}
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Vector3& position)
@@ -73,12 +73,12 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, const Transform
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent)
{
- return SpawnPrefab(prefab, Transform::Identity, parent, nullptr);
+ return SpawnPrefab(prefab, Transform(Vector3::Minimum), parent, nullptr);
}
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary* objectsCache, bool withSynchronization)
{
- return SpawnPrefab(prefab, Transform::Identity, parent, objectsCache, withSynchronization);
+ return SpawnPrefab(prefab, Transform(Vector3::Minimum), parent, objectsCache, withSynchronization);
}
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Actor* parent, Dictionary* objectsCache, bool withSynchronization)
@@ -191,7 +191,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
parent->Children.Add(root);
// Move root to the right location
- if (transform != Transform::Identity)
+ if (transform.Translation != Vector3::Minimum)
root->SetTransform(transform);
// Link actors hierarchy
diff --git a/Source/Engine/Particles/Particles.cpp b/Source/Engine/Particles/Particles.cpp
index 52845a0f8..784f28c98 100644
--- a/Source/Engine/Particles/Particles.cpp
+++ b/Source/Engine/Particles/Particles.cpp
@@ -1334,7 +1334,8 @@ void ParticlesSystem::Job(int32 index)
auto emitter = particleSystem->Emitters[track.AsEmitter.Index].Get();
auto& data = instance.Emitters[track.AsEmitter.Index];
ASSERT(emitter && emitter->IsLoaded());
- ASSERT(emitter->Capacity != 0 && emitter->Graph.Layout.Size != 0);
+ if (emitter->Capacity == 0 || emitter->Graph.Layout.Size == 0)
+ continue;
PROFILE_CPU_ASSET(emitter);
// Calculate new time position
diff --git a/Source/Engine/Physics/Actors/PhysicsColliderActor.cpp b/Source/Engine/Physics/Actors/PhysicsColliderActor.cpp
index 02645943c..f2ab5d8a2 100644
--- a/Source/Engine/Physics/Actors/PhysicsColliderActor.cpp
+++ b/Source/Engine/Physics/Actors/PhysicsColliderActor.cpp
@@ -1,7 +1,6 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "PhysicsColliderActor.h"
-#include "Engine/Scripting/Script.h"
#include "RigidBody.h"
PhysicsColliderActor::PhysicsColliderActor(const SpawnParams& params)
diff --git a/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp
index 684aeca19..5968bdd78 100644
--- a/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp
+++ b/Source/Engine/Physics/PhysX/SimulationEventCallbackPhysX.cpp
@@ -117,9 +117,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
{
// Skip sending events to removed actors
if (pairHeader.flags & (PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1))
- {
return;
- }
Collision c;
PxContactPairExtraDataIterator j(pairHeader.extraDataStream, pairHeader.extraDataStreamSize);
@@ -193,7 +191,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
RemovedCollisions.Add(c);
}
}
- ASSERT(!j.nextItemSet());
+ //ASSERT(!j.nextItemSet());
}
void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count)
diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp
index c5bc44ab9..474a92072 100644
--- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp
+++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp
@@ -451,6 +451,7 @@ DialogResult MessageBox::Show(Window* parent, const StringView& text, const Stri
default:
break;
}
+ flags |= MB_TASKMODAL;
// Show dialog
int result = MessageBoxW(parent ? static_cast(parent->GetNativePtr()) : nullptr, String(text).GetText(), String(caption).GetText(), flags);
diff --git a/Source/Engine/Renderer/DepthOfFieldPass.cpp b/Source/Engine/Renderer/DepthOfFieldPass.cpp
index cd7930f5c..707a441e6 100644
--- a/Source/Engine/Renderer/DepthOfFieldPass.cpp
+++ b/Source/Engine/Renderer/DepthOfFieldPass.cpp
@@ -204,7 +204,7 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame,
{
DepthOfFieldSettings& dofSettings = renderContext.List->Settings.DepthOfField;
const bool useDoF = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::DepthOfField) && dofSettings.Enabled;
- if (!useDoF || _platformSupportsDoF || checkIfSkipPass())
+ if (!useDoF || !_platformSupportsDoF || checkIfSkipPass())
return;
auto device = GPUDevice::Instance;
auto context = device->GetMainContext();
diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp
index efd147917..679ead4e3 100644
--- a/Source/Engine/Scripting/BinaryModule.cpp
+++ b/Source/Engine/Scripting/BinaryModule.cpp
@@ -1270,7 +1270,11 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
// Invoke the method
MObject* exception = nullptr;
+#if USE_NETCORE // NetCore uses the same path for both virtual and non-virtual calls
+ MObject* resultObject = mMethod->Invoke(mInstance, params, &exception);
+#else
MObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
+#endif
if (exception)
{
MException ex(exception);
diff --git a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp
index 291910b11..c0fda4d6e 100644
--- a/Source/Engine/ShadersCompilation/ShaderCompiler.cpp
+++ b/Source/Engine/ShadersCompilation/ShaderCompiler.cpp
@@ -460,16 +460,15 @@ bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, Shader
auto& element = layout[a];
if (!layoutVisible[a])
continue;
-
- // TODO: serialize whole struct?
-
- output->WriteByte(static_cast(element.Type));
- output->WriteByte(element.Index);
- output->WriteByte(static_cast(element.Format));
- output->WriteByte(element.InputSlot);
- output->WriteUint32(element.AlignedByteOffset);
- output->WriteByte(element.InputSlotClass);
- output->WriteUint32(element.InstanceDataStepRate);
+ GPUShaderProgramVS::InputElement data;
+ data.Type = static_cast(element.Type);
+ data.Index = element.Index;
+ data.Format = static_cast(element.Format);
+ data.InputSlot = element.InputSlot;
+ data.AlignedByteOffset = element.AlignedByteOffset;
+ data.InputSlotClass = element.InputSlotClass;
+ data.InstanceDataStepRate = element.InstanceDataStepRate;
+ output->Write(data);
}
return false;
diff --git a/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj b/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj
index 1dd5d4e01..3b8889487 100644
--- a/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj
+++ b/Source/Platforms/iOS/Binaries/Project/FlaxGame.xcodeproj/project.pbxproj
@@ -222,7 +222,7 @@ ${PBXResourcesGroup}
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = ${HeaderSearchPaths};
+ HEADER_SEARCH_PATHS = "${HeaderSearchPaths}";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -275,7 +275,7 @@ ${PBXResourcesGroup}
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = ${HeaderSearchPaths};
+ HEADER_SEARCH_PATHS = "${HeaderSearchPaths}";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
diff --git a/Source/ThirdParty/volk/volk.Build.cs b/Source/ThirdParty/volk/volk.Build.cs
index 2f4cfa0d6..67f7593d9 100644
--- a/Source/ThirdParty/volk/volk.Build.cs
+++ b/Source/ThirdParty/volk/volk.Build.cs
@@ -1,5 +1,6 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+using System.Collections.Generic;
using System.IO;
using Flax.Build;
using Flax.Build.NativeCpp;
@@ -62,4 +63,12 @@ public class volk : ThirdPartyModule
Log.ErrorOnce("Missing VulkanSDK.", ref _missingSDKError);
}
}
+
+ ///
+ public override void GetFilesToDeploy(List files)
+ {
+ base.GetFilesToDeploy(files);
+
+ files.Add(Path.Combine(FolderPath, "volk.h"));
+ }
}
diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
index 90e96d075..10e4d5846 100644
--- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
+++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs
@@ -3135,14 +3135,17 @@ namespace Flax.Build.Bindings
contents.AppendLine("#pragma once");
contents.AppendLine();
contents.AppendLine($"#define {binaryModuleNameUpper}_NAME \"{binaryModuleName}\"");
- if (version.Build == -1)
+ if (version.Build <= 0)
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor})");
- else
+ else if (version.Revision <= 0)
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor}, {version.Build})");
+ else
+ contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor}, {version.Build}, {version.Revision})");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_TEXT \"{version}\"");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MAJOR {version.Major}");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MINOR {version.Minor}");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_BUILD {version.Build}");
+ contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_REVISION {version.Revision}");
contents.AppendLine($"#define {binaryModuleNameUpper}_COMPANY \"{project.Company}\"");
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
contents.AppendLine();
diff --git a/Source/Tools/Flax.Build/ProjectInfo.cs b/Source/Tools/Flax.Build/ProjectInfo.cs
index 7830f59c1..ec615fc49 100644
--- a/Source/Tools/Flax.Build/ProjectInfo.cs
+++ b/Source/Tools/Flax.Build/ProjectInfo.cs
@@ -14,9 +14,9 @@ namespace Flax.Build
///
/// Writes the JSON representation of the object.
///
- /// The to write to.
+ /// The to write to.
/// The value.
- /// The calling serializer.
+ /// The calling serializer.
public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
@@ -25,73 +25,68 @@ namespace Flax.Build
///
/// Reads the JSON representation of the object.
///
- /// The to read from.
- /// Type of the object.
- /// The existing property value of the JSON that is being converted.
- /// The calling serializer.
+ /// The to read from.
+ /// Type of the object.
+ /// The serializer options.
/// The object value.
public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
- {
return null;
- }
- else
+
+ if (reader.TokenType == JsonTokenType.StartObject)
{
- if (reader.TokenType == JsonTokenType.StartObject)
+ try
{
- try
+ reader.Read();
+ var values = new Dictionary();
+ while (reader.TokenType == JsonTokenType.PropertyName)
{
+ var key = reader.GetString();
reader.Read();
- Dictionary values = new Dictionary();
- while (reader.TokenType == JsonTokenType.PropertyName)
- {
- var key = reader.GetString();
- reader.Read();
- var val = reader.GetInt32();
- reader.Read();
- values.Add(key, val);
- }
+ var val = reader.GetInt32();
+ reader.Read();
+ values.Add(key, val);
+ }
- int major = 0, minor = 0, build = 0;
- values.TryGetValue("Major", out major);
- values.TryGetValue("Minor", out minor);
- values.TryGetValue("Build", out build);
+ values.TryGetValue("Major", out var major);
+ values.TryGetValue("Minor", out var minor);
+ if (!values.TryGetValue("Build", out var build))
+ build = -1;
+ if (!values.TryGetValue("Revision", out var revision))
+ revision = -1;
- Version v = new Version(major, minor, build);
- return v;
- }
- catch (Exception ex)
- {
- throw new Exception(String.Format("Error parsing version string: {0}", reader.GetString()), ex);
- }
+ if (build <= 0)
+ return new Version(major, minor);
+ if (revision <= 0)
+ return new Version(major, minor, build);
+ return new Version(major, minor, build, revision);
}
- else if (reader.TokenType == JsonTokenType.String)
+ catch (Exception ex)
{
- try
- {
- Version v = new Version((string)reader.GetString()!);
- return v;
- }
- catch (Exception ex)
- {
- throw new Exception(String.Format("Error parsing version string: {0}", reader.GetString()), ex);
- }
- }
- else
- {
- throw new Exception(String.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.GetString()));
+ throw new Exception(string.Format("Error parsing version string: {0}", reader.GetString()), ex);
}
}
+
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ try
+ {
+ return new Version((string)reader.GetString()!);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception(string.Format("Error parsing version string: {0}", reader.GetString()), ex);
+ }
+ }
+ throw new Exception(string.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.GetString()));
}
///
/// Determines whether this instance can convert the specified object type.
///
/// Type of the object.
- ///
- /// true if this instance can convert the specified object type; otherwise, false.
- ///
+ /// true if this instance can convert the specified object type; otherwise, false.
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Version);
@@ -318,7 +313,7 @@ namespace Flax.Build
Log.Verbose("Loading project file from \"" + path + "\"...");
var contents = File.ReadAllText(path);
var project = JsonSerializer.Deserialize(contents.AsSpan(),
- new JsonSerializerOptions() { Converters = { new FlaxVersionConverter() }, IncludeFields = true, TypeInfoResolver = ProjectInfoSourceGenerationContext.Default });
+ new JsonSerializerOptions() { Converters = { new FlaxVersionConverter() }, IncludeFields = true, TypeInfoResolver = ProjectInfoSourceGenerationContext.Default });
project.ProjectPath = path;
project.ProjectFolderPath = Path.GetDirectoryName(path);