Merge branch 'master' into SnapToGrid

This commit is contained in:
NoriteSC
2023-10-29 03:33:44 +01:00
48 changed files with 899 additions and 729 deletions

BIN
Content/Editor/Particles/Smoke.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Particles/Sparks.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -33,4 +33,3 @@ public class %class% : Script
// Here you can add code that needs to be called every frame // Here you can add code that needs to be called every frame
} }
} }

View File

@@ -3,7 +3,8 @@
"Version": { "Version": {
"Major": 1, "Major": 1,
"Minor": 7, "Minor": 7,
"Build": 6402 "Revision": 0,
"Build": 6404
}, },
"Company": "Flax", "Company": "Flax",
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.", "Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",

View File

@@ -259,10 +259,7 @@ namespace FlaxEditor.Options
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{ {
if (sourceType == typeof(string)) if (sourceType == typeof(string))
{
return true; return true;
}
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
@@ -270,9 +267,7 @@ namespace FlaxEditor.Options
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{ {
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{
return false; return false;
}
return base.CanConvertTo(context, destinationType); return base.CanConvertTo(context, destinationType);
} }
@@ -284,7 +279,6 @@ namespace FlaxEditor.Options
InputBinding.TryParse(str, out var result); InputBinding.TryParse(str, out var result);
return result; return result;
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
@@ -295,7 +289,6 @@ namespace FlaxEditor.Options
{ {
return ((InputBinding)value).ToString(); return ((InputBinding)value).ToString();
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }
} }

View File

@@ -26,45 +26,108 @@ namespace FlaxEditor.Options
public float MouseWheelSensitivity { get; set; } = 1.0f; public float MouseWheelSensitivity { get; set; } = 1.0f;
/// <summary> /// <summary>
/// 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.
/// </summary> /// </summary>
[DefaultValue(1.0f), Limit(0.01f, 100.0f)] [DefaultValue(64), Limit(1, 128)]
[EditorDisplay("Defaults"), EditorOrder(110), Tooltip("The default movement speed for the viewport camera (must match the dropdown menu values in the viewport).")] [EditorDisplay("Camera"), EditorOrder(110), Tooltip("The total amount of steps the camera needs to go from minimum to maximum speed.")]
public float DefaultMovementSpeed { get; set; } = 1.0f; public int TotalCameraSpeedSteps { get; set; } = 64;
/// <summary>
/// Gets or sets the degree to which the camera will be eased when using camera flight in the editor window.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).
/// </summary>
[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;
/// <summary>
/// Gets or sets the default minimum camera movement speed.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default maximum camera movement speed.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default camera easing mode.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default camera easing mode.")]
public bool UseCameraEasing { get; set; } = true;
/// <summary> /// <summary>
/// Gets or sets the default near clipping plane distance for the viewport camera. /// Gets or sets the default near clipping plane distance for the viewport camera.
/// </summary> /// </summary>
[DefaultValue(10.0f), Limit(0.001f, 1000.0f)] [DefaultValue(10.0f), Limit(0.001f, 1000.0f)]
[EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default near clipping plane distance for the viewport camera.")] [EditorDisplay("Defaults"), EditorOrder(140), Tooltip("The default near clipping plane distance for the viewport camera.")]
public float DefaultNearPlane { get; set; } = 10.0f; public float NearPlane { get; set; } = 10.0f;
/// <summary> /// <summary>
/// Gets or sets the default far clipping plane distance for the viewport camera. /// Gets or sets the default far clipping plane distance for the viewport camera.
/// </summary> /// </summary>
[DefaultValue(40000.0f), Limit(10.0f)] [DefaultValue(40000.0f), Limit(10.0f)]
[EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default far clipping plane distance for the viewport camera.")] [EditorDisplay("Defaults"), EditorOrder(150), Tooltip("The default far clipping plane distance for the viewport camera.")]
public float DefaultFarPlane { get; set; } = 40000.0f; public float FarPlane { get; set; } = 40000.0f;
/// <summary> /// <summary>
/// Gets or sets the default field of view angle (in degrees) for the viewport camera. /// Gets or sets the default field of view angle (in degrees) for the viewport camera.
/// </summary> /// </summary>
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)] [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.")] [EditorDisplay("Defaults"), EditorOrder(160), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
public float DefaultFieldOfView { get; set; } = 60.0f; public float FieldOfView { get; set; } = 60.0f;
/// <summary> /// <summary>
/// Gets or sets if the panning direction is inverted for the viewport camera. /// Gets or sets the default camera orthographic mode.
/// </summary> /// </summary>
[DefaultValue(false)] [DefaultValue(false)]
[EditorDisplay("Defaults"), EditorOrder(150), Tooltip("Invert the panning direction for the viewport camera.")] [EditorDisplay("Defaults"), EditorOrder(170), Tooltip("The default camera orthographic mode.")]
public bool DefaultInvertPanning { get; set; } = false; public bool UseOrthographicProjection { get; set; } = false;
/// <summary> /// <summary>
/// Scales editor viewport grid. /// Gets or sets the default camera orthographic scale (if camera uses orthographic mode).
/// </summary>
[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;
/// <summary>
/// Gets or sets the default panning direction for the viewport camera.
/// </summary>
[DefaultValue(false)]
[EditorDisplay("Defaults"), EditorOrder(190), Tooltip("The default panning direction for the viewport camera.")]
public bool InvertPanning { get; set; } = false;
/// <summary>
/// Gets or sets the default relative panning mode.
/// </summary>
[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;
/// <summary>
/// Gets or sets the default panning speed (ignored if relative panning is speed enabled).
/// </summary>
[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;
/// <summary>
/// Gets or sets the default editor viewport grid scale.
/// </summary> /// </summary>
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)] [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; public float ViewportGridScale { get; set; } = 50.0f;
} }
} }

View File

@@ -154,7 +154,8 @@ bool ProjectInfo::LoadProject(const String& projectPath)
Version = ::Version( Version = ::Version(
JsonTools::GetInt(version, "Major", 0), JsonTools::GetInt(version, "Major", 0),
JsonTools::GetInt(version, "Minor", 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) if (Version.Revision() == 0)

View File

@@ -23,17 +23,11 @@ namespace FlaxEditor
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{ {
if (value == null) if (value == null)
{
writer.WriteNull(); writer.WriteNull();
}
else if (value is Version) else if (value is Version)
{
writer.WriteValue(value.ToString()); writer.WriteValue(value.ToString());
}
else else
{
throw new JsonSerializationException("Expected Version object value"); throw new JsonSerializationException("Expected Version object value");
}
} }
/// <summary> /// <summary>
@@ -47,65 +41,60 @@ namespace FlaxEditor
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{ {
if (reader.TokenType == JsonToken.Null) if (reader.TokenType == JsonToken.Null)
{
return null; return null;
}
else if (reader.TokenType == JsonToken.StartObject)
{ {
if (reader.TokenType == JsonToken.StartObject) try
{ {
try reader.Read();
var values = new Dictionary<string, int>();
while (reader.TokenType == JsonToken.PropertyName)
{ {
var key = reader.Value as string;
reader.Read(); reader.Read();
Dictionary<string, int> values = new Dictionary<string, int>(); var val = (long)reader.Value;
while (reader.TokenType == JsonToken.PropertyName) reader.Read();
{ values.Add(key, (int)val);
var key = reader.Value as string; }
reader.Read();
var val = (long)reader.Value;
reader.Read();
values.Add(key, (int)val);
}
int major = 0, minor = 0, build = 0; values.TryGetValue("Major", out var major);
values.TryGetValue("Major", out major); values.TryGetValue("Minor", out var minor);
values.TryGetValue("Minor", out minor); if (!values.TryGetValue("Build", out var build))
values.TryGetValue("Build", out build); build = -1;
if (!values.TryGetValue("Revision", out var revision))
revision = -1;
Version v = new Version(major, minor, build); if (build <= 0)
return v; return new Version(major, minor);
} if (revision <= 0)
catch (Exception ex) return new Version(major, minor, build);
{ return new Version(major, minor, build, revision);
throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
}
} }
else if (reader.TokenType == JsonToken.String) catch (Exception ex)
{ {
try throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
{
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));
} }
} }
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));
} }
/// <summary> /// <summary>
/// Determines whether this instance can convert the specified object type. /// Determines whether this instance can convert the specified object type.
/// </summary> /// </summary>
/// <param name="objectType">Type of the object.</param> /// <param name="objectType">Type of the object.</param>
/// <returns> /// <returns><c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.</returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType) public override bool CanConvert(Type objectType)
{ {
return objectType == typeof(Version); return objectType == typeof(Version);

View File

@@ -259,7 +259,10 @@ namespace FlaxEditor.Viewport.Cameras
// Pan // Pan
if (input.IsPanning) if (input.IsPanning)
{ {
var panningSpeed = 0.8f; var panningSpeed = (Viewport.RelativePanning)
? Mathf.Abs((position - TargetPoint).Length) * 0.005f
: Viewport.PanningSpeed;
if (Viewport.InvertPanning) if (Viewport.InvertPanning)
{ {
position += up * (mouseDelta.Y * panningSpeed); position += up * (mouseDelta.Y * panningSpeed);

View File

@@ -128,12 +128,26 @@ namespace FlaxEditor.Viewport
public const int FpsCameraFilteringFrames = 3; public const int FpsCameraFilteringFrames = 3;
/// <summary> /// <summary>
/// The speed widget button. /// The camera settings widget.
/// </summary> /// </summary>
protected ViewportWidgetButton _speedWidget; protected ViewportWidgetsContainer _cameraWidget;
/// <summary>
/// The camera settings widget button.
/// </summary>
protected ViewportWidgetButton _cameraButton;
/// <summary>
/// The orthographic mode widget button.
/// </summary>
protected ViewportWidgetButton _orthographicModeButton;
private readonly Editor _editor;
private float _mouseSensitivity; private float _mouseSensitivity;
private float _movementSpeed; private float _movementSpeed;
private float _minMovementSpeed;
private float _maxMovementSpeed;
private float _mouseAccelerationScale; private float _mouseAccelerationScale;
private bool _useMouseFiltering; private bool _useMouseFiltering;
private bool _useMouseAcceleration; private bool _useMouseAcceleration;
@@ -174,11 +188,17 @@ namespace FlaxEditor.Viewport
private float _fieldOfView; private float _fieldOfView;
private float _nearPlane; private float _nearPlane;
private float _farPlane; private float _farPlane;
private float _orthoSize = 1.0f; private float _orthoSize;
private bool _isOrtho = false; private bool _isOrtho;
private float _wheelMovementChangeDeltaSum = 0; private bool _useCameraEasing;
private float _cameraEasingDegree;
private float _panningSpeed;
private bool _relativePanning;
private bool _invertPanning; private bool _invertPanning;
private int _speedStep;
private int _maxSpeedSteps;
/// <summary> /// <summary>
/// Speed of the mouse. /// Speed of the mouse.
/// </summary> /// </summary>
@@ -189,6 +209,25 @@ namespace FlaxEditor.Viewport
/// </summary> /// </summary>
public float MouseWheelZoomSpeedFactor = 1; public float MouseWheelZoomSpeedFactor = 1;
/// <summary>
/// Format of the text for the camera move speed.
/// </summary>
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:#}";
}
}
/// <summary> /// <summary>
/// Gets or sets the camera movement speed. /// Gets or sets the camera movement speed.
/// </summary> /// </summary>
@@ -197,19 +236,40 @@ namespace FlaxEditor.Viewport
get => _movementSpeed; get => _movementSpeed;
set set
{ {
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++) _movementSpeed = value;
{
if (Math.Abs(value - EditorViewportCameraSpeedValues[i]) < 0.001f) if (_cameraButton != null)
{ _cameraButton.Text = string.Format(MovementSpeedTextFormat, _movementSpeed);
_movementSpeed = EditorViewportCameraSpeedValues[i];
if (_speedWidget != null)
_speedWidget.Text = _movementSpeed.ToString();
break;
}
}
} }
} }
/// <summary>
/// Gets or sets the minimum camera movement speed.
/// </summary>
public float MinMovementSpeed
{
get => _minMovementSpeed;
set => _minMovementSpeed = value;
}
/// <summary>
/// Gets or sets the maximum camera movement speed.
/// </summary>
public float MaxMovementSpeed
{
get => _maxMovementSpeed;
set => _maxMovementSpeed = value;
}
/// <summary>
/// Gets or sets the camera easing mode.
/// </summary>
public bool UseCameraEasing
{
get => _useCameraEasing;
set => _useCameraEasing = value;
}
/// <summary> /// <summary>
/// Gets the mouse movement position delta (user press and move). /// Gets the mouse movement position delta (user press and move).
/// </summary> /// </summary>
@@ -396,6 +456,15 @@ namespace FlaxEditor.Viewport
set => _isOrtho = value; set => _isOrtho = value;
} }
/// <summary>
/// Gets or sets if the panning speed should be relative to the camera target.
/// </summary>
public bool RelativePanning
{
get => _relativePanning;
set => _relativePanning = value;
}
/// <summary> /// <summary>
/// Gets or sets if the panning direction is inverted. /// Gets or sets if the panning direction is inverted.
/// </summary> /// </summary>
@@ -405,6 +474,15 @@ namespace FlaxEditor.Viewport
set => _invertPanning = value; set => _invertPanning = value;
} }
/// <summary>
/// Gets or sets the camera panning speed.
/// </summary>
public float PanningSpeed
{
get => _panningSpeed;
set => _panningSpeed = value;
}
/// <summary> /// <summary>
/// The input actions collection to processed during user input. /// The input actions collection to processed during user input.
/// </summary> /// </summary>
@@ -419,6 +497,8 @@ namespace FlaxEditor.Viewport
public EditorViewport(SceneRenderTask task, ViewportCamera camera, bool useWidgets) public EditorViewport(SceneRenderTask task, ViewportCamera camera, bool useWidgets)
: base(task) : base(task)
{ {
_editor = Editor.Instance;
_mouseAccelerationScale = 0.1f; _mouseAccelerationScale = 0.1f;
_useMouseFiltering = false; _useMouseFiltering = false;
_useMouseAcceleration = false; _useMouseAcceleration = false;
@@ -431,43 +511,299 @@ namespace FlaxEditor.Viewport
// Setup options // 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; 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) if (useWidgets)
{ {
var largestText = "Invert Panning"; #region Camera settings widget
var largestText = "Relative Panning";
var textSize = Style.Current.FontMedium.MeasureText(largestText); var textSize = Style.Current.FontMedium.MeasureText(largestText);
var xLocationForExtras = textSize.X + 5; var xLocationForExtras = textSize.X + 5;
// Camera speed widget var cameraSpeedTextWidth = Style.Current.FontMedium.MeasureText("0.00").X;
var camSpeed = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var camSpeedCM = new ContextMenu(); // Camera Settings Widget
var camSpeedButton = new ViewportWidgetButton(_movementSpeed.ToString(), Editor.Instance.Icons.CamSpeed32, camSpeedCM) _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, Tag = this,
TooltipText = "Camera speed scale" TooltipText = "Camera Settings",
Parent = _cameraWidget
}; };
_speedWidget = camSpeedButton; _cameraWidget.Parent = this;
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
{ // Orthographic/Perspective Mode Widget
var v = EditorViewportCameraSpeedValues[i]; _orthographicModeButton = new ViewportWidgetButton(string.Empty, Editor.Instance.Icons.CamSpeed32, null, true)
var button = camSpeedCM.AddButton(v.ToString()); {
button.Tag = v; Checked = !_isOrtho,
} TooltipText = "Toggle Orthographic/Perspective Mode",
camSpeedCM.ButtonClicked += button => MovementSpeed = (float)button.Tag; Parent = _cameraWidget
camSpeedCM.VisibleChanged += WidgetCamSpeedShowHide; };
camSpeedButton.Parent = camSpeed; _orthographicModeButton.Toggled += OnOrthographicModeToggled;
camSpeed.Parent = this;
// 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); var viewMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperLeft);
ViewWidgetButtonMenu = new ContextMenu(); ViewWidgetButtonMenu = new ContextMenu();
var viewModeButton = new ViewportWidgetButton("View", SpriteHandle.Invalid, ViewWidgetButtonMenu) var viewModeButton = new ViewportWidgetButton("View", SpriteHandle.Invalid, ViewWidgetButtonMenu)
@@ -484,8 +820,8 @@ namespace FlaxEditor.Viewport
// Show FPS // Show FPS
{ {
InitFpsCounter(); InitFpsCounter();
_showFpsButon = ViewWidgetShowMenu.AddButton("FPS Counter", () => ShowFpsCounter = !ShowFpsCounter); _showFpsButton = ViewWidgetShowMenu.AddButton("FPS Counter", () => ShowFpsCounter = !ShowFpsCounter);
_showFpsButon.CloseMenuOnClick = false; _showFpsButton.CloseMenuOnClick = false;
} }
} }
@@ -610,104 +946,6 @@ namespace FlaxEditor.Viewport
ViewWidgetButtonMenu.AddSeparator(); 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 // Brightness
{ {
var brightness = ViewWidgetButtonMenu.AddButton("Brightness"); var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
@@ -732,24 +970,7 @@ namespace FlaxEditor.Viewport
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale; ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
} }
// Invert Panning #endregion View mode widget
{
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;
}
} }
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Top").Orientation))); 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; task.Begin += OnRenderBegin;
} }
/// <summary>
/// Sets the viewport options to the default values.
/// </summary>
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());
}
/// <summary> /// <summary>
/// Gets a value indicating whether this viewport is using mouse currently (eg. user moving objects). /// Gets a value indicating whether this viewport is using mouse currently (eg. user moving objects).
/// </summary> /// </summary>
@@ -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);
}
/// <summary> /// <summary>
/// Increases or decreases the camera movement speed. /// Increases or decreases the camera movement speed.
/// </summary> /// </summary>
/// <param name="step">The stepping direction for speed adjustment.</param> /// <param name="step">The stepping direction for speed adjustment.</param>
protected void AdjustCameraMoveSpeed(int step) protected void AdjustCameraMoveSpeed(int step)
{ {
int camValueIndex = -1; _speedStep = Mathf.Clamp(_speedStep + step, 0, _maxSpeedSteps);
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
{
if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
{
camValueIndex = i;
break;
}
}
if (camValueIndex == -1)
return;
if (step > 0) // calculate new linear/eased progress
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)]; var progress = _useCameraEasing
else if (step < 0) ? Mathf.Pow((float)_speedStep / _maxSpeedSteps, _cameraEasingDegree)
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)]; : (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) private void OnEditorOptionsChanged(EditorOptions options)
{ {
_mouseSensitivity = options.Viewport.MouseSensitivity; _mouseSensitivity = options.Viewport.MouseSensitivity;
_maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps;
_cameraEasingDegree = options.Viewport.CameraEasingDegree;
OnCameraMovementProgressChanged();
} }
private void OnRenderBegin(RenderTask task, GPUContext context) private void OnRenderBegin(RenderTask task, GPUContext context)
@@ -863,7 +1239,7 @@ namespace FlaxEditor.Viewport
} }
private FpsCounter _fpsCounter; private FpsCounter _fpsCounter;
private ContextMenuButton _showFpsButon; private ContextMenuButton _showFpsButton;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether show or hide FPS counter. /// Gets or sets a value indicating whether show or hide FPS counter.
@@ -875,7 +1251,7 @@ namespace FlaxEditor.Viewport
{ {
_fpsCounter.Visible = value; _fpsCounter.Visible = value;
_fpsCounter.Enabled = 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
/// <param name="win">The parent window.</param> /// <param name="win">The parent window.</param>
protected virtual void OnControlMouseBegin(Window win) protected virtual void OnControlMouseBegin(Window win)
{ {
_wheelMovementChangeDeltaSum = 0;
// Hide cursor and start tracking mouse movement // Hide cursor and start tracking mouse movement
win.StartTrackingMouse(false); win.StartTrackingMouse(false);
win.Cursor = CursorType.Hidden; win.Cursor = CursorType.Hidden;
@@ -1113,8 +1487,8 @@ namespace FlaxEditor.Viewport
_camera.Update(deltaTime); _camera.Update(deltaTime);
useMovementSpeed = _camera.UseMovementSpeed; useMovementSpeed = _camera.UseMovementSpeed;
if (_speedWidget != null) if (_cameraButton != null)
_speedWidget.Parent.Visible = useMovementSpeed; _cameraButton.Parent.Visible = useMovementSpeed;
} }
// Get parent window // Get parent window
@@ -1217,18 +1591,8 @@ namespace FlaxEditor.Viewport
rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse; rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse;
if (rmbWheel) if (rmbWheel)
{ {
const float step = 4.0f; var step = _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
_wheelMovementChangeDeltaSum += _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity; AdjustCameraMoveSpeed(step > 0.0f ? 1 : -1);
if (_wheelMovementChangeDeltaSum >= step)
{
_wheelMovementChangeDeltaSum -= step;
AdjustCameraMoveSpeed(1);
}
else if (_wheelMovementChangeDeltaSum <= -step)
{
_wheelMovementChangeDeltaSum += step;
AdjustCameraMoveSpeed(-1);
}
} }
} }
@@ -1497,22 +1861,6 @@ namespace FlaxEditor.Viewport
new CameraViewpoint("Bottom", new Float3(-90, 0, 0)) 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 private struct ViewModeOptions
{ {
public readonly string Name; public readonly string Name;
@@ -1568,24 +1916,6 @@ namespace FlaxEditor.Viewport
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"), 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) private void WidgetViewModeShowHideClicked(ContextMenuButton button)
{ {
if (button.Tag is ViewMode v) if (button.Tag is ViewMode v)

View File

@@ -19,6 +19,7 @@ namespace FlaxEditor.Viewport.Widgets
private bool _checked; private bool _checked;
private bool _autoCheck; private bool _autoCheck;
private bool _isMosueDown; private bool _isMosueDown;
private float _forcedTextWidth;
/// <summary> /// <summary>
/// Event fired when user toggles checked state. /// Event fired when user toggles checked state.
@@ -63,14 +64,16 @@ namespace FlaxEditor.Viewport.Widgets
/// <param name="text">The text.</param> /// <param name="text">The text.</param>
/// <param name="icon">The icon.</param> /// <param name="icon">The icon.</param>
/// <param name="contextMenu">The context menu.</param> /// <param name="contextMenu">The context menu.</param>
/// <param name="autoCheck">if set to <c>true</c> will be automatic checked on mouse click.</param> /// <param name="autoCheck">If set to <c>true</c> will be automatic checked on mouse click.</param>
public ViewportWidgetButton(string text, SpriteHandle icon, ContextMenu contextMenu = null, bool autoCheck = false) /// <param name="textWidth">Forces the text to be drawn with the specified width.</param>
: base(0, 0, CalculateButtonWidth(0, icon.IsValid), ViewportWidgetsContainer.WidgetsHeight) 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; _text = text;
Icon = icon; Icon = icon;
_cm = contextMenu; _cm = contextMenu;
_autoCheck = autoCheck; _autoCheck = autoCheck;
_forcedTextWidth = textWidth;
if (_cm != null) if (_cm != null)
_cm.VisibleChanged += CmOnVisibleChanged; _cm.VisibleChanged += CmOnVisibleChanged;
@@ -160,7 +163,7 @@ namespace FlaxEditor.Viewport.Widgets
var style = Style.Current; var style = Style.Current;
if (style != null && style.FontMedium) 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);
} }
} }
} }

View File

@@ -13,9 +13,7 @@ namespace FlaxEngine.TypeConverters
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{ {
if (sourceType == typeof(string)) if (sourceType == typeof(string))
{
return true; return true;
}
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
@@ -23,9 +21,7 @@ namespace FlaxEngine.TypeConverters
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{ {
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{
return false; return false;
}
return base.CanConvertTo(context, destinationType); return base.CanConvertTo(context, destinationType);
} }

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Double2Converter : TypeConverter internal class Double2Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Double2(double.Parse(v[0], culture), double.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Double3Converter : TypeConverter internal class Double3Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Double3(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Double4Converter : TypeConverter internal class Double4Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 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); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Float2Converter : TypeConverter internal class Float2Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Float2(float.Parse(v[0], culture), float.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Float3Converter : TypeConverter internal class Float3Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Float3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,15 +7,13 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Float4Converter : TypeConverter internal class VectorConverter : TypeConverter
{ {
/// <inheritdoc /> /// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{ {
if (sourceType == typeof(string)) if (sourceType == typeof(string))
{
return true; return true;
}
return base.CanConvertFrom(context, sourceType); return base.CanConvertFrom(context, sourceType);
} }
@@ -23,18 +21,32 @@ namespace FlaxEngine.TypeConverters
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{ {
if (destinationType == typeof(string)) if (destinationType == typeof(string))
{
return false; return false;
}
return base.CanConvertTo(context, destinationType); 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
{
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 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); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Int2Converter : TypeConverter internal class Int2Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Int2(int.Parse(v[0], culture), int.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Int3Converter : TypeConverter internal class Int3Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Int3(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Int4Converter : TypeConverter internal class Int4Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 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); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class QuaternionConverter : TypeConverter internal class QuaternionConverter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 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); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Vector2Converter : TypeConverter internal class Vector2Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Vector2(float.Parse(v[0], culture), float.Parse(v[1], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Vector3Converter : TypeConverter internal class Vector3Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 new Vector3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);

View File

@@ -7,34 +7,14 @@ using System.Globalization;
namespace FlaxEngine.TypeConverters namespace FlaxEngine.TypeConverters
{ {
internal class Vector4Converter : TypeConverter internal class Vector4Converter : VectorConverter
{ {
/// <inheritdoc />
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
/// <inheritdoc />
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return false;
}
return base.CanConvertTo(context, destinationType);
}
/// <inheritdoc /> /// <inheritdoc />
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string str) 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 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); return base.ConvertFrom(context, culture, value);

View File

@@ -646,6 +646,12 @@ inline Vector2Base<T> operator/(typename TOtherFloat<T>::Type a, const Vector2Ba
return Vector2Base<T>(a) / b; return Vector2Base<T>(a) / b;
} }
template<typename T>
inline uint32 GetHash(const Vector2Base<T>& key)
{
return (*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y;
}
namespace Math namespace Math
{ {
template<typename T> template<typename T>

View File

@@ -977,6 +977,12 @@ inline Vector3Base<T> operator/(typename TOtherFloat<T>::Type a, const Vector3Ba
return Vector3Base<T>(a) / b; return Vector3Base<T>(a) / b;
} }
template<typename T>
inline uint32 GetHash(const Vector3Base<T>& key)
{
return (((*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y) * 397) ^ *(uint32*)&key.Z;
}
namespace Math namespace Math
{ {
template<typename T> template<typename T>

View File

@@ -552,6 +552,12 @@ inline Vector4Base<T> operator/(typename TOtherFloat<T>::Type a, const Vector4Ba
return Vector4Base<T>(a) / b; return Vector4Base<T>(a) / b;
} }
template<typename T>
inline uint32 GetHash(const Vector4Base<T>& key)
{
return (((((*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y) * 397) ^ *(uint32*)&key.Z) * 397) ^*(uint32*)&key.W;
}
namespace Math namespace Math
{ {
template<typename T> template<typename T>

View File

@@ -7,15 +7,15 @@ Version::Version(int32 major, int32 minor, int32 build, int32 revision)
{ {
_major = Math::Max(major, 0); _major = Math::Max(major, 0);
_minor = Math::Max(minor, 0); _minor = Math::Max(minor, 0);
_build = Math::Max(build, 0); _build = Math::Max(build, -1);
_revision = Math::Max(revision, 0); _revision = Math::Max(revision, -1);
} }
Version::Version(int32 major, int32 minor, int32 build) Version::Version(int32 major, int32 minor, int32 build)
{ {
_major = Math::Max(major, 0); _major = Math::Max(major, 0);
_minor = Math::Max(minor, 0); _minor = Math::Max(minor, 0);
_build = Math::Max(build, 0); _build = Math::Max(build, -1);
_revision = -1; _revision = -1;
} }

View File

@@ -1302,7 +1302,8 @@ namespace FlaxEngine.Interop
#if !USE_AOT #if !USE_AOT
internal bool TryGetDelegate(out Invoker.MarshalAndInvokeDelegate outDeleg, out object outDelegInvoke) 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<Type> methodTypes = new List<Type>(); List<Type> methodTypes = new List<Type>();
if (!method.IsStatic) if (!method.IsStatic)

View File

@@ -313,6 +313,8 @@ bool GPUDevice::Init()
_res->TasksManager.SetExecutor(CreateTasksExecutor()); _res->TasksManager.SetExecutor(CreateTasksExecutor());
LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory)); LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory));
if (!Limits.HasCompute)
LOG(Warning, "Compute Shaders are not supported");
return false; return false;
} }

View File

@@ -87,7 +87,11 @@ bool GPUShader::Create(MemoryReadStream& stream)
GPUShaderProgramInitializer initializer; GPUShaderProgramInitializer initializer;
#if !BUILD_RELEASE #if !BUILD_RELEASE
initializer.Owner = this; initializer.Owner = this;
const StringView name = GetName();
#else
const StringView name;
#endif #endif
const bool hasCompute = GPUDevice::Instance->Limits.HasCompute;
for (int32 i = 0; i < shadersCount; i++) for (int32 i = 0; i < shadersCount; i++)
{ {
const ShaderStage type = static_cast<ShaderStage>(stream.ReadByte()); const ShaderStage type = static_cast<ShaderStage>(stream.ReadByte());
@@ -117,10 +121,15 @@ bool GPUShader::Create(MemoryReadStream& stream)
stream.ReadBytes(&initializer.Bindings, sizeof(ShaderBindings)); stream.ReadBytes(&initializer.Bindings, sizeof(ShaderBindings));
// Create shader program // 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); GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream);
if (shader == nullptr) 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; return true;
} }

View File

@@ -122,6 +122,19 @@ public:
/// </summary> /// </summary>
class GPUShaderProgramVS : public GPUShaderProgram 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: public:
/// <summary> /// <summary>
/// Gets input layout description handle (platform dependent). /// Gets input layout description handle (platform dependent).

View File

@@ -15,32 +15,21 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{ {
case ShaderStage::Vertex: case ShaderStage::Vertex:
{ {
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS]; // Load Input Layout
// Temporary variables
byte Type, Format, Index, InputSlot, InputSlotClass;
uint32 AlignedByteOffset, InstanceDataStepRate;
// Load Input Layout (it may be empty)
byte inputLayoutSize; byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize); stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS); ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
for (int32 a = 0; a < inputLayoutSize; a++) for (int32 a = 0; a < inputLayoutSize; a++)
{ {
// Read description // Read description
// TODO: maybe use struct and load at once? GPUShaderProgramVS::InputElement inputElement;
stream.ReadByte(&Type); stream.Read(inputElement);
stream.ReadByte(&Index);
stream.ReadByte(&Format);
stream.ReadByte(&InputSlot);
stream.ReadUint32(&AlignedByteOffset);
stream.ReadByte(&InputSlotClass);
stream.ReadUint32(&InstanceDataStepRate);
// Get semantic name // Get semantic name
const char* semanticName = nullptr; const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ? // TODO: maybe use enum+mapping ?
switch (Type) switch (inputElement.Type)
{ {
case 1: case 1:
semanticName = "POSITION"; semanticName = "POSITION";
@@ -70,7 +59,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
semanticName = "BLENDWEIGHT"; semanticName = "BLENDWEIGHT";
break; break;
default: default:
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type); LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
break; break;
} }
@@ -78,12 +67,12 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
inputLayoutDesc[a] = inputLayoutDesc[a] =
{ {
semanticName, semanticName,
static_cast<UINT>(Index), static_cast<UINT>(inputElement.Index),
static_cast<DXGI_FORMAT>(Format), static_cast<DXGI_FORMAT>(inputElement.Format),
static_cast<UINT>(InputSlot), static_cast<UINT>(inputElement.InputSlot),
static_cast<UINT>(AlignedByteOffset), static_cast<UINT>(inputElement.AlignedByteOffset),
static_cast<D3D11_INPUT_CLASSIFICATION>(InputSlotClass), static_cast<D3D11_INPUT_CLASSIFICATION>(inputElement.InputSlotClass),
static_cast<UINT>(InstanceDataStepRate) static_cast<UINT>(inputElement.InstanceDataStepRate)
}; };
} }

View File

@@ -20,32 +20,21 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
{ {
case ShaderStage::Vertex: 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) // Load Input Layout (it may be empty)
byte inputLayoutSize; byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize); stream.ReadByte(&inputLayoutSize);
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS); ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
for (int32 a = 0; a < inputLayoutSize; a++) for (int32 a = 0; a < inputLayoutSize; a++)
{ {
// Read description // Read description
// TODO: maybe use struct and load at once? GPUShaderProgramVS::InputElement inputElement;
stream.ReadByte(&Type); stream.Read(inputElement);
stream.ReadByte(&Index);
stream.ReadByte(&Format);
stream.ReadByte(&InputSlot);
stream.ReadUint32(&AlignedByteOffset);
stream.ReadByte(&InputSlotClass);
stream.ReadUint32(&InstanceDataStepRate);
// Get semantic name // Get semantic name
const char* semanticName = nullptr; const char* semanticName = nullptr;
// TODO: maybe use enum+mapping ? // TODO: maybe use enum+mapping ?
switch (Type) switch (inputElement.Type)
{ {
case 1: case 1:
semanticName = "POSITION"; semanticName = "POSITION";
@@ -75,7 +64,7 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
semanticName = "BLENDWEIGHT"; semanticName = "BLENDWEIGHT";
break; break;
default: default:
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type); LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
break; break;
} }
@@ -83,12 +72,12 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
inputLayout[a] = inputLayout[a] =
{ {
semanticName, semanticName,
static_cast<UINT>(Index), static_cast<UINT>(inputElement.Index),
static_cast<DXGI_FORMAT>(Format), static_cast<DXGI_FORMAT>(inputElement.Format),
static_cast<UINT>(InputSlot), static_cast<UINT>(inputElement.InputSlot),
static_cast<UINT>(AlignedByteOffset), static_cast<UINT>(inputElement.AlignedByteOffset),
static_cast<D3D12_INPUT_CLASSIFICATION>(InputSlotClass), static_cast<D3D12_INPUT_CLASSIFICATION>(inputElement.InputSlotClass),
static_cast<UINT>(InstanceDataStepRate) static_cast<UINT>(inputElement.InstanceDataStepRate)
}; };
} }

View File

@@ -14,9 +14,9 @@
#include "Engine/Graphics/PixelFormatExtensions.h" #include "Engine/Graphics/PixelFormatExtensions.h"
#if PLATFORM_DESKTOP #if PLATFORM_DESKTOP
#define VULKAN_UNIFORM_RING_BUFFER_SIZE 24 * 1024 * 1024 #define VULKAN_UNIFORM_RING_BUFFER_SIZE (24 * 1024 * 1024)
#else #else
#define VULKAN_UNIFORM_RING_BUFFER_SIZE 8 * 1024 * 1024 #define VULKAN_UNIFORM_RING_BUFFER_SIZE (8 * 1024 * 1024)
#endif #endif
UniformBufferUploaderVulkan::UniformBufferUploaderVulkan(GPUDeviceVulkan* device) UniformBufferUploaderVulkan::UniformBufferUploaderVulkan(GPUDeviceVulkan* device)
@@ -153,10 +153,6 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
vertexBindingDescriptions[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 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) // Load Input Layout (it may be empty)
byte inputLayoutSize; byte inputLayoutSize;
stream.ReadByte(&inputLayoutSize); stream.ReadByte(&inputLayoutSize);
@@ -167,32 +163,26 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
for (int32 a = 0; a < inputLayoutSize; a++) for (int32 a = 0; a < inputLayoutSize; a++)
{ {
// Read description // Read description
// TODO: maybe use struct and load at once? GPUShaderProgramVS::InputElement inputElement;
stream.ReadByte(&Type); stream.Read(inputElement);
stream.ReadByte(&Index);
stream.ReadByte(&Format);
stream.ReadByte(&InputSlot);
stream.ReadUint32(&AlignedByteOffset);
stream.ReadByte(&InputSlotClass);
stream.ReadUint32(&InstanceDataStepRate);
const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)Format); const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)inputElement.Format);
if (AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN) if (inputElement.AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN)
offset = AlignedByteOffset; offset = inputElement.AlignedByteOffset;
auto& vertexBindingDescription = vertexBindingDescriptions[InputSlot]; auto& vertexBindingDescription = vertexBindingDescriptions[inputElement.InputSlot];
vertexBindingDescription.binding = InputSlot; vertexBindingDescription.binding = inputElement.InputSlot;
vertexBindingDescription.stride = Math::Max(vertexBindingDescription.stride, (uint32_t)(offset + size)); 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; vertexBindingDescription.inputRate = inputElement.InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
ASSERT(InstanceDataStepRate == 0 || InstanceDataStepRate == 1); ASSERT(inputElement.InstanceDataStepRate == 0 || inputElement.InstanceDataStepRate == 1);
auto& vertexAttributeDescription = vertexAttributeDescriptions[a]; auto& vertexAttributeDescription = vertexAttributeDescriptions[a];
vertexAttributeDescription.location = a; vertexAttributeDescription.location = a;
vertexAttributeDescription.binding = InputSlot; vertexAttributeDescription.binding = inputElement.InputSlot;
vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)Format); vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)inputElement.Format);
vertexAttributeDescription.offset = offset; vertexAttributeDescription.offset = offset;
bindingsCount = Math::Max(bindingsCount, (uint32)InputSlot + 1); bindingsCount = Math::Max(bindingsCount, (uint32)inputElement.InputSlot + 1);
offset += size; offset += size;
} }

View File

@@ -39,7 +39,7 @@ PrefabManagerService PrefabManagerServiceInstance;
Actor* PrefabManager::SpawnPrefab(Prefab* prefab) Actor* PrefabManager::SpawnPrefab(Prefab* prefab)
{ {
Actor* parent = Level::Scenes.Count() != 0 ? Level::Scenes.Get()[0] : nullptr; 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) 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) 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<Guid, const void*>* objectsCache, bool withSynchronization) Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid, const void*>* 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<Guid, const void*>* objectsCache, bool withSynchronization) Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Actor* parent, Dictionary<Guid, const void*>* objectsCache, bool withSynchronization)
@@ -191,7 +191,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
parent->Children.Add(root); parent->Children.Add(root);
// Move root to the right location // Move root to the right location
if (transform != Transform::Identity) if (transform.Translation != Vector3::Minimum)
root->SetTransform(transform); root->SetTransform(transform);
// Link actors hierarchy // Link actors hierarchy

View File

@@ -1334,7 +1334,8 @@ void ParticlesSystem::Job(int32 index)
auto emitter = particleSystem->Emitters[track.AsEmitter.Index].Get(); auto emitter = particleSystem->Emitters[track.AsEmitter.Index].Get();
auto& data = instance.Emitters[track.AsEmitter.Index]; auto& data = instance.Emitters[track.AsEmitter.Index];
ASSERT(emitter && emitter->IsLoaded()); 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); PROFILE_CPU_ASSET(emitter);
// Calculate new time position // Calculate new time position

View File

@@ -1,7 +1,6 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#include "PhysicsColliderActor.h" #include "PhysicsColliderActor.h"
#include "Engine/Scripting/Script.h"
#include "RigidBody.h" #include "RigidBody.h"
PhysicsColliderActor::PhysicsColliderActor(const SpawnParams& params) PhysicsColliderActor::PhysicsColliderActor(const SpawnParams& params)

View File

@@ -117,9 +117,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
{ {
// Skip sending events to removed actors // Skip sending events to removed actors
if (pairHeader.flags & (PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1)) if (pairHeader.flags & (PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1))
{
return; return;
}
Collision c; Collision c;
PxContactPairExtraDataIterator j(pairHeader.extraDataStream, pairHeader.extraDataStreamSize); PxContactPairExtraDataIterator j(pairHeader.extraDataStream, pairHeader.extraDataStreamSize);
@@ -193,7 +191,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
RemovedCollisions.Add(c); RemovedCollisions.Add(c);
} }
} }
ASSERT(!j.nextItemSet()); //ASSERT(!j.nextItemSet());
} }
void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count) void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count)

View File

@@ -451,6 +451,7 @@ DialogResult MessageBox::Show(Window* parent, const StringView& text, const Stri
default: default:
break; break;
} }
flags |= MB_TASKMODAL;
// Show dialog // Show dialog
int result = MessageBoxW(parent ? static_cast<HWND>(parent->GetNativePtr()) : nullptr, String(text).GetText(), String(caption).GetText(), flags); int result = MessageBoxW(parent ? static_cast<HWND>(parent->GetNativePtr()) : nullptr, String(text).GetText(), String(caption).GetText(), flags);

View File

@@ -204,7 +204,7 @@ void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame,
{ {
DepthOfFieldSettings& dofSettings = renderContext.List->Settings.DepthOfField; DepthOfFieldSettings& dofSettings = renderContext.List->Settings.DepthOfField;
const bool useDoF = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::DepthOfField) && dofSettings.Enabled; const bool useDoF = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::DepthOfField) && dofSettings.Enabled;
if (!useDoF || _platformSupportsDoF || checkIfSkipPass()) if (!useDoF || !_platformSupportsDoF || checkIfSkipPass())
return; return;
auto device = GPUDevice::Instance; auto device = GPUDevice::Instance;
auto context = device->GetMainContext(); auto context = device->GetMainContext();

View File

@@ -1270,7 +1270,11 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
// Invoke the method // Invoke the method
MObject* exception = nullptr; 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); MObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
#endif
if (exception) if (exception)
{ {
MException ex(exception); MException ex(exception);

View File

@@ -460,16 +460,15 @@ bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, Shader
auto& element = layout[a]; auto& element = layout[a];
if (!layoutVisible[a]) if (!layoutVisible[a])
continue; continue;
GPUShaderProgramVS::InputElement data;
// TODO: serialize whole struct? data.Type = static_cast<byte>(element.Type);
data.Index = element.Index;
output->WriteByte(static_cast<byte>(element.Type)); data.Format = static_cast<byte>(element.Format);
output->WriteByte(element.Index); data.InputSlot = element.InputSlot;
output->WriteByte(static_cast<byte>(element.Format)); data.AlignedByteOffset = element.AlignedByteOffset;
output->WriteByte(element.InputSlot); data.InputSlotClass = element.InputSlotClass;
output->WriteUint32(element.AlignedByteOffset); data.InstanceDataStepRate = element.InstanceDataStepRate;
output->WriteByte(element.InputSlotClass); output->Write(data);
output->WriteUint32(element.InstanceDataStepRate);
} }
return false; return false;

View File

@@ -222,7 +222,7 @@ ${PBXResourcesGroup}
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = ${HeaderSearchPaths}; HEADER_SEARCH_PATHS = "${HeaderSearchPaths}";
IPHONEOS_DEPLOYMENT_TARGET = 14.0; IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
@@ -275,7 +275,7 @@ ${PBXResourcesGroup}
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = ${HeaderSearchPaths}; HEADER_SEARCH_PATHS = "${HeaderSearchPaths}";
IPHONEOS_DEPLOYMENT_TARGET = 14.0; IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;

View File

@@ -1,5 +1,6 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using System.IO; using System.IO;
using Flax.Build; using Flax.Build;
using Flax.Build.NativeCpp; using Flax.Build.NativeCpp;
@@ -62,4 +63,12 @@ public class volk : ThirdPartyModule
Log.ErrorOnce("Missing VulkanSDK.", ref _missingSDKError); Log.ErrorOnce("Missing VulkanSDK.", ref _missingSDKError);
} }
} }
/// <inheritdoc />
public override void GetFilesToDeploy(List<string> files)
{
base.GetFilesToDeploy(files);
files.Add(Path.Combine(FolderPath, "volk.h"));
}
} }

View File

@@ -3135,14 +3135,17 @@ namespace Flax.Build.Bindings
contents.AppendLine("#pragma once"); contents.AppendLine("#pragma once");
contents.AppendLine(); contents.AppendLine();
contents.AppendLine($"#define {binaryModuleNameUpper}_NAME \"{binaryModuleName}\""); contents.AppendLine($"#define {binaryModuleNameUpper}_NAME \"{binaryModuleName}\"");
if (version.Build == -1) if (version.Build <= 0)
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor})"); 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})"); 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_TEXT \"{version}\"");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MAJOR {version.Major}"); contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MAJOR {version.Major}");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MINOR {version.Minor}"); contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MINOR {version.Minor}");
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_BUILD {version.Build}"); 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}_COMPANY \"{project.Company}\"");
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\""); contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
contents.AppendLine(); contents.AppendLine();

View File

@@ -14,9 +14,9 @@ namespace Flax.Build
/// <summary> /// <summary>
/// Writes the JSON representation of the object. /// Writes the JSON representation of the object.
/// </summary> /// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param> /// <param name="writer">The <see cref="Utf8JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param> /// <param name="options">The calling serializer.</param>
public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options) public override void Write(Utf8JsonWriter writer, Version value, JsonSerializerOptions options)
{ {
writer.WriteStringValue(value.ToString()); writer.WriteStringValue(value.ToString());
@@ -25,73 +25,68 @@ namespace Flax.Build
/// <summary> /// <summary>
/// Reads the JSON representation of the object. /// Reads the JSON representation of the object.
/// </summary> /// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param> /// <param name="reader">The <see cref="Utf8JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param> /// <param name="typeToConvert">Type of the object.</param>
/// <param name="existingValue">The existing property value of the JSON that is being converted.</param> /// <param name="options">The serializer options.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns> /// <returns>The object value.</returns>
public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) public override Version? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{ {
if (reader.TokenType == JsonTokenType.Null) if (reader.TokenType == JsonTokenType.Null)
{
return null; return null;
}
else if (reader.TokenType == JsonTokenType.StartObject)
{ {
if (reader.TokenType == JsonTokenType.StartObject) try
{ {
try reader.Read();
var values = new Dictionary<string, int>();
while (reader.TokenType == JsonTokenType.PropertyName)
{ {
var key = reader.GetString();
reader.Read(); reader.Read();
Dictionary<string, int> values = new Dictionary<string, int>(); var val = reader.GetInt32();
while (reader.TokenType == JsonTokenType.PropertyName) reader.Read();
{ values.Add(key, val);
var key = reader.GetString(); }
reader.Read();
var val = reader.GetInt32();
reader.Read();
values.Add(key, val);
}
int major = 0, minor = 0, build = 0; values.TryGetValue("Major", out var major);
values.TryGetValue("Major", out major); values.TryGetValue("Minor", out var minor);
values.TryGetValue("Minor", out minor); if (!values.TryGetValue("Build", out var build))
values.TryGetValue("Build", out build); build = -1;
if (!values.TryGetValue("Revision", out var revision))
revision = -1;
Version v = new Version(major, minor, build); if (build <= 0)
return v; return new Version(major, minor);
} if (revision <= 0)
catch (Exception ex) return new Version(major, minor, build);
{ return new Version(major, minor, build, revision);
throw new Exception(String.Format("Error parsing version string: {0}", reader.GetString()), ex);
}
} }
else if (reader.TokenType == JsonTokenType.String) catch (Exception ex)
{ {
try throw new Exception(string.Format("Error parsing version string: {0}", reader.GetString()), ex);
{
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()));
} }
} }
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()));
} }
/// <summary> /// <summary>
/// Determines whether this instance can convert the specified object type. /// Determines whether this instance can convert the specified object type.
/// </summary> /// </summary>
/// <param name="objectType">Type of the object.</param> /// <param name="objectType">Type of the object.</param>
/// <returns> /// <returns><c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.</returns>
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
/// </returns>
public override bool CanConvert(Type objectType) public override bool CanConvert(Type objectType)
{ {
return objectType == typeof(Version); return objectType == typeof(Version);
@@ -318,7 +313,7 @@ namespace Flax.Build
Log.Verbose("Loading project file from \"" + path + "\"..."); Log.Verbose("Loading project file from \"" + path + "\"...");
var contents = File.ReadAllText(path); var contents = File.ReadAllText(path);
var project = JsonSerializer.Deserialize<ProjectInfo>(contents.AsSpan(), var project = JsonSerializer.Deserialize<ProjectInfo>(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.ProjectPath = path;
project.ProjectFolderPath = Path.GetDirectoryName(path); project.ProjectFolderPath = Path.GetDirectoryName(path);