Merge remote-tracking branch 'origin/master' into sdl_platform
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Engine/Globals.h"
|
||||
|
||||
ThreadLocal<bool> ContentDeprecatedFlags;
|
||||
|
||||
void ContentDeprecated::Mark()
|
||||
@@ -467,11 +469,13 @@ void Asset::CancelStreaming()
|
||||
{
|
||||
// Cancel loading task but go over asset locker to prevent case if other load threads still loads asset while it's reimported on other thread
|
||||
Locker.Lock();
|
||||
auto loadTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask);
|
||||
auto loadingTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask);
|
||||
Locker.Unlock();
|
||||
if (loadTask)
|
||||
if (loadingTask)
|
||||
{
|
||||
loadTask->Cancel();
|
||||
Platform::AtomicStore(&_loadingTask, 0);
|
||||
LOG(Warning, "Cancel loading task for \'{0}\'", ToString());
|
||||
loadingTask->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,7 +594,7 @@ bool Asset::onLoad(LoadAssetTask* task)
|
||||
|
||||
#if USE_EDITOR
|
||||
// Auto-save deprecated assets to get rid of data in an old format
|
||||
if (isDeprecated && isLoaded)
|
||||
if (isDeprecated && isLoaded && !IsVirtual() && !GetPath().StartsWith(StringUtils::GetDirectoryName(Globals::TemporaryFolder)))
|
||||
{
|
||||
PROFILE_CPU_NAMED("Asset.Save");
|
||||
LOG(Info, "Resaving asset '{}' that uses deprecated data format", ToString());
|
||||
@@ -632,18 +636,11 @@ void Asset::onUnload_MainThread()
|
||||
|
||||
ASSERT(IsInMainThread());
|
||||
|
||||
// Cancel any streaming before calling OnUnloaded event
|
||||
CancelStreaming();
|
||||
|
||||
// Send event
|
||||
OnUnloaded(this);
|
||||
|
||||
// Check if is during loading
|
||||
auto loadingTask = (ContentLoadTask*)Platform::AtomicRead(&_loadingTask);
|
||||
if (loadingTask != nullptr)
|
||||
{
|
||||
// Cancel loading
|
||||
Platform::AtomicStore(&_loadingTask, 0);
|
||||
LOG(Warning, "Cancel loading task for \'{0}\'", ToString());
|
||||
loadingTask->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
@@ -34,6 +34,10 @@ public:
|
||||
|
||||
public:
|
||||
// [ContentLoadTask]
|
||||
String ToString() const override
|
||||
{
|
||||
return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : String::Empty);
|
||||
}
|
||||
bool HasReference(Object* obj) const override
|
||||
{
|
||||
return obj == _asset;
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
static CreateAssetResult Create(CreateAssetContext& context)
|
||||
{
|
||||
// Base
|
||||
IMPORT_SETUP(SkeletonMask, 1);
|
||||
IMPORT_SETUP(SkeletonMask, 2);
|
||||
|
||||
// Chunk 0
|
||||
if (context.AllocateChunk(0))
|
||||
|
||||
@@ -93,6 +93,9 @@ public:
|
||||
// Calculates the inverse of the specified matrix.
|
||||
static void Invert(const Double4x4& value, Double4x4& result);
|
||||
|
||||
// Creates a left-handed, look-at matrix.
|
||||
static void LookAt(const Double3& eye, const Double3& target, const Double3& up, Double4x4& result);
|
||||
|
||||
// Calculates the product of two matrices.
|
||||
static void Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result);
|
||||
|
||||
|
||||
@@ -1001,6 +1001,37 @@ void Double4x4::Invert(const Double4x4& value, Double4x4& result)
|
||||
result.M44 = +d44 * det;
|
||||
}
|
||||
|
||||
void Double4x4::LookAt(const Double3& eye, const Double3& target, const Double3& up, Double4x4& result)
|
||||
{
|
||||
Double3 xaxis, yaxis, zaxis;
|
||||
Double3::Subtract(target, eye, zaxis);
|
||||
zaxis.Normalize();
|
||||
Double3::Cross(up, zaxis, xaxis);
|
||||
xaxis.Normalize();
|
||||
Double3::Cross(zaxis, xaxis, yaxis);
|
||||
|
||||
result.M11 = xaxis.X;
|
||||
result.M21 = xaxis.Y;
|
||||
result.M31 = xaxis.Z;
|
||||
|
||||
result.M12 = yaxis.X;
|
||||
result.M22 = yaxis.Y;
|
||||
result.M32 = yaxis.Z;
|
||||
|
||||
result.M13 = zaxis.X;
|
||||
result.M23 = zaxis.Y;
|
||||
result.M33 = zaxis.Z;
|
||||
|
||||
result.M14 = 0.0f;
|
||||
result.M24 = 0.0f;
|
||||
result.M34 = 0.0f;
|
||||
|
||||
result.M41 = -Double3::Dot(xaxis, eye);
|
||||
result.M42 = -Double3::Dot(yaxis, eye);
|
||||
result.M43 = -Double3::Dot(zaxis, eye);
|
||||
result.M44 = 1.0f;
|
||||
}
|
||||
|
||||
void Double4x4::Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result)
|
||||
{
|
||||
result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41;
|
||||
|
||||
@@ -1149,7 +1149,7 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized.
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
@@ -1179,7 +1179,7 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quaternion that will rotate vector from into vector to, around their plan perpendicular axis.The input vectors don't need to be normalized.
|
||||
/// Gets the quaternion that will rotate the from into vector to, around their plan perpendicular axis. The input vectors don't need to be normalized.
|
||||
/// </summary>
|
||||
/// <param name="from">The source vector.</param>
|
||||
/// <param name="to">The destination vector.</param>
|
||||
|
||||
36
Source/Engine/Core/ScopeExit.h
Normal file
36
Source/Engine/Core/ScopeExit.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Core.h"
|
||||
|
||||
template<typename FuncType>
|
||||
struct ScopeExit
|
||||
{
|
||||
explicit ScopeExit(FuncType&& func)
|
||||
: _func((FuncType&&)func)
|
||||
{
|
||||
}
|
||||
|
||||
~ScopeExit()
|
||||
{
|
||||
_func();
|
||||
}
|
||||
|
||||
private:
|
||||
FuncType _func;
|
||||
};
|
||||
|
||||
namespace THelpers
|
||||
{
|
||||
struct ScopeExitInternal
|
||||
{
|
||||
template<typename FuncType>
|
||||
ScopeExit<FuncType> operator*(FuncType&& func)
|
||||
{
|
||||
return ScopeExit<FuncType>((FuncType&&)func);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define SCOPE_EXIT const auto CONCAT_MACROS(__scopeExit, __LINE__) = THelpers::ScopeExitInternal() * [&]()
|
||||
@@ -99,6 +99,7 @@ struct DebugGeometryBuffer
|
||||
{
|
||||
GPUBuffer* Buffer;
|
||||
float TimeLeft;
|
||||
bool Lines;
|
||||
Matrix Transform;
|
||||
};
|
||||
|
||||
@@ -234,6 +235,14 @@ void TeleportList(const Float3& delta, Array<DebugText3D>& list)
|
||||
}
|
||||
}
|
||||
|
||||
void TeleportList(const Float3& delta, Array<DebugGeometryBuffer>& list)
|
||||
{
|
||||
for (auto& v : list)
|
||||
{
|
||||
v.Transform.SetTranslation(v.Transform.GetTranslation() + delta);
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugDrawData
|
||||
{
|
||||
Array<DebugGeometryBuffer> GeometryBuffers;
|
||||
@@ -302,6 +311,7 @@ struct DebugDrawData
|
||||
|
||||
void Teleport(const Float3& delta)
|
||||
{
|
||||
TeleportList(delta, GeometryBuffers);
|
||||
TeleportList(delta, DefaultLines);
|
||||
TeleportList(delta, OneFrameLines);
|
||||
TeleportList(delta, DefaultTriangles);
|
||||
@@ -810,6 +820,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
defaultWireTriangles = WriteLists(vertexCounter, Context->DebugDrawDefault.DefaultWireTriangles, Context->DebugDrawDefault.OneFrameWireTriangles);
|
||||
{
|
||||
PROFILE_CPU_NAMED("Flush");
|
||||
ZoneValue(DebugDrawVB->Data.Count() / 1024); // Size in kB
|
||||
DebugDrawVB->Flush(context);
|
||||
}
|
||||
}
|
||||
@@ -869,8 +880,8 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
auto state = data.EnableDepthTest ? (geometry.Lines ? &DebugDrawPsLinesDepthTest : &DebugDrawPsTrianglesDepthTest) : (geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault);
|
||||
context->UpdateCB(cb, &tmp);
|
||||
auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault;
|
||||
context->SetState(state->Get(enableDepthWrite, true));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
@@ -918,8 +929,9 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
auto state = geometry.Lines ? &DebugDrawPsLinesDefault : &DebugDrawPsTrianglesDefault;
|
||||
context->UpdateCB(cb, &tmp);
|
||||
context->SetState(DebugDrawPsLinesDefault.Get(false, false));
|
||||
context->SetState(state->Get(false, false));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
}
|
||||
@@ -1164,6 +1176,7 @@ void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float durat
|
||||
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
|
||||
geometry.Buffer = lines;
|
||||
geometry.TimeLeft = duration;
|
||||
geometry.Lines = true;
|
||||
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
|
||||
}
|
||||
|
||||
@@ -1520,6 +1533,23 @@ void DebugDraw::DrawTriangles(const Span<Float3>& vertices, const Matrix& transf
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration, bool depthTest)
|
||||
{
|
||||
if (triangles == nullptr || triangles->GetSize() == 0)
|
||||
return;
|
||||
if (triangles->GetSize() % (sizeof(Vertex) * 3) != 0)
|
||||
{
|
||||
DebugLog::ThrowException("Cannot draw debug lines with incorrect amount of items in array");
|
||||
return;
|
||||
}
|
||||
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
|
||||
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
|
||||
geometry.Buffer = triangles;
|
||||
geometry.TimeLeft = duration;
|
||||
geometry.Lines = false;
|
||||
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
|
||||
}
|
||||
|
||||
void DebugDraw::DrawTriangles(const Array<Float3>& vertices, const Color& color, float duration, bool depthTest)
|
||||
{
|
||||
DrawTriangles(Span<Float3>(vertices.Get(), vertices.Count()), color, duration, depthTest);
|
||||
|
||||
@@ -74,7 +74,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
API_FUNCTION() static bool CanClear(void* context = nullptr);
|
||||
#endif
|
||||
|
||||
// Gets the last view position when rendering the current context. Can be sued for custom culling or LODing when drawing more complex shapes.
|
||||
// Gets the last view position when rendering the current context. Can be used for custom culling or LODing when drawing more complex shapes.
|
||||
static Vector3 GetViewPos();
|
||||
|
||||
/// <summary>
|
||||
@@ -296,12 +296,21 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawTriangles(const Span<Float3>& vertices, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the triangles using the provided vertex buffer that contains groups of 3 Vertex elements per-triangle.
|
||||
/// </summary>
|
||||
/// <param name="triangles">The GPU buffer with vertices for triangles (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawTriangles(GPUBuffer* triangles, const Matrix& transform, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
@@ -315,7 +324,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -336,7 +345,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -357,7 +366,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -376,7 +385,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -395,7 +404,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// Draws the triangles.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -416,7 +425,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
@@ -437,7 +446,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// </summary>
|
||||
/// <param name="vertices">The triangle vertices list.</param>
|
||||
/// <param name="indices">The triangle indices list (must have multiple of 3 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="transform">The custom matrix used to transform all triangle vertices.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
|
||||
@@ -443,6 +443,15 @@ bool Engine::IsEditor()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Engine::IsPlayMode()
|
||||
{
|
||||
#if USE_EDITOR
|
||||
return Editor::IsPlayMode;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int32 Engine::GetFramesPerSecond()
|
||||
{
|
||||
return EngineImpl::Fps;
|
||||
|
||||
@@ -178,6 +178,11 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() static bool IsEditor();
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the editor is in play mode or will always return true in a shipped applications.
|
||||
/// </summary>
|
||||
API_PROPERTY() static bool IsPlayMode();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of frames rendered during last second known as Frames Per Second. User scripts updates or fixed updates for physics may run at a different frequency than scene rendering. Use this property to get an accurate amount of frames rendered during the last second.
|
||||
/// </summary>
|
||||
|
||||
@@ -37,6 +37,21 @@ DEFINE_ENGINE_SERVICE_EVENT(LateFixedUpdate);
|
||||
DEFINE_ENGINE_SERVICE_EVENT(Draw);
|
||||
DEFINE_ENGINE_SERVICE_EVENT_INVERTED(BeforeExit);
|
||||
|
||||
#if TRACY_ENABLE
|
||||
|
||||
StringView FillEventNameBuffer(Char* buffer, StringView name, StringView postfix)
|
||||
{
|
||||
int32 size = 0;
|
||||
for (int32 j = 0; j < name.Length(); j++)
|
||||
if (name[j] != ' ')
|
||||
buffer[size++] = name[j];
|
||||
Platform::MemoryCopy(buffer + size, postfix.Get(), (postfix.Length() + 1) * sizeof(Char));
|
||||
size += postfix.Length();
|
||||
return StringView(buffer, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EngineService::EngineServicesArray& EngineService::GetServices()
|
||||
{
|
||||
static EngineServicesArray Services;
|
||||
@@ -78,14 +93,9 @@ void EngineService::OnInit()
|
||||
const StringView name(service->Name);
|
||||
#if TRACY_ENABLE
|
||||
ZoneScoped;
|
||||
int32 nameBufferLength = 0;
|
||||
Char nameBuffer[100];
|
||||
for (int32 j = 0; j < name.Length(); j++)
|
||||
if (name[j] != ' ')
|
||||
nameBuffer[nameBufferLength++] = name[j];
|
||||
Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Init"), 7 * sizeof(Char));
|
||||
nameBufferLength += 7;
|
||||
ZoneName(nameBuffer, nameBufferLength);
|
||||
StringView zoneName = FillEventNameBuffer(nameBuffer, name, StringView(TEXT("::Init"), 6));
|
||||
ZoneName(zoneName.Get(), zoneName.Length());
|
||||
#endif
|
||||
LOG(Info, "Initialize {0}...", name);
|
||||
service->IsInitialized = true;
|
||||
@@ -114,15 +124,10 @@ void EngineService::OnDispose()
|
||||
{
|
||||
#if TRACY_ENABLE
|
||||
ZoneScoped;
|
||||
const StringView name(service->Name);
|
||||
int32 nameBufferLength = 0;
|
||||
Char nameBuffer[100];
|
||||
for (int32 j = 0; j < name.Length(); j++)
|
||||
if (name[j] != ' ')
|
||||
nameBuffer[nameBufferLength++] = name[j];
|
||||
Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Dispose"), 10 * sizeof(Char));
|
||||
nameBufferLength += 10;
|
||||
ZoneName(nameBuffer, nameBufferLength);
|
||||
const StringView name(service->Name);
|
||||
StringView zoneName = FillEventNameBuffer(nameBuffer, name, StringView(TEXT("::Dispose"), 9));
|
||||
ZoneName(zoneName.Get(), zoneName.Length());
|
||||
#endif
|
||||
service->IsInitialized = false;
|
||||
service->Dispose();
|
||||
|
||||
@@ -67,6 +67,14 @@ public:
|
||||
return _type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets work synchronization start point
|
||||
/// </summary>
|
||||
FORCE_INLINE GPUSyncPoint GetSyncStart() const
|
||||
{
|
||||
return _syncPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets work finish synchronization point
|
||||
/// </summary>
|
||||
|
||||
@@ -36,7 +36,7 @@ GPUTasksContext::~GPUTasksContext()
|
||||
if (task->GetSyncPoint() <= _currentSyncPoint && task->GetState() != TaskState::Finished)
|
||||
{
|
||||
if (!Engine::IsRequestingExit)
|
||||
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
|
||||
LOG(Warning, "'{0}' has been canceled before a sync", task->ToString());
|
||||
task->CancelSync();
|
||||
}
|
||||
}
|
||||
@@ -51,18 +51,15 @@ void GPUTasksContext::Run(GPUTask* task)
|
||||
ASSERT(task != nullptr);
|
||||
|
||||
task->Execute(this);
|
||||
if (task->IsSyncing())
|
||||
//if (task->GetSyncStart() != 0)
|
||||
_tasksSyncing.Add(task);
|
||||
}
|
||||
|
||||
void GPUTasksContext::OnCancelSync(GPUTask* task)
|
||||
{
|
||||
ASSERT(task != nullptr);
|
||||
|
||||
_tasksSyncing.Remove(task);
|
||||
|
||||
if (!Engine::IsRequestingExit)
|
||||
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
|
||||
LOG(Warning, "'{0}' has been canceled before a sync", task->ToString());
|
||||
}
|
||||
|
||||
void GPUTasksContext::OnFrameBegin()
|
||||
|
||||
@@ -18,7 +18,7 @@ protected:
|
||||
CriticalSection _locker;
|
||||
GPUSyncPoint _currentSyncPoint;
|
||||
int32 _totalTasksDoneCount = 0;
|
||||
Array<GPUTask*, InlinedAllocation<64>> _tasksSyncing;
|
||||
Array<GPUTask*> _tasksSyncing;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -54,9 +54,9 @@ void GPUTask::OnCancel()
|
||||
if (IsSyncing())
|
||||
{
|
||||
// Task has been performed but is waiting for a CPU/GPU sync so we have to cancel that
|
||||
ASSERT(_context != nullptr);
|
||||
_context->OnCancelSync(this);
|
||||
_context = nullptr;
|
||||
SetState(TaskState::Canceled);
|
||||
}
|
||||
|
||||
// Base
|
||||
|
||||
@@ -475,6 +475,12 @@ bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array<const void*,
|
||||
_collisionProxy.Init<uint32>(vertices, triangles, (const Float3*)vbData[0], (const uint32*)ibData);
|
||||
#endif
|
||||
|
||||
// Free old buffers
|
||||
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[0]);
|
||||
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[1]);
|
||||
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[2]);
|
||||
SAFE_DELETE_GPU_RESOURCE(_indexBuffer);
|
||||
|
||||
// Initialize
|
||||
_vertexBuffers[0] = vertexBuffer0;
|
||||
_vertexBuffers[1] = vertexBuffer1;
|
||||
|
||||
@@ -322,15 +322,17 @@ class StreamTextureMipTask : public GPUUploadTextureMipTask
|
||||
{
|
||||
private:
|
||||
StreamingTexture* _streamingTexture;
|
||||
Task* _rootTask;
|
||||
FlaxStorage::LockData _dataLock;
|
||||
|
||||
public:
|
||||
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex)
|
||||
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex, Task* rootTask)
|
||||
: GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), 0, 0, false)
|
||||
, _streamingTexture(texture)
|
||||
, _rootTask(rootTask ? rootTask : this)
|
||||
, _dataLock(_streamingTexture->GetOwner()->LockData())
|
||||
{
|
||||
_streamingTexture->_streamingTasks.Add(this);
|
||||
_streamingTexture->_streamingTasks.Add(_rootTask);
|
||||
_texture.Released.Bind<StreamTextureMipTask, &StreamTextureMipTask::OnResourceReleased2>(this);
|
||||
}
|
||||
|
||||
@@ -341,7 +343,7 @@ private:
|
||||
if (_streamingTexture)
|
||||
{
|
||||
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
|
||||
_streamingTexture->_streamingTasks.Remove(this);
|
||||
_streamingTexture->_streamingTasks.Remove(_rootTask);
|
||||
_streamingTexture = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -393,7 +395,7 @@ protected:
|
||||
if (_streamingTexture)
|
||||
{
|
||||
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
|
||||
_streamingTexture->_streamingTasks.Remove(this);
|
||||
_streamingTexture->_streamingTasks.Remove(_rootTask);
|
||||
_streamingTexture = nullptr;
|
||||
}
|
||||
|
||||
@@ -443,7 +445,7 @@ Task* StreamingTexture::CreateStreamingTask(int32 residency)
|
||||
|
||||
// Add upload data task
|
||||
const int32 allocatedMipIndex = TotalIndexToTextureMipIndex(mipIndex);
|
||||
task = New<StreamTextureMipTask>(this, allocatedMipIndex);
|
||||
task = New<StreamTextureMipTask>(this, allocatedMipIndex, result);
|
||||
if (result)
|
||||
result->ContinueWith(task);
|
||||
else
|
||||
|
||||
@@ -766,7 +766,7 @@ void AnimatedModel::UpdateBounds()
|
||||
// Apply margin based on model dimensions
|
||||
const Vector3 modelBoxSize = modelBox.GetSize();
|
||||
const Vector3 center = box.GetCenter();
|
||||
const Vector3 sizeHalf = Vector3::Max(box.GetSize() + modelBoxSize * 0.2f, modelBoxSize) * 0.5f;
|
||||
const Vector3 sizeHalf = Vector3::Max(box.GetSize() + modelBoxSize * 0.2f, modelBoxSize) * (0.5f * BoundsScale);
|
||||
_box = BoundingBox(center - sizeHalf, center + sizeHalf);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
bool PerBoneMotionBlur = true;
|
||||
|
||||
/// <summary>
|
||||
/// If true, animation speed will be affected by the global time scale parameter.
|
||||
/// If true, animation speed will be affected by the global timescale parameter.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(30), DefaultValue(true), EditorDisplay(\"Skinned Model\")")
|
||||
bool UseTimeScale = true;
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
bool UpdateWhenOffscreen = false;
|
||||
|
||||
/// <summary>
|
||||
/// The animation update delta time scale. Can be used to speed up animation playback or create slow motion effect.
|
||||
/// The animation update delta timescale. Can be used to speed up animation playback or create slow motion effect.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(45), EditorDisplay(\"Skinned Model\")")
|
||||
float UpdateSpeed = 1.0f;
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
AnimationUpdateMode UpdateMode = AnimationUpdateMode::Auto;
|
||||
|
||||
/// <summary>
|
||||
/// The master scale parameter for the actor bounding box. Helps reducing mesh flickering effect on screen edges.
|
||||
/// The master scale parameter for the actor bounding box. Helps to reduce mesh flickering effect on screen edges.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(60), DefaultValue(1.5f), Limit(0), EditorDisplay(\"Skinned Model\")")
|
||||
float BoundsScale = 1.5f;
|
||||
@@ -388,7 +388,7 @@ public:
|
||||
API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the any animation playback is active on the any slot in Anim Graph (not paused).
|
||||
/// Checks if any animation playback is active on any slot in Anim Graph (not paused).
|
||||
/// </summary>
|
||||
API_FUNCTION() bool IsPlayingSlotAnimation();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Camera.h"
|
||||
#include "Engine/Level/SceneObjectsFactory.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
#include "Engine/Core/Math/Double4x4.h"
|
||||
#include "Engine/Core/Math/Viewport.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
@@ -238,7 +239,7 @@ Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewp
|
||||
viewport.Unproject(farPoint, ivp, farPoint);
|
||||
|
||||
Vector3 dir = Vector3::Normalize(farPoint - nearPoint);
|
||||
if (dir.IsZero())
|
||||
if (dir.IsZero() || dir.IsNanOrInfinity())
|
||||
return Ray::Identity;
|
||||
return Ray(nearPoint, dir);
|
||||
}
|
||||
@@ -302,12 +303,15 @@ void Camera::GetMatrices(Matrix& view, Matrix& projection, const Viewport& viewp
|
||||
}
|
||||
|
||||
// Create view matrix
|
||||
const Float3 direction = GetDirection();
|
||||
const Float3 position = _transform.Translation - origin;
|
||||
const Float3 target = position + direction;
|
||||
Float3 up;
|
||||
Float3::Transform(Float3::Up, GetOrientation(), up);
|
||||
Matrix::LookAt(position, target, up, view);
|
||||
const Vector3 direction = Vector3::Transform(Vector3::Forward, GetOrientation());
|
||||
const Vector3 position = _transform.Translation - origin;
|
||||
const Vector3 target = position + direction;
|
||||
|
||||
Vector3 up;
|
||||
Vector3::Transform(Vector3::Up, GetOrientation(), up);
|
||||
Real4x4 viewResult;
|
||||
Real4x4::LookAt(position, target, up, viewResult);
|
||||
view = Matrix(viewResult);
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
22
Source/Engine/Level/MeshReference.cs
Normal file
22
Source/Engine/Level/MeshReference.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
|
||||
using FlaxEngine.Json;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
partial class ModelInstanceActor
|
||||
{
|
||||
partial struct MeshReference : ICustomValueEquals
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool ValueEquals(object other)
|
||||
{
|
||||
var o = (MeshReference)other;
|
||||
return JsonSerializer.ValueEquals(Actor, o.Actor) &&
|
||||
LODIndex == o.LODIndex &&
|
||||
MeshIndex == o.MeshIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1090,7 +1090,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr
|
||||
root = dynamic_cast<Actor*>(sceneObjects.Value->At(targetActorIdx));
|
||||
}
|
||||
|
||||
// Try using the first actor without a parent as a new ro0t
|
||||
// Try using the first actor without a parent as a new root
|
||||
for (int32 i = 1; i < sceneObjects->Count(); i++)
|
||||
{
|
||||
SceneObject* obj = sceneObjects.Value->At(i);
|
||||
|
||||
@@ -223,7 +223,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
ASSERT(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity());
|
||||
CHECK_RETURN(!isnan(sphere.Radius) && !isinf(sphere.Radius) && !sphere.Center.IsNanOrInfinity(), false);
|
||||
|
||||
// Expand sphere based on the render modules rules (sprite or mesh size)
|
||||
for (int32 moduleIndex = 0; moduleIndex < emitter->Graph.RenderModules.Count(); moduleIndex++)
|
||||
@@ -244,7 +244,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
Vector2::Max(*((Vector2*)spriteSize), maxSpriteSize, maxSpriteSize);
|
||||
spriteSize += stride;
|
||||
}
|
||||
ASSERT(!maxSpriteSize.IsNanOrInfinity());
|
||||
CHECK_RETURN(!maxSpriteSize.IsNanOrInfinity(), false);
|
||||
|
||||
// Enlarge the emitter bounds sphere
|
||||
sphere.Radius += maxSpriteSize.MaxValue();
|
||||
@@ -267,7 +267,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
if (radius > maxRadius)
|
||||
maxRadius = radius;
|
||||
}
|
||||
ASSERT(!isnan(maxRadius) && !isinf(maxRadius));
|
||||
CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false);
|
||||
|
||||
// Enlarge the emitter bounds sphere
|
||||
sphere.Radius += maxRadius;
|
||||
@@ -315,7 +315,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
maxRibbonWidth = Math::Max(*((float*)ribbonWidth), maxRibbonWidth);
|
||||
ribbonWidth += stride;
|
||||
}
|
||||
ASSERT(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth));
|
||||
CHECK_RETURN(!isnan(maxRibbonWidth) && !isinf(maxRibbonWidth), false);
|
||||
|
||||
// Enlarge the emitter bounds sphere
|
||||
sphere.Radius += maxRibbonWidth * 0.5f;
|
||||
@@ -335,7 +335,7 @@ bool ParticleEmitterGraphCPUExecutor::ComputeBounds(ParticleEmitter* emitter, Pa
|
||||
maxRadius = Math::Max(*((float*)radius), maxRadius);
|
||||
radius += stride;
|
||||
}
|
||||
ASSERT(!isnan(maxRadius) && !isinf(maxRadius));
|
||||
CHECK_RETURN(!isnan(maxRadius) && !isinf(maxRadius), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -335,6 +335,7 @@ void Cloth::DrawPhysicsDebug(RenderView& view)
|
||||
#if WITH_CLOTH && COMPILE_WITH_DEBUG_DRAW
|
||||
if (_cloth)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
const ModelInstanceActor::MeshReference mesh = GetMesh();
|
||||
if (mesh.Actor == nullptr)
|
||||
return;
|
||||
|
||||
@@ -59,7 +59,7 @@ API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings", NoConstructor) class
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// The default gravity force value (in cm^2/s).
|
||||
/// The default gravity value (in cm/(s^2)).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Simulation\")")
|
||||
Vector3 DefaultGravity = Vector3(0, -981.0f, 0);
|
||||
|
||||
@@ -119,7 +119,7 @@ void Font::Invalidate()
|
||||
_characters.Clear();
|
||||
}
|
||||
|
||||
void Font::ProcessText(const StringView& text, Array<FontLineCache>& outputLines, const TextLayoutOptions& layout)
|
||||
void Font::ProcessText(const StringView& text, Array<FontLineCache, InlinedAllocation<8>>& outputLines, const TextLayoutOptions& layout)
|
||||
{
|
||||
int32 textLength = text.Length();
|
||||
if (textLength == 0)
|
||||
@@ -311,7 +311,7 @@ Float2 Font::MeasureText(const StringView& text, const TextLayoutOptions& layout
|
||||
return Float2::Zero;
|
||||
|
||||
// Process text
|
||||
Array<FontLineCache> lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> lines;
|
||||
ProcessText(text, lines, layout);
|
||||
|
||||
// Calculate bounds
|
||||
@@ -332,7 +332,7 @@ int32 Font::HitTestText(const StringView& text, const Float2& location, const Te
|
||||
return 0;
|
||||
|
||||
// Process text
|
||||
Array<FontLineCache> lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> lines;
|
||||
ProcessText(text, lines, layout);
|
||||
ASSERT(lines.HasItems());
|
||||
float scale = layout.Scale / FontManager::FontScale;
|
||||
@@ -417,7 +417,7 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo
|
||||
}
|
||||
|
||||
// Process text
|
||||
Array<FontLineCache> lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> lines;
|
||||
ProcessText(text, lines, layout);
|
||||
ASSERT(lines.HasItems());
|
||||
float scale = layout.Scale / FontManager::FontScale;
|
||||
|
||||
@@ -344,7 +344,7 @@ public:
|
||||
/// <param name="text">The input text.</param>
|
||||
/// <param name="layout">The layout properties.</param>
|
||||
/// <param name="outputLines">The output lines list.</param>
|
||||
void ProcessText(const StringView& text, Array<FontLineCache>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
|
||||
void ProcessText(const StringView& text, Array<FontLineCache, InlinedAllocation<8>>& outputLines, API_PARAM(Ref) const TextLayoutOptions& layout);
|
||||
|
||||
/// <summary>
|
||||
/// Processes text to get cached lines for rendering.
|
||||
@@ -352,9 +352,9 @@ public:
|
||||
/// <param name="text">The input text.</param>
|
||||
/// <param name="layout">The layout properties.</param>
|
||||
/// <returns>The output lines list.</returns>
|
||||
API_FUNCTION() Array<FontLineCache> ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout)
|
||||
API_FUNCTION() Array<FontLineCache, InlinedAllocation<8>> ProcessText(const StringView& text, API_PARAM(Ref) const TextLayoutOptions& layout)
|
||||
{
|
||||
Array<FontLineCache> lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> lines;
|
||||
ProcessText(text, lines, layout);
|
||||
return lines;
|
||||
}
|
||||
@@ -366,9 +366,9 @@ public:
|
||||
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
|
||||
/// <param name="layout">The layout properties.</param>
|
||||
/// <returns>The output lines list.</returns>
|
||||
API_FUNCTION() Array<FontLineCache> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
|
||||
API_FUNCTION() Array<FontLineCache, InlinedAllocation<8>> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange, API_PARAM(Ref) const TextLayoutOptions& layout)
|
||||
{
|
||||
Array<FontLineCache> lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> lines;
|
||||
ProcessText(textRange.Substring(text), lines, layout);
|
||||
return lines;
|
||||
}
|
||||
@@ -378,7 +378,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="text">The input text.</param>
|
||||
/// <returns>The output lines list.</returns>
|
||||
API_FUNCTION() FORCE_INLINE Array<FontLineCache> ProcessText(const StringView& text)
|
||||
API_FUNCTION() FORCE_INLINE Array<FontLineCache, InlinedAllocation<8>> ProcessText(const StringView& text)
|
||||
{
|
||||
return ProcessText(text, TextLayoutOptions());
|
||||
}
|
||||
@@ -389,7 +389,7 @@ public:
|
||||
/// <param name="text">The input text.</param>
|
||||
/// <param name="textRange">The input text range (substring range of the input text parameter).</param>
|
||||
/// <returns>The output lines list.</returns>
|
||||
API_FUNCTION() FORCE_INLINE Array<FontLineCache> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
|
||||
API_FUNCTION() FORCE_INLINE Array<FontLineCache, InlinedAllocation<8>> ProcessText(const StringView& text, API_PARAM(Ref) const TextRange& textRange)
|
||||
{
|
||||
return ProcessText(textRange.Substring(text), TextLayoutOptions());
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace
|
||||
|
||||
// Drawing
|
||||
Array<Render2DDrawCall> DrawCalls;
|
||||
Array<FontLineCache> Lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> Lines;
|
||||
Array<Float2> Lines2;
|
||||
bool IsScissorsRectEmpty;
|
||||
bool IsScissorsRectEnabled;
|
||||
|
||||
@@ -72,7 +72,7 @@ void ForwardPass::Dispose()
|
||||
_shader = nullptr;
|
||||
}
|
||||
|
||||
void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output)
|
||||
void ForwardPass::Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output)
|
||||
{
|
||||
PROFILE_GPU_CPU("Forward");
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
@@ -91,6 +91,16 @@ void ForwardPass::Render(RenderContext& renderContext, GPUTexture* input, GPUTex
|
||||
// Check if there is no objects to render or no resources ready
|
||||
auto& forwardList = mainCache->DrawCallsLists[(int32)DrawCallsListType::Forward];
|
||||
auto& distortionList = mainCache->DrawCallsLists[(int32)DrawCallsListType::Distortion];
|
||||
if ((forwardList.IsEmpty() && distortionList.IsEmpty())
|
||||
#if USE_EDITOR
|
||||
|| renderContext.View.Mode == ViewMode::PhysicsColliders
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Skip rendering
|
||||
Swap(input, output);
|
||||
return;
|
||||
}
|
||||
if (distortionList.IsEmpty() || checkIfSkipPass())
|
||||
{
|
||||
// Copy frame
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="input">Target with renderer frame ready for further processing.</param>
|
||||
/// <param name="output">The output frame.</param>
|
||||
void Render(RenderContext& renderContext, GPUTexture* input, GPUTexture* output);
|
||||
void Render(RenderContext& renderContext, GPUTexture*& input, GPUTexture*& output);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -276,11 +276,10 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input,
|
||||
int32 h2 = h1 >> 1;
|
||||
int32 h4 = h2 >> 1;
|
||||
int32 h8 = h4 >> 1;
|
||||
|
||||
int32 bloomMipCount = CalculateBloomMipCount(w1, h1);
|
||||
|
||||
// Ensure to have valid data and if at least one effect should be applied
|
||||
if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass() || w8 == 0 || h8 == 0)
|
||||
if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass() || w8 <= 1 || h8 <= 1)
|
||||
{
|
||||
// Resources are missing. Do not perform rendering. Just copy raw frame
|
||||
context->SetViewportAndScissors((float)output->Width(), (float)output->Height());
|
||||
|
||||
@@ -237,6 +237,12 @@ void Renderer::Render(SceneRenderTask* task)
|
||||
| ViewFlags::ContactShadows
|
||||
| ViewFlags::DepthOfField);
|
||||
}
|
||||
|
||||
// Force Debug Draw usage in some specific views that depend on it
|
||||
if (renderContext.View.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
renderContext.View.Flags |= ViewFlags::DebugDraw;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Perform the actual rendering
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace FlaxEngine.Json
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ICustomValueEquals
|
||||
{
|
||||
bool ValueEquals(object other);
|
||||
}
|
||||
|
||||
partial class JsonSerializer
|
||||
{
|
||||
internal class SerializerCache
|
||||
@@ -262,7 +267,7 @@ namespace FlaxEngine.Json
|
||||
return true;
|
||||
if (objA == null || objB == null)
|
||||
return false;
|
||||
|
||||
|
||||
// Special case when saving reference to prefab object and the objects are different but the point to the same prefab object
|
||||
// In that case, skip saving reference as it's defined in prefab (will be populated via IdsMapping during deserialization)
|
||||
if (objA is SceneObject sceneA && objB is SceneObject sceneB && sceneA && sceneB && sceneA.HasPrefabLink && sceneB.HasPrefabLink)
|
||||
@@ -311,6 +316,8 @@ namespace FlaxEngine.Json
|
||||
return !bEnumerator.MoveNext();
|
||||
}
|
||||
|
||||
if (objA is ICustomValueEquals customValueEquals && objA.GetType() == objB.GetType())
|
||||
return customValueEquals.ValueEquals(objB);
|
||||
return objA.Equals(objB);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, c
|
||||
else if (obj.IsString() && obj.GetStringLength() == 32)
|
||||
{
|
||||
auto value = JsonTools::GetGuid(obj);
|
||||
if (mapping.TryGet(value, value))
|
||||
if (value.IsValid() && mapping.TryGet(value, value))
|
||||
{
|
||||
// Unoptimized version:
|
||||
//obj.SetString(value.ToString(Guid::FormatType::N).ToSTD().c_str(), 32, document.GetAllocator());
|
||||
@@ -255,9 +255,8 @@ BoundingBox JsonTools::GetBoundingBox(const Value& value)
|
||||
|
||||
Guid JsonTools::GetGuid(const Value& value)
|
||||
{
|
||||
if (!value.IsString())
|
||||
if (!value.IsString() || value.GetStringLength() != 32)
|
||||
return Guid::Empty;
|
||||
CHECK_RETURN(value.GetStringLength() == 32, Guid::Empty);
|
||||
|
||||
// Split
|
||||
const char* a = value.GetString();
|
||||
@@ -267,10 +266,12 @@ Guid JsonTools::GetGuid(const Value& value)
|
||||
|
||||
// Parse
|
||||
Guid result;
|
||||
StringUtils::ParseHex(a, 8, &result.A);
|
||||
StringUtils::ParseHex(b, 8, &result.B);
|
||||
StringUtils::ParseHex(c, 8, &result.C);
|
||||
StringUtils::ParseHex(d, 8, &result.D);
|
||||
bool failed = StringUtils::ParseHex(a, 8, &result.A);
|
||||
failed |= StringUtils::ParseHex(b, 8, &result.B);
|
||||
failed |= StringUtils::ParseHex(c, 8, &result.C);
|
||||
failed |= StringUtils::ParseHex(d, 8, &result.D);
|
||||
if (failed)
|
||||
return Guid::Empty;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (byte)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (uint32)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (int16)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public:
|
||||
const auto member = node.FindMember(name);
|
||||
if (member != node.MemberEnd() && member->value.IsInt())
|
||||
{
|
||||
result = member->value.GetInt();
|
||||
result = (uint16)member->value.GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ void Terrain::DrawChunk(const RenderContext& renderContext, const Int2& patchCoo
|
||||
|
||||
void Terrain::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||
{
|
||||
_patches[pathIndex]->DrawPhysicsDebug(view);
|
||||
|
||||
@@ -104,6 +104,8 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z)
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
SAFE_DELETE_GPU_RESOURCE(_collisionTrianglesBuffer);
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
#endif
|
||||
_collisionVertices.Resize(0);
|
||||
}
|
||||
@@ -120,6 +122,9 @@ TerrainPatch::~TerrainPatch()
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
SAFE_DELETE_GPU_RESOURCE(_debugLines);
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
SAFE_DELETE_GPU_RESOURCE(_collisionTrianglesBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
RawDataAsset* TerrainPatch::GetHeightfield() const
|
||||
@@ -2225,6 +2230,8 @@ void TerrainPatch::DestroyCollision()
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
SAFE_DELETE(_collisionTrianglesBuffer);
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
#endif
|
||||
_collisionVertices.Resize(0);
|
||||
}
|
||||
@@ -2317,7 +2324,32 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view)
|
||||
return;
|
||||
if (view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
DEBUG_DRAW_TRIANGLES(GetCollisionTriangles(), Color::DarkOliveGreen, 0, true);
|
||||
const auto& triangles = GetCollisionTriangles();
|
||||
typedef DebugDraw::Vertex Vertex;
|
||||
if (!_collisionTrianglesBuffer)
|
||||
_collisionTrianglesBuffer = GPUDevice::Instance->CreateBuffer(TEXT("Terrain.CollisionTriangles"));
|
||||
const uint32 count = triangles.Count();
|
||||
if (_collisionTrianglesBuffer->GetElementsCount() != count)
|
||||
{
|
||||
if (_collisionTrianglesBuffer->Init(GPUBufferDescription::Vertex(Vertex::GetLayout(), sizeof(Vertex), count)))
|
||||
return;
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
}
|
||||
if (_collisionTrianglesBufferDirty)
|
||||
{
|
||||
const Color32 color(Color::DarkOliveGreen);
|
||||
Array<Vertex> vertices;
|
||||
vertices.Resize((int32)count);
|
||||
const Vector3* src = triangles.Get();
|
||||
Vertex* dst = vertices.Get();
|
||||
for (uint32 i = 0; i < count; i++)
|
||||
{
|
||||
dst[i] = { (Float3)src[i], color };
|
||||
}
|
||||
_collisionTrianglesBuffer->SetData(vertices.Get(), _collisionTrianglesBuffer->GetSize());
|
||||
_collisionTrianglesBufferDirty = false;
|
||||
}
|
||||
DebugDraw::DrawTriangles(_collisionTrianglesBuffer, Matrix::Identity, 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2351,6 +2383,7 @@ const Array<Vector3>& TerrainPatch::GetCollisionTriangles()
|
||||
PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
|
||||
|
||||
_collisionTriangles.Resize((rows - 1) * (cols - 1) * 6);
|
||||
_collisionTrianglesBufferDirty = true;
|
||||
Vector3* data = _collisionTriangles.Get();
|
||||
|
||||
#define GET_VERTEX(x, y) Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))); Vector3::Transform(v##x##y, world, v##x##y)
|
||||
|
||||
@@ -49,6 +49,8 @@ private:
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
Array<Vector3> _collisionTriangles; // TODO: large-worlds
|
||||
class GPUBuffer* _collisionTrianglesBuffer = nullptr;
|
||||
bool _collisionTrianglesBufferDirty = true;
|
||||
#endif
|
||||
Array<Float3> _collisionVertices; // TODO: large-worlds
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ void TestsRunnerService::Update()
|
||||
LOG(Info, "Running Flax Tests...");
|
||||
const int result = Catch::Session().run();
|
||||
if (result == 0)
|
||||
LOG(Info, "Result: {0}", result);
|
||||
LOG(Info, "Flax Tests result: {0}", result);
|
||||
else
|
||||
LOG(Error, "Result: {0}", result);
|
||||
LOG(Error, "Flax Tests result: {0}", result);
|
||||
Log::Logger::WriteFloor();
|
||||
Engine::RequestExit(result);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/ScopeExit.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Level/Actors/EmptyActor.h"
|
||||
#include "Engine/Level/Actors/DirectionalLight.h"
|
||||
@@ -27,6 +28,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab B with two children attached to the root
|
||||
AssetReference<Prefab> prefabB = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabB);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabB); };
|
||||
Guid id;
|
||||
Guid::Parse("665bb01c49a3370f14a023b5395de261", id);
|
||||
prefabB->ChangeID(id);
|
||||
@@ -55,6 +57,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab A with nested Prefab B attached to the root
|
||||
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabA);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabA); };
|
||||
Guid::Parse("02524a044184af56b6c664a0f98bd761", id);
|
||||
prefabA->ChangeID(id);
|
||||
auto prefabAInit = prefabA->Init(Prefab::TypeName,
|
||||
@@ -123,8 +126,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
Content::DeleteAsset(prefabA);
|
||||
Content::DeleteAsset(prefabB);
|
||||
}
|
||||
SECTION("Test Adding Object in Nested Prefab")
|
||||
{
|
||||
@@ -133,6 +134,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab B with just root object
|
||||
AssetReference<Prefab> prefabB = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabB);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabB); };
|
||||
Guid id;
|
||||
Guid::Parse("25dbe4b0416be0777a6ce59e8788b10f", id);
|
||||
prefabB->ChangeID(id);
|
||||
@@ -149,6 +151,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab A with two nested Prefab B attached to the root
|
||||
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabA);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabA); };
|
||||
Guid::Parse("4cb744714f746e31855f41815612d14b", id);
|
||||
prefabA->ChangeID(id);
|
||||
auto prefabAInit = prefabA->Init(Prefab::TypeName,
|
||||
@@ -243,8 +246,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
Content::DeleteAsset(prefabA);
|
||||
Content::DeleteAsset(prefabB);
|
||||
}
|
||||
SECTION("Test Syncing Changes In Nested Prefab Instance")
|
||||
{
|
||||
@@ -253,6 +254,7 @@ TEST_CASE("Prefabs")
|
||||
// Create TestActor prefab with just root object
|
||||
AssetReference<Prefab> testActorPrefab = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(testActorPrefab);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(testActorPrefab); };
|
||||
Guid id;
|
||||
Guid::Parse("7691e981482f2a486e10cfae149e07d3", id);
|
||||
testActorPrefab->ChangeID(id);
|
||||
@@ -269,6 +271,7 @@ TEST_CASE("Prefabs")
|
||||
// Create NestedActor prefab that inherits from TestActor prefab
|
||||
AssetReference<Prefab> nestedActorPrefab = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(nestedActorPrefab);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(nestedActorPrefab); };
|
||||
Guid::Parse("1d521df4465ad849e274748c6d14b703", id);
|
||||
nestedActorPrefab->ChangeID(id);
|
||||
auto nestedActorPrefabInit = nestedActorPrefab->Init(Prefab::TypeName,
|
||||
@@ -328,8 +331,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
nestedActor->DeleteObject();
|
||||
testActor->DeleteObject();
|
||||
Content::DeleteAsset(nestedActorPrefab);
|
||||
Content::DeleteAsset(testActorPrefab);
|
||||
}
|
||||
SECTION("Test Loading Nested Prefab After Changing Root")
|
||||
{
|
||||
@@ -338,6 +339,7 @@ TEST_CASE("Prefabs")
|
||||
// Create base prefab with 3 objects
|
||||
AssetReference<Prefab> prefabBase = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabBase);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabBase); };
|
||||
Guid id;
|
||||
Guid::Parse("2b3334524c696dcfa93cabacd2a4f404", id);
|
||||
prefabBase->ChangeID(id);
|
||||
@@ -366,6 +368,7 @@ TEST_CASE("Prefabs")
|
||||
// Create nested prefab but with 'old' state where root object is different
|
||||
AssetReference<Prefab> prefabNested = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabNested);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabNested); };
|
||||
Guid::Parse("a71447e947cbd2deea018a8377636ce6", id);
|
||||
prefabNested->ChangeID(id);
|
||||
auto prefabNestedInit = prefabNested->Init(Prefab::TypeName,
|
||||
@@ -411,8 +414,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceNested->DeleteObject();
|
||||
instanceBase->DeleteObject();
|
||||
Content::DeleteAsset(prefabNested);
|
||||
Content::DeleteAsset(prefabBase);
|
||||
}
|
||||
SECTION("Test Loading Nested Prefab After Changing and Deleting Root")
|
||||
{
|
||||
@@ -421,6 +422,7 @@ TEST_CASE("Prefabs")
|
||||
// Create base prefab with 1 object
|
||||
AssetReference<Prefab> prefabBase = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabBase);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabBase); };
|
||||
Guid id;
|
||||
Guid::Parse("3b3334524c696dcfa93cabacd2a4f404", id);
|
||||
prefabBase->ChangeID(id);
|
||||
@@ -455,6 +457,7 @@ TEST_CASE("Prefabs")
|
||||
// Create nested prefab but with 'old' state where root object is different
|
||||
AssetReference<Prefab> prefabNested1 = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabNested1);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabNested1); };
|
||||
Guid::Parse("671447e947cbd2deea018a8377636ce6", id);
|
||||
prefabNested1->ChangeID(id);
|
||||
auto prefabNestedInit1 = prefabNested1->Init(Prefab::TypeName,
|
||||
@@ -491,6 +494,7 @@ TEST_CASE("Prefabs")
|
||||
// Create nested prefab but with 'old' state where root object is different and doesn't exist anymore
|
||||
AssetReference<Prefab> prefabNested2 = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabNested2);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabNested2); };
|
||||
Guid::Parse("b71447e947cbd2deea018a8377636ce6", id);
|
||||
prefabNested2->ChangeID(id);
|
||||
auto prefabNestedInit2 = prefabNested2->Init(Prefab::TypeName,
|
||||
@@ -555,9 +559,6 @@ TEST_CASE("Prefabs")
|
||||
instanceNested2->DeleteObject();
|
||||
instanceNested1->DeleteObject();
|
||||
instanceBase->DeleteObject();
|
||||
Content::DeleteAsset(prefabNested2);
|
||||
Content::DeleteAsset(prefabNested1);
|
||||
Content::DeleteAsset(prefabBase);
|
||||
}
|
||||
SECTION("Test Applying Prefab Change To Object References")
|
||||
{
|
||||
@@ -566,6 +567,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab
|
||||
AssetReference<Prefab> prefab = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefab);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefab); };
|
||||
Guid id;
|
||||
Guid::Parse("690e55514cd6fdc2a269429a2bf84133", id);
|
||||
prefab->ChangeID(id);
|
||||
@@ -612,7 +614,6 @@ TEST_CASE("Prefabs")
|
||||
// Cleanup
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
Content::DeleteAsset(prefab);
|
||||
}
|
||||
SECTION("Test Applying Prefab With Missing Nested Prefab")
|
||||
{
|
||||
@@ -637,6 +638,7 @@ TEST_CASE("Prefabs")
|
||||
// Create Prefab A with nested Prefab B attached to the root
|
||||
AssetReference<Prefab> prefabA = Content::CreateVirtualAsset<Prefab>();
|
||||
REQUIRE(prefabA);
|
||||
SCOPE_EXIT{ Content::DeleteAsset(prefabA); };
|
||||
Guid::Parse("4cb744714f746e31855f41815612d14b", id);
|
||||
prefabA->ChangeID(id);
|
||||
auto prefabAInit = prefabA->Init(Prefab::TypeName,
|
||||
@@ -685,7 +687,6 @@ TEST_CASE("Prefabs")
|
||||
instanceA->DeleteObject();
|
||||
instanceB->DeleteObject();
|
||||
instanceC->DeleteObject();
|
||||
Content::DeleteAsset(prefabA);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ void Task::Cancel()
|
||||
bool Task::Wait(double timeoutMilliseconds) const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
double startTime = Platform::GetTimeSeconds() * 0.001;
|
||||
const double startTime = Platform::GetTimeSeconds();
|
||||
|
||||
// TODO: no active waiting! use a semaphore!
|
||||
|
||||
@@ -54,7 +54,7 @@ bool Task::Wait(double timeoutMilliseconds) const
|
||||
// Wait for child if has
|
||||
if (_continueWith)
|
||||
{
|
||||
auto spendTime = Platform::GetTimeSeconds() * 0.001 - startTime;
|
||||
const auto spendTime = (Platform::GetTimeSeconds() - startTime) * 1000.0;
|
||||
return _continueWith->Wait(timeoutMilliseconds - spendTime);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ bool Task::Wait(double timeoutMilliseconds) const
|
||||
return true;
|
||||
|
||||
Platform::Sleep(1);
|
||||
} while (timeoutMilliseconds <= 0.0 || Platform::GetTimeSeconds() * 0.001 - startTime < timeoutMilliseconds);
|
||||
} while (timeoutMilliseconds <= 0.0 || (Platform::GetTimeSeconds() - startTime) * 1000.0 < timeoutMilliseconds);
|
||||
|
||||
// Timeout reached!
|
||||
LOG(Warning, "\'{0}\' has timed out. Wait time: {1} ms", ToString(), timeoutMilliseconds);
|
||||
@@ -208,8 +208,8 @@ void Task::OnCancel()
|
||||
if (IsRunning())
|
||||
{
|
||||
// Wait for it a little bit
|
||||
const double timeout = 2000.0;
|
||||
LOG(Warning, "Cannot cancel \'{0}\' because it's still running, waiting for end with timeout: {1} ms", ToString(), timeout);
|
||||
constexpr double timeout = 10000.0; // 10s
|
||||
LOG(Warning, "Cannot cancel \'{0}\' because it's still running, waiting for end with timeout: {1}ms", ToString(), timeout);
|
||||
Wait(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,11 @@ namespace FlaxEngine.GUI
|
||||
/// </summary>
|
||||
protected float _cachedHeight = 16.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The items spacing.
|
||||
/// </summary>
|
||||
protected float _itemsSpacing = 2.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The items margin.
|
||||
/// </summary>
|
||||
@@ -168,9 +173,9 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item slots margin (the space between items).
|
||||
/// Gets or sets the item slots margin (the space around items).
|
||||
/// </summary>
|
||||
[EditorOrder(10), Tooltip("The item slots margin (the space between items).")]
|
||||
[EditorOrder(10)]
|
||||
public Margin ItemsMargin
|
||||
{
|
||||
get => _itemsMargin;
|
||||
@@ -184,6 +189,23 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item slots spacing (the margin between items).
|
||||
/// </summary>
|
||||
[EditorOrder(11)]
|
||||
public float ItemsSpacing
|
||||
{
|
||||
get => _itemsSpacing;
|
||||
set
|
||||
{
|
||||
if (!Mathf.NearEqual(_itemsSpacing, value))
|
||||
{
|
||||
_itemsSpacing = value;
|
||||
PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the panel close/open animation duration (in seconds).
|
||||
/// </summary>
|
||||
@@ -563,25 +585,27 @@ namespace FlaxEngine.GUI
|
||||
var slotsLeft = clientArea.Left + slotsMargin.Left;
|
||||
var slotsWidth = clientArea.Width - slotsMargin.Width;
|
||||
float minHeight = HeaderHeight;
|
||||
float y = clientArea.Top;
|
||||
float height = clientArea.Top + dropOffset;
|
||||
float y = clientArea.Top + slotsMargin.Top;
|
||||
bool anyAdded = false;
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
Control c = _children[i];
|
||||
if (c.IsScrollable && c.Visible)
|
||||
{
|
||||
var h = c.Height;
|
||||
y += slotsMargin.Top;
|
||||
|
||||
c.Bounds = new Rectangle(slotsLeft, y, slotsWidth, h);
|
||||
|
||||
h += slotsMargin.Bottom;
|
||||
h += _itemsSpacing;
|
||||
y += h;
|
||||
height += h + slotsMargin.Top;
|
||||
anyAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update panel height
|
||||
if (anyAdded)
|
||||
y -= _itemsSpacing;
|
||||
if (anyAdded)
|
||||
y += slotsMargin.Bottom;
|
||||
float height = dropOffset + y;
|
||||
_cachedHeight = height;
|
||||
if (_animationProgress >= 1.0f && _isClosed)
|
||||
y = minHeight;
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace FlaxEngine.GUI
|
||||
private Color _scrollbarTrackColor;
|
||||
private Color _scrollbarThumbColor;
|
||||
private Color _scrollbarThumbSelectedColor;
|
||||
private Rectangle _controlsBoundsBeforeLayout;
|
||||
|
||||
/// <summary>
|
||||
/// The cached scroll area bounds. Used to scroll contents of the panel control. Cached during performing layout.
|
||||
@@ -530,8 +531,25 @@ namespace FlaxEngine.GUI
|
||||
{
|
||||
// Arrange controls and get scroll bounds
|
||||
ArrangeAndGetBounds();
|
||||
UpdateScrollBars();
|
||||
_controlsBoundsBeforeLayout = _controlsBounds;
|
||||
}
|
||||
|
||||
// Update scroll bars
|
||||
/// <inheritdoc />
|
||||
protected override void PerformLayoutAfterChildren()
|
||||
{
|
||||
// If controls area changed during layout then update scroll bars again
|
||||
ArrangeAndGetBounds();
|
||||
if (_controlsBoundsBeforeLayout != _controlsBounds)
|
||||
{
|
||||
UpdateScrollBars();
|
||||
}
|
||||
|
||||
base.PerformLayoutAfterChildren();
|
||||
}
|
||||
|
||||
private void UpdateScrollBars()
|
||||
{
|
||||
var controlsBounds = _controlsBounds;
|
||||
var scrollBounds = controlsBounds;
|
||||
_scrollMargin.ExpandRectangle(ref scrollBounds);
|
||||
@@ -689,7 +707,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
viewOffset.Y = Mathf.Clamp(viewOffset.Y, VScrollBar.Minimum, VScrollBar.Maximum);
|
||||
VScrollBar.Value = viewOffset.Y;
|
||||
VScrollBar.TargetValue = viewOffset.Y;
|
||||
}
|
||||
|
||||
if (HScrollBar != null && HScrollBar.Enabled && width > MinSize)
|
||||
@@ -704,7 +722,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
viewOffset.X = Mathf.Clamp(viewOffset.X, HScrollBar.Minimum, HScrollBar.Maximum);
|
||||
HScrollBar.Value = viewOffset.X;
|
||||
HScrollBar.TargetValue = viewOffset.X;
|
||||
}
|
||||
|
||||
viewOffset *= -1;
|
||||
|
||||
@@ -72,8 +72,11 @@ namespace FlaxEngine.GUI
|
||||
get => _slotSpacing;
|
||||
set
|
||||
{
|
||||
_slotSpacing = value;
|
||||
PerformLayout();
|
||||
if (!Float2.NearEqual(ref _slotSpacing, ref value))
|
||||
{
|
||||
_slotSpacing = value;
|
||||
PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +92,11 @@ namespace FlaxEngine.GUI
|
||||
/// Initializes a new instance of the <see cref="UniformGridPanel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="slotPadding">The slot padding.</param>
|
||||
public UniformGridPanel(float slotPadding = 0)
|
||||
public UniformGridPanel(float slotPadding)
|
||||
{
|
||||
AutoFocus = false;
|
||||
SlotPadding = new Margin(slotPadding);
|
||||
SlotSpacing = new Float2(2);
|
||||
_slotPadding = new Margin(slotPadding);
|
||||
_slotSpacing = new Float2(2);
|
||||
_slotsH = _slotsV = 5;
|
||||
}
|
||||
|
||||
@@ -105,25 +108,32 @@ namespace FlaxEngine.GUI
|
||||
int slotsV = _slotsV;
|
||||
int slotsH = _slotsH;
|
||||
Float2 slotSize;
|
||||
Float2 size = Size;
|
||||
bool applySpacing = true;
|
||||
APPLY_SPACING:
|
||||
if (_slotsV + _slotsH == 0)
|
||||
{
|
||||
slotSize = HasChildren ? Children[0].Size : new Float2(32);
|
||||
slotsH = Mathf.CeilToInt(Width / slotSize.X);
|
||||
slotsV = Mathf.CeilToInt(Height / slotSize.Y);
|
||||
slotsH = Mathf.CeilToInt(size.X / slotSize.X);
|
||||
slotsV = Mathf.CeilToInt(size.Y / slotSize.Y);
|
||||
}
|
||||
else if (slotsH == 0)
|
||||
{
|
||||
float size = Height / slotsV;
|
||||
slotSize = new Float2(size);
|
||||
slotSize = new Float2(size.Y / slotsV);
|
||||
}
|
||||
else if (slotsV == 0)
|
||||
{
|
||||
float size = Width / slotsH;
|
||||
slotSize = new Float2(size);
|
||||
slotSize = new Float2(size.X / slotsH);
|
||||
}
|
||||
else
|
||||
{
|
||||
slotSize = new Float2(Width / slotsH, Height / slotsV);
|
||||
slotSize = new Float2(size.X / slotsH, size.Y / slotsV);
|
||||
}
|
||||
if (applySpacing && _slotSpacing != Float2.Zero)
|
||||
{
|
||||
applySpacing = false;
|
||||
size -= _slotSpacing * new Float2(slotsH > 1 ? slotsH - 1 : 0, slotsV > 1 ? slotsV - 1 : 0);
|
||||
goto APPLY_SPACING;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@@ -135,45 +145,9 @@ namespace FlaxEngine.GUI
|
||||
|
||||
for (int x = 0; x < end; x++)
|
||||
{
|
||||
var slotBounds = new Rectangle(slotSize.X * x, slotSize.Y * y, slotSize.X, slotSize.Y);
|
||||
var slotBounds = new Rectangle((slotSize + _slotSpacing) * new Float2(x, y), slotSize);
|
||||
_slotPadding.ShrinkRectangle(ref slotBounds);
|
||||
|
||||
if (slotsV > 1)
|
||||
{
|
||||
if (y == 0)
|
||||
{
|
||||
slotBounds.Height -= _slotSpacing.Y * 0.5f;
|
||||
}
|
||||
else if (y == slotsV - 1)
|
||||
{
|
||||
slotBounds.Height -= _slotSpacing.Y * 0.5f;
|
||||
slotBounds.Y += _slotSpacing.Y * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
slotBounds.Height -= _slotSpacing.Y;
|
||||
slotBounds.Y += _slotSpacing.Y * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
if (slotsH > 1)
|
||||
{
|
||||
if (x == 0)
|
||||
{
|
||||
slotBounds.Width -= _slotSpacing.X * 0.5f;
|
||||
}
|
||||
else if (x == slotsH - 1)
|
||||
{
|
||||
slotBounds.Width -= _slotSpacing.X * 0.5f;
|
||||
slotBounds.X += _slotSpacing.X * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
slotBounds.Width -= _slotSpacing.X;
|
||||
slotBounds.X += _slotSpacing.X * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
var c = _children[i++];
|
||||
c.Bounds = slotBounds;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ void TextRender::UpdateLayout()
|
||||
int32 kerning;
|
||||
|
||||
// Perform layout
|
||||
Array<FontLineCache> lines;
|
||||
Array<FontLineCache, InlinedAllocation<8>> lines;
|
||||
font->ProcessText(text, lines, _layoutOptions);
|
||||
|
||||
// Prepare buffers capacity
|
||||
|
||||
@@ -372,8 +372,8 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value)
|
||||
// Atan2
|
||||
case 41:
|
||||
{
|
||||
Value v1 = tryGetValue(node->GetBox(0), Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), Value::Zero);
|
||||
Value v1 = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||
Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero);
|
||||
value = writeFunction2(node, v1, v2, TEXT("atan2"));
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user