Merge branch 'master' into 1.5
This commit is contained in:
@@ -720,14 +720,14 @@ namespace FlaxEditor.Content.GUI
|
|||||||
if (itemsToFit < 1)
|
if (itemsToFit < 1)
|
||||||
itemsToFit = 1;
|
itemsToFit = 1;
|
||||||
float itemsWidth = width / Mathf.Max(itemsToFit, 1);
|
float itemsWidth = width / Mathf.Max(itemsToFit, 1);
|
||||||
itemsWidth = Mathf.Floor(itemsWidth);
|
|
||||||
float itemsHeight = itemsWidth / defaultItemsWidth * (ContentItem.DefaultHeight * viewScale);
|
float itemsHeight = itemsWidth / defaultItemsWidth * (ContentItem.DefaultHeight * viewScale);
|
||||||
itemsHeight = Mathf.Floor(itemsHeight);
|
var flooredItemsWidth = Mathf.Floor(itemsWidth);
|
||||||
|
var flooredItemsHeight = Mathf.Floor(itemsHeight);
|
||||||
x = itemsToFit == 1 ? 0 : itemsWidth / itemsToFit;
|
x = itemsToFit == 1 ? 0 : itemsWidth / itemsToFit;
|
||||||
for (int i = 0; i < _children.Count; i++)
|
for (int i = 0; i < _children.Count; i++)
|
||||||
{
|
{
|
||||||
var c = _children[i];
|
var c = _children[i];
|
||||||
c.Bounds = new Rectangle(x, y, itemsWidth, itemsHeight);
|
c.Bounds = new Rectangle(Mathf.Floor(x), Mathf.Floor(y), flooredItemsWidth, flooredItemsHeight);
|
||||||
|
|
||||||
x += itemsWidth + itemsWidth / itemsToFit;
|
x += itemsWidth + itemsWidth / itemsToFit;
|
||||||
if (x + itemsWidth > width)
|
if (x + itemsWidth > width)
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ namespace FlaxEditor.Gizmo
|
|||||||
if (!_isActive || !IsActive)
|
if (!_isActive || !IsActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Matrix m1, m2, m3;
|
// As all axisMesh have the same pivot, add a little offset to the x axisMesh, this way SortDrawCalls is able to sort the draw order
|
||||||
|
// https://github.com/FlaxEngine/FlaxEngine/issues/680
|
||||||
|
|
||||||
|
Matrix m1, m2, m3, mx1;
|
||||||
bool isXAxis = _activeAxis == Axis.X || _activeAxis == Axis.XY || _activeAxis == Axis.ZX;
|
bool isXAxis = _activeAxis == Axis.X || _activeAxis == Axis.XY || _activeAxis == Axis.ZX;
|
||||||
bool isYAxis = _activeAxis == Axis.Y || _activeAxis == Axis.XY || _activeAxis == Axis.YZ;
|
bool isYAxis = _activeAxis == Axis.Y || _activeAxis == Axis.XY || _activeAxis == Axis.YZ;
|
||||||
bool isZAxis = _activeAxis == Axis.Z || _activeAxis == Axis.YZ || _activeAxis == Axis.ZX;
|
bool isZAxis = _activeAxis == Axis.Z || _activeAxis == Axis.YZ || _activeAxis == Axis.ZX;
|
||||||
@@ -70,6 +73,8 @@ namespace FlaxEditor.Gizmo
|
|||||||
break;
|
break;
|
||||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||||
Matrix.Multiply(ref m3, ref world, out m1);
|
Matrix.Multiply(ref m3, ref world, out m1);
|
||||||
|
mx1 = m1;
|
||||||
|
mx1.M41 += 0.05f;
|
||||||
var axisMesh = _modelTranslateAxis.LODs[0].Meshes[0];
|
var axisMesh = _modelTranslateAxis.LODs[0].Meshes[0];
|
||||||
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
||||||
var boxSize = 10.0f;
|
var boxSize = 10.0f;
|
||||||
@@ -90,7 +95,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
boxMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialWireFocus : _materialWire, ref m3);
|
boxMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialWireFocus : _materialWire, ref m3);
|
||||||
|
|
||||||
// X axis
|
// X axis
|
||||||
axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m1);
|
axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref mx1);
|
||||||
|
|
||||||
// Y axis
|
// Y axis
|
||||||
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
|
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
|
||||||
@@ -143,12 +148,15 @@ namespace FlaxEditor.Gizmo
|
|||||||
break;
|
break;
|
||||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||||
Matrix.Multiply(ref m3, ref world, out m1);
|
Matrix.Multiply(ref m3, ref world, out m1);
|
||||||
|
mx1 = m1;
|
||||||
|
mx1.M41 -= 0.05f;
|
||||||
|
|
||||||
var axisMesh = _modelScaleAxis.LODs[0].Meshes[0];
|
var axisMesh = _modelScaleAxis.LODs[0].Meshes[0];
|
||||||
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
||||||
|
|
||||||
// X axis
|
// X axis
|
||||||
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
|
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
|
||||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
Matrix.Multiply(ref m2, ref mx1, out m3);
|
||||||
axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||||
|
|
||||||
// Y axis
|
// Y axis
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the objects transforming (optionally with duplicate).
|
/// Starts the objects transforming (optionally with duplicate).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void StartTransforming()
|
public void StartTransforming()
|
||||||
{
|
{
|
||||||
// Check if can start new action
|
// Check if can start new action
|
||||||
var count = SelectionCount;
|
var count = SelectionCount;
|
||||||
@@ -119,7 +119,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ends the objects transforming.
|
/// Ends the objects transforming.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void EndTransforming()
|
public void EndTransforming()
|
||||||
{
|
{
|
||||||
// Check if wasn't working at all
|
// Check if wasn't working at all
|
||||||
if (!_isTransforming)
|
if (!_isTransforming)
|
||||||
@@ -287,12 +287,29 @@ namespace FlaxEditor.Gizmo
|
|||||||
delta *= 0.5f;
|
delta *= 0.5f;
|
||||||
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
|
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
|
||||||
{
|
{
|
||||||
float snapValue = isScaling ? ScaleSnapValue : TranslationSnapValue;
|
var snapValue = new Vector3(isScaling ? ScaleSnapValue : TranslationSnapValue);
|
||||||
_translationScaleSnapDelta += delta;
|
_translationScaleSnapDelta += delta;
|
||||||
|
if (!isScaling && snapValue.X < 0.0f)
|
||||||
|
{
|
||||||
|
// Snap to object bounding box
|
||||||
|
GetSelectedObjectsBounds(out var b, out _);
|
||||||
|
if (b.Minimum.X < 0.0f)
|
||||||
|
snapValue.X = (Real)Math.Abs(b.Minimum.X) + b.Maximum.X;
|
||||||
|
else
|
||||||
|
snapValue.X = (Real)b.Minimum.X - b.Maximum.X;
|
||||||
|
if (b.Minimum.Y < 0.0f)
|
||||||
|
snapValue.Y = (Real)Math.Abs(b.Minimum.Y) + b.Maximum.Y;
|
||||||
|
else
|
||||||
|
snapValue.Y = (Real)b.Minimum.Y - b.Maximum.Y;
|
||||||
|
if (b.Minimum.Z < 0.0f)
|
||||||
|
snapValue.Z = (Real)Math.Abs(b.Minimum.Z) + b.Maximum.Z;
|
||||||
|
else
|
||||||
|
snapValue.Z = (Real)b.Minimum.Z - b.Maximum.Z;
|
||||||
|
}
|
||||||
delta = new Vector3(
|
delta = new Vector3(
|
||||||
(int)(_translationScaleSnapDelta.X / snapValue) * snapValue,
|
(int)(_translationScaleSnapDelta.X / snapValue.X) * snapValue.X,
|
||||||
(int)(_translationScaleSnapDelta.Y / snapValue) * snapValue,
|
(int)(_translationScaleSnapDelta.Y / snapValue.Y) * snapValue.Y,
|
||||||
(int)(_translationScaleSnapDelta.Z / snapValue) * snapValue);
|
(int)(_translationScaleSnapDelta.Z / snapValue.Z) * snapValue.Z);
|
||||||
_translationScaleSnapDelta -= delta;
|
_translationScaleSnapDelta -= delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,10 +463,9 @@ namespace FlaxEditor.Gizmo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply transformation (but to the parents, not whole selection pool)
|
// Apply transformation (but to the parents, not whole selection pool)
|
||||||
if (anyValid)
|
if (anyValid || (!_isTransforming && Owner.UseDuplicate))
|
||||||
{
|
{
|
||||||
StartTransforming();
|
StartTransforming();
|
||||||
|
|
||||||
LastDelta = new Transform(translationDelta, rotationDelta, scaleDelta);
|
LastDelta = new Transform(translationDelta, rotationDelta, scaleDelta);
|
||||||
OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta);
|
OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Common"), EditorOrder(220)]
|
[EditorDisplay("Common"), EditorOrder(220)]
|
||||||
public InputBinding ContentFinder = new InputBinding(KeyboardKeys.O, KeyboardKeys.Control);
|
public InputBinding ContentFinder = new InputBinding(KeyboardKeys.O, KeyboardKeys.Control);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "R")]
|
||||||
|
[EditorDisplay("Common"), EditorOrder(230)]
|
||||||
|
public InputBinding RotateSelection = new InputBinding(KeyboardKeys.R);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Scene
|
#region Scene
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Texture", true, typeof(FlaxEngine.Object), 0),
|
NodeElementArchetype.Factory.Input(0, "Texture", true, typeof(FlaxEngine.Object), 0),
|
||||||
NodeElementArchetype.Factory.Input(1, "Scale", true, typeof(float), 1, 0),
|
NodeElementArchetype.Factory.Input(1, "Scale", true, typeof(Float3), 1, 0),
|
||||||
NodeElementArchetype.Factory.Input(2, "Blend", true, typeof(float), 2, 1),
|
NodeElementArchetype.Factory.Input(2, "Blend", true, typeof(float), 2, 1),
|
||||||
NodeElementArchetype.Factory.Output(0, "Color", typeof(Float3), 3)
|
NodeElementArchetype.Factory.Output(0, "Color", typeof(Float3), 3)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
TooltipText = "Position snapping values"
|
TooltipText = "Position snapping values"
|
||||||
};
|
};
|
||||||
|
if (TransformGizmo.TranslationSnapValue < 0.0f)
|
||||||
|
_translateSnapping.Text = "Bounding Box";
|
||||||
|
|
||||||
for (int i = 0; i < EditorViewportTranslateSnapValues.Length; i++)
|
for (int i = 0; i < EditorViewportTranslateSnapValues.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -326,6 +328,9 @@ namespace FlaxEditor.Viewport
|
|||||||
var button = translateSnappingCM.AddButton(v.ToString());
|
var button = translateSnappingCM.AddButton(v.ToString());
|
||||||
button.Tag = v;
|
button.Tag = v;
|
||||||
}
|
}
|
||||||
|
var buttonBB = translateSnappingCM.AddButton("Bounding Box").LinkTooltip("Snaps the selection based on it's bounding volume");
|
||||||
|
buttonBB.Tag = -1.0f;
|
||||||
|
|
||||||
translateSnappingCM.ButtonClicked += OnWidgetTranslateSnapClick;
|
translateSnappingCM.ButtonClicked += OnWidgetTranslateSnapClick;
|
||||||
translateSnappingCM.VisibleChanged += OnWidgetTranslateSnapShowHide;
|
translateSnappingCM.VisibleChanged += OnWidgetTranslateSnapShowHide;
|
||||||
_translateSnapping.Parent = translateSnappingWidget;
|
_translateSnapping.Parent = translateSnappingWidget;
|
||||||
@@ -378,6 +383,7 @@ namespace FlaxEditor.Viewport
|
|||||||
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||||
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||||
InputActions.Add(options => options.FocusSelection, FocusSelection);
|
InputActions.Add(options => options.FocusSelection, FocusSelection);
|
||||||
|
InputActions.Add(options => options.RotateSelection, RotateSelection);
|
||||||
InputActions.Add(options => options.Delete, _editor.SceneEditing.Delete);
|
InputActions.Add(options => options.Delete, _editor.SceneEditing.Delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,28 +545,24 @@ namespace FlaxEditor.Viewport
|
|||||||
private void OnTranslateSnappingToggle(ViewportWidgetButton button)
|
private void OnTranslateSnappingToggle(ViewportWidgetButton button)
|
||||||
{
|
{
|
||||||
TransformGizmo.TranslationSnapEnable = !TransformGizmo.TranslationSnapEnable;
|
TransformGizmo.TranslationSnapEnable = !TransformGizmo.TranslationSnapEnable;
|
||||||
// cache value
|
|
||||||
_editor.ProjectCache.SetCustomData("TranslateSnapState", TransformGizmo.TranslationSnapEnable.ToString());
|
_editor.ProjectCache.SetCustomData("TranslateSnapState", TransformGizmo.TranslationSnapEnable.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRotateSnappingToggle(ViewportWidgetButton button)
|
private void OnRotateSnappingToggle(ViewportWidgetButton button)
|
||||||
{
|
{
|
||||||
TransformGizmo.RotationSnapEnabled = !TransformGizmo.RotationSnapEnabled;
|
TransformGizmo.RotationSnapEnabled = !TransformGizmo.RotationSnapEnabled;
|
||||||
// cache value
|
|
||||||
_editor.ProjectCache.SetCustomData("RotationSnapState", TransformGizmo.RotationSnapEnabled.ToString());
|
_editor.ProjectCache.SetCustomData("RotationSnapState", TransformGizmo.RotationSnapEnabled.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnScaleSnappingToggle(ViewportWidgetButton button)
|
private void OnScaleSnappingToggle(ViewportWidgetButton button)
|
||||||
{
|
{
|
||||||
TransformGizmo.ScaleSnapEnabled = !TransformGizmo.ScaleSnapEnabled;
|
TransformGizmo.ScaleSnapEnabled = !TransformGizmo.ScaleSnapEnabled;
|
||||||
// cache value
|
|
||||||
_editor.ProjectCache.SetCustomData("ScaleSnapState", TransformGizmo.ScaleSnapEnabled.ToString());
|
_editor.ProjectCache.SetCustomData("ScaleSnapState", TransformGizmo.ScaleSnapEnabled.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTransformSpaceToggle(ViewportWidgetButton button)
|
private void OnTransformSpaceToggle(ViewportWidgetButton button)
|
||||||
{
|
{
|
||||||
TransformGizmo.ToggleTransformSpace();
|
TransformGizmo.ToggleTransformSpace();
|
||||||
// cache value
|
|
||||||
_editor.ProjectCache.SetCustomData("TransformSpaceState", TransformGizmo.ActiveTransformSpace.ToString());
|
_editor.ProjectCache.SetCustomData("TransformSpaceState", TransformGizmo.ActiveTransformSpace.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,7 +593,6 @@ namespace FlaxEditor.Viewport
|
|||||||
var v = (float)button.Tag;
|
var v = (float)button.Tag;
|
||||||
TransformGizmo.ScaleSnapValue = v;
|
TransformGizmo.ScaleSnapValue = v;
|
||||||
_scaleSnapping.Text = v.ToString();
|
_scaleSnapping.Text = v.ToString();
|
||||||
// cache value
|
|
||||||
_editor.ProjectCache.SetCustomData("ScaleSnapValue", TransformGizmo.ScaleSnapValue.ToString("N"));
|
_editor.ProjectCache.SetCustomData("ScaleSnapValue", TransformGizmo.ScaleSnapValue.ToString("N"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,7 +631,6 @@ namespace FlaxEditor.Viewport
|
|||||||
var v = (float)button.Tag;
|
var v = (float)button.Tag;
|
||||||
TransformGizmo.RotationSnapValue = v;
|
TransformGizmo.RotationSnapValue = v;
|
||||||
_rotateSnapping.Text = v.ToString();
|
_rotateSnapping.Text = v.ToString();
|
||||||
// cache value
|
|
||||||
_editor.ProjectCache.SetCustomData("RotationSnapValue", TransformGizmo.RotationSnapValue.ToString("N"));
|
_editor.ProjectCache.SetCustomData("RotationSnapValue", TransformGizmo.RotationSnapValue.ToString("N"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,8 +667,10 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
var v = (float)button.Tag;
|
var v = (float)button.Tag;
|
||||||
TransformGizmo.TranslationSnapValue = v;
|
TransformGizmo.TranslationSnapValue = v;
|
||||||
_translateSnapping.Text = v.ToString();
|
if (v < 0.0f)
|
||||||
// cache value
|
_translateSnapping.Text = "Bounding Box";
|
||||||
|
else
|
||||||
|
_translateSnapping.Text = v.ToString();
|
||||||
_editor.ProjectCache.SetCustomData("TranslateSnapValue", TransformGizmo.TranslationSnapValue.ToString("N"));
|
_editor.ProjectCache.SetCustomData("TranslateSnapValue", TransformGizmo.TranslationSnapValue.ToString("N"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,6 +698,51 @@ namespace FlaxEditor.Viewport
|
|||||||
Gizmos.ForEach(x => x.OnSelectionChanged(selection));
|
Gizmos.ForEach(x => x.OnSelectionChanged(selection));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Press "R" to rotate the selected gizmo objects 45 degrees.
|
||||||
|
/// </summary>
|
||||||
|
public void RotateSelection()
|
||||||
|
{
|
||||||
|
var win = (WindowRootControl)Root;
|
||||||
|
var selection = _editor.SceneEditing.Selection;
|
||||||
|
var isShiftDown = win.GetKey(KeyboardKeys.Shift);
|
||||||
|
|
||||||
|
Quaternion rotationDelta;
|
||||||
|
if (isShiftDown)
|
||||||
|
rotationDelta = Quaternion.Euler(0.0f, -45.0f, 0.0f);
|
||||||
|
else
|
||||||
|
rotationDelta = Quaternion.Euler(0.0f, 45.0f, 0.0f);
|
||||||
|
|
||||||
|
bool useObjCenter = TransformGizmo.ActivePivot == TransformGizmoBase.PivotType.ObjectCenter;
|
||||||
|
Vector3 gizmoPosition = TransformGizmo.Position;
|
||||||
|
|
||||||
|
// Rotate selected objects
|
||||||
|
bool isPlayMode = Editor.Instance.StateMachine.IsPlayMode;
|
||||||
|
TransformGizmo.StartTransforming();
|
||||||
|
for (int i = 0; i < selection.Count; i++)
|
||||||
|
{
|
||||||
|
var obj = selection[i];
|
||||||
|
if (isPlayMode && obj.CanTransform == false)
|
||||||
|
continue;
|
||||||
|
var trans = obj.Transform;
|
||||||
|
var pivotOffset = trans.Translation - gizmoPosition;
|
||||||
|
if (useObjCenter || pivotOffset.IsZero)
|
||||||
|
{
|
||||||
|
trans.Orientation *= Quaternion.Invert(trans.Orientation) * rotationDelta * trans.Orientation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Matrix.RotationQuaternion(ref trans.Orientation, out var transWorld);
|
||||||
|
Matrix.RotationQuaternion(ref rotationDelta, out var deltaWorld);
|
||||||
|
Matrix world = transWorld * Matrix.Translation(pivotOffset) * deltaWorld * Matrix.Translation(-pivotOffset);
|
||||||
|
trans.SetRotation(ref world);
|
||||||
|
trans.Translation += world.TranslationVector;
|
||||||
|
}
|
||||||
|
obj.Transform = trans;
|
||||||
|
}
|
||||||
|
TransformGizmo.EndTransforming();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Focuses the viewport on the current selection of the gizmo.
|
/// Focuses the viewport on the current selection of the gizmo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ namespace FlaxEditor.Windows
|
|||||||
private readonly GameRoot _guiRoot;
|
private readonly GameRoot _guiRoot;
|
||||||
private bool _showGUI = true;
|
private bool _showGUI = true;
|
||||||
private bool _showDebugDraw = false;
|
private bool _showDebugDraw = false;
|
||||||
private bool _isMaximized = false;
|
private bool _isMaximized = false, _isUnlockingMouse = false;
|
||||||
|
private bool _cursorVisible = true;
|
||||||
private float _gameStartTime;
|
private float _gameStartTime;
|
||||||
private GUI.Docking.DockState _maximizeRestoreDockState;
|
private GUI.Docking.DockState _maximizeRestoreDockState;
|
||||||
private GUI.Docking.DockPanel _maximizeRestoreDockTo;
|
private GUI.Docking.DockPanel _maximizeRestoreDockTo;
|
||||||
@@ -460,14 +461,20 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
if (Editor.StateMachine.IsPlayMode)
|
if (Editor.StateMachine.IsPlayMode)
|
||||||
{
|
{
|
||||||
Screen.CursorVisible = true;
|
// Cache cursor
|
||||||
Focus(null);
|
_cursorVisible = Screen.CursorVisible;
|
||||||
Editor.Windows.MainWindow.Focus();
|
_cursorLockMode = Screen.CursorLock;
|
||||||
if (Editor.Windows.PropertiesWin.IsDocked)
|
|
||||||
Editor.Windows.PropertiesWin.Focus();
|
|
||||||
Screen.CursorVisible = true;
|
Screen.CursorVisible = true;
|
||||||
if (Screen.CursorLock == CursorLockMode.Clipped)
|
if (Screen.CursorLock == CursorLockMode.Clipped)
|
||||||
Screen.CursorLock = CursorLockMode.None;
|
Screen.CursorLock = CursorLockMode.None;
|
||||||
|
|
||||||
|
// Defocus
|
||||||
|
_isUnlockingMouse = true;
|
||||||
|
Focus(null);
|
||||||
|
_isUnlockingMouse = false;
|
||||||
|
Editor.Windows.MainWindow.Focus();
|
||||||
|
if (Editor.Windows.PropertiesWin.IsDocked)
|
||||||
|
Editor.Windows.PropertiesWin.Focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -552,9 +559,11 @@ namespace FlaxEditor.Windows
|
|||||||
Root.MousePosition = center;
|
Root.MousePosition = center;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore lock mode
|
// Restore cursor
|
||||||
if (_cursorLockMode != CursorLockMode.None)
|
if (_cursorLockMode != CursorLockMode.None)
|
||||||
Screen.CursorLock = _cursorLockMode;
|
Screen.CursorLock = _cursorLockMode;
|
||||||
|
if (!_cursorVisible)
|
||||||
|
Screen.CursorVisible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,11 +572,16 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
base.OnEndContainsFocus();
|
base.OnEndContainsFocus();
|
||||||
|
|
||||||
// Restore cursor visibility (could be hidden by the game)
|
if (!_isUnlockingMouse)
|
||||||
Screen.CursorVisible = true;
|
{
|
||||||
|
// Cache cursor
|
||||||
|
_cursorVisible = Screen.CursorVisible;
|
||||||
|
_cursorLockMode = Screen.CursorLock;
|
||||||
|
|
||||||
// Cache lock mode
|
// Restore cursor visibility (could be hidden by the game)
|
||||||
_cursorLockMode = Screen.CursorLock;
|
if (!_cursorVisible)
|
||||||
|
Screen.CursorVisible = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ bool AudioClip::StreamingTask::Run()
|
|||||||
{
|
{
|
||||||
AssetReference<AudioClip> ref = _asset.Get();
|
AssetReference<AudioClip> ref = _asset.Get();
|
||||||
if (ref == nullptr)
|
if (ref == nullptr)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
ScopeLock lock(ref->Locker);
|
||||||
const auto& queue = ref->StreamingQueue;
|
const auto& queue = ref->StreamingQueue;
|
||||||
|
if (queue.Count() == 0)
|
||||||
|
return false;
|
||||||
auto clip = ref.Get();
|
auto clip = ref.Get();
|
||||||
|
|
||||||
// Update the buffers
|
// Update the buffers
|
||||||
@@ -108,7 +109,6 @@ bool AudioClip::StreamingTask::Run()
|
|||||||
for (int32 sourceIndex = 0; sourceIndex < Audio::Sources.Count(); sourceIndex++)
|
for (int32 sourceIndex = 0; sourceIndex < Audio::Sources.Count(); sourceIndex++)
|
||||||
{
|
{
|
||||||
// TODO: collect refs to audio clip from sources and use faster iteration (but do it thread-safe)
|
// TODO: collect refs to audio clip from sources and use faster iteration (but do it thread-safe)
|
||||||
|
|
||||||
const auto src = Audio::Sources[sourceIndex];
|
const auto src = Audio::Sources[sourceIndex];
|
||||||
if (src->Clip == clip && src->GetState() == AudioSource::States::Playing)
|
if (src->Clip == clip && src->GetState() == AudioSource::States::Playing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -130,6 +130,10 @@ void AudioSource::Play()
|
|||||||
{
|
{
|
||||||
// Request faster streaming update
|
// Request faster streaming update
|
||||||
Clip->RequestStreamingUpdate();
|
Clip->RequestStreamingUpdate();
|
||||||
|
|
||||||
|
// If we are looping and streaming also update streaming buffers
|
||||||
|
if (_loop)
|
||||||
|
RequestStreamingBuffersUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -368,6 +372,7 @@ void AudioSource::Update()
|
|||||||
if (!UseStreaming() || SourceIDs.IsEmpty())
|
if (!UseStreaming() || SourceIDs.IsEmpty())
|
||||||
return;
|
return;
|
||||||
auto clip = Clip.Get();
|
auto clip = Clip.Get();
|
||||||
|
clip->Locker.Lock();
|
||||||
|
|
||||||
// Handle streaming buffers queue submit (ensure that clip has loaded the first chunk with audio data)
|
// Handle streaming buffers queue submit (ensure that clip has loaded the first chunk with audio data)
|
||||||
if (_needToUpdateStreamingBuffers && clip->Buffers[_streamingFirstChunk] != AUDIO_BUFFER_ID_INVALID)
|
if (_needToUpdateStreamingBuffers && clip->Buffers[_streamingFirstChunk] != AUDIO_BUFFER_ID_INVALID)
|
||||||
@@ -437,6 +442,8 @@ void AudioSource::Update()
|
|||||||
clip->RequestStreamingUpdate();
|
clip->RequestStreamingUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clip->Locker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::OnEnable()
|
void AudioSource::OnEnable()
|
||||||
|
|||||||
@@ -139,10 +139,12 @@ namespace ALC
|
|||||||
|
|
||||||
alSourcef(sourceID, AL_GAIN, source->GetVolume());
|
alSourcef(sourceID, AL_GAIN, source->GetVolume());
|
||||||
alSourcef(sourceID, AL_PITCH, source->GetPitch());
|
alSourcef(sourceID, AL_PITCH, source->GetPitch());
|
||||||
|
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
|
||||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
|
alSourcef(sourceID, AL_REFERENCE_DISTANCE, source->GetMinDistance());
|
||||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
alSourcef(sourceID, AL_ROLLOFF_FACTOR, source->GetAttenuation());
|
||||||
alSourcei(sourceID, AL_LOOPING, loop);
|
alSourcei(sourceID, AL_LOOPING, loop);
|
||||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
|
alSourcei(sourceID, AL_SOURCE_RELATIVE, !is3D);
|
||||||
|
alSourcei(sourceID, AL_BUFFER, 0);
|
||||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
||||||
alSource3f(sourceID, AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
|
alSource3f(sourceID, AL_VELOCITY, FLAX_POS_TO_OAL(velocity));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -281,7 +281,6 @@ bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
|
|||||||
auto& e = i->Value;
|
auto& e = i->Value;
|
||||||
if (e.Info.Path == path)
|
if (e.Info.Path == path)
|
||||||
{
|
{
|
||||||
// Validate file exists
|
|
||||||
if (!IsEntryValid(e))
|
if (!IsEntryValid(e))
|
||||||
{
|
{
|
||||||
LOG(Warning, "Missing file from registry: \'{0}\':{1}:{2}", e.Info.Path, e.Info.ID, e.Info.TypeName);
|
LOG(Warning, "Missing file from registry: \'{0}\':{1}:{2}", e.Info.Path, e.Info.ID, e.Info.TypeName);
|
||||||
@@ -304,15 +303,11 @@ bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
|
|||||||
bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
ScopeLock lock(_locker);
|
ScopeLock lock(_locker);
|
||||||
|
|
||||||
auto e = _registry.TryGet(id);
|
auto e = _registry.TryGet(id);
|
||||||
if (e != nullptr)
|
if (e != nullptr)
|
||||||
{
|
{
|
||||||
// Validate entry
|
|
||||||
if (!IsEntryValid(*e))
|
if (!IsEntryValid(*e))
|
||||||
{
|
{
|
||||||
LOG(Warning, "Missing file from registry: \'{0}\':{1}:{2}", e->Info.Path, e->Info.ID, e->Info.TypeName);
|
LOG(Warning, "Missing file from registry: \'{0}\':{1}:{2}", e->Info.Path, e->Info.ID, e->Info.TypeName);
|
||||||
@@ -325,7 +320,6 @@ bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
|||||||
info = e->Info;
|
info = e->Info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,8 +373,26 @@ void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
|||||||
// Check if storage contains ID which has been already registered
|
// Check if storage contains ID which has been already registered
|
||||||
if (FindAsset(e.ID, info))
|
if (FindAsset(e.ID, info))
|
||||||
{
|
{
|
||||||
|
#if PLATFORM_WINDOWS
|
||||||
|
// On Windows - if you start your project using a shortcut/VS commandline -project, and using a upper/lower drive letter, it could the cache (case doesn't matter on OS)
|
||||||
|
if (StringUtils::CompareIgnoreCase(storagePath.GetText(), info.Path.GetText()) != 0)
|
||||||
|
{
|
||||||
|
LOG(Warning, "Founded duplicated asset \'{0}\'. Locations: \'{1}\' and \'{2}\'", e.ID, storagePath, info.Path);
|
||||||
|
duplicatedEntries.Add(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove from registry so we can add it again later with the original ID, so we don't loose relations
|
||||||
|
for (auto j = _registry.Begin(); j.IsNotEnd(); ++j)
|
||||||
|
{
|
||||||
|
if (StringUtils::CompareIgnoreCase(j->Value.Info.Path.GetText(), storagePath.GetText()) == 0)
|
||||||
|
_registry.Remove(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
LOG(Warning, "Founded duplicated asset \'{0}\'. Locations: \'{1}\' and \'{2}\'", e.ID, storagePath, info.Path);
|
LOG(Warning, "Founded duplicated asset \'{0}\'. Locations: \'{1}\' and \'{2}\'", e.ID, storagePath, info.Path);
|
||||||
duplicatedEntries.Add(i);
|
duplicatedEntries.Add(i);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,7 +563,6 @@ bool AssetsCache::RenameAsset(const StringView& oldPath, const StringView& newPa
|
|||||||
bool AssetsCache::IsEntryValid(Entry& e)
|
bool AssetsCache::IsEntryValid(Entry& e)
|
||||||
{
|
{
|
||||||
#if ENABLE_ASSETS_DISCOVERY
|
#if ENABLE_ASSETS_DISCOVERY
|
||||||
|
|
||||||
// Check if file exists
|
// Check if file exists
|
||||||
if (FileSystem::FileExists(e.Info.Path))
|
if (FileSystem::FileExists(e.Info.Path))
|
||||||
{
|
{
|
||||||
@@ -601,10 +612,8 @@ bool AssetsCache::IsEntryValid(Entry& e)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// In game we don't care about it because all cached asset entries are valid (precached)
|
// In game we don't care about it because all cached asset entries are valid (precached)
|
||||||
// Skip only entries with missing file
|
// Skip only entries with missing file
|
||||||
return e.Info.Path.HasChars();
|
return e.Info.Path.HasChars();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ bool String::IsANSI() const
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
for (int32 i = 0; i < _length; i++)
|
for (int32 i = 0; i < _length; i++)
|
||||||
{
|
{
|
||||||
if (_data[i] > 255)
|
if (_data[i] > 127)
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
|
|
||||||
Nullable<bool> Fullscreen;
|
Nullable<bool> Fullscreen;
|
||||||
Nullable<Float2> Size;
|
Nullable<Float2> Size;
|
||||||
static CursorLockMode CursorLock = CursorLockMode::None;
|
bool CursorVisible = true;
|
||||||
|
CursorLockMode CursorLock = CursorLockMode::None;
|
||||||
|
|
||||||
class ScreenService : public EngineService
|
class ScreenService : public EngineService
|
||||||
{
|
{
|
||||||
@@ -25,6 +26,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Update() override;
|
||||||
void Draw() override;
|
void Draw() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -88,12 +90,7 @@ Float2 Screen::GameViewportToScreen(const Float2& viewportPos)
|
|||||||
|
|
||||||
bool Screen::GetCursorVisible()
|
bool Screen::GetCursorVisible()
|
||||||
{
|
{
|
||||||
#if USE_EDITOR
|
return CursorVisible;
|
||||||
const auto win = Editor::Managed->GetGameWindow(true);
|
|
||||||
#else
|
|
||||||
const auto win = Engine::MainWindow;
|
|
||||||
#endif
|
|
||||||
return win ? win->GetCursor() != CursorType::Hidden : true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::SetCursorVisible(const bool value)
|
void Screen::SetCursorVisible(const bool value)
|
||||||
@@ -107,6 +104,7 @@ void Screen::SetCursorVisible(const bool value)
|
|||||||
{
|
{
|
||||||
win->SetCursor(value ? CursorType::Default : CursorType::Hidden);
|
win->SetCursor(value ? CursorType::Default : CursorType::Hidden);
|
||||||
}
|
}
|
||||||
|
CursorVisible = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
CursorLockMode Screen::GetCursorLock()
|
CursorLockMode Screen::GetCursorLock()
|
||||||
@@ -137,6 +135,14 @@ void Screen::SetCursorLock(CursorLockMode mode)
|
|||||||
CursorLock = mode;
|
CursorLock = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScreenService::Update()
|
||||||
|
{
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Sync current cursor state in Editor (eg. when viewport focus can change)
|
||||||
|
Screen::SetCursorVisible(CursorVisible);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void ScreenService::Draw()
|
void ScreenService::Draw()
|
||||||
{
|
{
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|||||||
@@ -697,6 +697,7 @@ ManagedBinaryModule::ManagedBinaryModule(MAssembly* assembly)
|
|||||||
// Bind for C# assembly events
|
// Bind for C# assembly events
|
||||||
assembly->Loading.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnLoading>(this);
|
assembly->Loading.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnLoading>(this);
|
||||||
assembly->Loaded.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnLoaded>(this);
|
assembly->Loaded.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnLoaded>(this);
|
||||||
|
assembly->Unloading.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnUnloading>(this);
|
||||||
assembly->Unloaded.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnUnloaded>(this);
|
assembly->Unloaded.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnUnloaded>(this);
|
||||||
|
|
||||||
if (Assembly->IsLoaded())
|
if (Assembly->IsLoaded())
|
||||||
@@ -1117,17 +1118,24 @@ void ManagedBinaryModule::InitType(MClass* mclass)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManagedBinaryModule::OnUnloaded(MAssembly* assembly)
|
void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
|
||||||
// Clear managed-only types
|
// Clear managed types typenames
|
||||||
for (int32 i = _firstManagedTypeIndex; i < Types.Count(); i++)
|
for (int32 i = _firstManagedTypeIndex; i < Types.Count(); i++)
|
||||||
{
|
{
|
||||||
const ScriptingType& type = Types[i];
|
const ScriptingType& type = Types[i];
|
||||||
const MString typeName(type.Fullname.Get(), type.Fullname.Length());
|
const MString typeName(type.Fullname.Get(), type.Fullname.Length());
|
||||||
TypeNameToTypeIndex.Remove(typeName);
|
TypeNameToTypeIndex.Remove(typeName);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManagedBinaryModule::OnUnloaded(MAssembly* assembly)
|
||||||
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
|
|
||||||
|
// Clear managed-only types
|
||||||
Types.Resize(_firstManagedTypeIndex);
|
Types.Resize(_firstManagedTypeIndex);
|
||||||
for (int32 i = 0; i < _managedMemoryBlocks.Count(); i++)
|
for (int32 i = 0; i < _managedMemoryBlocks.Count(); i++)
|
||||||
Allocator::Free(_managedMemoryBlocks[i]);
|
Allocator::Free(_managedMemoryBlocks[i]);
|
||||||
|
|||||||
@@ -309,6 +309,7 @@ private:
|
|||||||
void OnLoading(MAssembly* assembly);
|
void OnLoading(MAssembly* assembly);
|
||||||
void OnLoaded(MAssembly* assembly);
|
void OnLoaded(MAssembly* assembly);
|
||||||
void InitType(MClass* mclass);
|
void InitType(MClass* mclass);
|
||||||
|
void OnUnloading(MAssembly* assembly);
|
||||||
void OnUnloaded(MAssembly* assembly);
|
void OnUnloaded(MAssembly* assembly);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -868,6 +868,20 @@ ScriptingObject* Scripting::TryFindObject(Guid id, MClass* type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptingObject* Scripting::TryFindObject(MClass* mclass)
|
||||||
|
{
|
||||||
|
if (mclass == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
ScopeLock lock(_objectsLocker);
|
||||||
|
for (auto i = _objectsDictionary.Begin(); i.IsNotEnd(); ++i)
|
||||||
|
{
|
||||||
|
const auto obj = i->Value;
|
||||||
|
if (obj->GetClass() == mclass)
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
ScriptingObject* Scripting::FindObject(const MObject* managedInstance)
|
ScriptingObject* Scripting::FindObject(const MObject* managedInstance)
|
||||||
{
|
{
|
||||||
if (managedInstance == nullptr)
|
if (managedInstance == nullptr)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public:
|
|||||||
/// <param name="fullname">The full name of the type eg: System.Int64.</param>
|
/// <param name="fullname">The full name of the type eg: System.Int64.</param>
|
||||||
/// <returns>The MClass object or null if missing.</returns>
|
/// <returns>The MClass object or null if missing.</returns>
|
||||||
static MClass* FindClass(const StringAnsiView& fullname);
|
static MClass* FindClass(const StringAnsiView& fullname);
|
||||||
|
|
||||||
#if USE_MONO
|
#if USE_MONO
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the class from the given Mono class object within whole assembly.
|
/// Finds the class from the given Mono class object within whole assembly.
|
||||||
@@ -144,6 +144,12 @@ public:
|
|||||||
/// <returns>The found object or null if missing.</returns>
|
/// <returns>The found object or null if missing.</returns>
|
||||||
static ScriptingObject* FindObject(Guid id, MClass* type = nullptr);
|
static ScriptingObject* FindObject(Guid id, MClass* type = nullptr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to find the object by the given class.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The found object or null if missing.</returns>
|
||||||
|
static ScriptingObject* TryFindObject(MClass* type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find the object by the given identifier.
|
/// Tries to find the object by the given identifier.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
24
Source/Engine/Tests/TestModelTool.cpp
Normal file
24
Source/Engine/Tests/TestModelTool.cpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#include "Engine/Tools/ModelTool/ModelTool.h"
|
||||||
|
#include <ThirdParty/catch2/catch.hpp>
|
||||||
|
|
||||||
|
TEST_CASE("ModelTool")
|
||||||
|
{
|
||||||
|
SECTION("Test DetectLodIndex")
|
||||||
|
{
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh")) == 0);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh LOD")) == 0);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh LOD0")) == 0);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh LOD1")) == 1);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh_LOD1")) == 1);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh_lod1")) == 1);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh_lod2")) == 2);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("lod0")) == 0);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("lod1")) == 1);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("lod_2")) == 2);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh_lod_0")) == 0);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh_lod_1")) == 1);
|
||||||
|
CHECK(ModelTool::DetectLodIndex(TEXT("mesh lod_2")) == 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Flax.Build;
|
using Flax.Build;
|
||||||
|
using Flax.Build.NativeCpp;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Engine tests module.
|
/// Engine tests module.
|
||||||
@@ -14,6 +15,14 @@ public class Tests : EngineModule
|
|||||||
Deploy = false;
|
Deploy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Setup(BuildOptions options)
|
||||||
|
{
|
||||||
|
base.Setup(options);
|
||||||
|
|
||||||
|
options.PrivateDependencies.Add("ModelTool");
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void GetFilesToDeploy(List<string> files)
|
public override void GetFilesToDeploy(List<string> files)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -467,7 +467,7 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto texture = eatBox(textureBox->GetParent<Node>(), textureBox->FirstConnection());
|
const auto texture = eatBox(textureBox->GetParent<Node>(), textureBox->FirstConnection());
|
||||||
const auto scale = tryGetValue(scaleBox, node->Values[0]).AsFloat();
|
const auto scale = tryGetValue(scaleBox, node->Values[0]).AsFloat3();
|
||||||
const auto blend = tryGetValue(blendBox, node->Values[1]).AsFloat();
|
const auto blend = tryGetValue(blendBox, node->Values[1]).AsFloat();
|
||||||
|
|
||||||
auto result = writeLocal(Value::InitForZero(ValueType::Float4), node);
|
auto result = writeLocal(Value::InitForZero(ValueType::Float4), node);
|
||||||
|
|||||||
@@ -641,6 +641,7 @@ bool ModelTool::ImportDataAssimp(const char* path, ImportedModelData& data, Opti
|
|||||||
aiProcess_JoinIdenticalVertices |
|
aiProcess_JoinIdenticalVertices |
|
||||||
aiProcess_LimitBoneWeights |
|
aiProcess_LimitBoneWeights |
|
||||||
aiProcess_Triangulate |
|
aiProcess_Triangulate |
|
||||||
|
aiProcess_SortByPType |
|
||||||
aiProcess_GenUVCoords |
|
aiProcess_GenUVCoords |
|
||||||
aiProcess_FindDegenerates |
|
aiProcess_FindDegenerates |
|
||||||
aiProcess_FindInvalidData |
|
aiProcess_FindInvalidData |
|
||||||
|
|||||||
@@ -1552,21 +1552,21 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
|
|||||||
|
|
||||||
int32 ModelTool::DetectLodIndex(const String& nodeName)
|
int32 ModelTool::DetectLodIndex(const String& nodeName)
|
||||||
{
|
{
|
||||||
const int32 index = nodeName.FindLast(TEXT("LOD"));
|
int32 index = nodeName.FindLast(TEXT("LOD"), StringSearchCase::IgnoreCase);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
|
// Some models use LOD_0 to identify LOD levels
|
||||||
|
if (nodeName.Length() > index + 4 && nodeName[index + 3] == '_')
|
||||||
|
index++;
|
||||||
|
|
||||||
int32 num;
|
int32 num;
|
||||||
if (!StringUtils::Parse(nodeName.Get() + index + 3, &num))
|
if (!StringUtils::Parse(nodeName.Get() + index + 3, &num))
|
||||||
{
|
{
|
||||||
if (num >= 0 && num < MODEL_MAX_LODS)
|
if (num >= 0 && num < MODEL_MAX_LODS)
|
||||||
{
|
|
||||||
return num;
|
return num;
|
||||||
}
|
|
||||||
|
|
||||||
LOG(Warning, "Invalid mesh level of detail index at node \'{0}\'. Maximum supported amount of LODs is {1}.", nodeName, MODEL_MAX_LODS);
|
LOG(Warning, "Invalid mesh level of detail index at node \'{0}\'. Maximum supported amount of LODs is {1}.", nodeName, MODEL_MAX_LODS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,16 @@ namespace FlaxEngine.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<TextBoxBase> TextBoxEditEnd;
|
public event Action<TextBoxBase> TextBoxEditEnd;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when a key is down.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<KeyboardKeys> KeyDown;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when a key is up.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<KeyboardKeys> KeyUp;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this is a multiline text box control.
|
/// Gets or sets a value indicating whether this is a multiline text box control.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1168,12 +1178,20 @@ namespace FlaxEngine.GUI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnKeyUp(KeyboardKeys key)
|
||||||
|
{
|
||||||
|
base.OnKeyUp(key);
|
||||||
|
KeyUp?.Invoke(key);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool OnKeyDown(KeyboardKeys key)
|
public override bool OnKeyDown(KeyboardKeys key)
|
||||||
{
|
{
|
||||||
var window = Root;
|
var window = Root;
|
||||||
bool shiftDown = window.GetKey(KeyboardKeys.Shift);
|
bool shiftDown = window.GetKey(KeyboardKeys.Shift);
|
||||||
bool ctrDown = window.GetKey(KeyboardKeys.Control);
|
bool ctrDown = window.GetKey(KeyboardKeys.Control);
|
||||||
|
KeyDown?.Invoke(key);
|
||||||
|
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -948,10 +948,6 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
// Set flag
|
// Set flag
|
||||||
_isDragOver = true;
|
_isDragOver = true;
|
||||||
|
|
||||||
// Hide tooltip
|
|
||||||
Tooltip?.Hide();
|
|
||||||
|
|
||||||
return DragDropEffect.None;
|
return DragDropEffect.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,6 +994,8 @@ namespace FlaxEngine.GUI
|
|||||||
[NoAnimate]
|
[NoAnimate]
|
||||||
public virtual void DoDragDrop(DragData data)
|
public virtual void DoDragDrop(DragData data)
|
||||||
{
|
{
|
||||||
|
// Hide tooltip
|
||||||
|
Tooltip?.Hide();
|
||||||
Root.DoDragDrop(data);
|
Root.DoDragDrop(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user