Merge remote-tracking branch 'origin/master' into dotnet7
This commit is contained in:
BIN
Content/Editor/Gizmo/Axis.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/Axis.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/MaterialSphere.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/Gizmo/MaterialSphere.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/Gizmo/RotationAxis.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/Gizmo/RotationAxis.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/Gizmo/ScaleAxis.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/ScaleAxis.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/TranslateAxis.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/TranslateAxis.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/TranslationAxis.flax
(Stored with Git LFS)
Normal file
BIN
Content/Editor/Gizmo/TranslationAxis.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Editor/Gizmo/WireCircle.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/WireCircle.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/GI/DDGI.flax
(Stored with Git LFS)
BIN
Content/Shaders/GI/DDGI.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/GlobalSignDistanceField.flax
(Stored with Git LFS)
BIN
Content/Shaders/GlobalSignDistanceField.flax
(Stored with Git LFS)
Binary file not shown.
@@ -174,9 +174,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
for (int i = 0; i < subInputs.Length; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(subInputs[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check all entered subtags and create any that dont exist
|
||||
for (int j = 0; j <= i; j++)
|
||||
@@ -296,6 +294,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
settingsObj.Tags.Add(tagName);
|
||||
settingsObj.Tags.Sort();
|
||||
settingsAsset.SetInstance(settingsObj);
|
||||
settingsAsset.Save();
|
||||
|
||||
// Reload editor window to reflect new tag
|
||||
assetWindow?.RefreshAsset();
|
||||
@@ -417,7 +416,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (!uniqueText)
|
||||
return;
|
||||
|
||||
OnAddTagButtonClicked(nameTextBox.Text, tree, nameTextBox, addTagDropPanel, pickerData);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#if PLATFORM_WINDOWS
|
||||
#define USE_IS_FOREGROUND
|
||||
#else
|
||||
#endif
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -326,6 +330,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
#if USE_IS_FOREGROUND
|
||||
/// <summary>
|
||||
/// Returns true if context menu is in foreground (eg. context window or any child window has user focus or user opened additional popup within this context).
|
||||
/// </summary>
|
||||
@@ -385,6 +390,57 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
private void OnWindowGotFocus()
|
||||
{
|
||||
}
|
||||
|
||||
private void OnWindowLostFocus()
|
||||
{
|
||||
// Skip for parent menus (child should handle lost of focus)
|
||||
if (_childCM != null)
|
||||
return;
|
||||
|
||||
if (_parentCM != null)
|
||||
{
|
||||
if (IsMouseOver)
|
||||
return;
|
||||
|
||||
// Check if any external popup is focused
|
||||
foreach (var externalPopup in ExternalPopups)
|
||||
{
|
||||
if (externalPopup && externalPopup.IsFocused)
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if mouse is over any of the parents
|
||||
ContextMenuBase focusCM = null;
|
||||
var cm = _parentCM;
|
||||
while (cm != null)
|
||||
{
|
||||
if (cm.IsMouseOver)
|
||||
focusCM = cm;
|
||||
cm = cm._parentCM;
|
||||
}
|
||||
|
||||
if (focusCM != null)
|
||||
{
|
||||
// Focus on the clicked parent and hide any open sub-menus
|
||||
focusCM.HideChild();
|
||||
focusCM._window?.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
// User clicked outside the context menus, hide the whole context menu tree
|
||||
TopmostCM.Hide();
|
||||
}
|
||||
}
|
||||
else if (!IsMouseOver)
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsMouseOver
|
||||
@@ -405,6 +461,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_IS_FOREGROUND
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
@@ -416,6 +473,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
|
||||
@@ -55,8 +55,6 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseEnter(Float2 location)
|
||||
{
|
||||
base.OnMouseEnter(location);
|
||||
|
||||
// Skip if has no children
|
||||
if (ContextMenu.HasChildren == false)
|
||||
return;
|
||||
@@ -66,8 +64,28 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
if (parentContextMenu == ContextMenu)
|
||||
return;
|
||||
|
||||
if (ContextMenu.IsOpened)
|
||||
return;
|
||||
|
||||
base.OnMouseEnter(location);
|
||||
|
||||
// Hide parent CM popups and set itself as child
|
||||
parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0)));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
// Skip if already shown
|
||||
var parentContextMenu = ParentContextMenu;
|
||||
if (parentContextMenu == ContextMenu)
|
||||
return true;
|
||||
if (ContextMenu.IsOpened)
|
||||
return true;
|
||||
|
||||
// Hide parent CM popups and set itself as child
|
||||
parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0)));
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,6 +700,8 @@ namespace FlaxEditor.GUI.Tree
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
UpdateMouseOverFlags(location);
|
||||
|
||||
// Check if mouse hits bar and node isn't a root
|
||||
if (_mouseOverHeader)
|
||||
{
|
||||
@@ -728,6 +730,8 @@ namespace FlaxEditor.GUI.Tree
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
UpdateMouseOverFlags(location);
|
||||
|
||||
// Clear flag for left button
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
@@ -815,21 +819,7 @@ namespace FlaxEditor.GUI.Tree
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
// Cache flags
|
||||
_mouseOverArrow = HasAnyVisibleChild && ArrowRect.Contains(location);
|
||||
_mouseOverHeader = new Rectangle(0, 0, Width, _headerHeight - 1).Contains(location);
|
||||
if (_mouseOverHeader)
|
||||
{
|
||||
// Allow non-scrollable controls to stay on top of the header and override the mouse behaviour
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
if (!Children[i].IsScrollable && IntersectsChildContent(Children[i], location, out _))
|
||||
{
|
||||
_mouseOverHeader = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateMouseOverFlags(location);
|
||||
|
||||
// Check if start drag and drop
|
||||
if (_isMouseDown && Float2.Distance(_mouseDownPos, location) > 10.0f)
|
||||
@@ -852,6 +842,25 @@ namespace FlaxEditor.GUI.Tree
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMouseOverFlags(Vector2 location)
|
||||
{
|
||||
// Cache flags
|
||||
_mouseOverArrow = HasAnyVisibleChild && ArrowRect.Contains(location);
|
||||
_mouseOverHeader = new Rectangle(0, 0, Width, _headerHeight - 1).Contains(location);
|
||||
if (_mouseOverHeader)
|
||||
{
|
||||
// Allow non-scrollable controls to stay on top of the header and override the mouse behaviour
|
||||
for (int i = 0; i < Children.Count; i++)
|
||||
{
|
||||
if (!Children[i].IsScrollable && IntersectsChildContent(Children[i], location, out _))
|
||||
{
|
||||
_mouseOverHeader = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
|
||||
@@ -6,44 +6,48 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
public partial class TransformGizmoBase
|
||||
{
|
||||
private Model _modelTranslateAxis;
|
||||
// Models
|
||||
private Model _modelTranslationAxis;
|
||||
private Model _modelScaleAxis;
|
||||
private Model _modelBox;
|
||||
private Model _modelCircle;
|
||||
private Model _modelRotationAxis;
|
||||
private Model _modelSphere;
|
||||
private Model _modelCube;
|
||||
|
||||
// Materials
|
||||
private MaterialInstance _materialAxisX;
|
||||
private MaterialInstance _materialAxisY;
|
||||
private MaterialInstance _materialAxisZ;
|
||||
private MaterialInstance _materialAxisFocus;
|
||||
private MaterialBase _materialWire;
|
||||
private MaterialBase _materialWireFocus;
|
||||
private MaterialBase _materialSphere;
|
||||
|
||||
private void InitDrawing()
|
||||
{
|
||||
// Load content (but async - don't wait and don't block execution)
|
||||
_modelTranslateAxis = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Gizmo/TranslateAxis");
|
||||
// Axis Models
|
||||
_modelTranslationAxis = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Gizmo/TranslationAxis");
|
||||
_modelScaleAxis = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Gizmo/ScaleAxis");
|
||||
_modelBox = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Gizmo/WireBox");
|
||||
_modelCircle = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Gizmo/WireCircle");
|
||||
_modelRotationAxis = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Gizmo/RotationAxis");
|
||||
_modelSphere = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Primitives/Sphere");
|
||||
_modelCube = FlaxEngine.Content.LoadAsyncInternal<Model>("Editor/Primitives/Cube");
|
||||
|
||||
// Axis Materials
|
||||
_materialAxisX = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisX");
|
||||
_materialAxisY = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisY");
|
||||
_materialAxisZ = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisZ");
|
||||
_materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisFocus");
|
||||
_materialWire = FlaxEngine.Content.LoadAsyncInternal<MaterialBase>("Editor/Gizmo/MaterialWire");
|
||||
_materialWireFocus = FlaxEngine.Content.LoadAsyncInternal<MaterialBase>("Editor/Gizmo/MaterialWireFocus");
|
||||
_materialSphere = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialSphere");
|
||||
|
||||
// Ensure that every asset was loaded
|
||||
if (_modelTranslateAxis == null ||
|
||||
if (_modelTranslationAxis == null ||
|
||||
_modelScaleAxis == null ||
|
||||
_modelBox == null ||
|
||||
_modelCircle == null ||
|
||||
_modelRotationAxis == null ||
|
||||
_modelSphere == null ||
|
||||
_modelCube == null ||
|
||||
_materialAxisX == null ||
|
||||
_materialAxisY == null ||
|
||||
_materialAxisZ == null ||
|
||||
_materialAxisFocus == null ||
|
||||
_materialWire == null ||
|
||||
_materialWireFocus == null)
|
||||
_materialSphere == null)
|
||||
{
|
||||
// Error
|
||||
Platform.Fatal("Failed to load transform gizmo resources.");
|
||||
}
|
||||
}
|
||||
@@ -58,6 +62,8 @@ namespace FlaxEditor.Gizmo
|
||||
// https://github.com/FlaxEngine/FlaxEngine/issues/680
|
||||
|
||||
Matrix m1, m2, m3, mx1;
|
||||
float boxScale = 300f;
|
||||
float boxSize = 0.085f;
|
||||
bool isXAxis = _activeAxis == Axis.X || _activeAxis == Axis.XY || _activeAxis == Axis.ZX;
|
||||
bool isYAxis = _activeAxis == Axis.Y || _activeAxis == Axis.XY || _activeAxis == Axis.YZ;
|
||||
bool isZAxis = _activeAxis == Axis.Z || _activeAxis == Axis.YZ || _activeAxis == Axis.ZX;
|
||||
@@ -65,114 +71,137 @@ namespace FlaxEditor.Gizmo
|
||||
renderContext.View.GetWorldMatrix(ref _gizmoWorld, out Matrix world);
|
||||
|
||||
const float gizmoModelsScale2RealGizmoSize = 0.075f;
|
||||
Mesh sphereMesh, cubeMesh;
|
||||
switch (_activeMode)
|
||||
{
|
||||
case Mode.Translate:
|
||||
{
|
||||
if (!_modelTranslateAxis || !_modelTranslateAxis.IsLoaded || !_modelBox || !_modelBox.IsLoaded)
|
||||
if (!_modelTranslationAxis || !_modelTranslationAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded)
|
||||
break;
|
||||
var transAxisMesh = _modelTranslationAxis.LODs[0].Meshes[0];
|
||||
cubeMesh = _modelCube.LODs[0].Meshes[0];
|
||||
sphereMesh = _modelSphere.LODs[0].Meshes[0];
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||
Matrix.Multiply(ref m3, ref world, out m1);
|
||||
mx1 = m1;
|
||||
mx1.M41 += 0.05f;
|
||||
var axisMesh = _modelTranslateAxis.LODs[0].Meshes[0];
|
||||
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
||||
var boxSize = 10.0f;
|
||||
|
||||
// XY plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, 1.0f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * 0.5f, boxSize * 0.5f, 0.0f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
boxMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialWireFocus : _materialWire, ref m3);
|
||||
|
||||
// ZX plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, 1.0f, boxSize), Quaternion.Identity, new Vector3(boxSize * 0.5f, 0.0f, boxSize * 0.5f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
boxMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialWireFocus : _materialWire, ref m3);
|
||||
|
||||
// YZ plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, 1.0f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * 0.5f, boxSize * 0.5f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
boxMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialWireFocus : _materialWire, ref m3);
|
||||
|
||||
// X axis
|
||||
axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref mx1);
|
||||
|
||||
// Y axis
|
||||
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
axisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
axisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
transAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
|
||||
// Y axis
|
||||
Matrix.RotationX(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
transAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationX(Mathf.Pi, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
transAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
|
||||
// XY plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
|
||||
// ZX plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
|
||||
// YZ plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3);
|
||||
|
||||
// Center sphere
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Mode.Rotate:
|
||||
{
|
||||
if (!_modelCircle || !_modelCircle.IsLoaded || !_modelBox || !_modelBox.IsLoaded)
|
||||
if (!_modelRotationAxis || !_modelRotationAxis.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded)
|
||||
break;
|
||||
var circleMesh = _modelCircle.LODs[0].Meshes[0];
|
||||
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
||||
Matrix.Scaling(8.0f, out m3);
|
||||
var rotationAxisMesh = _modelRotationAxis.LODs[0].Meshes[0];
|
||||
sphereMesh = _modelSphere.LODs[0].Meshes[0];
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||
Matrix.Multiply(ref m3, ref world, out m1);
|
||||
mx1 = m1;
|
||||
mx1.M41 += 0.05f;
|
||||
|
||||
// X axis
|
||||
Matrix.RotationZ(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
circleMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
rotationAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
|
||||
// Y axis
|
||||
circleMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m1);
|
||||
rotationAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m1);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationX(-Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
circleMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
rotationAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
|
||||
// Center box
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||
Matrix.Multiply(ref m3, ref world, out m1);
|
||||
Matrix.Scaling(1.0f, out m2);
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
boxMesh.Draw(ref renderContext, isCenter ? _materialWireFocus : _materialWire, ref m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Mode.Scale:
|
||||
{
|
||||
if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelBox || !_modelBox.IsLoaded)
|
||||
if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelCube || !_modelCube.IsLoaded || !_modelSphere || !_modelSphere.IsLoaded)
|
||||
break;
|
||||
var scaleAxisMesh = _modelScaleAxis.LODs[0].Meshes[0];
|
||||
cubeMesh = _modelCube.LODs[0].Meshes[0];
|
||||
sphereMesh = _modelSphere.LODs[0].Meshes[0];
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||
Matrix.Multiply(ref m3, ref world, out m1);
|
||||
mx1 = m1;
|
||||
mx1.M41 -= 0.05f;
|
||||
|
||||
var axisMesh = _modelScaleAxis.LODs[0].Meshes[0];
|
||||
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
||||
|
||||
// X axis
|
||||
Matrix.RotationY(-Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref mx1, out m3);
|
||||
axisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
scaleAxisMesh.Draw(ref renderContext, isXAxis ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
|
||||
// Y axis
|
||||
Matrix.RotationX(Mathf.PiOverTwo, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
axisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3);
|
||||
scaleAxisMesh.Draw(ref renderContext, isYAxis ? _materialAxisFocus : _materialAxisY, ref m3);
|
||||
|
||||
// Z axis
|
||||
Matrix.RotationX(Mathf.Pi, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
axisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
scaleAxisMesh.Draw(ref renderContext, isZAxis ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
|
||||
// XY plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
cubeMesh.Draw(ref renderContext, _activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX, ref m3);
|
||||
|
||||
// ZX plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
cubeMesh.Draw(ref renderContext, _activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ, ref m3);
|
||||
|
||||
// YZ plane
|
||||
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
cubeMesh.Draw(ref renderContext, _activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY, ref m3);
|
||||
|
||||
// Center box
|
||||
Matrix.Scaling(10.0f, out m2);
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m2);
|
||||
Matrix.Multiply(ref m2, ref m1, out m3);
|
||||
boxMesh.Draw(ref renderContext, isCenter ? _materialWireFocus : _materialWire, ref m3);
|
||||
sphereMesh.Draw(ref renderContext, isCenter ? _materialAxisFocus : _materialSphere, ref m3);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -102,9 +102,15 @@ namespace FlaxEditor.Gizmo
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
|
||||
/*// Center
|
||||
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.Center;
|
||||
closestIntersection = intersection;
|
||||
}*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Mode.Rotate:
|
||||
{
|
||||
// Circles
|
||||
@@ -124,41 +130,53 @@ namespace FlaxEditor.Gizmo
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
|
||||
// Center
|
||||
/*if (CenterSphere.Intersects(ref ray, out intersection) && intersection < closestintersection)
|
||||
{
|
||||
_activeAxis = Axis.Center;
|
||||
closestintersection = intersection;
|
||||
}*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Mode.Scale:
|
||||
{
|
||||
// Spheres collision
|
||||
if (ScaleXSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection)
|
||||
// Boxes collision
|
||||
if (XAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.X;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
if (ScaleYSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection)
|
||||
if (YAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.Y;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
if (ScaleZSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection)
|
||||
if (ZAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.Z;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
|
||||
// Center
|
||||
if (CenterBox.Intersects(ref ray, out intersection) && intersection < closestIntersection)
|
||||
// Quad planes collision
|
||||
if (closestIntersection >= float.MaxValue)
|
||||
closestIntersection = float.MinValue;
|
||||
|
||||
if (XYBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.XY;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
if (XZBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.ZX;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
if (YZBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.YZ;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
|
||||
/*// Center
|
||||
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
|
||||
{
|
||||
_activeAxis = Axis.Center;
|
||||
closestIntersection = intersection;
|
||||
}
|
||||
}*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7,56 +7,53 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
public partial class TransformGizmoBase
|
||||
{
|
||||
private const float GizmoScaleFactor = 18;
|
||||
private const float LineLength = 3.0f;
|
||||
private const float LineOffset = 1.0f;
|
||||
private const float MultiAxisThickness = 0.05f;
|
||||
private const float SingleAxisThickness = 0.3f;
|
||||
private const float ScaleSpheresRadius = 0.7f;
|
||||
private const float CenterBoxSize = 0.8f;
|
||||
private const float CenterSphereRadius = 0.1f;
|
||||
private const float HalfLineOffset = LineOffset / 2;
|
||||
/// <summary>
|
||||
/// Scale of the gizmo itself
|
||||
/// </summary>
|
||||
private const float GizmoScaleFactor = 24;
|
||||
|
||||
private readonly Vector3[] _translationLineVertices =
|
||||
{
|
||||
// -- X Axis -- // index 0 - 5
|
||||
new Vector3(HalfLineOffset, 0, 0),
|
||||
new Vector3(LineLength, 0, 0),
|
||||
new Vector3(LineOffset, 0, 0),
|
||||
new Vector3(LineOffset, LineOffset, 0),
|
||||
new Vector3(LineOffset, 0, 0),
|
||||
new Vector3(LineOffset, 0, LineOffset),
|
||||
/// <summary>
|
||||
/// The length of each axis (outwards)
|
||||
/// </summary>
|
||||
private const float AxisLength = 3.5f;
|
||||
|
||||
// -- Y Axis -- // index 6 - 11
|
||||
new Vector3(0, HalfLineOffset, 0),
|
||||
new Vector3(0, LineLength, 0),
|
||||
new Vector3(0, LineOffset, 0),
|
||||
new Vector3(LineOffset, LineOffset, 0),
|
||||
new Vector3(0, LineOffset, 0),
|
||||
new Vector3(0, LineOffset, LineOffset),
|
||||
/// <summary>
|
||||
/// Offset to move axis away from center
|
||||
/// </summary>
|
||||
private const float AxisOffset = 0.8f;
|
||||
|
||||
// -- Z Axis -- // index 12 - 17
|
||||
new Vector3(0, 0, HalfLineOffset),
|
||||
new Vector3(0, 0, LineLength),
|
||||
new Vector3(0, 0, LineOffset),
|
||||
new Vector3(LineOffset, 0, LineOffset),
|
||||
new Vector3(0, 0, LineOffset),
|
||||
new Vector3(0, LineOffset, LineOffset)
|
||||
};
|
||||
/// <summary>
|
||||
/// How thick the axis should be
|
||||
/// </summary>
|
||||
private const float AxisThickness = 0.3f;
|
||||
|
||||
private BoundingBox XAxisBox = new BoundingBox(new Vector3(LineOffset, -SingleAxisThickness, -SingleAxisThickness), new Vector3(LineOffset + LineLength, SingleAxisThickness, SingleAxisThickness));
|
||||
private BoundingBox YAxisBox = new BoundingBox(new Vector3(-SingleAxisThickness, LineOffset, -SingleAxisThickness), new Vector3(SingleAxisThickness, LineOffset + LineLength, SingleAxisThickness));
|
||||
private BoundingBox ZAxisBox = new BoundingBox(new Vector3(-SingleAxisThickness, -SingleAxisThickness, LineOffset), new Vector3(SingleAxisThickness, SingleAxisThickness, LineOffset + LineLength));
|
||||
private BoundingBox XZBox = new BoundingBox(Vector3.Zero, new Vector3(LineOffset, MultiAxisThickness, LineOffset));
|
||||
private BoundingBox XYBox = new BoundingBox(Vector3.Zero, new Vector3(LineOffset, LineOffset, MultiAxisThickness));
|
||||
private BoundingBox YZBox = new BoundingBox(Vector3.Zero, new Vector3(MultiAxisThickness, LineOffset, LineOffset));
|
||||
private BoundingBox CenterBoxRaw = new BoundingBox(new Vector3(-0.5f * CenterBoxSize), new Vector3(0.5f * CenterBoxSize));
|
||||
private float RotateRadiusRaw = 4.0f;
|
||||
/// <summary>
|
||||
/// Center box scale
|
||||
/// </summary>
|
||||
private const float CenterBoxScale = 0.8f;
|
||||
|
||||
private BoundingSphere ScaleXSphere => new BoundingSphere(Vector3.Transform(_translationLineVertices[1], _gizmoWorld), ScaleSpheresRadius * _screenScale);
|
||||
private BoundingSphere ScaleYSphere => new BoundingSphere(Vector3.Transform(_translationLineVertices[7], _gizmoWorld), ScaleSpheresRadius * _screenScale);
|
||||
private BoundingSphere ScaleZSphere => new BoundingSphere(Vector3.Transform(_translationLineVertices[13], _gizmoWorld), ScaleSpheresRadius * _screenScale);
|
||||
/// <summary>
|
||||
/// The inner minimum of the multiscale
|
||||
/// </summary>
|
||||
private const float InnerExtend = AxisOffset + 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// The outer maximum of the multiscale
|
||||
/// </summary>
|
||||
private const float OuterExtend = AxisOffset * 3.5f;
|
||||
|
||||
// Cube with the size AxisThickness, then moves it along the axis (AxisThickness) and finally makes it really long (AxisLength)
|
||||
private BoundingBox XAxisBox = new BoundingBox(new Vector3(-AxisThickness), new Vector3(AxisThickness)).MakeOffsetted(AxisOffset * Vector3.UnitX).Merge(AxisLength * Vector3.UnitX);
|
||||
private BoundingBox YAxisBox = new BoundingBox(new Vector3(-AxisThickness), new Vector3(AxisThickness)).MakeOffsetted(AxisOffset * Vector3.UnitY).Merge(AxisLength * Vector3.UnitY);
|
||||
private BoundingBox ZAxisBox = new BoundingBox(new Vector3(-AxisThickness), new Vector3(AxisThickness)).MakeOffsetted(AxisOffset * Vector3.UnitZ).Merge(AxisLength * Vector3.UnitZ);
|
||||
|
||||
private BoundingBox XZBox = new BoundingBox(new Vector3(InnerExtend, 0, InnerExtend), new Vector3(OuterExtend, 0, OuterExtend));
|
||||
private BoundingBox XYBox = new BoundingBox(new Vector3(InnerExtend, InnerExtend, 0), new Vector3(OuterExtend, OuterExtend, 0));
|
||||
private BoundingBox YZBox = new BoundingBox(new Vector3(0, InnerExtend, InnerExtend), new Vector3(0, OuterExtend, OuterExtend));
|
||||
|
||||
private BoundingBox CenterBoxRaw = new BoundingBox(new Vector3(-0.5f * CenterBoxScale), new Vector3(0.5f * CenterBoxScale));
|
||||
private OrientedBoundingBox CenterBox => new OrientedBoundingBox(CenterBoxRaw) * _gizmoWorld;
|
||||
private const float RotateRadiusRaw = 4.0f;
|
||||
|
||||
private Mode _activeMode = Mode.Translate;
|
||||
private Axis _activeAxis = Axis.None;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace
|
||||
// Load product info
|
||||
Array<byte> productInfoData;
|
||||
const String productInfoPath = directory / TEXT("product-info.json");
|
||||
if (File::ReadAllBytes(productInfoPath, productInfoData))
|
||||
if (!FileSystem::FileExists(productInfoPath) || File::ReadAllBytes(productInfoPath, productInfoData))
|
||||
return;
|
||||
rapidjson_flax::Document document;
|
||||
document.Parse((char*)productInfoData.Get(), productInfoData.Count());
|
||||
@@ -193,6 +193,7 @@ void RiderCodeEditor::FindEditors(Array<CodeEditor*>* output)
|
||||
// TODO: detect Snap installations
|
||||
// TODO: detect by reading the jetbrains-rider.desktop file from ~/.local/share/applications and /usr/share/applications?
|
||||
|
||||
SearchDirectory(&installations, TEXT("/usr/share/rider/"));
|
||||
FileSystem::GetChildDirectories(subDirectories, TEXT("/usr/share/rider"));
|
||||
|
||||
// Default suggested location for standalone installations
|
||||
|
||||
@@ -543,7 +543,9 @@ bool EditorUtilities::GetTexture(const Guid& textureId, TextureData& textureData
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: disable streaming for a texture or set max quality override
|
||||
const bool useGPU = texture->IsVirtual();
|
||||
if (useGPU)
|
||||
{
|
||||
int32 waits = 1000;
|
||||
const auto targetResidency = texture->StreamingTexture()->GetMaxResidency();
|
||||
ASSERT(targetResidency > 0);
|
||||
@@ -555,6 +557,7 @@ bool EditorUtilities::GetTexture(const Guid& textureId, TextureData& textureData
|
||||
// Get texture data from GPU
|
||||
if (!texture->GetTexture()->DownloadData(textureData))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get texture data from asset
|
||||
if (!texture->GetTextureData(textureData))
|
||||
|
||||
@@ -37,12 +37,8 @@ String JsonAssetBase::GetData() const
|
||||
if (Data == nullptr)
|
||||
return String::Empty;
|
||||
PROFILE_CPU_NAMED("JsonAsset.GetData");
|
||||
|
||||
// Get serialized data
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
rapidjson_flax::Writer<rapidjson_flax::StringBuffer> writer(buffer);
|
||||
Data->Accept(writer);
|
||||
|
||||
OnGetData(buffer);
|
||||
return String((const char*)buffer.GetString(), (int32)buffer.GetSize());
|
||||
}
|
||||
|
||||
@@ -83,6 +79,12 @@ bool JsonAssetBase::Init(const StringView& dataTypeName, const StringAnsiView& d
|
||||
return loadAsset() != LoadResult::Ok;
|
||||
}
|
||||
|
||||
void JsonAssetBase::OnGetData(rapidjson_flax::StringBuffer& buffer) const
|
||||
{
|
||||
PrettyJsonWriter writerObj(buffer);
|
||||
Data->Accept(writerObj.GetWriter());
|
||||
}
|
||||
|
||||
const String& JsonAssetBase::GetPath() const
|
||||
{
|
||||
#if USE_EDITOR
|
||||
@@ -144,6 +146,53 @@ void JsonAssetBase::GetReferences(const StringAnsiView& json, Array<Guid>& outpu
|
||||
FindIds(document, output);
|
||||
}
|
||||
|
||||
bool JsonAssetBase::Save(const StringView& path)
|
||||
{
|
||||
// Validate state
|
||||
if (WaitForLoaded())
|
||||
{
|
||||
LOG(Error, "Asset loading failed. Cannot save it.");
|
||||
return true;
|
||||
}
|
||||
if (IsVirtual() && path.IsEmpty())
|
||||
{
|
||||
LOG(Error, "To save virtual asset asset you need to specify the target asset path location.");
|
||||
return true;
|
||||
}
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
// Serialize to json file
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
PrettyJsonWriter writerObj(buffer);
|
||||
JsonWriter& writer = writerObj;
|
||||
writer.StartObject();
|
||||
{
|
||||
// Json resource header
|
||||
writer.JKEY("ID");
|
||||
writer.Guid(GetID());
|
||||
writer.JKEY("TypeName");
|
||||
writer.String(DataTypeName);
|
||||
writer.JKEY("EngineBuild");
|
||||
writer.Int(FLAXENGINE_VERSION_BUILD);
|
||||
|
||||
// Json resource data
|
||||
rapidjson_flax::StringBuffer dataBuffer;
|
||||
OnGetData(dataBuffer);
|
||||
writer.JKEY("Data");
|
||||
writer.RawValue(dataBuffer.GetString(), (int32)dataBuffer.GetSize());
|
||||
}
|
||||
writer.EndObject();
|
||||
|
||||
// Save json to file
|
||||
if (File::WriteAllBytes(path.HasChars() ? path : StringView(GetPath()), (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
||||
{
|
||||
LOG(Error, "Cannot save \'{0}\'", ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void JsonAssetBase::GetReferences(Array<Guid>& output) const
|
||||
{
|
||||
if (Data == nullptr)
|
||||
|
||||
@@ -72,8 +72,19 @@ public:
|
||||
/// <param name="json">The Json string.</param>
|
||||
/// <param name="output">The output list of object IDs references by the asset (appended, not cleared).</param>
|
||||
API_FUNCTION() static void GetReferences(const StringAnsiView& json, API_PARAM(Out) Array<Guid, HeapAllocation>& output);
|
||||
|
||||
/// <summary>
|
||||
/// Saves this asset to the file. Supported only in Editor.
|
||||
/// </summary>
|
||||
/// <param name="path">The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset.</param>
|
||||
/// <returns>True if cannot save data, otherwise false.</returns>
|
||||
API_FUNCTION() bool Save(const StringView& path = StringView::Empty);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Gets the serialized Json data (from runtime state).
|
||||
virtual void OnGetData(rapidjson_flax::StringBuffer& buffer) const;
|
||||
|
||||
public:
|
||||
// [Asset]
|
||||
const String& GetPath() const override;
|
||||
|
||||
@@ -560,12 +560,8 @@ bool FlaxStorage::Load()
|
||||
|
||||
bool FlaxStorage::Reload()
|
||||
{
|
||||
// Check if wasn't already loaded
|
||||
if (!IsLoaded())
|
||||
{
|
||||
LOG(Warning, "{0} isn't loaded.", ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
OnReloading(this);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Streaming/StreamingSettings.h"
|
||||
#if FLAX_TESTS
|
||||
#if FLAX_TESTS || USE_EDITOR
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#endif
|
||||
|
||||
@@ -91,6 +91,19 @@ GameSettings* GameSettings::Get()
|
||||
// Silence missing GameSettings during test run before Editor creates it (not important)
|
||||
if (!FileSystem::FileExists(assetPath))
|
||||
return nullptr;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
// Log once missing GameSettings in Editor
|
||||
if (!FileSystem::FileExists(assetPath))
|
||||
{
|
||||
static bool LogOnce = true;
|
||||
if (LogOnce)
|
||||
{
|
||||
LogOnce = false;
|
||||
LOG(Error, "Missing file game settings asset ({0})", assetPath);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
GameSettingsAsset = Content::LoadAsync<JsonAsset>(assetPath);
|
||||
if (GameSettingsAsset == nullptr)
|
||||
|
||||
@@ -617,12 +617,11 @@ public:
|
||||
FunctionType* bindings = (FunctionType*)Platform::AtomicRead((intptr volatile*)&_ptr);
|
||||
for (intptr i = 0; i < size; i++)
|
||||
{
|
||||
auto function = (StubSignature)Platform::AtomicRead((intptr volatile*)&bindings[i]._function);
|
||||
if (function != nullptr)
|
||||
{
|
||||
auto callee = (void*)Platform::AtomicRead((intptr volatile*)&bindings[i]._callee);
|
||||
auto function = (StubSignature)Platform::AtomicRead((intptr volatile*)&bindings->_function);
|
||||
auto callee = (void*)Platform::AtomicRead((intptr volatile*)&bindings->_callee);
|
||||
if (function != nullptr && function == (StubSignature)Platform::AtomicRead((intptr volatile*)&bindings->_function))
|
||||
function(callee, Forward<Params>(params)...);
|
||||
}
|
||||
++bindings;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -419,6 +419,31 @@ namespace FlaxEngine
|
||||
return box;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="BoundingBox" /> that is as large as the box and point.
|
||||
/// </summary>
|
||||
/// <param name="value1">The box to merge.</param>
|
||||
/// <param name="value2">The point to merge.</param>
|
||||
/// <param name="result">When the method completes, contains the newly constructed bounding box.</param>
|
||||
public static void Merge(ref BoundingBox value1, ref Vector3 value2, out BoundingBox result)
|
||||
{
|
||||
Vector3.Min(ref value1.Minimum, ref value2, out result.Minimum);
|
||||
Vector3.Max(ref value1.Maximum, ref value2, out result.Maximum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="BoundingBox" /> that is as large as the box and point.
|
||||
/// </summary>
|
||||
/// <param name="value2">The point to merge.</param>
|
||||
/// <returns>The newly constructed bounding box.</returns>
|
||||
public BoundingBox Merge(Vector3 value2)
|
||||
{
|
||||
BoundingBox result;
|
||||
Vector3.Min(ref Minimum, ref value2, out result.Minimum);
|
||||
Vector3.Max(ref Maximum, ref value2, out result.Maximum);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms bounding box using the given transformation matrix.
|
||||
/// </summary>
|
||||
@@ -498,6 +523,19 @@ namespace FlaxEngine
|
||||
result = new BoundingBox(min, max);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the bounding box that is offseted by the given vector. Adds the offset value to minimum and maximum points.
|
||||
/// </summary>
|
||||
/// <param name="offset">The bounds offset.</param>
|
||||
/// <returns>The offsetted bounds.</returns>
|
||||
public BoundingBox MakeOffsetted(Vector3 offset)
|
||||
{
|
||||
BoundingBox result;
|
||||
Vector3.Add(ref Minimum, ref offset, out result.Minimum);
|
||||
Vector3.Add(ref Maximum, ref offset, out result.Maximum);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the bounding box that is offseted by the given vector. Adds the offset value to minimum and maximum points.
|
||||
/// </summary>
|
||||
|
||||
@@ -377,12 +377,9 @@ void GPUBuffer::SetData(const void* data, uint32 size)
|
||||
Log::ArgumentOutOfRangeException(TEXT("Buffer.SetData"));
|
||||
return;
|
||||
}
|
||||
|
||||
void* mapped = Map(GPUResourceMapMode::Write);
|
||||
if (!mapped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Platform::MemoryCopy(mapped, data, size);
|
||||
Unmap();
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets a CPU pointer to the resource by mapping its contents. Denies the GPU access to that resource.
|
||||
/// </summary>
|
||||
/// <remarks>Always call Unmap if the returned pointer is valid to release resources.</remarks>
|
||||
/// <param name="mode">The map operation mode.</param>
|
||||
/// <returns>The pointer of the mapped CPU buffer with resource data or null if failed.</returns>
|
||||
API_FUNCTION() virtual void* Map(GPUResourceMapMode mode) = 0;
|
||||
|
||||
@@ -231,6 +231,7 @@ bool MaterialShader::Load(MemoryReadStream& shaderCacheStream, const MaterialInf
|
||||
_cb = nullptr;
|
||||
}
|
||||
_cbData.Resize(cbSize, false);
|
||||
Platform::MemoryClear(_cbData.Get(), cbSize);
|
||||
}
|
||||
|
||||
// Initialize the material based on type (create pipeline states and setup)
|
||||
|
||||
@@ -527,9 +527,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false)
|
||||
{
|
||||
var vertices = VertexCount;
|
||||
var result = new Vertex0[vertices];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0))
|
||||
var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
@@ -541,9 +540,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public Vertex1[] DownloadVertexBuffer1(bool forceGpu = false)
|
||||
{
|
||||
var vertices = VertexCount;
|
||||
var result = new Vertex1[vertices];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB1))
|
||||
var result = (Vertex1[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex1), (int)InternalBufferType.VB1);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
@@ -560,10 +558,8 @@ namespace FlaxEngine
|
||||
{
|
||||
if (!HasVertexColors)
|
||||
return null;
|
||||
|
||||
var vertices = VertexCount;
|
||||
var result = new Vertex2[vertices];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB2))
|
||||
var result = (Vertex2[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex2), (int)InternalBufferType.VB2);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
@@ -582,7 +578,7 @@ namespace FlaxEngine
|
||||
var vb1 = DownloadVertexBuffer1(forceGpu);
|
||||
var vb2 = DownloadVertexBuffer2(forceGpu);
|
||||
|
||||
var vertices = VertexCount;
|
||||
var vertices = vb0.Length;
|
||||
var result = new Vertex[vertices];
|
||||
for (int i = 0; i < vertices; i++)
|
||||
{
|
||||
@@ -618,9 +614,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public uint[] DownloadIndexBuffer(bool forceGpu = false)
|
||||
{
|
||||
var triangles = TriangleCount;
|
||||
var result = new uint[triangles * 3];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32))
|
||||
var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
@@ -633,9 +628,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public ushort[] DownloadIndexBufferUShort(bool forceGpu = false)
|
||||
{
|
||||
var triangles = TriangleCount;
|
||||
var result = new ushort[triangles * 3];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16))
|
||||
var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -746,75 +746,11 @@ enum class InternalBufferType
|
||||
IB32 = 4,
|
||||
};
|
||||
|
||||
void ConvertMeshData(Mesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData)
|
||||
MonoArray* Mesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
|
||||
{
|
||||
auto vertices = mesh->GetVertexCount();
|
||||
auto triangles = mesh->GetTriangleCount();
|
||||
auto indices = triangles * 3;
|
||||
auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer();
|
||||
|
||||
void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0);
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0ElementType) * vertices);
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::VB1:
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB1ElementType) * vertices);
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::VB2:
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB2ElementType) * vertices);
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB16:
|
||||
{
|
||||
if (use16BitIndexBuffer)
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dst = (uint16*)managedArrayPtr;
|
||||
auto src = (uint32*)srcData;
|
||||
for (int32 i = 0; i < indices; i++)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB32:
|
||||
{
|
||||
if (use16BitIndexBuffer)
|
||||
{
|
||||
auto dst = (uint32*)managedArrayPtr;
|
||||
auto src = (uint16*)srcData;
|
||||
for (int32 i = 0; i < indices; i++)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
|
||||
{
|
||||
Mesh* mesh = this;
|
||||
InternalBufferType type = (InternalBufferType)typeI;
|
||||
auto mesh = this;
|
||||
auto type = (InternalBufferType)typeI;
|
||||
auto model = mesh->GetModel();
|
||||
ASSERT(model && resultObj);
|
||||
|
||||
ScopeLock lock(model->Locker);
|
||||
|
||||
// Virtual assets always fetch from GPU memory
|
||||
@@ -823,23 +759,7 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
|
||||
if (!mesh->IsInitialized() && forceGpu)
|
||||
{
|
||||
LOG(Error, "Cannot load mesh data from GPU if it's not loaded.");
|
||||
return true;
|
||||
}
|
||||
if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32)
|
||||
{
|
||||
if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3)
|
||||
{
|
||||
LOG(Error, "Invalid buffer size.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mono_array_length(resultObj) != mesh->GetVertexCount())
|
||||
{
|
||||
LOG(Error, "Invalid buffer size.");
|
||||
return true;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MeshBufferType bufferType;
|
||||
@@ -859,35 +779,96 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
|
||||
bufferType = MeshBufferType::Index;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
BytesContainer data;
|
||||
int32 dataCount;
|
||||
if (forceGpu)
|
||||
{
|
||||
// Get data from GPU
|
||||
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
|
||||
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
return nullptr;
|
||||
task->Start();
|
||||
model->Locker.Unlock();
|
||||
if (task->Wait())
|
||||
{
|
||||
LOG(Error, "Task failed.");
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
model->Locker.Lock();
|
||||
|
||||
// Extract elements count from result data
|
||||
switch (bufferType)
|
||||
{
|
||||
case MeshBufferType::Index:
|
||||
dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32));
|
||||
break;
|
||||
case MeshBufferType::Vertex0:
|
||||
dataCount = data.Length() / sizeof(VB0ElementType);
|
||||
break;
|
||||
case MeshBufferType::Vertex1:
|
||||
dataCount = data.Length() / sizeof(VB1ElementType);
|
||||
break;
|
||||
case MeshBufferType::Vertex2:
|
||||
dataCount = data.Length() / sizeof(VB2ElementType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get data from CPU
|
||||
int32 count;
|
||||
if (DownloadDataCPU(bufferType, data, count))
|
||||
return true;
|
||||
if (DownloadDataCPU(bufferType, data, dataCount))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConvertMeshData(mesh, type, resultObj, data.Get());
|
||||
return false;
|
||||
// Convert into managed array
|
||||
MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
|
||||
void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
|
||||
const int32 elementSize = data.Length() / dataCount;
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
case InternalBufferType::VB1:
|
||||
case InternalBufferType::VB2:
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB16:
|
||||
{
|
||||
if (elementSize == sizeof(uint16))
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dst = (uint16*)managedArrayPtr;
|
||||
auto src = (uint32*)data.Get();
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB32:
|
||||
{
|
||||
if (elementSize == sizeof(uint16))
|
||||
{
|
||||
auto dst = (uint32*)managedArrayPtr;
|
||||
auto src = (uint16*)data.Get();
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -321,6 +321,6 @@ private:
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
|
||||
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
|
||||
API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -516,64 +516,12 @@ enum class InternalBufferType
|
||||
IB32 = 4,
|
||||
};
|
||||
|
||||
void ConvertMeshData(SkinnedMesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData)
|
||||
{
|
||||
auto vertices = mesh->GetVertexCount();
|
||||
auto triangles = mesh->GetTriangleCount();
|
||||
auto indices = triangles * 3;
|
||||
auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer();
|
||||
|
||||
void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0);
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0SkinnedElementType) * vertices);
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB16:
|
||||
{
|
||||
if (use16BitIndexBuffer)
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dst = (uint16*)managedArrayPtr;
|
||||
auto src = (uint32*)srcData;
|
||||
for (int32 i = 0; i < indices; i++)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB32:
|
||||
{
|
||||
if (use16BitIndexBuffer)
|
||||
{
|
||||
auto dst = (uint32*)managedArrayPtr;
|
||||
auto src = (uint16*)srcData;
|
||||
for (int32 i = 0; i < indices; i++)
|
||||
{
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
|
||||
MonoArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
|
||||
{
|
||||
SkinnedMesh* mesh = this;
|
||||
InternalBufferType type = (InternalBufferType)typeI;
|
||||
auto model = mesh->GetSkinnedModel();
|
||||
ASSERT(model && resultObj);
|
||||
ScopeLock lock(model->Locker);
|
||||
|
||||
// Virtual assets always fetch from GPU memory
|
||||
forceGpu |= model->IsVirtual();
|
||||
@@ -581,23 +529,7 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
|
||||
if (!mesh->IsInitialized() && forceGpu)
|
||||
{
|
||||
LOG(Error, "Cannot load mesh data from GPU if it's not loaded.");
|
||||
return true;
|
||||
}
|
||||
if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32)
|
||||
{
|
||||
if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3)
|
||||
{
|
||||
LOG(Error, "Invalid buffer size.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mono_array_length(resultObj) != mesh->GetVertexCount())
|
||||
{
|
||||
LOG(Error, "Invalid buffer size.");
|
||||
return true;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MeshBufferType bufferType;
|
||||
@@ -610,37 +542,89 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
|
||||
case InternalBufferType::IB32:
|
||||
bufferType = MeshBufferType::Index;
|
||||
break;
|
||||
default: CRASH;
|
||||
return true;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
BytesContainer data;
|
||||
int32 dataCount;
|
||||
if (forceGpu)
|
||||
{
|
||||
// Get data from GPU
|
||||
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
|
||||
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
return nullptr;
|
||||
task->Start();
|
||||
model->Locker.Unlock();
|
||||
if (task->Wait())
|
||||
{
|
||||
LOG(Error, "Task failed.");
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
model->Locker.Lock();
|
||||
|
||||
// Extract elements count from result data
|
||||
switch (bufferType)
|
||||
{
|
||||
case MeshBufferType::Index:
|
||||
dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32));
|
||||
break;
|
||||
case MeshBufferType::Vertex0:
|
||||
dataCount = data.Length() / sizeof(VB0SkinnedElementType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get data from CPU
|
||||
int32 count;
|
||||
if (DownloadDataCPU(bufferType, data, count))
|
||||
return true;
|
||||
if (DownloadDataCPU(bufferType, data, dataCount))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Convert into managed memory
|
||||
ConvertMeshData(mesh, type, resultObj, data.Get());
|
||||
return false;
|
||||
// Convert into managed array
|
||||
MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
|
||||
void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
|
||||
const int32 elementSize = data.Length() / dataCount;
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB16:
|
||||
{
|
||||
if (elementSize == sizeof(uint16))
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto dst = (uint16*)managedArrayPtr;
|
||||
auto src = (uint32*)data.Get();
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InternalBufferType::IB32:
|
||||
{
|
||||
if (elementSize == sizeof(uint16))
|
||||
{
|
||||
auto dst = (uint32*)managedArrayPtr;
|
||||
auto src = (uint16*)data.Get();
|
||||
for (int32 i = 0; i < dataCount; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -199,6 +199,6 @@ private:
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
|
||||
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
|
||||
API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -17,23 +17,24 @@ struct RenderContext;
|
||||
/// </remarks>
|
||||
API_CLASS(Abstract) class FLAXENGINE_API PostProcessEffect : public Script
|
||||
{
|
||||
API_AUTO_SERIALIZATION();
|
||||
DECLARE_SCRIPTING_TYPE(PostProcessEffect);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Effect rendering location within rendering pipeline.
|
||||
/// </summary>
|
||||
API_FIELD() PostProcessEffectLocation Location = PostProcessEffectLocation::Default;
|
||||
API_FIELD(Attributes="EditorDisplay(\"Post Process Effect\"), ExpandGroups") PostProcessEffectLocation Location = PostProcessEffectLocation::Default;
|
||||
|
||||
/// <summary>
|
||||
/// True whether use a single render target as both input and output. Use this if your effect doesn't need to copy the input buffer to the output but can render directly to the single texture. Can be used to optimize game performance.
|
||||
/// </summary>
|
||||
API_FIELD() bool UseSingleTarget = false;
|
||||
API_FIELD(Attributes="EditorDisplay(\"Post Process Effect\")") bool UseSingleTarget = false;
|
||||
|
||||
/// <summary>
|
||||
/// Effect rendering order. Post effects are sorted before rendering (from the lowest order to the highest order).
|
||||
/// </summary>
|
||||
API_FIELD() int32 Order = 0;
|
||||
API_FIELD(Attributes="EditorDisplay(\"Post Process Effect\")") int32 Order = 0;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -253,6 +253,14 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
// Ignore deprecation warnings in defaults
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
RenderView() = default;
|
||||
RenderView(const RenderView& other) = default;
|
||||
RenderView(RenderView&& other) = default;
|
||||
RenderView& operator=(const RenderView& other) = default;
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// Set up view with custom params
|
||||
// @param viewProjection View * Projection matrix
|
||||
void SetUp(const Matrix& viewProjection);
|
||||
|
||||
@@ -274,9 +274,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false)
|
||||
{
|
||||
var vertices = VertexCount;
|
||||
var result = new Vertex0[vertices];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0))
|
||||
var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
@@ -292,7 +291,7 @@ namespace FlaxEngine
|
||||
|
||||
var vb0 = DownloadVertexBuffer0(forceGpu);
|
||||
|
||||
var vertices = VertexCount;
|
||||
var vertices = vb0.Length;
|
||||
var result = new Vertex[vertices];
|
||||
for (int i = 0; i < vertices; i++)
|
||||
{
|
||||
@@ -319,9 +318,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public uint[] DownloadIndexBuffer(bool forceGpu = false)
|
||||
{
|
||||
var triangles = TriangleCount;
|
||||
var result = new uint[triangles * 3];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32))
|
||||
var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
@@ -334,9 +332,8 @@ namespace FlaxEngine
|
||||
/// <returns>The gathered data.</returns>
|
||||
public ushort[] DownloadIndexBufferUShort(bool forceGpu = false)
|
||||
{
|
||||
var triangles = TriangleCount;
|
||||
var result = new ushort[triangles * 3];
|
||||
if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16))
|
||||
var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16);
|
||||
if (result == null)
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@ GPUBufferView* GPUBufferDX11::View() const
|
||||
|
||||
void* GPUBufferDX11::Map(GPUResourceMapMode mode)
|
||||
{
|
||||
if (!IsInMainThread())
|
||||
const bool isMainThread = IsInMainThread();
|
||||
if (!isMainThread)
|
||||
_device->Locker.Lock();
|
||||
ASSERT(!_mapped);
|
||||
|
||||
@@ -31,7 +32,7 @@ void* GPUBufferDX11::Map(GPUResourceMapMode mode)
|
||||
{
|
||||
case GPUResourceMapMode::Read:
|
||||
mapType = D3D11_MAP_READ;
|
||||
if (_desc.Usage == GPUResourceUsage::StagingReadback)
|
||||
if (_desc.Usage == GPUResourceUsage::StagingReadback && isMainThread)
|
||||
mapFlags = D3D11_MAP_FLAG_DO_NOT_WAIT;
|
||||
break;
|
||||
case GPUResourceMapMode::Write:
|
||||
@@ -47,18 +48,19 @@ void* GPUBufferDX11::Map(GPUResourceMapMode mode)
|
||||
const HRESULT result = _device->GetIM()->Map(_resource, 0, mapType, mapFlags, &map);
|
||||
if (result != DXGI_ERROR_WAS_STILL_DRAWING)
|
||||
LOG_DIRECTX_RESULT(result);
|
||||
|
||||
_mapped = map.pData != nullptr;
|
||||
if (!_mapped && !isMainThread)
|
||||
_device->Locker.Unlock();
|
||||
|
||||
return map.pData;
|
||||
}
|
||||
|
||||
void GPUBufferDX11::Unmap()
|
||||
{
|
||||
if (_mapped)
|
||||
{
|
||||
ASSERT(_mapped);
|
||||
_mapped = false;
|
||||
_device->GetIM()->Unmap(_resource, 0);
|
||||
}
|
||||
|
||||
if (!IsInMainThread())
|
||||
_device->Locker.Unlock();
|
||||
}
|
||||
|
||||
@@ -471,6 +471,26 @@ bool Actor::HasTag(const StringView& tag) const
|
||||
return Tags.Contains(tag);
|
||||
}
|
||||
|
||||
void Actor::AddTag(const Tag& tag)
|
||||
{
|
||||
Tags.AddUnique(tag);
|
||||
}
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
const String& Actor::GetTag() const
|
||||
{
|
||||
return Tags.Count() != 0 ? Tags[0].ToString() : String::Empty;
|
||||
}
|
||||
|
||||
void Actor::SetTag(const StringView& value)
|
||||
{
|
||||
const Tag tag = Tags::Get(value);
|
||||
Tags.Set(&tag, 1);
|
||||
}
|
||||
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
|
||||
void Actor::SetLayer(int32 layerIndex)
|
||||
{
|
||||
layerIndex = Math::Clamp(layerIndex, 0, 31);
|
||||
|
||||
@@ -130,6 +130,25 @@ public:
|
||||
/// <param name="tag">The tag to check.</param>
|
||||
API_FUNCTION() bool HasTag(const StringView& tag) const;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a tag to the actor
|
||||
/// </summary>
|
||||
/// <param name="tag">The tag to add.</param>
|
||||
API_FUNCTION() void AddTag(const Tag& tag);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the tag.
|
||||
/// [Deprecated in v1.5]
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="HideInEditor, NoSerialize, NoAnimate")
|
||||
DEPRECATED const String& GetTag() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the name of the tag.
|
||||
/// [Deprecated in v1.5]
|
||||
/// </summary>
|
||||
API_PROPERTY() DEPRECATED void SetTag(const StringView& value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor name.
|
||||
/// </summary>
|
||||
|
||||
@@ -103,7 +103,7 @@ void Lightmap::EnsureSize(int32 size)
|
||||
#if COMPILE_WITH_ASSETS_IMPORTER
|
||||
|
||||
Guid id = Guid::New();
|
||||
LOG(Info, "Cannot load lightmap {0} ({1}:{2}). Creating new one.", id, _index, textureIndex);
|
||||
LOG(Info, "Cannot load lightmap ({1}:{2}). Creating new one with ID={0}.", id, _index, textureIndex);
|
||||
String assetPath;
|
||||
_manager->GetCachedLightmapPath(&assetPath, _index, textureIndex);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
/// Gets attached texture objects
|
||||
/// </summary>
|
||||
/// <param name="lightmaps">Lightmaps textures array</param>
|
||||
void GetTextures(GPUTexture* lightmaps[]) const
|
||||
void GetTextures(GPUTexture* lightmaps[3]) const
|
||||
{
|
||||
lightmaps[0] = _textures[0] ? _textures[0]->GetTexture() : nullptr;
|
||||
lightmaps[1] = _textures[1] ? _textures[1]->GetTexture() : nullptr;
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
/// Gets attached texture objects
|
||||
/// </summary>
|
||||
/// <param name="lightmaps">Lightmaps textures array</param>
|
||||
void GetTextures(Texture* lightmaps[]) const
|
||||
void GetTextures(Texture* lightmaps[3]) const
|
||||
{
|
||||
lightmaps[0] = _textures[0].Get();
|
||||
lightmaps[1] = _textures[1].Get();
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
#include "LocalizedStringTable.h"
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Engine/Serialization/SerializationFwd.h"
|
||||
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/ContentImporters/CreateJson.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#endif
|
||||
@@ -55,75 +54,6 @@ String LocalizedStringTable::GetPluralString(const String& id, int32 n) const
|
||||
return String::Format(result.GetText(), n);
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool LocalizedStringTable::Save(const StringView& path)
|
||||
{
|
||||
// Validate state
|
||||
if (WaitForLoaded())
|
||||
{
|
||||
LOG(Error, "Asset loading failed. Cannot save it.");
|
||||
return true;
|
||||
}
|
||||
if (IsVirtual() && path.IsEmpty())
|
||||
{
|
||||
LOG(Error, "To save virtual asset asset you need to specify the target asset path location.");
|
||||
return true;
|
||||
}
|
||||
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
// Serialize data
|
||||
rapidjson_flax::StringBuffer outputData;
|
||||
PrettyJsonWriter writerObj(outputData);
|
||||
JsonWriter& writer = writerObj;
|
||||
writer.StartObject();
|
||||
{
|
||||
writer.JKEY("Locale");
|
||||
writer.String(Locale);
|
||||
|
||||
if (FallbackTable.GetID().IsValid())
|
||||
{
|
||||
writer.JKEY("FallbackTable");
|
||||
writer.Guid(FallbackTable.GetID());
|
||||
}
|
||||
|
||||
writer.JKEY("Entries");
|
||||
writer.StartObject();
|
||||
for (auto& e : Entries)
|
||||
{
|
||||
writer.Key(e.Key);
|
||||
if (e.Value.Count() == 1)
|
||||
{
|
||||
writer.String(e.Value[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.StartArray();
|
||||
for (auto& q : e.Value)
|
||||
writer.String(q);
|
||||
writer.EndArray();
|
||||
}
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndObject();
|
||||
|
||||
// Save asset
|
||||
#if COMPILE_WITH_ASSETS_IMPORTER
|
||||
const bool saveResult = CreateJson::Create(path.HasChars() ? path : StringView(GetPath()), outputData, TypeName);
|
||||
if (saveResult)
|
||||
#endif
|
||||
{
|
||||
LOG(Error, "Cannot save \'{0}\'", ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Asset::LoadResult LocalizedStringTable::loadAsset()
|
||||
{
|
||||
// Base
|
||||
@@ -170,3 +100,41 @@ void LocalizedStringTable::unload(bool isReloading)
|
||||
FallbackTable = nullptr;
|
||||
Entries.Clear();
|
||||
}
|
||||
|
||||
void LocalizedStringTable::OnGetData(rapidjson_flax::StringBuffer& buffer) const
|
||||
{
|
||||
PrettyJsonWriter writerObj(buffer);
|
||||
JsonWriter& writer = writerObj;
|
||||
writer.StartObject();
|
||||
{
|
||||
writer.JKEY("Locale");
|
||||
writer.String(Locale);
|
||||
|
||||
if (FallbackTable.GetID().IsValid())
|
||||
{
|
||||
writer.JKEY("FallbackTable");
|
||||
writer.Guid(FallbackTable.GetID());
|
||||
}
|
||||
|
||||
writer.JKEY("Entries");
|
||||
writer.StartObject();
|
||||
for (auto& e : Entries)
|
||||
{
|
||||
writer.Key(e.Key);
|
||||
if (e.Value.Count() == 1)
|
||||
{
|
||||
writer.String(e.Value[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.StartArray();
|
||||
for (auto& q : e.Value)
|
||||
writer.String(q);
|
||||
writer.EndArray();
|
||||
}
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
|
||||
@@ -61,19 +61,9 @@ public:
|
||||
/// <returns>The localized text.</returns>
|
||||
API_FUNCTION() String GetPluralString(const String& id, int32 n) const;
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
/// Saves this asset to the file. Supported only in Editor.
|
||||
/// </summary>
|
||||
/// <param name="path">The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset.</param>
|
||||
/// <returns>True if cannot save data, otherwise false.</returns>
|
||||
API_FUNCTION() bool Save(const StringView& path = StringView::Empty);
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// [JsonAssetBase]
|
||||
LoadResult loadAsset() override;
|
||||
void unload(bool isReloading) override;
|
||||
void OnGetData(rapidjson_flax::StringBuffer& buffer) const override;
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConfi
|
||||
/// [Deprecated in v1.3]
|
||||
/// </summary>
|
||||
API_FIELD()
|
||||
DEPRECATED NetworkDriverType NetworkDriverType = NetworkDriverType::ENet;
|
||||
DEPRECATED NetworkDriverType NetworkDriverType;
|
||||
|
||||
/// <summary>
|
||||
/// The network driver instance (implements INetworkDriver) that will be used to create and manage the peer, send and receive messages.
|
||||
@@ -81,4 +81,12 @@ API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConfi
|
||||
/// </remarks>
|
||||
API_FIELD()
|
||||
uint16 MessagePoolSize = 2048;
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
/// <summary>Ctor.</summary>
|
||||
NetworkConfig()
|
||||
{
|
||||
NetworkDriverType = NetworkDriverType::ENet;
|
||||
}
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
};
|
||||
|
||||
@@ -104,6 +104,8 @@ int32 ParticleSystemInstance::GetParticlesCount() const
|
||||
if (GPUParticlesCountReadback && GPUParticlesCountReadback->IsAllocated())
|
||||
{
|
||||
auto data = static_cast<uint32*>(GPUParticlesCountReadback->Map(GPUResourceMapMode::Read));
|
||||
if (data)
|
||||
{
|
||||
for (const auto& emitter : Emitters)
|
||||
{
|
||||
if (emitter.Buffer && emitter.Buffer->Mode == ParticlesSimulationMode::GPU && emitter.Buffer->GPU.HasValidCount)
|
||||
@@ -114,6 +116,7 @@ int32 ParticleSystemInstance::GetParticlesCount() const
|
||||
}
|
||||
GPUParticlesCountReadback->Unmap();
|
||||
}
|
||||
}
|
||||
else if (Emitters.HasItems())
|
||||
{
|
||||
// Initialize readback buffer (next GPU particles simulation update will copy the particle counters)
|
||||
|
||||
@@ -537,8 +537,7 @@ String StringUtils::GetZZString(const Char* str)
|
||||
if (*end == '\0')
|
||||
end++;
|
||||
}
|
||||
const int len = end - str;
|
||||
return String(str, len);
|
||||
return String(str, (int32)(end - str));
|
||||
}
|
||||
|
||||
#undef STRING_UTILS_ITOSTR_BUFFER_SIZE
|
||||
|
||||
@@ -689,8 +689,8 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
||||
objectsBufferCapacity = counter;
|
||||
notReady = false;
|
||||
}
|
||||
}
|
||||
_culledObjectsSizeBuffer->Unmap();
|
||||
}
|
||||
|
||||
// Allow to be ready if the buffer was already used
|
||||
if (notReady && surfaceAtlasData.CulledObjectsBuffer && surfaceAtlasData.CulledObjectsBuffer->IsAllocated())
|
||||
|
||||
@@ -549,8 +549,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
|
||||
_cascadeIndex = cascadeIndex;
|
||||
_sdfData = &sdfData;
|
||||
const float objectMargin = _voxelSize * GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN;
|
||||
_sdfDataOriginMax = sdfData.Origin - objectMargin;
|
||||
_sdfDataOriginMax = sdfData.Origin + objectMargin;
|
||||
_sdfDataOriginMin = -sdfData.Origin - objectMargin;
|
||||
_sdfDataOriginMax = -sdfData.Origin + objectMargin;
|
||||
{
|
||||
PROFILE_CPU_NAMED("Draw");
|
||||
BoundingBox cascadeBoundsWorld = cascadeBounds.MakeOffsetted(sdfData.Origin);
|
||||
@@ -958,9 +958,9 @@ void GlobalSignDistanceFieldPass::RasterizeModelSDF(Actor* actor, const ModelBas
|
||||
{
|
||||
// Setup object data
|
||||
BoundingBox objectBoundsCascade;
|
||||
Vector3::Clamp(objectBounds.Minimum - _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum);
|
||||
Vector3::Clamp(objectBounds.Minimum + _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum);
|
||||
Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum);
|
||||
Vector3::Clamp(objectBounds.Maximum - _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum);
|
||||
Vector3::Clamp(objectBounds.Maximum + _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum);
|
||||
Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum);
|
||||
const Int3 objectChunkMin(objectBoundsCascade.Minimum / _chunkSize);
|
||||
const Int3 objectChunkMax(objectBoundsCascade.Maximum / _chunkSize);
|
||||
@@ -1019,9 +1019,9 @@ void GlobalSignDistanceFieldPass::RasterizeHeightfield(Actor* actor, GPUTexture*
|
||||
{
|
||||
// Setup object data
|
||||
BoundingBox objectBoundsCascade;
|
||||
Vector3::Clamp(objectBounds.Minimum - _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum);
|
||||
Vector3::Clamp(objectBounds.Minimum + _sdfDataOriginMin, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Minimum);
|
||||
Vector3::Subtract(objectBoundsCascade.Minimum, _cascadeBounds.Minimum, objectBoundsCascade.Minimum);
|
||||
Vector3::Clamp(objectBounds.Maximum - _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum);
|
||||
Vector3::Clamp(objectBounds.Maximum + _sdfDataOriginMax, _cascadeBounds.Minimum, _cascadeBounds.Maximum, objectBoundsCascade.Maximum);
|
||||
Vector3::Subtract(objectBoundsCascade.Maximum, _cascadeBounds.Minimum, objectBoundsCascade.Maximum);
|
||||
const Int3 objectChunkMin(objectBoundsCascade.Minimum / _chunkSize);
|
||||
const Int3 objectChunkMax(objectBoundsCascade.Maximum / _chunkSize);
|
||||
|
||||
@@ -406,7 +406,10 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont
|
||||
|
||||
// Get the light accumulation buffer
|
||||
auto outputFormat = renderContext.Buffers->GetOutputFormat();
|
||||
auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), outputFormat, GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget | GPUTextureFlags::UnorderedAccess);
|
||||
auto tempFlags = GPUTextureFlags::ShaderResource | GPUTextureFlags::RenderTarget;
|
||||
if (GPUDevice::Instance->Limits.HasCompute)
|
||||
tempFlags |= GPUTextureFlags::UnorderedAccess;
|
||||
auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), outputFormat, tempFlags);
|
||||
auto lightBuffer = RenderTargetPool::Get(tempDesc);
|
||||
RENDER_TARGET_POOL_SET_NAME(lightBuffer, "LightBuffer");
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ void ShadowsOfMordor::Builder::SceneBuildCache::UpdateLightmaps()
|
||||
// Download buffer data
|
||||
if (lightmapEntry.LightmapData->DownloadData(ImportLightmapTextureData))
|
||||
{
|
||||
LOG(Warning, "Cannot download LightmapData.");
|
||||
LOG(Error, "Cannot download LightmapData.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ void ShadowsOfMordor::Builder::updateLightmaps()
|
||||
{
|
||||
auto texture = textures[textureIndex];
|
||||
GPUDevice::Instance->Locker.Unlock();
|
||||
if (texture->WaitForLoaded())
|
||||
if (texture == nullptr || texture->WaitForLoaded())
|
||||
{
|
||||
LOG(Error, "Lightmap load failed.");
|
||||
return;
|
||||
|
||||
@@ -276,6 +276,7 @@ void ShadowsOfMordor::Builder::saveState()
|
||||
context->Flush();
|
||||
Platform::Sleep(10);
|
||||
void* mapped = lightmapDataStaging->Map(GPUResourceMapMode::Read);
|
||||
ASSERT(mapped);
|
||||
stream->WriteInt32(lightmapDataSize);
|
||||
stream->WriteBytes(mapped, lightmapDataSize);
|
||||
lightmapDataStaging->Unmap();
|
||||
|
||||
@@ -637,8 +637,8 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
|
||||
// Write operations
|
||||
auto framesCount = writeLocal(VariantType::Float, String::Format(TEXT("{0}.x * {1}.y"), framesXY.Value, framesXY.Value), node);
|
||||
frame = writeLocal(VariantType::Float, String::Format(TEXT("fmod(floor({0}), {1})"), frame.Value, framesCount.Value), node);
|
||||
auto framesXYInv = writeOperation2(node, Value::One, framesXY, '/');
|
||||
frame = writeLocal(VariantType::Float, String::Format(TEXT("fmod({0}, {1})"), frame.Value, framesCount.Value), node);
|
||||
auto framesXYInv = writeOperation2(node, Value::One.AsFloat2(), framesXY, '/');
|
||||
auto frameY = writeLocal(VariantType::Float, String::Format(TEXT("abs({0} * {1}.y - (floor({2} * {3}.x) + {0} * 1))"), invertY.Value, framesXY.Value, frame.Value, framesXYInv.Value), node);
|
||||
auto frameX = writeLocal(VariantType::Float, String::Format(TEXT("abs({0} * {1}.x - (({2} - {1}.x * floor({2} * {3}.x)) + {0} * 1))"), invertX.Value, framesXY.Value, frame.Value, framesXYInv.Value), node);
|
||||
value = writeLocal(VariantType::Float2, String::Format(TEXT("({3} + float2({0}, {1})) * {2}"), frameX.Value, frameY.Value, framesXYInv.Value, uv.Value), node);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace FlaxEngine.GUI
|
||||
|
||||
// Scrolling
|
||||
|
||||
private float _clickChange = 20, _scrollChange = 30;
|
||||
private float _clickChange = 20, _scrollChange = 75;
|
||||
private float _minimum, _maximum = 100;
|
||||
private float _value, _targetValue;
|
||||
private readonly Orientation _orientation;
|
||||
@@ -146,6 +146,24 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the speed for the scroll on mouse wheel.
|
||||
/// </summary>
|
||||
public float ScrollSpeedWheel
|
||||
{
|
||||
get => _scrollChange;
|
||||
set => _scrollChange = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the speed for the scroll on mouse click.
|
||||
/// </summary>
|
||||
public float ScrollSpeedClick
|
||||
{
|
||||
get => _clickChange;
|
||||
set => _clickChange = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value slow down.
|
||||
/// </summary>
|
||||
|
||||
@@ -179,6 +179,8 @@ namespace FlaxEngine.GUI
|
||||
/// <param name="target">The target.</param>
|
||||
public void OnMouseLeaveControl(Control target)
|
||||
{
|
||||
if (Visible)
|
||||
Hide();
|
||||
_lastTarget = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,9 +160,9 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
uint sdfCascade = GetGlobalSDFCascade(GlobalSDF, probePosition);
|
||||
float4 CachedProbeOffsets[64];
|
||||
// TODO: test performance diff when using shared memory and larger thread group (is it worth it?)
|
||||
for(uint x = 0; x < 4; x++)
|
||||
for(uint y = 0; y < 4; y++)
|
||||
for(uint z = 0; z < 4; z++)
|
||||
for (uint x = 0; x < 4; x++)
|
||||
for (uint y = 0; y < 4; y++)
|
||||
for (uint z = 0; z < 4; z++)
|
||||
{
|
||||
float3 offset = Remap(float3(x, y, z), 0, 3, -0.5f, 0.5f) * relocateLimit;
|
||||
float offsetSdf = SampleGlobalSDFCascade(GlobalSDF, GlobalSDFTex, probeBasePosition + offset, sdfCascade);
|
||||
@@ -273,7 +273,7 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
float4 probeData = LoadDDGIProbeData(DDGI, ProbesData, CascadeIndex, probeIndex);
|
||||
uint probeState = DecodeDDGIProbeState(probeData);
|
||||
uint probeRaysCount = GetProbeRaysCount(DDGI, probeState);
|
||||
if (probeState == DDGI_PROBE_STATE_INACTIVE || probeRaysCount < rayIndex)
|
||||
if (probeState == DDGI_PROBE_STATE_INACTIVE || rayIndex >= probeRaysCount)
|
||||
return; // Skip disabled probes or if current thread's ray is unused
|
||||
float3 probePosition = DecodeDDGIProbePosition(DDGI, probeData, CascadeIndex, probeIndex, probeCoords);
|
||||
float3 probeRayDirection = GetProbeRayDirection(DDGI, rayIndex);
|
||||
|
||||
@@ -342,6 +342,16 @@ namespace Flax.Build.NativeCpp
|
||||
}
|
||||
}
|
||||
|
||||
// Relative to ThirdParty includes for library includes
|
||||
if (!isValid && isLibraryInclude)
|
||||
{
|
||||
includedFilePath = Path.Combine(Globals.Root, "Source", "ThirdParty", includedFile);
|
||||
if (FileExists(includedFilePath))
|
||||
{
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
// Invalid include
|
||||
|
||||
@@ -105,6 +105,7 @@ namespace Flax.Build.Projects.VisualStudio
|
||||
vcProjectFileContent.AppendLine(" <Keyword>MakeFileProj</Keyword>");
|
||||
if (Version >= VisualStudioVersion.VisualStudio2022)
|
||||
vcProjectFileContent.AppendLine(" <ResolveNuGetPackages>false</ResolveNuGetPackages>");
|
||||
vcProjectFileContent.AppendLine(" <VCTargetsPath Condition=\"$(Configuration.Contains('Linux'))\">./</VCTargetsPath>");
|
||||
vcProjectFileContent.AppendLine(" </PropertyGroup>");
|
||||
|
||||
// Default properties
|
||||
@@ -343,6 +344,32 @@ namespace Flax.Build.Projects.VisualStudio
|
||||
|
||||
vcUserFileContent.AppendLine("</Project>");
|
||||
|
||||
if (platforms.Any(x => x.Target == TargetPlatform.Linux))
|
||||
{
|
||||
// Override MSBuild .targets file with one that runs NMake commands (workaround for Rider on Linux)
|
||||
var cppTargetsFileContent = new StringBuilder();
|
||||
cppTargetsFileContent.AppendLine("<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" TreatAsLocalProperty=\"Platform\">");
|
||||
cppTargetsFileContent.AppendLine(" <Target Name=\"Build\">");
|
||||
cppTargetsFileContent.AppendLine(" <Exec Command='$(NMakeBuildCommandLine)'/>");
|
||||
cppTargetsFileContent.AppendLine(" </Target>");
|
||||
cppTargetsFileContent.AppendLine(" <Target Name=\"Rebuild\">");
|
||||
cppTargetsFileContent.AppendLine(" <Exec Command='$(NMakeReBuildCommandLine)'/>");
|
||||
cppTargetsFileContent.AppendLine(" </Target>");
|
||||
cppTargetsFileContent.AppendLine(" <Target Name=\"Clean\">");
|
||||
cppTargetsFileContent.AppendLine(" <Exec Command='$(NMakeCleanCommandLine)'/>");
|
||||
cppTargetsFileContent.AppendLine(" </Target>");
|
||||
cppTargetsFileContent.AppendLine(" <PropertyGroup>");
|
||||
cppTargetsFileContent.AppendLine(" <TargetExt></TargetExt>");
|
||||
cppTargetsFileContent.AppendLine(" <TargetName>$(RootNamespace)$(Configuration.Split('.')[0])</TargetName>");
|
||||
cppTargetsFileContent.AppendLine(" <TargetPath>$(OutDir)/$(TargetName)$(TargetExt)</TargetPath>");
|
||||
cppTargetsFileContent.AppendLine(" </PropertyGroup>");
|
||||
cppTargetsFileContent.AppendLine("</Project>");
|
||||
|
||||
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.targets"), cppTargetsFileContent.ToString());
|
||||
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.Default.props"), vcUserFileContent.ToString());
|
||||
Utilities.WriteFileIfChanged(Path.Combine(projectDirectory, "Microsoft.Cpp.props"), vcUserFileContent.ToString());
|
||||
}
|
||||
|
||||
// Save the files
|
||||
Utilities.WriteFileIfChanged(project.Path, vcProjectFileContent.ToString());
|
||||
Utilities.WriteFileIfChanged(project.Path + ".filters", vcFiltersFileContent.ToString());
|
||||
|
||||
Reference in New Issue
Block a user