From e2462c81517b18d1eb8e5dff8b607d085cddd5b6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 2 Oct 2024 17:00:58 +0200 Subject: [PATCH 01/37] Add ability to edit position curve in timeline with a gizmo in a viewport --- Source/Editor/GUI/CurveEditor.Base.cs | 9 + Source/Editor/GUI/CurveEditor.cs | 26 +++ .../GUI/Timeline/EditCurveTrackGizmo.cs | 203 ++++++++++++++++++ .../GUI/Timeline/SceneAnimationTimeline.cs | 73 +++++-- Source/Editor/Gizmo/GizmoBase.cs | 30 ++- 5 files changed, 325 insertions(+), 16 deletions(-) create mode 100644 Source/Editor/GUI/Timeline/EditCurveTrackGizmo.cs diff --git a/Source/Editor/GUI/CurveEditor.Base.cs b/Source/Editor/GUI/CurveEditor.Base.cs index 6a919f0c2..25de316fa 100644 --- a/Source/Editor/GUI/CurveEditor.Base.cs +++ b/Source/Editor/GUI/CurveEditor.Base.cs @@ -241,6 +241,15 @@ namespace FlaxEditor.GUI /// The keyframe value. public abstract void SetKeyframeValue(int index, object value); + /// + /// Sets the existing keyframe value (as boxed object). + /// + /// The keyframe index. + /// The keyframe value. + /// The keyframe 'In' tangent value (boxed). + /// The keyframe 'Out' tangent value (boxed). + public abstract void SetKeyframeValue(int index, object value, object tangentIn, object tangentOut); + /// /// Gets the keyframe point (in keyframes space). /// diff --git a/Source/Editor/GUI/CurveEditor.cs b/Source/Editor/GUI/CurveEditor.cs index bc96cf3bc..3499ef5d3 100644 --- a/Source/Editor/GUI/CurveEditor.cs +++ b/Source/Editor/GUI/CurveEditor.cs @@ -1289,6 +1289,18 @@ namespace FlaxEditor.GUI OnEdited(); } + /// + public override void SetKeyframeValue(int index, object value, object tangentIn, object tangentOut) + { + var k = _keyframes[index]; + k.Value = (T)value; + _keyframes[index] = k; + + UpdateKeyframes(); + UpdateTooltips(); + OnEdited(); + } + /// public override Float2 GetKeyframePoint(int index, int component) { @@ -2011,6 +2023,20 @@ namespace FlaxEditor.GUI OnEdited(); } + /// + public override void SetKeyframeValue(int index, object value, object tangentIn, object tangentOut) + { + var k = _keyframes[index]; + k.Value = (T)value; + k.TangentIn = (T)tangentIn; + k.TangentOut = (T)tangentOut; + _keyframes[index] = k; + + UpdateKeyframes(); + UpdateTooltips(); + OnEdited(); + } + /// public override Float2 GetKeyframePoint(int index, int component) { diff --git a/Source/Editor/GUI/Timeline/EditCurveTrackGizmo.cs b/Source/Editor/GUI/Timeline/EditCurveTrackGizmo.cs new file mode 100644 index 000000000..7cb1e7c5b --- /dev/null +++ b/Source/Editor/GUI/Timeline/EditCurveTrackGizmo.cs @@ -0,0 +1,203 @@ +// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. + +using FlaxEditor.Gizmo; +using FlaxEditor.GUI.Timeline.Tracks; +using FlaxEditor.GUI.Timeline.Undo; +using FlaxEditor.SceneGraph; +using FlaxEngine; + +namespace FlaxEditor.GUI.Timeline +{ + /// + /// Gizmo for editing position curve. Managed by the . + /// + sealed class EditCurveTrackGizmo : TransformGizmoBase + { + public const float KeyframeSize = 10.0f; + public const float TangentSize = 6.0f; + + private readonly SceneAnimationTimeline _timeline; + private CurvePropertyTrack _track; + private int _keyframe = -1; + private int _item = -1; + private byte[] _curveEditingStartData; + + public int Keyframe => _keyframe; + public int Item => _item; + + public EditCurveTrackGizmo(IGizmoOwner owner, SceneAnimationTimeline timeline) + : base(owner) + { + _timeline = timeline; + } + + public void SelectKeyframe(CurvePropertyTrack track, int keyframe, int item) + { + _track = track; + _keyframe = keyframe; + _item = item; + } + + public override BoundingSphere FocusBounds + { + get + { + if (_track == null) + return BoundingSphere.Empty; + var curve = (BezierCurveEditor)_track.Curve; + var keyframes = curve.Keyframes; + var k = keyframes[_keyframe]; + if (_item == 1) + k.Value += k.TangentIn; + else if (_item == 2) + k.Value += k.TangentOut; + return new BoundingSphere(k.Value, KeyframeSize); + } + } + + protected override int SelectionCount => _track != null ? 1 : 0; + + protected override SceneGraphNode GetSelectedObject(int index) + { + return null; + } + + protected override Transform GetSelectedTransform(int index) + { + if (_track == null) + return Transform.Identity; + var curve = (BezierCurveEditor)_track.Curve; + var keyframes = curve.Keyframes; + var k = keyframes[_keyframe]; + if (_item == 1) + k.Value += k.TangentIn; + else if (_item == 2) + k.Value += k.TangentOut; + return new Transform(k.Value); + } + + protected override void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty) + { + bounds = BoundingBox.Empty; + navigationDirty = false; + if (_track == null) + return; + var curve = (BezierCurveEditor)_track.Curve; + var keyframes = curve.Keyframes; + var k = keyframes[_keyframe]; + if (_item == 1) + k.Value += k.TangentIn; + else if (_item == 2) + k.Value += k.TangentOut; + bounds = new BoundingBox(k.Value - KeyframeSize, k.Value + KeyframeSize); + } + + protected override bool IsSelected(SceneGraphNode obj) + { + return false; + } + + protected override void OnStartTransforming() + { + base.OnStartTransforming(); + + // Start undo + _curveEditingStartData = EditTrackAction.CaptureData(_track); + } + + protected override void OnEndTransforming() + { + base.OnEndTransforming(); + + // End undo + var after = EditTrackAction.CaptureData(_track); + if (!Utils.ArraysEqual(_curveEditingStartData, after)) + _track.Timeline.AddBatchedUndoAction(new EditTrackAction(_track.Timeline, _track, _curveEditingStartData, after)); + _curveEditingStartData = null; + } + + protected override void OnApplyTransformation(ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta) + { + base.OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta); + + var curve = (BezierCurveEditor)_track.Curve; + var keyframes = curve.Keyframes; + var k = keyframes[_keyframe]; + if (_item == 0) + k.Value += translationDelta; + else if (_item == 1) + k.TangentIn += translationDelta; + else if (_item == 2) + k.TangentOut += translationDelta; + curve.SetKeyframeValue(_keyframe, k.Value, k.TangentIn, k.TangentOut); + } + + public override void Pick() + { + if (_track == null) + return; + var selectRay = Owner.MouseRay; + var curve = (BezierCurveEditor)_track.Curve; + var keyframes = curve.Keyframes; + for (var i = 0; i < keyframes.Count; i++) + { + var k = keyframes[i]; + + var sphere = new BoundingSphere(k.Value, KeyframeSize); + if (sphere.Intersects(ref selectRay)) + { + SelectKeyframe(_track, i, 0); + return; + } + + if (!k.TangentIn.IsZero) + { + var t = k.Value + k.TangentIn; + var box = BoundingBox.FromSphere(new BoundingSphere(t, TangentSize)); + if (box.Intersects(ref selectRay)) + { + SelectKeyframe(_track, i, 1); + return; + } + } + + if (!k.TangentOut.IsZero) + { + var t = k.Value + k.TangentOut; + var box = BoundingBox.FromSphere(new BoundingSphere(t, TangentSize)); + if (box.Intersects(ref selectRay)) + { + SelectKeyframe(_track, i, 2); + return; + } + } + } + } + + public override void Update(float dt) + { + base.Update(dt); + + // Deactivate when track gets deselected + if (_track != null && !_timeline.SelectedTracks.Contains(_track)) + Owner.Gizmos.Active = Owner.Gizmos.Get(); + } + + public override void OnActivated() + { + base.OnActivated(); + + ActiveMode = Mode.Translate; + } + + public override void OnDeactivated() + { + // Clear selection + _track = null; + _keyframe = -1; + _item = -1; + + base.OnDeactivated(); + } + } +} diff --git a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs index ceac9931b..9f3f49e34 100644 --- a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs +++ b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs @@ -1,11 +1,12 @@ // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. using System; +using FlaxEngine; using FlaxEditor.Content; +using FlaxEditor.Gizmo; using FlaxEditor.GUI.Drag; using FlaxEditor.GUI.Timeline.Tracks; using FlaxEditor.SceneGraph; -using FlaxEngine; namespace FlaxEditor.GUI.Timeline { @@ -25,6 +26,7 @@ namespace FlaxEditor.GUI.Timeline } private SceneAnimationPlayer _player; + private EditCurveTrackGizmo _curveTrackGizmo; private bool _showSelected3dTrack = true; internal Guid _id; @@ -239,6 +241,19 @@ namespace FlaxEditor.GUI.Timeline } } + private void SelectKeyframeGizmo(CurvePropertyTrack track, int keyframe, int item) + { + var mainGizmo = Editor.Instance.MainTransformGizmo; + if (!mainGizmo.IsActive) + return; // Skip when using vertex painting or terrain or foliage tools + if (_curveTrackGizmo == null) + { + _curveTrackGizmo = new EditCurveTrackGizmo(mainGizmo.Owner, this); + } + _curveTrackGizmo.SelectKeyframe(track, keyframe, item); + _curveTrackGizmo.Activate(); + } + /// public override void OnPlay() { @@ -289,8 +304,17 @@ namespace FlaxEditor.GUI.Timeline UpdatePlaybackState(); // Draw all selected 3D position tracks as Bezier curve in editor viewport - if (ShowSelected3dTrack) + if (!VisibleInHierarchy || !EnabledInHierarchy) { + // Disable curve transform gizmo to normal gizmo + if (_curveTrackGizmo != null && _curveTrackGizmo.IsActive) + _curveTrackGizmo.Owner.Gizmos.Get().Activate(); + } + else if (ShowSelected3dTrack) + { + bool select = FlaxEngine.Input.GetMouseButtonDown(MouseButton.Left); + Ray selectRay = Editor.Instance.MainTransformGizmo.Owner.MouseRay; + const float coveredAlpha = 0.1f; foreach (var track in SelectedTracks) { if ( @@ -302,31 +326,44 @@ namespace FlaxEditor.GUI.Timeline { var curve = (BezierCurveEditor)curveTrack.Curve; var keyframes = curve.Keyframes; + var selectedKeyframe = _curveTrackGizmo?.Keyframe ?? -1; + var selectedItem = _curveTrackGizmo?.Item ?? -1; for (var i = 0; i < keyframes.Count; i++) { var k = keyframes[i]; - DebugDraw.DrawSphere(new BoundingSphere(k.Value, 10.0f), Color.Red); - DebugDraw.DrawSphere(new BoundingSphere(k.Value, 9.5f), new Color(1, 0, 0, 0.1f), 0, false); + var selected = selectedKeyframe == i && selectedItem == 0; + var sphere = new BoundingSphere(k.Value, EditCurveTrackGizmo.KeyframeSize); + DebugDraw.DrawSphere(sphere, selected ? Color.Yellow : Color.Red); + sphere.Radius *= 0.95f; + DebugDraw.DrawSphere(sphere, new Color(1, 0, 0, coveredAlpha), 0, false); + if (select && sphere.Intersects(ref selectRay)) + SelectKeyframeGizmo(curveTrack, i, 0); if (!k.TangentIn.IsZero) { + selected = selectedKeyframe == i && selectedItem == 1; var t = k.Value + k.TangentIn; DebugDraw.DrawLine(k.Value, t, Color.Yellow); - DebugDraw.DrawLine(k.Value, t, Color.Yellow.AlphaMultiplied(0.1f), 0, false); - var box = BoundingBox.FromSphere(new BoundingSphere(t, 6.0f)); - DebugDraw.DrawBox(box, Color.AliceBlue); - DebugDraw.DrawBox(box, Color.AliceBlue.AlphaMultiplied(0.1f), 0, false); + DebugDraw.DrawLine(k.Value, t, Color.Yellow.AlphaMultiplied(coveredAlpha), 0, false); + var box = BoundingBox.FromSphere(new BoundingSphere(t, EditCurveTrackGizmo.TangentSize)); + DebugDraw.DrawBox(box, selected ? Color.Yellow : Color.AliceBlue); + DebugDraw.DrawBox(box, Color.AliceBlue.AlphaMultiplied(coveredAlpha), 0, false); + if (select && box.Intersects(ref selectRay)) + SelectKeyframeGizmo(curveTrack, i, 2); } if (!k.TangentOut.IsZero) { + selected = selectedKeyframe == i && selectedItem == 2; var t = k.Value + k.TangentOut; DebugDraw.DrawLine(k.Value, t, Color.Yellow); - DebugDraw.DrawLine(k.Value, t, Color.Yellow.AlphaMultiplied(0.1f), 0, false); - var box = BoundingBox.FromSphere(new BoundingSphere(t, 6.0f)); - DebugDraw.DrawBox(box, Color.AliceBlue); - DebugDraw.DrawBox(box, Color.AliceBlue.AlphaMultiplied(0.1f), 0, false); + DebugDraw.DrawLine(k.Value, t, Color.Yellow.AlphaMultiplied(coveredAlpha), 0, false); + var box = BoundingBox.FromSphere(new BoundingSphere(t, EditCurveTrackGizmo.TangentSize)); + DebugDraw.DrawBox(box, selected ? Color.Yellow : Color.AliceBlue); + DebugDraw.DrawBox(box, Color.AliceBlue.AlphaMultiplied(coveredAlpha), 0, false); + if (select && box.Intersects(ref selectRay)) + SelectKeyframeGizmo(curveTrack, i, 2); } if (i != 0) @@ -341,6 +378,18 @@ namespace FlaxEditor.GUI.Timeline } } + /// + public override void OnDestroy() + { + if (_curveTrackGizmo != null) + { + _curveTrackGizmo.Destroy(); + _curveTrackGizmo = null; + } + + base.OnDestroy(); + } + /// protected override void OnShowViewContextMenu(ContextMenu.ContextMenu menu) { diff --git a/Source/Editor/Gizmo/GizmoBase.cs b/Source/Editor/Gizmo/GizmoBase.cs index af119444d..72990ea1f 100644 --- a/Source/Editor/Gizmo/GizmoBase.cs +++ b/Source/Editor/Gizmo/GizmoBase.cs @@ -12,15 +12,17 @@ namespace FlaxEditor.Gizmo [HideInEditor] public abstract class GizmoBase { + private IGizmoOwner _owner; + /// /// Gets the gizmo owner. /// - public IGizmoOwner Owner { get; } + public IGizmoOwner Owner => _owner; /// /// Gets a value indicating whether this gizmo is active. /// - public bool IsActive => Owner.Gizmos.Active == this; + public bool IsActive => _owner.Gizmos.Active == this; /// /// Gets a value indicating whether this gizmo is using mouse currently (eg. user moving objects). @@ -39,8 +41,8 @@ namespace FlaxEditor.Gizmo protected GizmoBase(IGizmoOwner owner) { // Link - Owner = owner; - Owner.Gizmos.Add(this); + _owner = owner; + _owner.Gizmos.Add(this); } /// @@ -94,5 +96,25 @@ namespace FlaxEditor.Gizmo public virtual void Draw(ref RenderContext renderContext) { } + + /// + /// Activates thi gizmo mode. + /// + public void Activate() + { + _owner.Gizmos.Active = this; + } + + /// + /// Removes the gizmo from the owner. + /// + public void Destroy() + { + if (_owner != null) + { + _owner.Gizmos.Remove(this); + _owner = null; + } + } } } From c3162ca2cb1874e8e8477e44c3422466b6ae52c1 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Wed, 2 Oct 2024 10:55:43 -0500 Subject: [PATCH 02/37] Fix missing EditorDisplay attribute on Distance and Hinge Joints for thier Flags --- Source/Engine/Physics/Joints/DistanceJoint.h | 2 +- Source/Engine/Physics/Joints/HingeJoint.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Physics/Joints/DistanceJoint.h b/Source/Engine/Physics/Joints/DistanceJoint.h index 0f0f59b01..d39b70d25 100644 --- a/Source/Engine/Physics/Joints/DistanceJoint.h +++ b/Source/Engine/Physics/Joints/DistanceJoint.h @@ -52,7 +52,7 @@ public: /// /// Gets the joint mode flags. Controls joint behaviour. /// - API_PROPERTY(Attributes="EditorOrder(100), DefaultValue(DistanceJointFlag.MinDistance | DistanceJointFlag.MaxDistance)") + API_PROPERTY(Attributes="EditorOrder(100), EditorDisplay(\"Joint\"), DefaultValue(DistanceJointFlag.MinDistance | DistanceJointFlag.MaxDistance)") FORCE_INLINE DistanceJointFlag GetFlags() const { return _flags; diff --git a/Source/Engine/Physics/Joints/HingeJoint.h b/Source/Engine/Physics/Joints/HingeJoint.h index 21f5026e4..c0bef43f5 100644 --- a/Source/Engine/Physics/Joints/HingeJoint.h +++ b/Source/Engine/Physics/Joints/HingeJoint.h @@ -80,7 +80,7 @@ public: /// /// Gets the joint mode flags. Controls joint behaviour. /// - API_PROPERTY(Attributes="EditorOrder(100), DefaultValue(HingeJointFlag.Limit | HingeJointFlag.Drive)") + API_PROPERTY(Attributes="EditorOrder(100), EditorDisplay(\"Joint\"), DefaultValue(HingeJointFlag.Limit | HingeJointFlag.Drive)") FORCE_INLINE HingeJointFlag GetFlags() const { return _flags; From c6e121a777b79b31059bf05c0f58153bce1684ae Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 3 Oct 2024 13:39:58 +0200 Subject: [PATCH 03/37] Add 2k res to scene anim renderer --- Source/Editor/Windows/Assets/SceneAnimationWindow.cs | 12 ++++++++++-- Source/Editor/Windows/GameWindow.cs | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs index 9b0875752..20219a079 100644 --- a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs +++ b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs @@ -97,6 +97,9 @@ namespace FlaxEditor.Windows.Assets [EditorDisplay(null, "1920x1080 (Full HD)")] _1920x1080, + [EditorDisplay(null, "2560x1440 (2K)")] + _2560x1440, + [EditorDisplay(null, "3840x2160 (4K)")] _3840x2160, @@ -173,6 +176,7 @@ namespace FlaxEditor.Windows.Assets case ResolutionModes._640x480: return new Int2(640, 480); case ResolutionModes._1280x720: return new Int2(1280, 720); case ResolutionModes._1920x1080: return new Int2(1920, 1080); + case ResolutionModes._2560x1440: return new Int2(2560, 1440); case ResolutionModes._3840x2160: return new Int2(3840, 2160); case ResolutionModes._7680x4320: return new Int2(7680, 4320); case ResolutionModes.Custom: return new Int2(Width, Height); @@ -456,8 +460,12 @@ namespace FlaxEditor.Windows.Assets _window.Editor.StateMachine.CurrentState.UpdateFPS(); for (int i = 0; i < _stagingTextures.Length; i++) { - _stagingTextures[i].Texture.ReleaseGPU(); - Object.Destroy(ref _stagingTextures[i].Texture); + var texture = _stagingTextures[i].Texture; + if (texture) + { + texture.ReleaseGPU(); + Object.Destroy(ref texture); + } } if (_progress != null) { diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index 34a97286c..56e4c4380 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -553,14 +553,14 @@ namespace FlaxEditor.Windows }); _defaultViewportScaling.Add(new ViewportScaleOptions { - Label = "1920x1080 Resolution", + Label = "1920x1080 Resolution (Full HD)", ScaleType = ViewportScaleType.Resolution, Size = new Int2(1920, 1080), Active = false, }); _defaultViewportScaling.Add(new ViewportScaleOptions { - Label = "2560x1440 Resolution", + Label = "2560x1440 Resolution (2K)", ScaleType = ViewportScaleType.Resolution, Size = new Int2(2560, 1440), Active = false, From 497cd19fe537fc1cd0351817b508c9d72d8cb728 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 3 Oct 2024 17:10:01 +0200 Subject: [PATCH 04/37] Fix managed interop bug --- Source/Engine/Engine/NativeInterop.Unmanaged.cs | 16 +++++++++------- Source/Engine/Scripting/Runtime/DotNet.cpp | 14 +++++++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 62fd95117..852dcb52c 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -319,14 +319,15 @@ namespace FlaxEngine.Interop var arr = (NativeMethodDefinitions*)NativeAlloc(methods.Count, Unsafe.SizeOf()); for (int i = 0; i < methods.Count; i++) { + var method = methods[i]; IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); var classMethod = new NativeMethodDefinitions { - name = NativeAllocStringAnsi(methods[i].Name), - numParameters = methods[i].GetParameters().Length, - methodAttributes = (uint)methods[i].Attributes, + name = NativeAllocStringAnsi(method.Name), + numParameters = method.GetParameters().Length, + methodAttributes = (uint)method.Attributes, }; - classMethod.typeHandle = GetMethodGCHandle(methods[i]); + classMethod.typeHandle = GetMethodGCHandle(method); Unsafe.Write(ptr.ToPointer(), classMethod); } *classMethods = arr; @@ -377,14 +378,15 @@ namespace FlaxEngine.Interop var arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf()); for (int i = 0; i < properties.Length; i++) { + var property = properties[i]; IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); - var getterMethod = properties[i].GetGetMethod(true); - var setterMethod = properties[i].GetSetMethod(true); + var getterMethod = property.GetGetMethod(true); + var setterMethod = property.GetSetMethod(true); var classProperty = new NativePropertyDefinitions { - name = NativeAllocStringAnsi(properties[i].Name), + name = NativeAllocStringAnsi(property.Name), }; if (getterMethod != null) { diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 26b011855..c2155a148 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -1000,11 +1000,12 @@ const Array& MClass::GetMethods() const int methodsCount; static void* GetClassMethodsPtr = GetStaticMethodPointer(TEXT("GetClassMethods")); CallStaticMethod(GetClassMethodsPtr, _handle, &methods, &methodsCount); + _methods.Resize(methodsCount); for (int32 i = 0; i < methodsCount; i++) { NativeMethodDefinitions& definition = methods[i]; MMethod* method = New(const_cast(this), StringAnsi(definition.name), definition.handle, definition.numParameters, definition.methodAttributes); - _methods.Add(method); + _methods[i] = method; MCore::GC::FreeMemory((void*)definition.name); } MCore::GC::FreeMemory(methods); @@ -1036,11 +1037,12 @@ const Array& MClass::GetFields() const int numFields; static void* GetClassFieldsPtr = GetStaticMethodPointer(TEXT("GetClassFields")); CallStaticMethod(GetClassFieldsPtr, _handle, &fields, &numFields); + _fields.Resize(numFields); for (int32 i = 0; i < numFields; i++) { NativeFieldDefinitions& definition = fields[i]; MField* field = New(const_cast(this), definition.fieldHandle, definition.name, definition.fieldType, definition.fieldOffset, definition.fieldAttributes); - _fields.Add(field); + _fields[i] = field; MCore::GC::FreeMemory((void*)definition.name); } MCore::GC::FreeMemory(fields); @@ -1083,11 +1085,12 @@ const Array& MClass::GetProperties() const int numProperties; static void* GetClassPropertiesPtr = GetStaticMethodPointer(TEXT("GetClassProperties")); CallStaticMethod(GetClassPropertiesPtr, _handle, &foundProperties, &numProperties); + _properties.Resize(numProperties); for (int i = 0; i < numProperties; i++) { const NativePropertyDefinitions& definition = foundProperties[i]; MProperty* property = New(const_cast(this), definition.name, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes); - _properties.Add(property); + _properties[i] = property; MCore::GC::FreeMemory((void*)definition.name); } MCore::GC::FreeMemory(foundProperties); @@ -1108,10 +1111,11 @@ const Array& MClass::GetInterfaces() const int numInterfaces; static void* GetClassInterfacesPtr = GetStaticMethodPointer(TEXT("GetClassInterfaces")); CallStaticMethod(GetClassInterfacesPtr, _handle, &foundInterfaceTypes, &numInterfaces); + _interfaces.Resize(numInterfaces); for (int32 i = 0; i < numInterfaces; i++) { MClass* interfaceClass = GetOrCreateClass(foundInterfaceTypes[i]); - _interfaces.Add(interfaceClass); + _interfaces[i] = interfaceClass; } MCore::GC::FreeMemory(foundInterfaceTypes); @@ -1504,7 +1508,7 @@ MProperty::MProperty(MClass* parentClass, const char* name, void* getterHandle, { _hasGetMethod = getterHandle != nullptr; if (_hasGetMethod) - _getMethod = New(parentClass, StringAnsi("get_" + _name), getterHandle, 1, getterAttributes); + _getMethod = New(parentClass, StringAnsi("get_" + _name), getterHandle, 0, getterAttributes); else _getMethod = nullptr; _hasSetMethod = setterHandle != nullptr; From 1414eb98521e781197681aae5f65034ad8f8c942 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 3 Oct 2024 17:10:34 +0200 Subject: [PATCH 05/37] Add Variant enum parsing by name and fix enum printing to string --- Source/Engine/Core/Types/Variant.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 3aea34368..221f6f660 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -2740,12 +2740,12 @@ String Variant::ToString() const const auto items = typeHandle.GetType().Enum.Items; for (int32 i = 0; items[i].Name; i++) { - if (items[i].Value == AsUint) + if (items[i].Value == AsUint64) return String(items[i].Name); } } } - return StringUtils::ToString(AsUint); + return StringUtils::ToString(AsUint64); case VariantType::Int64: return StringUtils::ToString(AsInt64); case VariantType::Uint64: @@ -3098,7 +3098,27 @@ Variant Variant::Parse(const StringView& text, const VariantType& type) break; case VariantType::Uint64: case VariantType::Enum: - StringUtils::Parse(text.Get(), &result.AsUint64); + if (!StringUtils::Parse(text.Get(), &result.AsUint64)) + { + } + else if (type.TypeName) + { + const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(StringAnsiView(type.TypeName)); + if (typeHandle && typeHandle.GetType().Type == ScriptingTypes::Enum) + { + const auto items = typeHandle.GetType().Enum.Items; + StringAsANSI<32> textAnsi(text.Get(), text.Length()); + StringAnsiView textAnsiView(textAnsi.Get()); + for (int32 i = 0; items[i].Name; i++) + { + if (textAnsiView == items[i].Name) + { + result.AsUint64 = items[i].Value; + break; + } + } + } + } break; case VariantType::Float: StringUtils::Parse(text.Get(), &result.AsFloat); From c8f57ea82bdc8a8894eb4067b0377aec1cca2825 Mon Sep 17 00:00:00 2001 From: Amir Alizadeh Date: Thu, 3 Oct 2024 21:46:59 +0330 Subject: [PATCH 06/37] Fix RichTextBox selection bug --- .../Engine/UI/GUI/Common/RichTextBoxBase.cs | 73 ++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index df5582cc3..17dc25e16 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -60,6 +60,51 @@ namespace FlaxEngine.GUI return false; } + /// + /// Gets the text block or the nearest text block of the character at the given index. + /// + /// The character index. + /// The result text block descriptor. + /// If true, the when the index is between two text blocks, it will return the next block. + /// True if a text block is found, otherwise false. + public bool GetNearestTextBlock(int index, out TextBlock result, bool snapToNext = false) + { + var textBlocksSpan = CollectionsMarshal.AsSpan(_textBlocks); + int blockCount = _textBlocks.Count; + + for (int i = 0; i < blockCount; i++) + { + ref TextBlock currentBlock = ref textBlocksSpan[i]; + + if (currentBlock.Range.Contains(index)) + { + result = currentBlock; + return true; + } + + if (i < blockCount - 1) + { + ref TextBlock nextBlock = ref textBlocksSpan[i + 1]; + if (index >= currentBlock.Range.EndIndex && index < nextBlock.Range.StartIndex) + { + result = snapToNext ? nextBlock : currentBlock; + return true; + } + } + } + + // Handle case when index is outside all text ranges + if (index >= 0 && blockCount > 0) + { + result = (index <= textBlocksSpan[0].Range.StartIndex) ? textBlocksSpan[0] : textBlocksSpan[blockCount - 1]; + return true; + } + + // If no text block is found + result = new TextBlock(); + return false; + } + /// /// Updates the text blocks. /// @@ -221,6 +266,30 @@ namespace FlaxEngine.GUI return base.OnMouseDoubleClick(location, button); } + /// + protected override void SetSelection(int start, int end, bool withScroll = true) + { + int snappedStart = start; + int snappedEnd = end; + + if (start != -1 && end != -1) + { + bool movingBack = (_selectionStart != -1 && _selectionEnd != -1) && (end < _selectionEnd || start < _selectionStart); + + GetNearestTextBlock(start, out TextBlock startTextBlock, !movingBack); + GetNearestTextBlock(end, out TextBlock endTextBlock, !movingBack); + + snappedStart = startTextBlock.Range.Contains(start) ? start : (movingBack ? startTextBlock.Range.EndIndex - 1 : startTextBlock.Range.StartIndex); + + snappedEnd = endTextBlock.Range.Contains(end) ? end : (movingBack ? endTextBlock.Range.EndIndex - 1 : endTextBlock.Range.StartIndex); + + snappedStart = movingBack ? Math.Min(start, snappedStart) : Math.Max(start, snappedStart); + snappedEnd = movingBack ? Math.Min(end, snappedEnd) : Math.Max(end, snappedEnd); + } + + base.SetSelection(snappedStart, snappedEnd, withScroll); + } + /// public override void DrawSelf() { @@ -289,8 +358,8 @@ namespace FlaxEngine.GUI // Selection if (hasSelection && textBlock.Style.BackgroundSelectedBrush != null && textBlock.Range.Intersect(ref selection)) { - var leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : font.GetCharPosition(_text, selection.StartIndex); - var rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : font.GetCharPosition(_text, selection.EndIndex); + var leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : GetCharPosition(selection.StartIndex, out _); + var rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : GetCharPosition(selection.EndIndex, out _); float height = font.Height; float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); alpha *= alpha; From e860f969be581f2dabb019863139a9aecd37cd2c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Oct 2024 15:57:41 +0200 Subject: [PATCH 07/37] Add attributes support for dotnet interop for methods, fields and properties --- .../Engine/Engine/NativeInterop.Unmanaged.cs | 54 ++++++++- Source/Engine/Engine/NativeInterop.cs | 2 + .../Engine/Scripting/ManagedCLR/MProperty.h | 4 +- Source/Engine/Scripting/Runtime/DotNet.cpp | 104 +++++++++--------- 4 files changed, 107 insertions(+), 57 deletions(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 852dcb52c..e3d66a2ef 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -49,6 +49,7 @@ namespace FlaxEngine.Interop internal struct NativePropertyDefinitions { internal IntPtr name; + internal ManagedHandle propertyHandle; internal ManagedHandle getterHandle; internal ManagedHandle setterHandle; internal uint getterAttributes; @@ -379,6 +380,17 @@ namespace FlaxEngine.Interop for (int i = 0; i < properties.Length; i++) { var property = properties[i]; + + ManagedHandle propertyHandle = ManagedHandle.Alloc(property); +#if FLAX_EDITOR + if (type.IsCollectible) + propertyHandleCacheCollectible.Add(propertyHandle); + else +#endif + { + propertyHandleCache.Add(propertyHandle); + } + IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf() * i); var getterMethod = property.GetGetMethod(true); @@ -387,6 +399,7 @@ namespace FlaxEngine.Interop var classProperty = new NativePropertyDefinitions { name = NativeAllocStringAnsi(property.Name), + propertyHandle = propertyHandle, }; if (getterMethod != null) { @@ -404,12 +417,8 @@ namespace FlaxEngine.Interop *classPropertiesCount = properties.Length; } - [UnmanagedCallersOnly] - internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount) + internal static void GetAttributes(object[] attributeValues, ManagedHandle** classAttributes, int* classAttributesCount) { - Type type = Unsafe.As(typeHandle.Target); - object[] attributeValues = type.GetCustomAttributes(false); - ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf()); for (int i = 0; i < attributeValues.Length; i++) { @@ -424,6 +433,38 @@ namespace FlaxEngine.Interop *classAttributesCount = attributeValues.Length; } + [UnmanagedCallersOnly] + internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount) + { + Type type = Unsafe.As(typeHandle.Target); + object[] attributeValues = type.GetCustomAttributes(false); + GetAttributes(attributeValues, classAttributes, classAttributesCount); + } + + [UnmanagedCallersOnly] + internal static void GetMethodAttributes(ManagedHandle methodHandle, ManagedHandle** classAttributes, int* classAttributesCount) + { + MethodHolder methodHolder = Unsafe.As(methodHandle.Target); + object[] attributeValues = methodHolder.method.GetCustomAttributes(false); + GetAttributes(attributeValues, classAttributes, classAttributesCount); + } + + [UnmanagedCallersOnly] + internal static void GetFieldAttributes(ManagedHandle fieldHandle, ManagedHandle** classAttributes, int* classAttributesCount) + { + FieldHolder field = Unsafe.As(fieldHandle.Target); + object[] attributeValues = field.field.GetCustomAttributes(false); + GetAttributes(attributeValues, classAttributes, classAttributesCount); + } + + [UnmanagedCallersOnly] + internal static void GetPropertyAttributes(ManagedHandle propertyHandle, ManagedHandle** classAttributes, int* classAttributesCount) + { + PropertyInfo property = Unsafe.As(propertyHandle.Target); + object[] attributeValues = property.GetCustomAttributes(false); + GetAttributes(attributeValues, classAttributes, classAttributesCount); + } + [UnmanagedCallersOnly] internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle) { @@ -1027,6 +1068,9 @@ namespace FlaxEngine.Interop foreach (var handle in fieldHandleCacheCollectible) handle.Free(); fieldHandleCacheCollectible.Clear(); + foreach (var handle in propertyHandleCacheCollectible) + handle.Free(); + propertyHandleCacheCollectible.Clear(); _typeSizeCache.Clear(); diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 8317383cd..3591df299 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -38,11 +38,13 @@ namespace FlaxEngine.Interop private static ConcurrentDictionary cachedDelegates = new(); private static Dictionary managedTypes = new(new TypeComparer()); private static List fieldHandleCache = new(); + private static List propertyHandleCache = new(); #if FLAX_EDITOR private static List methodHandlesCollectible = new(); private static ConcurrentDictionary cachedDelegatesCollectible = new(); private static Dictionary managedTypesCollectible = new(new TypeComparer()); private static List fieldHandleCacheCollectible = new(); + private static List propertyHandleCacheCollectible = new(); #endif private static Dictionary classAttributesCacheCollectible = new(); private static Dictionary assemblyHandles = new(); diff --git a/Source/Engine/Scripting/ManagedCLR/MProperty.h b/Source/Engine/Scripting/ManagedCLR/MProperty.h index a9ce918f8..dbbed8ab3 100644 --- a/Source/Engine/Scripting/ManagedCLR/MProperty.h +++ b/Source/Engine/Scripting/ManagedCLR/MProperty.h @@ -16,6 +16,8 @@ class FLAXENGINE_API MProperty protected: #if USE_MONO MonoProperty* _monoProperty; +#elif USE_NETCORE + void* _handle; #endif mutable MMethod* _getMethod; @@ -34,7 +36,7 @@ public: #if USE_MONO explicit MProperty(MonoProperty* monoProperty, const char* name, MClass* parentClass); #elif USE_NETCORE - MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes); + MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes); #endif /// diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index c2155a148..4a71e9c2f 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -211,7 +211,25 @@ MClass* GetClass(MType* typeHandle); MClass* GetOrCreateClass(MType* typeHandle); MType* GetObjectType(MObject* obj); -void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass); +void* GetCustomAttribute(const Array& attributes, const MClass* attributeClass) +{ + for (MObject* attr : attributes) + { + MClass* attrClass = MCore::Object::GetClass(attr); + if (attrClass == attributeClass) + return attr; + } + return nullptr; +} + +void GetCustomAttributes(Array& result, void* handle, void* getAttributesFunc) +{ + MObject** attributes; + int numAttributes; + CallStaticMethod(getAttributesFunc, handle, &attributes, &numAttributes); + result.Set(attributes, numAttributes); + MCore::GC::FreeMemory(attributes); +} // Structures used to pass information from runtime, must match with the structures in managed side struct NativeClassDefinitions @@ -244,6 +262,7 @@ struct NativeFieldDefinitions struct NativePropertyDefinitions { const char* name; + void* propertyHandle; void* getterHandle; void* setterHandle; MMethodAttributes getterAttributes; @@ -1089,7 +1108,7 @@ const Array& MClass::GetProperties() const for (int i = 0; i < numProperties; i++) { const NativePropertyDefinitions& definition = foundProperties[i]; - MProperty* property = New(const_cast(this), definition.name, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes); + MProperty* property = New(const_cast(this), definition.name, definition.propertyHandle, definition.getterHandle, definition.setterHandle, definition.getterAttributes, definition.setterAttributes); _properties[i] = property; MCore::GC::FreeMemory((void*)definition.name); } @@ -1125,7 +1144,7 @@ const Array& MClass::GetInterfaces() const bool MClass::HasAttribute(const MClass* klass) const { - return GetCustomAttribute(this, klass) != nullptr; + return GetCustomAttribute(GetAttributes(), klass) != nullptr; } bool MClass::HasAttribute() const @@ -1135,7 +1154,7 @@ bool MClass::HasAttribute() const MObject* MClass::GetAttribute(const MClass* klass) const { - return (MObject*)GetCustomAttribute(this, klass); + return (MObject*)GetCustomAttribute(GetAttributes(), klass); } const Array& MClass::GetAttributes() const @@ -1145,14 +1164,8 @@ const Array& MClass::GetAttributes() const ScopeLock lock(BinaryModule::Locker); if (_hasCachedAttributes) return _attributes; - - MObject** attributes; - int numAttributes; static void* GetClassAttributesPtr = GetStaticMethodPointer(TEXT("GetClassAttributes")); - CallStaticMethod(GetClassAttributesPtr, _handle, &attributes, &numAttributes); - _attributes.Set(attributes, numAttributes); - MCore::GC::FreeMemory(attributes); - + GetCustomAttributes(_attributes, _handle, GetClassAttributesPtr); _hasCachedAttributes = true; return _attributes; } @@ -1191,17 +1204,17 @@ MMethod* MEvent::GetRemoveMethod() const bool MEvent::HasAttribute(const MClass* klass) const { - return false; // TODO: implement MEvent in .NET + return GetCustomAttribute(GetAttributes(), klass) != nullptr; } bool MEvent::HasAttribute() const { - return false; // TODO: implement MEvent in .NET + return !GetAttributes().IsEmpty(); } MObject* MEvent::GetAttribute(const MClass* klass) const { - return nullptr; // TODO: implement MEvent in .NET + return (MObject*)GetCustomAttribute(GetAttributes(), klass); } const Array& MEvent::GetAttributes() const @@ -1313,29 +1326,29 @@ void MField::SetValue(MObject* instance, void* value) const bool MField::HasAttribute(const MClass* klass) const { - // TODO: implement MField attributes in .NET - return false; + return GetCustomAttribute(GetAttributes(), klass) != nullptr; } bool MField::HasAttribute() const { - // TODO: implement MField attributes in .NET - return false; + return !GetAttributes().IsEmpty(); } MObject* MField::GetAttribute(const MClass* klass) const { - // TODO: implement MField attributes in .NET - return nullptr; + return (MObject*)GetCustomAttribute(GetAttributes(), klass); } const Array& MField::GetAttributes() const { if (_hasCachedAttributes) return _attributes; + ScopeLock lock(BinaryModule::Locker); + if (_hasCachedAttributes) + return _attributes; + static void* GetFieldAttributesPtr = GetStaticMethodPointer(TEXT("GetFieldAttributes")); + GetCustomAttributes(_attributes, _handle, GetFieldAttributesPtr); _hasCachedAttributes = true; - - // TODO: implement MField attributes in .NET return _attributes; } @@ -1475,35 +1488,36 @@ bool MMethod::GetParameterIsOut(int32 paramIdx) const bool MMethod::HasAttribute(const MClass* klass) const { - // TODO: implement MMethod attributes in .NET - return false; + return GetCustomAttribute(GetAttributes(), klass) != nullptr; } bool MMethod::HasAttribute() const { - // TODO: implement MMethod attributes in .NET - return false; + return !GetAttributes().IsEmpty(); } MObject* MMethod::GetAttribute(const MClass* klass) const { - // TODO: implement MMethod attributes in .NET - return nullptr; + return (MObject*)GetCustomAttribute(GetAttributes(), klass); } const Array& MMethod::GetAttributes() const { if (_hasCachedAttributes) return _attributes; + ScopeLock lock(BinaryModule::Locker); + if (_hasCachedAttributes) + return _attributes; + static void* GetMethodAttributesPtr = GetStaticMethodPointer(TEXT("GetMethodAttributes")); + GetCustomAttributes(_attributes, _handle, GetMethodAttributesPtr); _hasCachedAttributes = true; - - // TODO: implement MMethod attributes in .NET return _attributes; } -MProperty::MProperty(MClass* parentClass, const char* name, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes) +MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes) : _parentClass(parentClass) , _name(name) + , _handle(handle) , _hasCachedAttributes(false) { _hasGetMethod = getterHandle != nullptr; @@ -1552,29 +1566,29 @@ void MProperty::SetValue(MObject* instance, void* value, MObject** exception) co bool MProperty::HasAttribute(const MClass* klass) const { - // TODO: implement MProperty attributes in .NET - return false; + return GetCustomAttribute(GetAttributes(), klass) != nullptr; } bool MProperty::HasAttribute() const { - // TODO: implement MProperty attributes in .NET - return false; + return !GetAttributes().IsEmpty(); } MObject* MProperty::GetAttribute(const MClass* klass) const { - // TODO: implement MProperty attributes in .NET - return nullptr; + return (MObject*)GetCustomAttribute(GetAttributes(), klass); } const Array& MProperty::GetAttributes() const { if (_hasCachedAttributes) return _attributes; + ScopeLock lock(BinaryModule::Locker); + if (_hasCachedAttributes) + return _attributes; + static void* GetPropertyAttributesPtr = GetStaticMethodPointer(TEXT("GetPropertyAttributes")); + GetCustomAttributes(_attributes, _handle, GetPropertyAttributesPtr); _hasCachedAttributes = true; - - // TODO: implement MProperty attributes in .NET return _attributes; } @@ -1637,18 +1651,6 @@ MType* GetObjectType(MObject* obj) return (MType*)typeHandle; } -void* GetCustomAttribute(const MClass* klass, const MClass* attributeClass) -{ - const Array& attributes = klass->GetAttributes(); - for (MObject* attr : attributes) - { - MClass* attrClass = MCore::Object::GetClass(attr); - if (attrClass == attributeClass) - return attr; - } - return nullptr; -} - #if DOTNET_HOST_CORECLR const char_t* NativeInteropTypeName = FLAX_CORECLR_TEXT("FlaxEngine.Interop.NativeInterop, FlaxEngine.CSharp"); From 6fecf1d58ac6478123ed7d1ad733f88cee38fd19 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Oct 2024 15:58:05 +0200 Subject: [PATCH 08/37] Fix crash when setting static dotnet field from unmanaged code --- Source/Engine/Engine/NativeInterop.Unmanaged.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index e3d66a2ef..71caee1e9 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -891,7 +891,7 @@ namespace FlaxEngine.Interop [UnmanagedCallersOnly] internal static void FieldSetValue(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr) { - object fieldOwner = fieldOwnerHandle.Target; + object fieldOwner = fieldOwnerHandle.IsAllocated ? fieldOwnerHandle.Target : null; FieldHolder field = Unsafe.As(fieldHandle.Target); object value = MarshalToManaged(valuePtr, field.field.FieldType); field.field.SetValue(fieldOwner, value); From b9849e2b5ce046c14324959c5bd265429661b083 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Oct 2024 15:58:27 +0200 Subject: [PATCH 09/37] Fix parsing numbers to support sign --- Source/Engine/Core/Types/Variant.cpp | 12 +-- Source/Engine/Platform/StringUtils.h | 130 ++++++++++++++++++--------- 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp index 221f6f660..95e815b81 100644 --- a/Source/Engine/Core/Types/Variant.cpp +++ b/Source/Engine/Core/Types/Variant.cpp @@ -3082,23 +3082,23 @@ Variant Variant::Parse(const StringView& text, const VariantType& type) result.AsBool = true; break; case VariantType::Int16: - StringUtils::Parse(text.Get(), &result.AsInt16); + StringUtils::Parse(text.Get(), text.Length(), &result.AsInt16); break; case VariantType::Uint16: - StringUtils::Parse(text.Get(), &result.AsUint16); + StringUtils::Parse(text.Get(), text.Length(), &result.AsUint16); break; case VariantType::Int: - StringUtils::Parse(text.Get(), &result.AsInt); + StringUtils::Parse(text.Get(), text.Length(), &result.AsInt); break; case VariantType::Uint: - StringUtils::Parse(text.Get(), &result.AsUint); + StringUtils::Parse(text.Get(), text.Length(), &result.AsUint); break; case VariantType::Int64: - StringUtils::Parse(text.Get(), &result.AsInt64); + StringUtils::Parse(text.Get(), text.Length(), &result.AsInt64); break; case VariantType::Uint64: case VariantType::Enum: - if (!StringUtils::Parse(text.Get(), &result.AsUint64)) + if (!StringUtils::Parse(text.Get(), text.Length(), &result.AsUint64)) { } else if (type.TypeName) diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index af82f9f8b..eb567b651 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -195,30 +195,6 @@ public: // Converts hexadecimal character into the value. static int32 HexDigit(Char c); - // Parses text to unsigned integer value. Returns true if failed to convert the value. - template - static bool ParseHex(const CharType* str, uint32* result) - { - uint32 sum = 0; - const CharType* p = str; - if (*p == '0' && *(p + 1) == 'x') - p += 2; - while (*p) - { - int32 c = *p - '0'; - if (c < 0 || c > 9) - { - c = ToLower(*p) - 'a' + 10; - if (c < 10 || c > 15) - return true; - } - sum = 16 * sum + c; - p++; - } - *result = sum; - return false; - } - // Parses text to unsigned integer value. Returns true if failed to convert the value. template static bool ParseHex(const CharType* str, int32 length, uint32* result) @@ -244,28 +220,18 @@ public: return false; } - // Parses text to scalar integer value. Returns true if failed to convert the value. - template - static bool Parse(const T* str, U* result) + // Parses text to unsigned integer value. Returns true if failed to convert the value. + template + static bool ParseHex(const CharType* str, uint32* result) { - U sum = 0; - const T* p = str; - while (*p) - { - int32 c = *p++ - 48; - if (c < 0 || c > 9) - return true; - sum = 10 * sum + c; - } - *result = sum; - return false; + return ParseHex(str, Length(str), result); } - // Parses text to scalar integer value. Returns true if failed to convert the value. - template - static bool Parse(const T* str, uint32 length, U* result) + // Parses text to the unsigned integer value. Returns true if failed to convert the value. + template + static bool Parse(const T* str, int32 length, uint64* result) { - U sum = 0; + int64 sum = 0; const T* p = str; while (length--) { @@ -277,6 +243,86 @@ public: *result = sum; return false; } + template + static bool Parse(const T* str, uint32 length, uint32* result) + { + uint64 tmp; + const bool b = Parse(str, length, &tmp); + *result = (uint32)tmp; + return b; + } + template + static bool Parse(const T* str, uint32 length, uint16* result) + { + uint64 tmp; + const bool b = Parse(str, length, &tmp); + *result = (uint16)tmp; + return b; + } + template + static bool Parse(const T* str, uint32 length, uint8* result) + { + uint64 tmp; + const bool b = Parse(str, length, &tmp); + *result = (uint8)tmp; + return b; + } + + // Parses text to the integer value. Returns true if failed to convert the value. + template + static bool Parse(const T* str, int32 length, int64* result) + { + int64 sum = 0; + const T* p = str; + bool negate = false; + while (length--) + { + int32 c = *p++ - 48; + if (c == -3) + { + negate = true; + continue; + } + if (c < 0 || c > 9) + return true; + sum = 10 * sum + c; + } + if (negate) + sum = -sum; + *result = sum; + return false; + } + template + static bool Parse(const T* str, uint32 length, int32* result) + { + int64 tmp; + const bool b = Parse(str, length, &tmp); + *result = (int32)tmp; + return b; + } + template + static bool Parse(const T* str, uint32 length, int16* result) + { + int64 tmp; + const bool b = Parse(str, length, &tmp); + *result = (int16)tmp; + return b; + } + template + static bool Parse(const T* str, uint32 length, int8* result) + { + int64 tmp; + const bool b = Parse(str, length, &tmp); + *result = (int8)tmp; + return b; + } + + // Parses text to scalar integer value. Returns true if failed to convert the value. + template + static bool Parse(const T* str, U* result) + { + return Parse(str, Length(str), result); + } // Parses text to the scalar value. Returns true if failed to convert the value. static bool Parse(const Char* str, float* result); From 573e99dd2d08af7c07ede3ebb2a3900b56e94438 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Oct 2024 22:16:38 +0200 Subject: [PATCH 10/37] Fix compilation regression --- Source/Engine/Platform/StringUtils.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index eb567b651..7b2b0572a 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -224,7 +224,7 @@ public: template static bool ParseHex(const CharType* str, uint32* result) { - return ParseHex(str, Length(str), result); + return StringUtils::ParseHex(str, StringUtils::Length(str), result); } // Parses text to the unsigned integer value. Returns true if failed to convert the value. @@ -247,7 +247,7 @@ public: static bool Parse(const T* str, uint32 length, uint32* result) { uint64 tmp; - const bool b = Parse(str, length, &tmp); + const bool b = StringUtils::Parse(str, length, &tmp); *result = (uint32)tmp; return b; } @@ -255,7 +255,7 @@ public: static bool Parse(const T* str, uint32 length, uint16* result) { uint64 tmp; - const bool b = Parse(str, length, &tmp); + const bool b = StringUtils::Parse(str, length, &tmp); *result = (uint16)tmp; return b; } @@ -263,7 +263,7 @@ public: static bool Parse(const T* str, uint32 length, uint8* result) { uint64 tmp; - const bool b = Parse(str, length, &tmp); + const bool b = StringUtils::Parse(str, length, &tmp); *result = (uint8)tmp; return b; } @@ -296,7 +296,7 @@ public: static bool Parse(const T* str, uint32 length, int32* result) { int64 tmp; - const bool b = Parse(str, length, &tmp); + const bool b = StringUtils::Parse(str, length, &tmp); *result = (int32)tmp; return b; } @@ -304,7 +304,7 @@ public: static bool Parse(const T* str, uint32 length, int16* result) { int64 tmp; - const bool b = Parse(str, length, &tmp); + const bool b = StringUtils::Parse(str, length, &tmp); *result = (int16)tmp; return b; } @@ -312,7 +312,7 @@ public: static bool Parse(const T* str, uint32 length, int8* result) { int64 tmp; - const bool b = Parse(str, length, &tmp); + const bool b = StringUtils::Parse(str, length, &tmp); *result = (int8)tmp; return b; } @@ -321,7 +321,7 @@ public: template static bool Parse(const T* str, U* result) { - return Parse(str, Length(str), result); + return StringUtils::Parse(str, StringUtils::Length(str), result); } // Parses text to the scalar value. Returns true if failed to convert the value. From 6b10ebdc2c21f42a0d302d4abcecb7dfe83616d3 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 4 Oct 2024 15:29:45 -0500 Subject: [PATCH 11/37] Add options to reconstruct z channel for textures. --- .../TextureTool/TextureTool.DirectXTex.cpp | 37 +++++++++++++++++++ .../Engine/Tools/TextureTool/TextureTool.cpp | 4 ++ Source/Engine/Tools/TextureTool/TextureTool.h | 4 ++ 3 files changed, 45 insertions(+) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index 094daefda..e62d32842 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -829,6 +829,43 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path SET_CURRENT_IMG(timage); } + // Reconstruct Z Channel + if (!keepAsIs & options.ReconstructZChannel) + { + auto& timage = GET_TMP_IMG(); + bool isunorm = (DirectX::FormatDataType(currentImage->GetMetadata().format) == DirectX::FORMAT_TYPE_UNORM) != 0; + result = TransformImage(currentImage->GetImages(), currentImage->GetImageCount(), currentImage->GetMetadata(), + [&](DirectX::XMVECTOR* outPixels, const DirectX::XMVECTOR* inPixels, size_t w, size_t y) + { + static const DirectX::XMVECTORU32 s_selectz = { { { DirectX::XM_SELECT_0, DirectX::XM_SELECT_0, DirectX::XM_SELECT_1, DirectX::XM_SELECT_0 } } }; + + UNREFERENCED_PARAMETER(y); + + for (size_t j = 0; j < w; ++j) + { + const DirectX::XMVECTOR value = inPixels[j]; + DirectX::XMVECTOR z; + if (isunorm) + { + DirectX::XMVECTOR x2 = DirectX::XMVectorMultiplyAdd(value, DirectX::g_XMTwo, DirectX::g_XMNegativeOne); + x2 = DirectX::XMVectorSqrt(DirectX::XMVectorSubtract(DirectX::g_XMOne, DirectX::XMVector2Dot(x2, x2))); + z = DirectX::XMVectorMultiplyAdd(x2, DirectX::g_XMOneHalf, DirectX::g_XMOneHalf); + } + else + { + z = DirectX::XMVectorSqrt(DirectX::XMVectorSubtract(DirectX::g_XMOne, DirectX::XMVector2Dot(value, value))); + } + outPixels[j] = XMVectorSelect(value, z, s_selectz); + } + }, timage); + if (FAILED(result)) + { + errorMsg = String::Format(TEXT("Cannot reconstruct z channel in texture, error: {0:x}"), static_cast(result)); + return true; + } + SET_CURRENT_IMG(timage); + } + // Generate mip maps chain if (!keepAsIs && useMipLevels && options.GenerateMipMaps) { diff --git a/Source/Engine/Tools/TextureTool/TextureTool.cpp b/Source/Engine/Tools/TextureTool/TextureTool.cpp index ff0a66177..48df4cb31 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.cpp @@ -76,6 +76,9 @@ void TextureTool::Options::Serialize(SerializeStream& stream, const void* otherO stream.JKEY("InvertGreenChannel"); stream.Bool(InvertGreenChannel); + stream.JKEY("ReconstructZChannel"); + stream.Bool(ReconstructZChannel); + stream.JKEY("Resize"); stream.Bool(Resize); @@ -134,6 +137,7 @@ void TextureTool::Options::Deserialize(DeserializeStream& stream, ISerializeModi GenerateMipMaps = JsonTools::GetBool(stream, "GenerateMipMaps", GenerateMipMaps); FlipY = JsonTools::GetBool(stream, "FlipY", FlipY); InvertGreenChannel = JsonTools::GetBool(stream, "InvertGreenChannel", InvertGreenChannel); + ReconstructZChannel = JsonTools::GetBool(stream, "ReconstructZChannel", ReconstructZChannel); Resize = JsonTools::GetBool(stream, "Resize", Resize); PreserveAlphaCoverage = JsonTools::GetBool(stream, "PreserveAlphaCoverage", PreserveAlphaCoverage); PreserveAlphaCoverageReference = JsonTools::GetFloat(stream, "PreserveAlphaCoverageReference", PreserveAlphaCoverageReference); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 85d8b2d20..179508c68 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -61,6 +61,10 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool API_FIELD(Attributes = "EditorOrder(71)") bool InvertGreenChannel = false; + // True if to invert the green channel on a normal map. Good for OpenGL to DirectX conversion. + API_FIELD(Attributes = "EditorOrder(72)") + bool ReconstructZChannel = false; + // Texture size scale. Allows increasing or decreasing the imported texture resolution. Default is 1. API_FIELD(Attributes="EditorOrder(80), Limit(0.0001f, 1000.0f, 0.01f)") float Scale = 1.0f; From 8e72b1f326072fb3482270639ad6947583f7522f Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 4 Oct 2024 15:39:02 -0500 Subject: [PATCH 12/37] Fix comment. --- Source/Engine/Tools/TextureTool/TextureTool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 179508c68..3acf41eb9 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -61,7 +61,7 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool API_FIELD(Attributes = "EditorOrder(71)") bool InvertGreenChannel = false; - // True if to invert the green channel on a normal map. Good for OpenGL to DirectX conversion. + // Rebuild Z (blue) channel assuming X/Y are normals. API_FIELD(Attributes = "EditorOrder(72)") bool ReconstructZChannel = false; From 58e1396c15bc0eb3e628f8324e27f2f258fa82dd Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 4 Oct 2024 22:39:10 +0200 Subject: [PATCH 13/37] Fix rich text box snapping to be ignored at text end #2964 --- Source/Engine/UI/GUI/Common/RichTextBoxBase.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index 17dc25e16..4a49f5bad 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -280,11 +280,16 @@ namespace FlaxEngine.GUI GetNearestTextBlock(end, out TextBlock endTextBlock, !movingBack); snappedStart = startTextBlock.Range.Contains(start) ? start : (movingBack ? startTextBlock.Range.EndIndex - 1 : startTextBlock.Range.StartIndex); - snappedEnd = endTextBlock.Range.Contains(end) ? end : (movingBack ? endTextBlock.Range.EndIndex - 1 : endTextBlock.Range.StartIndex); snappedStart = movingBack ? Math.Min(start, snappedStart) : Math.Max(start, snappedStart); snappedEnd = movingBack ? Math.Min(end, snappedEnd) : Math.Max(end, snappedEnd); + + // Don't snap if selection is right in the end of the text + if (start == _text.Length) + snappedStart = _text.Length; + if (end == _text.Length) + snappedEnd = _text.Length; } base.SetSelection(snappedStart, snappedEnd, withScroll); From 2a5de178faa134b40adb36e8d60d2f60192ed8ae Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 4 Oct 2024 19:21:15 -0500 Subject: [PATCH 14/37] Small fix for Reconstructing Z Channel and add keeping aspect ration when resizing. --- .../Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp | 9 +++++---- Source/Engine/Tools/TextureTool/TextureTool.cpp | 4 ++++ Source/Engine/Tools/TextureTool/TextureTool.h | 4 ++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index e62d32842..aa1e5fece 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -661,7 +661,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path if (sourceWidth != width || sourceHeight != height) { // During resizing we need to keep texture aspect ratio - const bool keepAspectRatio = false; // TODO: expose as import option + const bool keepAspectRatio = options.KeepAspectRatio; if (keepAspectRatio) { const float aspectRatio = static_cast(sourceWidth) / sourceHeight; @@ -728,7 +728,8 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path bool keepAsIs = false; if (!options.FlipY && - !options.InvertGreenChannel && + !options.InvertGreenChannel && + !options.ReconstructZChannel && options.Compress && type == ImageType::DDS && mipLevels == sourceMipLevels && @@ -833,7 +834,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path if (!keepAsIs & options.ReconstructZChannel) { auto& timage = GET_TMP_IMG(); - bool isunorm = (DirectX::FormatDataType(currentImage->GetMetadata().format) == DirectX::FORMAT_TYPE_UNORM) != 0; + bool isunorm = (DirectX::FormatDataType(sourceDxgiFormat) == DirectX::FORMAT_TYPE_UNORM) != 0; result = TransformImage(currentImage->GetImages(), currentImage->GetImageCount(), currentImage->GetMetadata(), [&](DirectX::XMVECTOR* outPixels, const DirectX::XMVECTOR* inPixels, size_t w, size_t y) { @@ -855,7 +856,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path { z = DirectX::XMVectorSqrt(DirectX::XMVectorSubtract(DirectX::g_XMOne, DirectX::XMVector2Dot(value, value))); } - outPixels[j] = XMVectorSelect(value, z, s_selectz); + outPixels[j] = DirectX::XMVectorSelect(value, z, s_selectz); } }, timage); if (FAILED(result)) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.cpp b/Source/Engine/Tools/TextureTool/TextureTool.cpp index 48df4cb31..34be2c9fb 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.cpp @@ -82,6 +82,9 @@ void TextureTool::Options::Serialize(SerializeStream& stream, const void* otherO stream.JKEY("Resize"); stream.Bool(Resize); + stream.JKEY("KeepAspectRatio"); + stream.Bool(KeepAspectRatio); + stream.JKEY("PreserveAlphaCoverage"); stream.Bool(PreserveAlphaCoverage); @@ -139,6 +142,7 @@ void TextureTool::Options::Deserialize(DeserializeStream& stream, ISerializeModi InvertGreenChannel = JsonTools::GetBool(stream, "InvertGreenChannel", InvertGreenChannel); ReconstructZChannel = JsonTools::GetBool(stream, "ReconstructZChannel", ReconstructZChannel); Resize = JsonTools::GetBool(stream, "Resize", Resize); + KeepAspectRatio = JsonTools::GetBool(stream, "KeepAspectRatio", KeepAspectRatio); PreserveAlphaCoverage = JsonTools::GetBool(stream, "PreserveAlphaCoverage", PreserveAlphaCoverage); PreserveAlphaCoverageReference = JsonTools::GetFloat(stream, "PreserveAlphaCoverageReference", PreserveAlphaCoverageReference); TextureGroup = JsonTools::GetInt(stream, "TextureGroup", TextureGroup); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 3acf41eb9..494618c60 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -77,6 +77,10 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool API_FIELD(Attributes="EditorOrder(100)") bool Resize = false; + // Keeps the aspect ratio when resizing. + API_FIELD(Attributes="EditorOrder(101), VisibleIf(nameof(Resize))") + bool KeepAspectRatio = false; + // The width of the imported texture. If Resize property is set to true then texture will be resized during the import to this value during the import, otherwise it will be ignored. API_FIELD(Attributes="HideInEditor") int32 SizeX = 1024; From 305d3a64966ea7dba4e83f7d5a9bb1fb91c67389 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 4 Oct 2024 19:31:55 -0500 Subject: [PATCH 15/37] Add FlipX to texture tool. --- .../TextureTool/TextureTool.DirectXTex.cpp | 19 +++++++++++++++++-- .../Engine/Tools/TextureTool/TextureTool.cpp | 4 ++++ Source/Engine/Tools/TextureTool/TextureTool.h | 10 +++++++--- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp index aa1e5fece..dc2b20778 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.DirectXTex.cpp @@ -727,7 +727,8 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path } bool keepAsIs = false; - if (!options.FlipY && + if (!options.FlipY && + !options.FlipX && !options.InvertGreenChannel && !options.ReconstructZChannel && options.Compress && @@ -788,7 +789,7 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path SET_CURRENT_IMG(tmpImg); } - // Check flip/rotate source image + // Check flip/rotate Y source image if (!keepAsIs && options.FlipY) { auto& tmpImg = GET_TMP_IMG(); @@ -802,6 +803,20 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path SET_CURRENT_IMG(tmpImg); } + // Check flip/rotate X source image + if (!keepAsIs && options.FlipX) + { + auto& tmpImg = GET_TMP_IMG(); + DirectX::TEX_FR_FLAGS flags = DirectX::TEX_FR_FLIP_HORIZONTAL; + result = FlipRotate(currentImage->GetImages(), currentImage->GetImageCount(), currentImage->GetMetadata(), flags, tmpImg); + if (FAILED(result)) + { + errorMsg = String::Format(TEXT("Cannot rotate/flip texture, error: {0:x}"), static_cast(result)); + return true; + } + SET_CURRENT_IMG(tmpImg); + } + // Check if invert green channel if (!keepAsIs && options.InvertGreenChannel) { diff --git a/Source/Engine/Tools/TextureTool/TextureTool.cpp b/Source/Engine/Tools/TextureTool/TextureTool.cpp index 34be2c9fb..550e26699 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.cpp @@ -73,6 +73,9 @@ void TextureTool::Options::Serialize(SerializeStream& stream, const void* otherO stream.JKEY("FlipY"); stream.Bool(FlipY); + stream.JKEY("FlipX"); + stream.Bool(FlipX); + stream.JKEY("InvertGreenChannel"); stream.Bool(InvertGreenChannel); @@ -139,6 +142,7 @@ void TextureTool::Options::Deserialize(DeserializeStream& stream, ISerializeModi sRGB = JsonTools::GetBool(stream, "sRGB", sRGB); GenerateMipMaps = JsonTools::GetBool(stream, "GenerateMipMaps", GenerateMipMaps); FlipY = JsonTools::GetBool(stream, "FlipY", FlipY); + FlipX = JsonTools::GetBool(stream, "FlipX", FlipX); InvertGreenChannel = JsonTools::GetBool(stream, "InvertGreenChannel", InvertGreenChannel); ReconstructZChannel = JsonTools::GetBool(stream, "ReconstructZChannel", ReconstructZChannel); Resize = JsonTools::GetBool(stream, "Resize", Resize); diff --git a/Source/Engine/Tools/TextureTool/TextureTool.h b/Source/Engine/Tools/TextureTool/TextureTool.h index 494618c60..13bac0dc5 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.h +++ b/Source/Engine/Tools/TextureTool/TextureTool.h @@ -53,16 +53,20 @@ API_CLASS(Namespace="FlaxEngine.Tools", Static) class FLAXENGINE_API TextureTool API_FIELD(Attributes="EditorOrder(60)") bool GenerateMipMaps = true; - // True if flip Y coordinate of the texture. + // True if flip Y coordinate of the texture (Flips over X axis). API_FIELD(Attributes="EditorOrder(70)") bool FlipY = false; + // True if flip X coordinate of the texture (Flips over Y axis). + API_FIELD(Attributes="EditorOrder(71)") + bool FlipX = false; + // True if to invert the green channel on a normal map. Good for OpenGL to DirectX conversion. - API_FIELD(Attributes = "EditorOrder(71)") + API_FIELD(Attributes = "EditorOrder(72)") bool InvertGreenChannel = false; // Rebuild Z (blue) channel assuming X/Y are normals. - API_FIELD(Attributes = "EditorOrder(72)") + API_FIELD(Attributes = "EditorOrder(73)") bool ReconstructZChannel = false; // Texture size scale. Allows increasing or decreasing the imported texture resolution. Default is 1. From c6fa20abaab20338dc81e6c7e3481acd3442f544 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 5 Oct 2024 23:15:38 +0200 Subject: [PATCH 16/37] Better fix for 573e99dd2d08af7c07ede3ebb2a3900b56e94438 --- Source/Engine/Platform/StringUtils.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index 7b2b0572a..af9267e16 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -196,12 +196,12 @@ public: static int32 HexDigit(Char c); // Parses text to unsigned integer value. Returns true if failed to convert the value. - template - static bool ParseHex(const CharType* str, int32 length, uint32* result) + template + static bool ParseHex(const T* str, int32 length, uint32* result) { uint32 sum = 0; - const CharType* p = str; - const CharType* end = str + length; + const T* p = str; + const T* end = str + length; if (*p == '0' && *(p + 1) == 'x') p += 2; while (*p && p < end) @@ -221,10 +221,10 @@ public: } // Parses text to unsigned integer value. Returns true if failed to convert the value. - template - static bool ParseHex(const CharType* str, uint32* result) + template + static bool ParseHex(const T* str, uint32* result) { - return StringUtils::ParseHex(str, StringUtils::Length(str), result); + return StringUtils::ParseHex(str, StringUtils::Length((const T*)str), result); } // Parses text to the unsigned integer value. Returns true if failed to convert the value. @@ -321,7 +321,7 @@ public: template static bool Parse(const T* str, U* result) { - return StringUtils::Parse(str, StringUtils::Length(str), result); + return StringUtils::Parse((const T*)str, StringUtils::Length((const T*)str), (U*)result); } // Parses text to the scalar value. Returns true if failed to convert the value. From 9b7e5be50e7b0d1c915ad795dbf403b132fcf735 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 5 Oct 2024 23:22:06 +0200 Subject: [PATCH 17/37] Add new features to `stb` too (as unsupported) #2968 --- .../Tools/TextureTool/TextureTool.stb.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index 1301327ef..15058752d 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -458,7 +458,7 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu { if (!options.InternalLoad.IsBinded() || options.InternalLoad(textureData)) return true; - if (options.FlipY) + if (options.FlipY || options.FlipX) { // TODO: impl this errorMsg = TEXT("Flipping images imported from Internal source is not supported by stb."); @@ -489,7 +489,7 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu if (sourceWidth != width || sourceHeight != height) { // During resizing we need to keep texture aspect ratio - const bool keepAspectRatio = false; // TODO: expose as import option + const bool keepAspectRatio = options.KeepAspectRatio; // TODO: expose as import option if (keepAspectRatio) { const float aspectRatio = static_cast(sourceWidth) / sourceHeight; @@ -536,6 +536,22 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu return true; } + if (options.FlipX) + { + // TODO: impl this + LOG(Warning "Option 'Flip X' is not supported"); + } + if (options.InvertGreenChannel) + { + // TODO: impl this + LOG(Warning "Option 'Invert Green Channel' is not supported"); + } + if (options.ReconstructZChannel) + { + // TODO: impl this + LOG(Warning "Option 'Reconstruct Z Channel' is not supported"); + } + // Generate mip maps chain if (useMipLevels && options.GenerateMipMaps) { From 84201b346b9360b6c9e3c9b1a101a0218ff34f7d Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 5 Oct 2024 23:11:38 -0500 Subject: [PATCH 18/37] Add opening file proxy for windows. --- Source/Editor/Content/Proxy/FileProxy.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/Editor/Content/Proxy/FileProxy.cs b/Source/Editor/Content/Proxy/FileProxy.cs index 4e12ab588..d162e5f35 100644 --- a/Source/Editor/Content/Proxy/FileProxy.cs +++ b/Source/Editor/Content/Proxy/FileProxy.cs @@ -32,6 +32,14 @@ namespace FlaxEditor.Content /// public override EditorWindow Open(Editor editor, ContentItem item) { +#if PLATFORM_WINDOWS + CreateProcessSettings settings = new CreateProcessSettings + { + ShellExecute = true, + FileName = item.Path + }; + Platform.CreateProcess(ref settings); +#endif return null; } From 13acf3c14377458ceed0657d21a42e294407765c Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sat, 5 Oct 2024 23:44:26 -0500 Subject: [PATCH 19/37] Quick fix for #2963 --- Source/Editor/GUI/Docking/FloatWindowDockPanel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs b/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs index 302508f5c..a1dc73068 100644 --- a/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs +++ b/Source/Editor/GUI/Docking/FloatWindowDockPanel.cs @@ -139,6 +139,8 @@ namespace FlaxEditor.GUI.Docking /// protected override void OnLastTabRemoved() { + if (ChildPanelsCount > 0) + return; // Close window _window?.Close(); } From 283f26b95cc116e4b79f9c20bc24495a58c6d311 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Sun, 6 Oct 2024 14:54:44 -0500 Subject: [PATCH 20/37] Fix video audio not looping. --- Source/Engine/Video/MF/VideoBackendMF.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Engine/Video/MF/VideoBackendMF.cpp b/Source/Engine/Video/MF/VideoBackendMF.cpp index 727a94158..d396d7672 100644 --- a/Source/Engine/Video/MF/VideoBackendMF.cpp +++ b/Source/Engine/Video/MF/VideoBackendMF.cpp @@ -397,6 +397,7 @@ namespace MF // Loop playerMF.Time.Ticks %= player.Duration.Ticks; playerMF.Seek = 1; + player.PlayAudio(); } else { From 4a4120864d865550329128ba78d3705a38483dd6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 6 Oct 2024 23:23:41 +0200 Subject: [PATCH 21/37] Better fix for c6fa20abaab20338dc81e6c7e3481acd3442f544 --- Source/Engine/Tools/TextureTool/TextureTool.stb.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp index 15058752d..8ca585c32 100644 --- a/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp +++ b/Source/Engine/Tools/TextureTool/TextureTool.stb.cpp @@ -539,17 +539,17 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu if (options.FlipX) { // TODO: impl this - LOG(Warning "Option 'Flip X' is not supported"); + LOG(Warning, "Option 'Flip X' is not supported"); } if (options.InvertGreenChannel) { // TODO: impl this - LOG(Warning "Option 'Invert Green Channel' is not supported"); + LOG(Warning, "Option 'Invert Green Channel' is not supported"); } if (options.ReconstructZChannel) { // TODO: impl this - LOG(Warning "Option 'Reconstruct Z Channel' is not supported"); + LOG(Warning, "Option 'Reconstruct Z Channel' is not supported"); } // Generate mip maps chain From 28bf60e62d2d6e10b9b17f99daf57f53bb20a0a0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 6 Oct 2024 23:54:20 +0200 Subject: [PATCH 22/37] Fix compilation --- Source/Engine/Platform/Base/StringUtilsBase.cpp | 15 +++++++++++++++ Source/Engine/Platform/StringUtils.h | 7 +++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Platform/Base/StringUtilsBase.cpp b/Source/Engine/Platform/Base/StringUtilsBase.cpp index 96d4fa338..5ee094a54 100644 --- a/Source/Engine/Platform/Base/StringUtilsBase.cpp +++ b/Source/Engine/Platform/Base/StringUtilsBase.cpp @@ -15,6 +15,21 @@ constexpr char DirectorySeparatorChar = '\\'; constexpr char AltDirectorySeparatorChar = '/'; constexpr char VolumeSeparatorChar = ':'; +#if PLATFORM_TEXT_IS_CHAR16 + +int32 StringUtils::Length(const wchar_t* str) +{ + int32 result = 0; + if (str) + { + while (*str) + str++; + } + return result; +} + +#endif + const Char* StringUtils::FindIgnoreCase(const Char* str, const Char* toFind) { if (toFind == nullptr || str == nullptr) diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index af9267e16..1bff2c2ae 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -115,6 +115,9 @@ public: public: // Gets the string length. Returns 0 if str is null. static int32 Length(const Char* str); +#if PLATFORM_TEXT_IS_CHAR16 + static int32 Length(const wchar_t* str); +#endif // Gets the string length. Returns 0 if str is null. static int32 Length(const char* str); @@ -224,7 +227,7 @@ public: template static bool ParseHex(const T* str, uint32* result) { - return StringUtils::ParseHex(str, StringUtils::Length((const T*)str), result); + return StringUtils::ParseHex(str, StringUtils::Length(str), result); } // Parses text to the unsigned integer value. Returns true if failed to convert the value. @@ -321,7 +324,7 @@ public: template static bool Parse(const T* str, U* result) { - return StringUtils::Parse((const T*)str, StringUtils::Length((const T*)str), (U*)result); + return StringUtils::Parse(str, StringUtils::Length(str), result); } // Parses text to the scalar value. Returns true if failed to convert the value. From 3434731c2a9996b7b036815f89a8370e8f411629 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 7 Oct 2024 00:40:22 +0200 Subject: [PATCH 23/37] Another blind fix --- Source/Editor/ProjectInfo.cpp | 37 ++++++++++++++++++- .../Engine/Platform/Base/StringUtilsBase.cpp | 15 -------- Source/Engine/Platform/Defines.h | 4 +- Source/Engine/Platform/StringUtils.h | 3 -- 4 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Source/Editor/ProjectInfo.cpp b/Source/Editor/ProjectInfo.cpp index 28fc0301c..7fef490fe 100644 --- a/Source/Editor/ProjectInfo.cpp +++ b/Source/Editor/ProjectInfo.cpp @@ -13,6 +13,37 @@ using namespace pugi; Array ProjectInfo::ProjectsCache; +struct XmlCharAsChar +{ +#if PLATFORM_TEXT_IS_CHAR16 + Char* Str = nullptr; + + XmlCharAsChar(const pugi::char_t* str) + { + if (!str) + return; + int32 length = 0; + while (str[length]) + length++; + Str = (Char*)Platform::Allocate(length * sizeof(Char), sizeof(Char)); + for (int32 i = 0; i <= length; i++) + Str[i] = (Char)str[i]; + } + + ~XmlCharAsChar() + { + Platform::Free(Str); + } +#else + const Char* Str; + + XmlCharAsChar(const pugi::char_t* str) + : Str(str) + { + } +#endif +}; + void ShowProjectLoadError(const Char* errorMsg, const String& projectRootFolder) { Platform::Error(String::Format(TEXT("Failed to load project. {0}\nPath: '{1}'"), errorMsg, projectRootFolder)); @@ -28,8 +59,9 @@ Vector3 GetVector3FromXml(const xml_node& parent, const PUGIXML_CHAR* name, cons const auto z = node.child_value(PUGIXML_TEXT("Z")); if (x && y && z) { + XmlCharAsChar xs(x), ys(y), zs(z); Vector3 v; - if (!StringUtils::Parse(x, &v.X) && !StringUtils::Parse(y, &v.Y) && !StringUtils::Parse(z, &v.Z)) + if (!StringUtils::Parse(xs.Str, &v.X) && !StringUtils::Parse(ys.Str, &v.Y) && !StringUtils::Parse(zs.Str, &v.Z)) { return v; } @@ -44,8 +76,9 @@ int32 GetIntFromXml(const xml_node& parent, const PUGIXML_CHAR* name, const int3 const auto node = parent.child_value(name); if (node) { + XmlCharAsChar s(node); int32 v; - if (!StringUtils::Parse(node, &v)) + if (!StringUtils::Parse(s.Str, &v)) { return v; } diff --git a/Source/Engine/Platform/Base/StringUtilsBase.cpp b/Source/Engine/Platform/Base/StringUtilsBase.cpp index 5ee094a54..96d4fa338 100644 --- a/Source/Engine/Platform/Base/StringUtilsBase.cpp +++ b/Source/Engine/Platform/Base/StringUtilsBase.cpp @@ -15,21 +15,6 @@ constexpr char DirectorySeparatorChar = '\\'; constexpr char AltDirectorySeparatorChar = '/'; constexpr char VolumeSeparatorChar = ':'; -#if PLATFORM_TEXT_IS_CHAR16 - -int32 StringUtils::Length(const wchar_t* str) -{ - int32 result = 0; - if (str) - { - while (*str) - str++; - } - return result; -} - -#endif - const Char* StringUtils::FindIgnoreCase(const Char* str, const Char* toFind) { if (toFind == nullptr || str == nullptr) diff --git a/Source/Engine/Platform/Defines.h b/Source/Engine/Platform/Defines.h index 40b250983..b2f857937 100644 --- a/Source/Engine/Platform/Defines.h +++ b/Source/Engine/Platform/Defines.h @@ -186,8 +186,8 @@ API_ENUM() enum class ArchitectureType #ifndef PLATFORM_ARCH_ARM64 #define PLATFORM_ARCH_ARM64 0 #endif -#ifndef PLATFORM_WCHAR_IS_CHAR16 -#define PLATFORM_WCHAR_IS_CHAR16 0 +#ifndef PLATFORM_TEXT_IS_CHAR16 +#define PLATFORM_TEXT_IS_CHAR16 0 #endif #ifndef PLATFORM_DEBUG_BREAK #define PLATFORM_DEBUG_BREAK diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index 1bff2c2ae..248f0c3d7 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -115,9 +115,6 @@ public: public: // Gets the string length. Returns 0 if str is null. static int32 Length(const Char* str); -#if PLATFORM_TEXT_IS_CHAR16 - static int32 Length(const wchar_t* str); -#endif // Gets the string length. Returns 0 if str is null. static int32 Length(const char* str); From 198dddd2ce53b1c877db3f345fe15a8d01a3863e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 7 Oct 2024 10:01:51 +0200 Subject: [PATCH 24/37] Fix large worlds build --- Source/Editor/ProjectInfo.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Editor/ProjectInfo.cpp b/Source/Editor/ProjectInfo.cpp index 7fef490fe..2fe8e2b1e 100644 --- a/Source/Editor/ProjectInfo.cpp +++ b/Source/Editor/ProjectInfo.cpp @@ -60,14 +60,13 @@ Vector3 GetVector3FromXml(const xml_node& parent, const PUGIXML_CHAR* name, cons if (x && y && z) { XmlCharAsChar xs(x), ys(y), zs(z); - Vector3 v; + Float3 v; if (!StringUtils::Parse(xs.Str, &v.X) && !StringUtils::Parse(ys.Str, &v.Y) && !StringUtils::Parse(zs.Str, &v.Z)) { - return v; + return (Vector3)v; } } } - return defaultValue; } From 735b573705d3b62ca6816ced327f19157cc5cedd Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 7 Oct 2024 18:03:55 +0200 Subject: [PATCH 25/37] Bump up build number --- Flax.flaxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index ca1a1aff8..33dc6e45b 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -4,7 +4,7 @@ "Major": 1, "Minor": 9, "Revision": 0, - "Build": 6604 + "Build": 6605 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.", From 9694446fcaf3befc4e104e28e17bb1010933fb1e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 8 Oct 2024 12:15:01 +0200 Subject: [PATCH 26/37] Optimize `Color32` to use packed bits for quick comparisons --- Source/Engine/Core/Math/Color32.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Core/Math/Color32.h b/Source/Engine/Core/Math/Color32.h index 48910131f..17d5d65d1 100644 --- a/Source/Engine/Core/Math/Color32.h +++ b/Source/Engine/Core/Math/Color32.h @@ -80,12 +80,12 @@ public: public: bool operator==(const Color32& other) const { - return R == other.R && G == other.G && B == other.B && A == other.A; + return Raw == other.Raw; } bool operator!=(const Color32& other) const { - return R != other.R || G != other.G || B != other.B || A != other.A; + return Raw != other.Raw; } Color32 operator+(const Color32& b) const @@ -138,7 +138,7 @@ public: // Returns true if color is fully transparent (all components are equal zero). bool IsTransparent() const { - return R + G + B + A == 0; + return Raw == 0; } // Returns true if color has opacity channel in use (different from 255). @@ -222,7 +222,7 @@ namespace Math { FORCE_INLINE static bool NearEqual(const Color32& a, const Color32& b) { - return a == b; + return a.Raw == b.Raw; } } From 600ac568a9f7e4f2e55fcf3963f19a355e7115b3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 9 Oct 2024 12:14:53 +0200 Subject: [PATCH 27/37] Change default shadows update rate at far plane to be 1 to prevent artifacts Users can tweak this down manually when optimizing game (dynamic games might stay at 1) --- Source/Engine/Level/Actors/Light.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/Light.h b/Source/Engine/Level/Actors/Light.h index 3138d996f..e43520df5 100644 --- a/Source/Engine/Level/Actors/Light.h +++ b/Source/Engine/Level/Actors/Light.h @@ -174,7 +174,7 @@ public: /// Frequency of shadow updates at the maximum distance from the view at which shadows are still rendered. This value is multiplied by ShadowsUpdateRate and allows scaling the update rate in-between the shadow range. For example, if light is near view, it will get normal shadow updates but will reduce this rate when far from view. See ShadowsUpdateRate to learn more. /// API_FIELD(Attributes="EditorOrder(105), EditorDisplay(\"Shadow\", \"Update Rate At Distance\"), Limit(0.0f, 1.0f)") - float ShadowsUpdateRateAtDistance = 0.5f; + float ShadowsUpdateRateAtDistance = 1.0f; /// /// Defines the resolution of the shadow map texture used to draw objects projection from light-point-of-view. Higher values increase shadow quality at cost of performance. From 73842d97932de6d41e9829f2c0921531d3b93c5e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 9 Oct 2024 12:17:39 +0200 Subject: [PATCH 28/37] Fix properties order in Light shadows section --- Source/Engine/Level/Actors/Light.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Actors/Light.h b/Source/Engine/Level/Actors/Light.h index e43520df5..bcb914740 100644 --- a/Source/Engine/Level/Actors/Light.h +++ b/Source/Engine/Level/Actors/Light.h @@ -173,7 +173,7 @@ public: /// /// Frequency of shadow updates at the maximum distance from the view at which shadows are still rendered. This value is multiplied by ShadowsUpdateRate and allows scaling the update rate in-between the shadow range. For example, if light is near view, it will get normal shadow updates but will reduce this rate when far from view. See ShadowsUpdateRate to learn more. /// - API_FIELD(Attributes="EditorOrder(105), EditorDisplay(\"Shadow\", \"Update Rate At Distance\"), Limit(0.0f, 1.0f)") + API_FIELD(Attributes="EditorOrder(101), EditorDisplay(\"Shadow\", \"Update Rate At Distance\"), Limit(0.0f, 1.0f)") float ShadowsUpdateRateAtDistance = 1.0f; /// From 79471af0c186441005294a1562264c7d95abc8f5 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 11:19:06 +0200 Subject: [PATCH 29/37] Fix bug in new shadows rendering when there are too many lights --- Source/Engine/Renderer/ShadowsPass.cpp | 38 ++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index b30005b51..0487d7ce2 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -330,6 +330,7 @@ public: for (auto it = Lights.Begin(); it.IsNotEnd(); ++it) { auto& atlasLight = it->Value; + atlasLight.StaticState = ShadowAtlasLight::Unused; atlasLight.Cache.StaticValid = false; for (int32 i = 0; i < atlasLight.TilesCount; i++) atlasLight.Tiles[i].ClearDynamic(); @@ -370,7 +371,8 @@ public: for (auto& e : Lights) { auto& atlasLight = e.Value; - if (atlasLight.StaticState == ShadowAtlasLight::CopyStaticShadow && atlasLight.Bounds.Intersects(bounds)) + if ((atlasLight.StaticState == ShadowAtlasLight::CopyStaticShadow || atlasLight.StaticState == ShadowAtlasLight::NoStaticGeometry) + && atlasLight.Bounds.Intersects(bounds)) { // Invalidate static shadow atlasLight.Cache.StaticValid = false; @@ -719,8 +721,14 @@ bool ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render } switch (atlasLight.StaticState) { - case ShadowAtlasLight::CopyStaticShadow: case ShadowAtlasLight::NoStaticGeometry: + // Light was modified so attempt to find the static shadow again + if (!atlasLight.Cache.StaticValid && atlasLight.HasStaticShadowContext) + { + atlasLight.StaticState = ShadowAtlasLight::WaitForGeometryCheck; + break; + } + case ShadowAtlasLight::CopyStaticShadow: case ShadowAtlasLight::FailedToInsertTiles: // Skip collecting static draws atlasLight.HasStaticShadowContext = false; @@ -728,7 +736,7 @@ bool ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render } if (atlasLight.HasStaticShadowContext) { - // If rendering finds any static draws then it's set to true + // If rendering finds any static draws then it will be set to true for (auto& tile : atlasLight.Tiles) tile.HasStaticGeometry = false; } @@ -1367,7 +1375,7 @@ void ShadowsPass::RenderShadowMaps(RenderContextBatch& renderContextBatch) const ShadowsCustomBuffer* shadowsPtr = renderContext.Buffers->FindCustomBuffer(TEXT("Shadows"), false); if (shadowsPtr == nullptr || shadowsPtr->Lights.IsEmpty() || shadowsPtr->LastFrameUsed != Engine::FrameCount) return; - PROFILE_GPU_CPU("ShadowMaps"); + PROFILE_GPU_CPU("Shadow Maps"); const ShadowsCustomBuffer& shadows = *shadowsPtr; GPUContext* context = GPUDevice::Instance->GetMainContext(); context->ResetSR(); @@ -1384,9 +1392,29 @@ void ShadowsPass::RenderShadowMaps(RenderContextBatch& renderContextBatch) for (auto& e : shadows.Lights) { ShadowAtlasLight& atlasLight = e.Value; - if (atlasLight.StaticState != ShadowAtlasLight::UpdateStaticShadow || !atlasLight.HasStaticShadowContext || atlasLight.ContextCount == 0) + if (!atlasLight.HasStaticShadowContext || atlasLight.ContextCount == 0) continue; int32 contextIndex = 0; + + if (atlasLight.StaticState == ShadowAtlasLight::WaitForGeometryCheck) + { + // Check for any static geometry to use in static shadow map + for (int32 tileIndex = 0; tileIndex < atlasLight.TilesCount; tileIndex++) + { + ShadowAtlasLightTile& tile = atlasLight.Tiles[tileIndex]; + contextIndex++; // Skip dynamic context + auto& shadowContextStatic = renderContextBatch.Contexts[atlasLight.ContextIndex + contextIndex++]; + if (!shadowContextStatic.List->DrawCallsLists[(int32)DrawCallsListType::Depth].IsEmpty() || !shadowContextStatic.List->ShadowDepthDrawCallsList.IsEmpty()) + { + tile.HasStaticGeometry = true; + } + } + } + + if (atlasLight.StaticState != ShadowAtlasLight::UpdateStaticShadow) + continue; + + contextIndex = 0; for (int32 tileIndex = 0; tileIndex < atlasLight.TilesCount; tileIndex++) { ShadowAtlasLightTile& tile = atlasLight.Tiles[tileIndex]; From 0fcd6a194a9f4af5706a83b9b90ca337088a1f49 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 18:08:32 +0200 Subject: [PATCH 30/37] Update Assimp lib for Linux --- Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a | 3 --- Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a | 4 ++-- Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a | 3 --- Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a | 3 --- Source/ThirdParty/assimp/assimp.Build.cs | 1 - Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs | 2 -- 6 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a delete mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a delete mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a deleted file mode 100644 index 92c1baf0b..000000000 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4eb25101716011a5b4c872c5cd303c3292a61e5f661e9296d95502b5705e2e53 -size 181458 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a index 4dccc7f4b..8680fe1af 100644 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8cbd73a154e270cc03d3da292b2c3cc73ee473b221f43722d060dc114916d6d5 -size 7996212 +oid sha256:fc6f4d94de6fccc854c5ec2cfc98b6516391448f92e9a1ecab6b24709e0c6f87 +size 10378226 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a deleted file mode 100644 index 6bcd58a96..000000000 --- a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6aa0849de08ac7f7332c63941b6ed028c329971b7d0ce9de44580e46b7560f2d -size 519048 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a deleted file mode 100644 index 792b3daf5..000000000 --- a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b67f00759cb59c91e5fe3fcf8bc107c6ac5f54c1929cea246892298ec40f6ec -size 543624 diff --git a/Source/ThirdParty/assimp/assimp.Build.cs b/Source/ThirdParty/assimp/assimp.Build.cs index dc0f0f06c..2276ca2e2 100644 --- a/Source/ThirdParty/assimp/assimp.Build.cs +++ b/Source/ThirdParty/assimp/assimp.Build.cs @@ -37,7 +37,6 @@ public class assimp : DepsModule case TargetPlatform.Linux: case TargetPlatform.Mac: options.OutputFiles.Add(Path.Combine(depsRoot, "libassimp.a")); - options.OutputFiles.Add(Path.Combine(depsRoot, "libIrrXML.a")); break; default: throw new InvalidPlatformException(options.Platform.Target); } diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs index 3cc1bacf0..8712839eb 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs @@ -128,7 +128,6 @@ namespace Flax.Deps.Dependencies configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); - Utilities.FileCopy(Path.Combine(root, "lib", "libIrrXML.a"), Path.Combine(depsFolder, "libIrrXML.a")); break; } case TargetPlatform.Mac: @@ -141,7 +140,6 @@ namespace Flax.Deps.Dependencies configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, architecture); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); - Utilities.FileCopy(Path.Combine(root, "lib", "libIrrXML.a"), Path.Combine(depsFolder, "libIrrXML.a")); } break; } From 2d6257a3902252c0492c41a3477241e8b843f6d4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 20:32:44 +0200 Subject: [PATCH 31/37] Revert "Update Assimp lib for Linux" This reverts commit 0fcd6a194a9f4af5706a83b9b90ca337088a1f49. --- Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a | 3 +++ Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a | 4 ++-- Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a | 3 +++ Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a | 3 +++ Source/ThirdParty/assimp/assimp.Build.cs | 1 + Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs | 2 ++ 6 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a create mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a create mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a new file mode 100644 index 000000000..92c1baf0b --- /dev/null +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4eb25101716011a5b4c872c5cd303c3292a61e5f661e9296d95502b5705e2e53 +size 181458 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a index 8680fe1af..4dccc7f4b 100644 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc6f4d94de6fccc854c5ec2cfc98b6516391448f92e9a1ecab6b24709e0c6f87 -size 10378226 +oid sha256:8cbd73a154e270cc03d3da292b2c3cc73ee473b221f43722d060dc114916d6d5 +size 7996212 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a new file mode 100644 index 000000000..6bcd58a96 --- /dev/null +++ b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6aa0849de08ac7f7332c63941b6ed028c329971b7d0ce9de44580e46b7560f2d +size 519048 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a new file mode 100644 index 000000000..792b3daf5 --- /dev/null +++ b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b67f00759cb59c91e5fe3fcf8bc107c6ac5f54c1929cea246892298ec40f6ec +size 543624 diff --git a/Source/ThirdParty/assimp/assimp.Build.cs b/Source/ThirdParty/assimp/assimp.Build.cs index 2276ca2e2..dc0f0f06c 100644 --- a/Source/ThirdParty/assimp/assimp.Build.cs +++ b/Source/ThirdParty/assimp/assimp.Build.cs @@ -37,6 +37,7 @@ public class assimp : DepsModule case TargetPlatform.Linux: case TargetPlatform.Mac: options.OutputFiles.Add(Path.Combine(depsRoot, "libassimp.a")); + options.OutputFiles.Add(Path.Combine(depsRoot, "libIrrXML.a")); break; default: throw new InvalidPlatformException(options.Platform.Target); } diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs index 8712839eb..3cc1bacf0 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs @@ -128,6 +128,7 @@ namespace Flax.Deps.Dependencies configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); + Utilities.FileCopy(Path.Combine(root, "lib", "libIrrXML.a"), Path.Combine(depsFolder, "libIrrXML.a")); break; } case TargetPlatform.Mac: @@ -140,6 +141,7 @@ namespace Flax.Deps.Dependencies configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, architecture); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); + Utilities.FileCopy(Path.Combine(root, "lib", "libIrrXML.a"), Path.Combine(depsFolder, "libIrrXML.a")); } break; } From cc8afbc220ab301385275ba948b08584ffd5d05b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 21:28:30 +0200 Subject: [PATCH 32/37] Update Assimp for Mac --- Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a | 3 --- Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libassimp.a | 4 ++-- Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a | 3 --- Source/Platforms/Mac/Binaries/ThirdParty/x64/libassimp.a | 2 +- Source/ThirdParty/assimp/assimp.Build.cs | 1 - Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs | 2 +- 6 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a delete mode 100644 Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a deleted file mode 100644 index 6bcd58a96..000000000 --- a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libIrrXML.a +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6aa0849de08ac7f7332c63941b6ed028c329971b7d0ce9de44580e46b7560f2d -size 519048 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libassimp.a b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libassimp.a index 622b54e48..0aeab8ca5 100644 --- a/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libassimp.a +++ b/Source/Platforms/Mac/Binaries/ThirdParty/ARM64/libassimp.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:05ed7fbba9701903c4d488eebda74ff71316af984bda5b125ff4822e53c05f3a -size 66547240 +oid sha256:512690a2639b29649b19531e8f24f0e50600c5c225c674568d28e168b5078838 +size 7427096 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a deleted file mode 100644 index 792b3daf5..000000000 --- a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libIrrXML.a +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4b67f00759cb59c91e5fe3fcf8bc107c6ac5f54c1929cea246892298ec40f6ec -size 543624 diff --git a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libassimp.a b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libassimp.a index da1ab7c0b..ae7e0edd9 100644 --- a/Source/Platforms/Mac/Binaries/ThirdParty/x64/libassimp.a +++ b/Source/Platforms/Mac/Binaries/ThirdParty/x64/libassimp.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ead9834575a8b7dcab9f8539b59342a850d72d968ab4bdf6e1775510c7a38659 +oid sha256:1fc8320db7b98865e00e750277dec9aff82a3842454cb784d944c44b4aacfcbc size 7830128 diff --git a/Source/ThirdParty/assimp/assimp.Build.cs b/Source/ThirdParty/assimp/assimp.Build.cs index dc0f0f06c..2276ca2e2 100644 --- a/Source/ThirdParty/assimp/assimp.Build.cs +++ b/Source/ThirdParty/assimp/assimp.Build.cs @@ -37,7 +37,6 @@ public class assimp : DepsModule case TargetPlatform.Linux: case TargetPlatform.Mac: options.OutputFiles.Add(Path.Combine(depsRoot, "libassimp.a")); - options.OutputFiles.Add(Path.Combine(depsRoot, "libIrrXML.a")); break; default: throw new InvalidPlatformException(options.Platform.Target); } diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs index 3cc1bacf0..f5bb8298c 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs @@ -136,12 +136,12 @@ namespace Flax.Deps.Dependencies // Build for Mac foreach (var architecture in new[] { TargetArchitecture.x64, TargetArchitecture.ARM64 }) { + Utilities.Run("make", "clean", null, root, Utilities.RunOptions.ThrowExceptionOnError); RunCmake(root, platform, architecture, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF " + globalConfig); Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError); configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, architecture); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); - Utilities.FileCopy(Path.Combine(root, "lib", "libIrrXML.a"), Path.Combine(depsFolder, "libIrrXML.a")); } break; } From 9e04f0b05483fdcd80204f68ae87b2bf353a8a42 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 22:09:03 +0200 Subject: [PATCH 33/37] Update Assimp for Linux (use clang 7) --- .../Linux/Binaries/ThirdParty/x64/libIrrXML.a | 3 --- .../Linux/Binaries/ThirdParty/x64/libassimp.a | 4 ++-- .../Tools/Flax.Build/Deps/Dependencies/Assimp.cs | 15 ++++++++++----- 3 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a deleted file mode 100644 index 92c1baf0b..000000000 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libIrrXML.a +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4eb25101716011a5b4c872c5cd303c3292a61e5f661e9296d95502b5705e2e53 -size 181458 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a index 4dccc7f4b..8680fe1af 100644 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8cbd73a154e270cc03d3da292b2c3cc73ee473b221f43722d060dc114916d6d5 -size 7996212 +oid sha256:fc6f4d94de6fccc854c5ec2cfc98b6516391448f92e9a1ecab6b24709e0c6f87 +size 10378226 diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs index f5bb8298c..307f0e309 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs @@ -1,6 +1,6 @@ // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. -using System; +using System.Collections.Generic; using System.IO; using Flax.Build; @@ -122,13 +122,18 @@ namespace Flax.Deps.Dependencies } case TargetPlatform.Linux: { + var envVars = new Dictionary + { + { "CC", "clang-7" }, + { "CC_FOR_BUILD", "clang-7" } + }; + // Build for Linux - RunCmake(root, platform, TargetArchitecture.x64, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF " + globalConfig); - Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError); + RunCmake(root, platform, TargetArchitecture.x64, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF " + globalConfig, envVars); + Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError, envVars); configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, TargetArchitecture.x64); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); - Utilities.FileCopy(Path.Combine(root, "lib", "libIrrXML.a"), Path.Combine(depsFolder, "libIrrXML.a")); break; } case TargetPlatform.Mac: @@ -136,12 +141,12 @@ namespace Flax.Deps.Dependencies // Build for Mac foreach (var architecture in new[] { TargetArchitecture.x64, TargetArchitecture.ARM64 }) { - Utilities.Run("make", "clean", null, root, Utilities.RunOptions.ThrowExceptionOnError); RunCmake(root, platform, architecture, " -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF " + globalConfig); Utilities.Run("make", null, null, root, Utilities.RunOptions.ThrowExceptionOnError); configHeaderFilePath = Path.Combine(root, "include", "assimp", "config.h"); var depsFolder = GetThirdPartyFolder(options, platform, architecture); Utilities.FileCopy(Path.Combine(root, "lib", "libassimp.a"), Path.Combine(depsFolder, "libassimp.a")); + Utilities.Run("make", "clean", null, root, Utilities.RunOptions.ThrowExceptionOnError); } break; } From b37ba9279ee71c5565d291d7b80692ef248042e9 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 22:51:59 +0200 Subject: [PATCH 34/37] Update Assimp for Linux (use clang 13) Migrate to Ubuntu 24 for CI/CD builds CLang 7 used before is no longer avaliable on latest Ubuntu distro --- .github/workflows/build_linux.yml | 4 ++-- .github/workflows/cd.yml | 4 ++-- .github/workflows/tests.yml | 2 +- Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a | 4 ++-- Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index b3348c288..d65662673 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -10,7 +10,7 @@ jobs: # Editor editor-linux: name: Editor (Linux, Development x64) - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-24.04" steps: - name: Checkout repo uses: actions/checkout@v3 @@ -41,7 +41,7 @@ jobs: # Game game-linux: name: Game (Linux, Release x64) - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-24.04" steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index d83b40363..bb9fe3e6a 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -76,7 +76,7 @@ jobs: # Linux package-linux-editor: name: Editor (Linux) - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-24.04" steps: - name: Checkout repo uses: actions/checkout@v3 @@ -110,7 +110,7 @@ jobs: path: Output/FlaxEditorLinux.zip package-linux-game: name: Game (Linux) - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-24.04" steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e36642cdf..2242a546c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ jobs: # Tests on Linux tests-linux: name: Tests (Linux) - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-24.04" steps: - name: Checkout repo uses: actions/checkout@v3 diff --git a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a index 8680fe1af..92b3c5545 100644 --- a/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a +++ b/Source/Platforms/Linux/Binaries/ThirdParty/x64/libassimp.a @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc6f4d94de6fccc854c5ec2cfc98b6516391448f92e9a1ecab6b24709e0c6f87 -size 10378226 +oid sha256:b3510d6c5585f08fc9fcbf2044bb0dc0238e2501c1914e3b98aef36bc8cd2711 +size 10303430 diff --git a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs index 307f0e309..652bbccb9 100644 --- a/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs +++ b/Source/Tools/Flax.Build/Deps/Dependencies/Assimp.cs @@ -124,8 +124,9 @@ namespace Flax.Deps.Dependencies { var envVars = new Dictionary { - { "CC", "clang-7" }, - { "CC_FOR_BUILD", "clang-7" } + { "CC", "clang-13" }, + { "CC_FOR_BUILD", "clang-13" }, + { "CXX", "clang++-13" }, }; // Build for Linux From 5c0110769aa71780e93698e4f53c9d38d1756a08 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 22:57:44 +0200 Subject: [PATCH 35/37] Remove custom source for Linux CI/CD --- .github/workflows/build_linux.yml | 2 -- .github/workflows/build_linux_sources.list | 4 ---- .github/workflows/cd.yml | 4 ---- .github/workflows/tests.yml | 2 -- 4 files changed, 12 deletions(-) delete mode 100644 .github/workflows/build_linux_sources.list diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index d65662673..4b2aa4510 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -16,8 +16,6 @@ jobs: uses: actions/checkout@v3 - name: Install dependencies run: | - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Setup Vulkan diff --git a/.github/workflows/build_linux_sources.list b/.github/workflows/build_linux_sources.list deleted file mode 100644 index 4d8f94f35..000000000 --- a/.github/workflows/build_linux_sources.list +++ /dev/null @@ -1,4 +0,0 @@ -deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse -deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse -deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse -deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index bb9fe3e6a..30ac942f2 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -86,8 +86,6 @@ jobs: git lfs pull - name: Install dependencies run: | - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Setup Vulkan @@ -120,8 +118,6 @@ jobs: git lfs pull - name: Install dependencies run: | - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Setup Vulkan diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2242a546c..9a77fb5c6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,8 +28,6 @@ jobs: git lfs pull - name: Install dependencies run: | - sudo rm -f /etc/apt/sources.list.d/* - sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Build From 56ebbecd3b09e55c3e70107254c55b59d28022b3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 23:24:07 +0200 Subject: [PATCH 36/37] Remove apt update on Linux CI/CD --- .github/workflows/build_linux.yml | 1 - .github/workflows/cd.yml | 2 -- .github/workflows/tests.yml | 1 - 3 files changed, 4 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 4b2aa4510..6290ff525 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -16,7 +16,6 @@ jobs: uses: actions/checkout@v3 - name: Install dependencies run: | - sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Setup Vulkan uses: ./.github/actions/vulkan diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 30ac942f2..4b4f9a827 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -86,7 +86,6 @@ jobs: git lfs pull - name: Install dependencies run: | - sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Setup Vulkan uses: ./.github/actions/vulkan @@ -118,7 +117,6 @@ jobs: git lfs pull - name: Install dependencies run: | - sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Setup Vulkan uses: ./.github/actions/vulkan diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9a77fb5c6..b828974a0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,7 +28,6 @@ jobs: git lfs pull - name: Install dependencies run: | - sudo apt-get update sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev - name: Build run: | From b45f6c13216502c53568d210ac4350d42ad80b20 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 10 Oct 2024 23:27:01 +0200 Subject: [PATCH 37/37] Disable editor screenshot when running without graphics --- Source/Editor/Modules/WindowsModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs index 02dd6d151..b9f3e246b 100644 --- a/Source/Editor/Modules/WindowsModule.cs +++ b/Source/Editor/Modules/WindowsModule.cs @@ -950,7 +950,7 @@ namespace FlaxEditor.Modules MainWindow = null; // Capture project icon screenshot (not in play mode and if editor was used for some time) - if (!Editor.StateMachine.IsPlayMode && Time.TimeSinceStartup >= 5.0f) + if (!Editor.StateMachine.IsPlayMode && Time.TimeSinceStartup >= 5.0f && GPUDevice.Instance?.RendererType != RendererType.Null) { Editor.Log("Capture project icon screenshot"); _projectIconScreenshotTimeout = Time.TimeSinceStartup + 0.8f; // wait 800ms for a screenshot task