Merge branch 'master' into Improve-HighlightedPopUpColor

This commit is contained in:
Phantom
2026-03-12 17:34:46 +01:00
28 changed files with 332 additions and 92 deletions

Binary file not shown.

View File

@@ -4,7 +4,7 @@
"Major": 1,
"Minor": 11,
"Revision": 0,
"Build": 6807
"Build": 6808
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",

View File

@@ -690,7 +690,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
return grid;
}
private CustomElementsContainer<UniformGridPanel> UniformPanelCapsuleForObjectWithText(LayoutElementsContainer el, string text, ValueContainer values, Color borderColor, out FloatValueBox valueBox)
private CustomElementsContainer<UniformGridPanel> UniformPanelCapsuleForObjectWithText(LayoutElementsContainer el, string text, ValueContainer values, Color highlightColor, out FloatValueBox valueBox)
{
valueBox = null;
var grid = UniformGridTwoByOne(el);
@@ -701,8 +701,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
{
valueBox = floatEditorElement.ValueBox;
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
valueBox.BorderColor = Color.Lerp(borderColor, back, ActorTransformEditor.AxisGreyOutFactor);
valueBox.BorderSelectedColor = borderColor;
valueBox.HighlightColor = highlightColor;
valueBox.BorderSelectedColor = highlightColor;
}
return grid;
}

View File

@@ -14,22 +14,17 @@ namespace FlaxEditor.CustomEditors.Editors
/// <summary>
/// The X axis color.
/// </summary>
public static Color AxisColorX = new Color(1.0f, 0.0f, 0.02745f, 1.0f);
public static Color AxisColorX = new Color(0.8f, 0.0f, 0.027f, 1.0f);
/// <summary>
/// The Y axis color.
/// </summary>
public static Color AxisColorY = new Color(0.239215f, 1.0f, 0.047058f, 1.0f);
public static Color AxisColorY = new Color(0.239215f, 0.65f, 0.047058f, 1.0f);
/// <summary>
/// The Z axis color.
/// </summary>
public static Color AxisColorZ = new Color(0.0f, 0.0235294f, 1.0f, 1.0f);
/// <summary>
/// The axes colors grey out scale when input field is not focused.
/// </summary>
public static float AxisGreyOutFactor = 0.6f;
public static Color AxisColorZ = new Color(0.0f, 0.0235294f, 0.9f, 1.0f);
/// <summary>
/// Custom editor for actor position property.
@@ -43,18 +38,20 @@ namespace FlaxEditor.CustomEditors.Editors
base.Initialize(layout);
if (XElement.ValueBox.Parent is UniformGridPanel ug)
{
ug.SlotPadding = new Margin(3.0f, 0.0f, 0.0f, 0.0f);
CheckLayout(ug);
}
// Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
XElement.ValueBox.BorderColor = Color.Lerp(AxisColorX, back, AxisGreyOutFactor);
XElement.ValueBox.BorderSelectedColor = AxisColorX;
XElement.ValueBox.Category = Utils.ValueCategory.Distance;
YElement.ValueBox.BorderColor = Color.Lerp(AxisColorY, back, AxisGreyOutFactor);
YElement.ValueBox.BorderSelectedColor = AxisColorY;
YElement.ValueBox.Category = Utils.ValueCategory.Distance;
ZElement.ValueBox.BorderColor = Color.Lerp(AxisColorZ, back, AxisGreyOutFactor);
ZElement.ValueBox.BorderSelectedColor = AxisColorZ;
XElement.ValueBox.HighlightColor = AxisColorX;
XElement.ValueBox.Category = Utils.ValueCategory.Distance;
YElement.ValueBox.HighlightColor = AxisColorY;
YElement.ValueBox.Category = Utils.ValueCategory.Distance;
ZElement.ValueBox.HighlightColor = AxisColorZ;
ZElement.ValueBox.Category = Utils.ValueCategory.Distance;
}
}
@@ -71,18 +68,20 @@ namespace FlaxEditor.CustomEditors.Editors
base.Initialize(layout);
if (XElement.ValueBox.Parent is UniformGridPanel ug)
{
ug.SlotPadding = new Margin(3.0f, 0.0f, 0.0f, 0.0f);
CheckLayout(ug);
}
// Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
XElement.ValueBox.BorderColor = Color.Lerp(AxisColorX, back, AxisGreyOutFactor);
XElement.ValueBox.BorderSelectedColor = AxisColorX;
XElement.ValueBox.Category = Utils.ValueCategory.Angle;
YElement.ValueBox.BorderColor = Color.Lerp(AxisColorY, back, AxisGreyOutFactor);
YElement.ValueBox.BorderSelectedColor = AxisColorY;
YElement.ValueBox.Category = Utils.ValueCategory.Angle;
ZElement.ValueBox.BorderColor = Color.Lerp(AxisColorZ, back, AxisGreyOutFactor);
ZElement.ValueBox.BorderSelectedColor = AxisColorZ;
XElement.ValueBox.HighlightColor = AxisColorX;
XElement.ValueBox.Category = Utils.ValueCategory.Angle;
YElement.ValueBox.HighlightColor = AxisColorY;
YElement.ValueBox.Category = Utils.ValueCategory.Angle;
ZElement.ValueBox.HighlightColor = AxisColorZ;
ZElement.ValueBox.Category = Utils.ValueCategory.Angle;
}
}
@@ -129,17 +128,19 @@ namespace FlaxEditor.CustomEditors.Editors
}
if (XElement.ValueBox.Parent is UniformGridPanel ug)
{
ug.SlotPadding = new Margin(3.0f, 0.0f, 0.0f, 0.0f);
CheckLayout(ug);
}
// Override colors
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
var grayOutFactor = 0.6f;
XElement.ValueBox.BorderColor = Color.Lerp(AxisColorX, back, grayOutFactor);
XElement.ValueBox.BorderSelectedColor = AxisColorX;
YElement.ValueBox.BorderColor = Color.Lerp(AxisColorY, back, grayOutFactor);
YElement.ValueBox.BorderSelectedColor = AxisColorY;
ZElement.ValueBox.BorderColor = Color.Lerp(AxisColorZ, back, grayOutFactor);
ZElement.ValueBox.BorderSelectedColor = AxisColorZ;
XElement.ValueBox.HighlightColor = AxisColorX;
YElement.ValueBox.HighlightColor = AxisColorY;
ZElement.ValueBox.HighlightColor = AxisColorZ;
}
/// <summary>

View File

@@ -89,6 +89,11 @@ namespace FlaxEditor.GUI.Input
/// </summary>
public bool IsSliding => _isSliding;
/// <summary>
/// The color of the highlight to the left of the value box.
/// </summary>
public Color HighlightColor;
/// <summary>
/// Occurs when sliding starts.
/// </summary>
@@ -211,6 +216,12 @@ namespace FlaxEditor.GUI.Input
Render2D.DrawRectangle(bounds, style.SelectionBorder);
}
}
if (HighlightColor != Color.Transparent)
{
var highlightRect = new Rectangle(-3.0f, 0.0f, 3.0f, Height);
Render2D.FillRectangle(highlightRect, HighlightColor);
}
}
/// <inheritdoc />

View File

@@ -180,6 +180,11 @@ namespace FlaxEditor
/// </summary>
public bool EnableCamera => _view != null && EnableBackground;
/// <summary>
/// True if enable grid drawing.
/// </summary>
public bool ShowGrid { get; set; } = true;
/// <summary>
/// Transform gizmo to use sync with (selection, snapping, transformation settings).
/// </summary>
@@ -387,19 +392,53 @@ namespace FlaxEditor
if (_mouseMovesWidget && _activeWidget.UIControl)
{
// Calculate transform delta
var resizeAxisAbs = _activeWidget.ResizeAxis.Absolute;
var resizeAxisPos = Float2.Clamp(_activeWidget.ResizeAxis, Float2.Zero, Float2.One);
var resizeAxisNeg = Float2.Clamp(-_activeWidget.ResizeAxis, Float2.Zero, Float2.One);
var delta = location - _mouseMovesPos;
// TODO: scale/size snapping?
delta *= resizeAxisAbs;
// Resize control via widget
var moveLocation = _mouseMovesPos + delta;
var control = _activeWidget.UIControl.Control;
var uiControlDelta = GetControlDelta(control, ref _mouseMovesPos, ref moveLocation);
control.LocalLocation += uiControlDelta * resizeAxisNeg;
control.Size += uiControlDelta * resizeAxisPos - uiControlDelta * resizeAxisNeg;
// Transform delta to control local space
var rotation = GetTotalRotation(control) * Mathf.DegreesToRadians;
var cos = Mathf.Cos(rotation);
var sin = Mathf.Sin(rotation);
var localDeltaX = uiControlDelta.X * cos + uiControlDelta.Y * sin;
var localDeltaY = uiControlDelta.Y * cos - uiControlDelta.X * sin;
var localDelta = new Float2(localDeltaX, localDeltaY);
localDelta *= _activeWidget.ResizeAxis.Absolute;
// Calculate size change
var resizeAxisPos = Float2.Clamp(_activeWidget.ResizeAxis, Float2.Zero, Float2.One);
var resizeAxisNeg = Float2.Clamp(-_activeWidget.ResizeAxis, Float2.Zero, Float2.One);
var dSizeScaled = localDelta * resizeAxisPos - localDelta * resizeAxisNeg;
var scale = control.Scale;
var dSize = new Float2(
Mathf.Abs(scale.X) > Mathf.Epsilon ? dSizeScaled.X / scale.X : 0,
Mathf.Abs(scale.Y) > Mathf.Epsilon ? dSizeScaled.Y / scale.Y : 0);
// Apply size change
control.Size += dSize;
// Calculate location offset to keep the opposite edge stationary
// When PivotRelative is false, resizing keeps Top-Left (Location) constant,
// so we only need to slide back if we are resizing Left or Top edges.
if (!control.PivotRelative)
{
var pivotOffset = Float2.Zero;
if (_activeWidget.ResizeAxis.X < 0 && Mathf.Abs(dSize.X) > Mathf.Epsilon)
pivotOffset.X = -dSize.X * scale.X;
if (_activeWidget.ResizeAxis.Y < 0 && Mathf.Abs(dSize.Y) > Mathf.Epsilon)
pivotOffset.Y = -dSize.Y * scale.Y;
// Transform offset back to parent space and apply
var dLocationX = pivotOffset.X * cos - pivotOffset.Y * sin;
var dLocationY = pivotOffset.X * sin + pivotOffset.Y * cos;
var dLocation = new Float2(dLocationX, dLocationY);
control.LocalLocation += dLocation;
}
// Don't move if layout doesn't allow it
if (control.Parent != null)
@@ -492,17 +531,20 @@ namespace FlaxEditor
// Draw background
Surface.VisjectSurface.DrawBackgroundDefault(Editor.Instance.UI.VisjectSurfaceBackground, Width, Height);
// Draw grid
var viewRect = GetClientArea();
var upperLeft = _view.PointFromParent(viewRect.Location);
var bottomRight = _view.PointFromParent(viewRect.Size);
var min = Float2.Min(upperLeft, bottomRight);
var max = Float2.Max(upperLeft, bottomRight);
var pixelRange = (max - min) * ViewScale;
Render2D.PushClip(ref viewRect);
DrawAxis(Float2.UnitX, viewRect, min.X, max.X, pixelRange.X);
DrawAxis(Float2.UnitY, viewRect, min.Y, max.Y, pixelRange.Y);
Render2D.PopClip();
if (ShowGrid)
{
// Draw grid
var viewRect = GetClientArea();
var upperLeft = _view.PointFromParent(viewRect.Location);
var bottomRight = _view.PointFromParent(viewRect.Size);
var min = Float2.Min(upperLeft, bottomRight);
var max = Float2.Max(upperLeft, bottomRight);
var pixelRange = (max - min) * ViewScale;
Render2D.PushClip(ref viewRect);
DrawAxis(Float2.UnitX, viewRect, min.X, max.X, pixelRange.X);
DrawAxis(Float2.UnitY, viewRect, min.Y, max.Y, pixelRange.Y);
Render2D.PopClip();
}
}
base.Draw();
@@ -634,7 +676,7 @@ namespace FlaxEditor
// Draw sizing widgets
if (_widgets == null)
_widgets = new List<Widget>();
var widgetSize = 10.0f;
var widgetSize = 8.0f;
var viewScale = ViewScale;
if (viewScale < 0.7f)
widgetSize *= viewScale;
@@ -685,7 +727,7 @@ namespace FlaxEditor
anchorRectSize *= viewScale;
// Make anchor rects and rotate if parent is rotated.
var parentRotation = controlParent.Rotation * Mathf.DegreesToRadians;
var parentRotation = GetTotalRotation(controlParent) * Mathf.DegreesToRadians;
var rect1Axis = new Float2(-1, -1);
var rect1 = new Rectangle(anchorUpperLeft +
@@ -717,17 +759,25 @@ namespace FlaxEditor
}
}
private float GetTotalRotation(Control control)
{
if (control.Parent != null)
return control.Rotation + GetTotalRotation(control.Parent);
return control.Rotation;
}
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, float scale, Float2 resizeAxis, CursorType cursor)
{
var style = Style.Current;
var control = uiControl.Control;
var rotation = control.Rotation;
var rotation = GetTotalRotation(control);
var rotationInRadians = rotation * Mathf.DegreesToRadians;
var rect = new Rectangle((pos +
new Float2(resizeAxis.X * Mathf.Cos(rotationInRadians) - resizeAxis.Y * Mathf.Sin(rotationInRadians),
resizeAxis.Y * Mathf.Cos(rotationInRadians) + resizeAxis.X * Mathf.Sin(rotationInRadians)) * 10 * scale) - size * 0.5f,
size);
var position = (pos + new Float2(resizeAxis.X * Mathf.Cos(rotationInRadians) - resizeAxis.Y * Mathf.Sin(rotationInRadians),
resizeAxis.Y * Mathf.Cos(rotationInRadians) + resizeAxis.X * Mathf.Sin(rotationInRadians)) * 4 * (scale < 0.7f ? scale : 1));
var halfSize = size * 0.5f;
// Keep at 0, 0 rect position until later to correctly render rotation.
var rect = new Rectangle(0, 0, size);
// Find more correct cursor at different angles
var unwindRotation = Mathf.UnwindDegrees(rotation);
if (unwindRotation is (>= 45 and < 135) or (> -135 and <= -45) )
@@ -749,6 +799,10 @@ namespace FlaxEditor
default: break;
}
}
Render2D.PushTransform(Matrix3x3.Translation2D(position));
Render2D.PushTransform(Matrix3x3.RotationZ(rotationInRadians));
Render2D.PushTransform(Matrix3x3.Translation2D(-1 * halfSize));
if (rect.Contains(ref mousePos))
{
Render2D.FillRectangle(rect, style.Foreground);
@@ -759,9 +813,14 @@ namespace FlaxEditor
Render2D.FillRectangle(rect, style.ForegroundGrey);
Render2D.DrawRectangle(rect, style.Foreground);
}
Render2D.PopTransform();
Render2D.PopTransform();
Render2D.PopTransform();
if (!_mouseMovesWidget && uiControl != null)
{
// Collect widget
rect.Location = position - halfSize;
_widgets.Add(new Widget
{
UIControl = uiControl,

View File

@@ -6,7 +6,6 @@ using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Modules;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting;
@@ -15,7 +14,6 @@ using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Json;
using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.Viewport
@@ -185,6 +183,7 @@ namespace FlaxEditor.Viewport
showGridButton.Clicked += () =>
{
_gridGizmo.Enabled = !_gridGizmo.Enabled;
_uiRoot.ShowGrid = _gridGizmo.Enabled;
showGridButton.Checked = _gridGizmo.Enabled;
};
showGridButton.Checked = true;

View File

@@ -2,6 +2,7 @@
//#define USE_AUTODESK_FBX_SDK
using System.Collections.Generic;
using System.Reflection;
using FlaxEditor.GUI.Dialogs;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -45,9 +46,16 @@ namespace FlaxEditor.Windows
VerticalAlignment = TextAlignment.Center,
Parent = this
};
var assembly = typeof(Editor).Assembly;
var assemblyCopyright = assembly.GetCustomAttribute<AssemblyCopyrightAttribute>();
var assemblyInformationalVersion = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
var versionParts = assemblyInformationalVersion.InformationalVersion.Split('+');
string versionInfo = string.Empty;
if (versionParts.Length == 3)
versionInfo = $"\nBranch: {versionParts[1]}+{(versionParts[2].Length == 40 ? versionParts[2].Substring(0, 8) : versionParts[2])}";
new Label(nameLabel.Left, nameLabel.Bottom + 4, nameLabel.Width, 50)
{
Text = string.Format("Version: {0}\nCopyright (c) 2012-2025 Wojciech Figat.\nAll rights reserved.", Globals.EngineVersion),
Text = $"Version: {Globals.EngineVersion}{versionInfo}\n{assemblyCopyright.Copyright.Replace(". ", ".\n")}",
HorizontalAlignment = TextAlignment.Near,
VerticalAlignment = TextAlignment.Near,
Parent = this

View File

@@ -595,7 +595,11 @@ void EngineImpl::InitLog()
#if COMPILE_WITH_DEV_ENV
LOG(Info, "Compiled for Dev Environment");
#endif
#if defined(FLAXENGINE_BRANCH) && defined(FLAXENGINE_COMMIT)
LOG(Info, "Version " FLAXENGINE_VERSION_TEXT ", " FLAXENGINE_BRANCH ", " FLAXENGINE_COMMIT);
#else
LOG(Info, "Version " FLAXENGINE_VERSION_TEXT);
#endif
const Char* cpp = TEXT("?");
if (__cplusplus == 202101L) cpp = TEXT("C++23");
else if (__cplusplus == 202002L) cpp = TEXT("C++20");

View File

@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#include "PointLight.h"
#include "Engine/Content/Deprecated.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/RenderView.h"
@@ -196,6 +197,14 @@ void PointLight::Deserialize(DeserializeStream& stream, ISerializeModifier* modi
DESERIALIZE(UseInverseSquaredFalloff);
DESERIALIZE(UseIESBrightness);
DESERIALIZE(IESBrightnessScale);
// [Deprecated on 12.03.2026, expires on 12.03.2028]
if (modifier->EngineBuild <= 6807 && SERIALIZE_FIND_MEMBER(stream, "UseInverseSquaredFalloff") != stream.MemberEnd() && UseInverseSquaredFalloff)
{
// Convert old non-physical brightness value that was used for Inverse Squared Falloff which wasn't based on proper cm/m units calculations
MARK_CONTENT_DEPRECATED();
Brightness = Math::Sqrt(Brightness * 0.01f);
}
}
bool PointLight::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)

View File

@@ -1,6 +1,8 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#include "SpotLight.h"
#include "Engine/Content/Deprecated.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Content/Assets/IESProfile.h"
@@ -282,6 +284,14 @@ void SpotLight::Deserialize(DeserializeStream& stream, ISerializeModifier* modif
DESERIALIZE(UseInverseSquaredFalloff);
DESERIALIZE(UseIESBrightness);
DESERIALIZE(IESBrightnessScale);
// [Deprecated on 12.03.2026, expires on 12.03.2028]
if (modifier->EngineBuild <= 6807 && SERIALIZE_FIND_MEMBER(stream, "UseInverseSquaredFalloff") != stream.MemberEnd() && UseInverseSquaredFalloff)
{
// Convert old non-physical brightness value that was used for Inverse Squared Falloff which wasn't based on proper cm/m units calculations
MARK_CONTENT_DEPRECATED();
Brightness = Math::Sqrt(Brightness * 0.01f);
}
}
bool SpotLight::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)

View File

@@ -958,9 +958,6 @@ bool LevelImpl::unloadScene(Scene* scene)
// Simple enqueue scene root object to be deleted
scene->DeleteObject();
// Force flush deleted objects so we actually delete unloaded scene objects (prevent from reloading their managed objects, etc.)
ObjectsRemovalService::Flush();
return false;
}

View File

@@ -389,11 +389,14 @@ void Scene::BeginPlay(SceneBeginData* data)
if (model == nullptr)
CreateCsgModel();
}
Ticking.SetTicking(true);
}
void Scene::EndPlay()
{
// Improve scene cleanup performance by removing all data from scene rendering and ticking containers
Ticking.SetTicking(false);
Ticking.Clear();
Rendering.Clear();
Navigation.Clear();

View File

@@ -44,7 +44,7 @@ void SceneTicking::TickData::Tick()
{
TickScripts(Scripts);
for (int32 i = 0; i < Ticks.Count(); i++)
for (int32 i = 0; i < Ticks.Count() && _canTick; i++)
Ticks.Get()[i].Call();
}
@@ -66,7 +66,7 @@ void SceneTicking::TickData::TickExecuteInEditor()
{
TickScripts(ScriptsExecuteInEditor);
for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++)
for (int32 i = 0; i < TicksExecuteInEditor.Count() && _canTick; i++)
TicksExecuteInEditor.Get()[i].Call();
}
@@ -89,10 +89,8 @@ SceneTicking::FixedUpdateTickData::FixedUpdateTickData()
void SceneTicking::FixedUpdateTickData::TickScripts(const Array<Script*>& scripts)
{
for (auto* script : scripts)
{
script->OnFixedUpdate();
}
for (int32 i = 0; i < scripts.Count() && _canTick; i++)
scripts.Get()[i]->OnFixedUpdate();
}
SceneTicking::UpdateTickData::UpdateTickData()
@@ -102,36 +100,30 @@ SceneTicking::UpdateTickData::UpdateTickData()
void SceneTicking::UpdateTickData::TickScripts(const Array<Script*>& scripts)
{
for (auto* script : scripts)
{
script->OnUpdate();
}
for (int32 i = 0; i < scripts.Count() && _canTick; i++)
scripts.Get()[i]->OnUpdate();
}
SceneTicking::LateUpdateTickData::LateUpdateTickData()
: TickData(64)
: TickData(0)
{
}
void SceneTicking::LateUpdateTickData::TickScripts(const Array<Script*>& scripts)
{
for (auto* script : scripts)
{
script->OnLateUpdate();
}
for (int32 i = 0; i < scripts.Count() && _canTick; i++)
scripts.Get()[i]->OnLateUpdate();
}
SceneTicking::LateFixedUpdateTickData::LateFixedUpdateTickData()
: TickData(64)
: TickData(0)
{
}
void SceneTicking::LateFixedUpdateTickData::TickScripts(const Array<Script*>& scripts)
{
for (auto* script : scripts)
{
script->OnLateFixedUpdate();
}
for (int32 i = 0; i < scripts.Count() && _canTick; i++)
scripts.Get()[i]->OnLateFixedUpdate();
}
void SceneTicking::AddScript(Script* obj)
@@ -167,3 +159,11 @@ void SceneTicking::Clear()
LateUpdate.Clear();
LateFixedUpdate.Clear();
}
void SceneTicking::SetTicking(bool enable)
{
FixedUpdate._canTick = enable;
Update._canTick = enable;
LateUpdate._canTick = enable;
LateFixedUpdate._canTick = enable;
}

View File

@@ -46,6 +46,9 @@ public:
/// </summary>
class FLAXENGINE_API TickData
{
protected:
friend SceneTicking;
bool _canTick = true;
public:
Array<Script*> Scripts;
Array<Tick> Ticks;
@@ -134,6 +137,11 @@ public:
/// </summary>
void Clear();
/// <summary>
/// Changes the ability to tick. When disabled, the ticking functions won't be called. Can be called during ticking (eg. when scene is unloaded) to stp performing any more ticks.
/// </summary>
void SetTicking(bool enable);
public:
/// <summary>
/// The fixed update tick function.

View File

@@ -1440,8 +1440,28 @@ void Render2D::DrawRectangle(const Rectangle& rect, const Color& color1, const C
RENDER2D_CHECK_RENDERING_STATE;
const auto& mask = ClipLayersStack.Peek().Mask;
float thick = thickness;
thickness *= (TransformCached.M11 + TransformCached.M22 + TransformCached.M33) * 0.3333333f;
// When lines thickness is very large, don't use corner caps and place line ends to not overlap
if (thickness > 4.0f)
{
thick *= Math::Lerp(0.6f, 1.0f, Math::Saturate(thick - 4.0f)); // Smooth transition between soft LineAA and harsh FillRect
Float2 totalMin = rect.GetUpperLeft() - Float2(thick * 0.5f);
Float2 totalMax = rect.GetBottomRight() + Float2(thick * 0.5f);
Float2 size = totalMax - totalMin;
Render2DDrawCall& drawCall = DrawCalls.AddOne();
drawCall.Type = NeedAlphaWithTint(color1, color2, color3, color4) ? DrawCallType::FillRect : DrawCallType::FillRectNoAlpha;
drawCall.StartIB = IBIndex;
drawCall.CountIB = 6 * 4;
// TODO: interpolate colors from corners to extended rectangle edges properly
WriteRect(Rectangle(totalMin.X, totalMin.Y, size.X, thick), color1, color2, color2, color1);
WriteRect(Rectangle(totalMin.X, totalMin.Y + rect.Size.Y, size.X, thick), color4, color3, color3, color4);
WriteRect(Rectangle(totalMin.X, totalMin.Y + thick, thick, rect.Size.Y - thick), color1, color1, color4, color4);
WriteRect(Rectangle(totalMax.X - thick, totalMin.Y + thick, thick, rect.Size.Y - thick), color2, color2, color3, color3);
return;
}
Float2 points[5];
ApplyTransform(rect.GetUpperLeft(), points[0]);
ApplyTransform(rect.GetUpperRight(), points[1]);

View File

@@ -90,6 +90,7 @@ public:
Float3 ProbesOrigin;
float ProbesSpacing = 0.0f;
Int3 ProbeScrollOffsets;
bool PendingUpdate = true;
Int3 ProbeScrollClears;
void Clear()
@@ -97,6 +98,7 @@ public:
ProbesOrigin = Float3::Zero;
ProbeScrollOffsets = Int3::Zero;
ProbeScrollClears = Int3::Zero;
PendingUpdate = true;
}
} Cascades[4];
@@ -457,9 +459,12 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
//const uint64 cascadeFrequencies[] = { 1, 1, 1, 1 };
//const uint64 cascadeFrequencies[] = { 10, 10, 10, 10 };
bool cascadeSkipUpdate[4];
int32 maxCascadesPerFrame = renderContext.View.IsSingleFrame ? cascadesCount : 2;
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
{
cascadeSkipUpdate[cascadeIndex] = !clear && (ddgiData.LastFrameUsed % cascadeFrequencies[cascadeIndex]) != 0 && GPU_SPREAD_WORKLOAD;
auto& cascade = ddgiData.Cascades[cascadeIndex];
cascade.PendingUpdate |= !clear && (ddgiData.LastFrameUsed % cascadeFrequencies[cascadeIndex]) != 0 && GPU_SPREAD_WORKLOAD;
cascadeSkipUpdate[cascadeIndex] = !cascade.PendingUpdate || maxCascadesPerFrame-- <= 0;
}
// Compute scrolling (probes are placed around camera but are scrolling to increase stability during movement)
@@ -468,6 +473,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
if (cascadeSkipUpdate[cascadeIndex])
continue;
auto& cascade = ddgiData.Cascades[cascadeIndex];
cascade.PendingUpdate = false;
// Calculate the count of grid cells between the view origin and the scroll anchor
const Float3 volumeOrigin = cascade.ProbesOrigin + Float3(cascade.ProbeScrollOffsets) * cascade.ProbesSpacing;

View File

@@ -722,6 +722,10 @@ bool TextureTool::ImportTextureDirectXTex(ImageType type, const StringView& path
errorMsg = String::Format(TEXT("Imported texture has not full mip chain, loaded mips count: {0}, expected: {1}"), sourceMipLevels, mipLevels);
return true;
}
if (options.GenerateMipMaps && !isPowerOfTwo)
{
LOG(Warning, "Cannot generate mip maps for texture '{}' that size is not power of two. Use Resize or Max Size to change dimensions.", StringUtils::GetFileName(path), width, height);
}
// Allocate memory for texture data
auto& data = textureData.Items;

View File

@@ -543,6 +543,10 @@ bool TextureTool::ImportTextureStb(ImageType type, const StringView& path, Textu
errorMsg = String::Format(TEXT("Imported texture has not full mip chain, loaded mips count: {0}, expected: {1}"), sourceMipLevels, mipLevels);
return true;
}
if (options.GenerateMipMaps && !isPowerOfTwo)
{
LOG(Warning, "Cannot generate mip maps for texture '{}' that size is not power of two. Use Resize or Max Size to change dimensions.", StringUtils::GetFileName(path), width, height);
}
// Decompress if texture is compressed (next steps need decompressed input data, for eg. mip maps generation or format changing)
if (PixelFormatExtensions::IsCompressed(textureDataSrc->Format))

View File

@@ -166,8 +166,26 @@ namespace FlaxEngine.GUI
[NoSerialize, HideInEditor]
public Float2 LocalLocation
{
get => _bounds.Location - (_parent != null ? _parent._bounds.Size * (_anchorMax + _anchorMin) * 0.5f : Float2.Zero) + _bounds.Size * _pivot;
set => Bounds = new Rectangle(value + (_parent != null ? _parent.Bounds.Size * (_anchorMax + _anchorMin) * 0.5f : Float2.Zero) - _bounds.Size * _pivot, _bounds.Size);
get
{
var anchor = Float2.Zero;
if (_parent != null)
{
_parent.GetDesireClientArea(out var parentBounds);
anchor = parentBounds.Location + parentBounds.Size * (_anchorMin + _anchorMax) * 0.5f;
}
return _bounds.Location - anchor + _bounds.Size * _pivot;
}
set
{
var anchor = Float2.Zero;
if (_parent != null)
{
_parent.GetDesireClientArea(out var parentBounds);
anchor = parentBounds.Location + parentBounds.Size * (_anchorMin + _anchorMax) * 0.5f;
}
Bounds = new Rectangle(value + anchor - _bounds.Size * _pivot, _bounds.Size);
}
}
/// <summary>

View File

@@ -6,7 +6,6 @@ namespace FlaxEngine.GUI
/// Base class for container controls that can offset controls in a view (eg. scroll panels).
/// </summary>
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
[HideInEditor]
public class ScrollableControl : ContainerControl
{
/// <summary>

View File

@@ -131,6 +131,7 @@ SamplerComparisonState ShadowSamplerLinear : register(s5);
#define SAMPLE_RT_LINEAR(rt, texCoord) rt.SampleLevel(SamplerLinearClamp, texCoord, 0)
#define HDR_CLAMP_MAX 65472.0
#define PI 3.1415926535897932
#define UNITS_TO_METERS_SCALE 0.01f
// Structure that contains information about GBuffer
struct GBufferData

View File

@@ -351,6 +351,7 @@ META_CS(true, FEATURE_LEVEL_SM5)
void CS_UpdateProbesInitArgs()
{
uint activeProbesCount = ActiveProbes.Load(0); // Counter at 0
activeProbesCount = min(activeProbesCount, ProbesCount);
uint arg = 0;
for (uint probesOffset = 0; probesOffset < activeProbesCount; probesOffset += DDGI_TRACE_RAYS_PROBES_COUNT_LIMIT)
{

View File

@@ -68,20 +68,25 @@ void GetRadialLightAttenuation(
// Distance attenuation
if (lightData.InverseSquared)
{
// Convert scene units to meters for inverse-squared falloff
const float distanceScale = UNITS_TO_METERS_SCALE;
const float distanceScaleSqr = distanceScale * distanceScale;
float distanceSqrScaled = distanceSqr * distanceScaleSqr;
float distanceBiasSqrScaled = distanceBiasSqr * distanceScaleSqr;
BRANCH
if (lightData.SourceLength > 0)
{
float3 l01 = lightData.Direction * lightData.SourceLength;
float3 l0 = toLight - 0.5 * l01;
float3 l1 = toLight + 0.5 * l01;
float3 l01 = lightData.Direction * (lightData.SourceLength * distanceScale);
float3 l0 = (toLight * distanceScale) - 0.5 * l01;
float3 l1 = (toLight * distanceScale) + 0.5 * l01;
float lengthL0 = length(l0);
float lengthL1 = length(l1);
attenuation = rcp((lengthL0 * lengthL1 + dot(l0, l1)) * 0.5 + distanceBiasSqr);
attenuation = rcp((lengthL0 * lengthL1 + dot(l0, l1)) * 0.5 + distanceBiasSqrScaled);
NoL = saturate(0.5 * (dot(N, l0) / lengthL0 + dot(N, l1) / lengthL1));
}
else
{
attenuation = rcp(distanceSqr + distanceBiasSqr);
attenuation = rcp(distanceSqrScaled + distanceBiasSqrScaled);
NoL = saturate(dot(N, L));
}
attenuation *= Square(saturate(1 - Square(distanceSqr * Square(lightData.RadiusInv))));

View File

@@ -2429,7 +2429,7 @@ namespace Flax.Build.Bindings
contents.AppendLine();
contents.AppendLine($"[assembly: AssemblyTitle(\"{binaryModuleName}\")]");
contents.AppendLine("[assembly: AssemblyDescription(\"\")]");
contents.AppendLine("[assembly: AssemblyConfiguration(\"\")]");
contents.AppendLine($"[assembly: AssemblyConfiguration(\"{buildData.Configuration}\")]");
contents.AppendLine($"[assembly: AssemblyCompany(\"{project.Company}\")]");
contents.AppendLine("[assembly: AssemblyProduct(\"FlaxEngine\")]");
contents.AppendLine($"[assembly: AssemblyCopyright(\"{project.Copyright}\")]");
@@ -2439,6 +2439,7 @@ namespace Flax.Build.Bindings
contents.AppendLine($"[assembly: Guid(\"{id:d}\")]");
contents.AppendLine($"[assembly: AssemblyVersion(\"{project.Version}\")]");
contents.AppendLine($"[assembly: AssemblyFileVersion(\"{project.Version}\")]");
contents.AppendLine($"[assembly: AssemblyInformationalVersion(\"{project.VersionControlInfo}\")]");
#if USE_NETCORE
contents.AppendLine("[assembly: DisableRuntimeMarshalling]");
#endif

View File

@@ -3289,6 +3289,10 @@ namespace Flax.Build.Bindings
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_REVISION {version.Revision}");
contents.AppendLine($"#define {binaryModuleNameUpper}_COMPANY \"{project.Company}\"");
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
if (project.VersionControlBranch.Length != 0)
contents.AppendLine($"#define {binaryModuleNameUpper}_BRANCH \"{project.VersionControlBranch}\"");
if (project.VersionControlCommit.Length != 0)
contents.AppendLine($"#define {binaryModuleNameUpper}_COMMIT \"{project.VersionControlCommit}\"");
contents.AppendLine();
contents.AppendLine("class BinaryModule;");
contents.AppendLine($"extern \"C\" {binaryModuleNameUpper}_API BinaryModule* GetBinaryModule{binaryModuleName}();");

View File

@@ -145,6 +145,7 @@ namespace Flax.Build
public sealed class ProjectInfo
{
private static List<ProjectInfo> _projectsCache;
private string _versionControlCommit, _versionControlBranch;
/// <summary>
/// The project reference.
@@ -232,6 +233,51 @@ namespace Flax.Build
[System.Text.Json.Serialization.JsonConverter(typeof(ConfigurationDictionaryConverter))]
public Dictionary<string, string> Configuration;
/// <summary>
/// Gets the name of the branch from Version Control System (VCS) used by the project. Empty when unused.
/// </summary>
public string VersionControlBranch
{
get
{
if (_versionControlBranch == null)
InitVersionControlInfo();
return _versionControlBranch;
}
}
/// <summary>
/// Gets the commit hash/changeset identifier from Version Control System (VCS) used by the project. Empty when unused.
/// </summary>
public string VersionControlCommit
{
get
{
if (_versionControlCommit == null)
InitVersionControlInfo();
return _versionControlCommit;
}
}
/// <summary>
/// Gets the informative version of the project including any Version Control System (VCS) information such as branch name, commit hash or changeset identifier.
/// </summary>
public string VersionControlInfo
{
get
{
if (_versionControlCommit == null)
InitVersionControlInfo();
var version = Version.ToString();
if (_versionControlBranch.Length != 0)
version += "+" + _versionControlBranch;
if (_versionControlCommit.Length != 0)
version += "+" + _versionControlCommit;
return version;
}
}
/// <summary>
/// True if project is using C#-only and no native toolsets is required to build and use scripts.
/// </summary>
@@ -267,6 +313,26 @@ namespace Flax.Build
});
}
private void InitVersionControlInfo()
{
_versionControlBranch = string.Empty;
_versionControlCommit = string.Empty;
// Git
if (Directory.Exists(Path.Combine(ProjectFolderPath, ".git")))
{
try
{
_versionControlBranch = Utilities.ReadProcessOutput("git", "rev-parse --abbrev-ref HEAD", ProjectFolderPath);
_versionControlCommit = Utilities.ReadProcessOutput("git", "rev-parse HEAD", ProjectFolderPath);
}
catch (Exception)
{
// Ignored
}
}
}
/// <summary>
/// Gets all projects including this project, it's references and their references (any deep level of references).
/// </summary>

View File

@@ -587,8 +587,9 @@ namespace Flax.Build
/// </summary>
/// <param name="filename">The executable file path.</param>
/// <param name="args">The custom arguments.</param>
/// <param name="workspace">The custom folder to run program in it.</param>
/// <returns>Returned process output.</returns>
public static string ReadProcessOutput(string filename, string args = null)
public static string ReadProcessOutput(string filename, string args = null, string workspace = null)
{
Process p = new Process
{
@@ -599,6 +600,7 @@ namespace Flax.Build
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
WorkingDirectory = workspace,
}
};
p.Start();