Merge remote-tracking branch 'origin/master' into dotnet7
# Conflicts: # README.md
This commit is contained in:
@@ -115,6 +115,11 @@ void SlotBucketInit(AnimGraphInstanceData::Bucket& bucket)
|
||||
bucket.Slot.LoopsLeft = 0;
|
||||
}
|
||||
|
||||
void InstanceDataBucketInit(AnimGraphInstanceData::Bucket& bucket)
|
||||
{
|
||||
bucket.InstanceData.Init = true;
|
||||
}
|
||||
|
||||
bool SortMultiBlend1D(const byte& a, const byte& b, AnimGraphNode* n)
|
||||
{
|
||||
// Sort items by X location from the lowest to the highest
|
||||
@@ -432,10 +437,12 @@ bool AnimGraphBase::onNodeLoaded(Node* n)
|
||||
}
|
||||
// Animation Slot
|
||||
case 32:
|
||||
{
|
||||
ADD_BUCKET(SlotBucketInit);
|
||||
break;
|
||||
}
|
||||
// Animation Instance Data
|
||||
case 33:
|
||||
ADD_BUCKET(InstanceDataBucketInit);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
// Custom
|
||||
|
||||
@@ -315,6 +315,12 @@ public:
|
||||
int32 LoopsLeft;
|
||||
};
|
||||
|
||||
struct InstanceDataBucket
|
||||
{
|
||||
bool Init;
|
||||
float Data[4];
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The single data storage bucket for the instanced animation graph node. Used to store the node state (playback position, state, transition data).
|
||||
/// </summary>
|
||||
@@ -327,6 +333,7 @@ public:
|
||||
BlendPoseBucket BlendPose;
|
||||
StateMachineBucket StateMachine;
|
||||
SlotBucket Slot;
|
||||
InstanceDataBucket InstanceData;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2035,10 +2035,22 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Animation Instance Data
|
||||
case 33:
|
||||
{
|
||||
auto& bucket = context.Data->State[node->BucketIndex].InstanceData;
|
||||
if (bucket.Init)
|
||||
{
|
||||
bucket.Init = false;
|
||||
*(Float4*)bucket.Data = (Float4)tryGetValue(node->GetBox(1), Value::Zero);
|
||||
}
|
||||
value = *(Float4*)bucket.Data;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context.ValueCache.Add(boxBase, value);
|
||||
context.ValueCache[boxBase] = value;
|
||||
}
|
||||
|
||||
void AnimGraphExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& value)
|
||||
|
||||
@@ -55,8 +55,7 @@ LoadingThread::~LoadingThread()
|
||||
// Check if has thread attached
|
||||
if (_thread != nullptr)
|
||||
{
|
||||
if (_thread->IsRunning())
|
||||
_thread->Kill(true);
|
||||
_thread->Kill(true);
|
||||
Delete(_thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "Engine/Core/ISerializable.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents the reference to the scene asset. Stores the unique ID of the scene to reference. Can be used to load the selected scene.
|
||||
|
||||
@@ -21,7 +21,11 @@ namespace THelpers
|
||||
template <typename T>
|
||||
struct TIsTriviallyDestructibleImpl<T, false>
|
||||
{
|
||||
enum { Value = __has_trivial_destructor(T) };
|
||||
#if defined(__clang__) && __clang_major__ >= 15
|
||||
enum { Value = __is_trivially_destructible(T) };
|
||||
#else
|
||||
enum { Value = __has_trivial_destructor(T) };
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -261,7 +265,11 @@ struct TIsCopyConstructible
|
||||
template<typename T>
|
||||
struct TIsTriviallyCopyConstructible
|
||||
{
|
||||
enum { Value = TOrValue<__has_trivial_copy(T), TIsPODType<T>>::Value };
|
||||
#if defined(__clang__) && __clang_major__ >= 15
|
||||
enum { Value = TOrValue<__is_trivially_copyable(T), TIsPODType<T>>::Value };
|
||||
#else
|
||||
enum { Value = TOrValue<__has_trivial_copy(T), TIsPODType<T>>::Value };
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -289,7 +297,11 @@ struct TIsTriviallyDestructible
|
||||
template<typename T>
|
||||
struct TIsTriviallyCopyAssignable
|
||||
{
|
||||
enum { Value = TOrValue<__has_trivial_assign(T), TIsPODType<T>>::Value };
|
||||
#if defined(__clang__) && __clang_major__ >= 15
|
||||
enum { Value = TOrValue<__is_trivially_assignable(T, const T), TIsPODType<T>>::Value };
|
||||
#else
|
||||
enum { Value = TOrValue<__has_trivial_assign(T), TIsPODType<T>>::Value };
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -172,6 +172,7 @@ void ScreenSpaceReflectionsSettings::BlendWith(ScreenSpaceReflectionsSettings& o
|
||||
const bool isHalf = weight >= 0.5f;
|
||||
|
||||
BLEND_FLOAT(Intensity);
|
||||
BLEND_ENUM(TraceMode);
|
||||
BLEND_ENUM(DepthResolution);
|
||||
BLEND_ENUM(RayTracePassResolution);
|
||||
BLEND_FLOAT(BRDFBias);
|
||||
|
||||
@@ -134,9 +134,15 @@ bool RenderTask::Resize(int32 width, int32 height)
|
||||
SceneRenderTask::SceneRenderTask(const SpawnParams& params)
|
||||
: RenderTask(params)
|
||||
{
|
||||
Buffers = New<RenderBuffers>();
|
||||
|
||||
// Initialize view
|
||||
View.Position = Float3::Zero;
|
||||
View.Direction = Float3::Forward;
|
||||
Buffers = New<RenderBuffers>();
|
||||
Matrix::PerspectiveFov(PI_OVER_2, 1.0f, View.Near, View.Far, View.Projection);
|
||||
View.NonJitteredProjection = View.Projection;
|
||||
Matrix::Invert(View.Projection, View.IP);
|
||||
View.SetFace(4);
|
||||
}
|
||||
|
||||
SceneRenderTask::~SceneRenderTask()
|
||||
|
||||
@@ -100,10 +100,8 @@ public:
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the order in which multiple volumes are blended together.
|
||||
/// The volume with the highest priority takes precedence over all other overlapping volumes.
|
||||
/// Gets the order in which multiple volumes are blended together. The volume with the highest priority takes precedence over all other overlapping volumes.
|
||||
/// </summary>
|
||||
/// <returns>The result.</returns>
|
||||
API_PROPERTY(Attributes="EditorDisplay(\"PostFx Volume\"), EditorOrder(60)")
|
||||
FORCE_INLINE int32 GetPriority() const
|
||||
{
|
||||
@@ -111,10 +109,8 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the order in which multiple volumes are blended together.
|
||||
/// The volume with the highest priority takes precedence over all other overlapping volumes.
|
||||
/// Sets the order in which multiple volumes are blended together. The volume with the highest priority takes precedence over all other overlapping volumes.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() FORCE_INLINE void SetPriority(int32 value)
|
||||
{
|
||||
_priority = value;
|
||||
@@ -123,7 +119,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the distance inside the volume at which blending with the volume's settings occurs.
|
||||
/// </summary>
|
||||
/// <returns>The result.</returns>
|
||||
API_PROPERTY(Attributes="EditorDisplay(\"PostFx Volume\"), EditorOrder(70)")
|
||||
FORCE_INLINE float GetBlendRadius() const
|
||||
{
|
||||
@@ -133,7 +128,6 @@ public:
|
||||
/// <summary>
|
||||
/// Sets the distance inside the volume at which blending with the volume's settings occurs.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() void SetBlendRadius(float value)
|
||||
{
|
||||
_blendRadius = Math::Clamp(value, 0.0f, 1000.0f);
|
||||
@@ -142,7 +136,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the amount of influence the volume's properties have. 0 is no effect; 1 is full effect.
|
||||
/// </summary>
|
||||
/// <returns>The result.</returns>
|
||||
API_PROPERTY(Attributes="EditorDisplay(\"PostFx Volume\"), EditorOrder(80)")
|
||||
FORCE_INLINE float GetBlendWeight() const
|
||||
{
|
||||
@@ -152,18 +145,14 @@ public:
|
||||
/// <summary>
|
||||
/// Sets the amount of influence the volume's properties have. 0 is no effect; 1 is full effect.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() void SetBlendWeight(float value)
|
||||
{
|
||||
_blendWeight = Math::Saturate(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whether the bounds of the volume are taken into account.
|
||||
/// If false, the volume affects the entire world, regardless of its bounds.
|
||||
/// If true, the volume only has an effect within its bounds.
|
||||
/// Gets the value indicating whether the bounds of the volume are taken into account. If false, the volume affects the entire world, regardless of its bounds. If true, the volume only has an effect within its bounds.
|
||||
/// </summary>
|
||||
/// <returns>The result.</returns>
|
||||
API_PROPERTY(Attributes="EditorDisplay(\"PostFx Volume\"), EditorOrder(90)")
|
||||
FORCE_INLINE bool GetIsBounded() const
|
||||
{
|
||||
@@ -171,11 +160,8 @@ public:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value indicating whether the bounds of the volume are taken into account.
|
||||
/// If false, the volume affects the entire world, regardless of its bounds.
|
||||
/// If true, the volume only has an effect within its bounds.
|
||||
/// Sets the value indicating whether the bounds of the volume are taken into account. If false, the volume affects the entire world, regardless of its bounds. If true, the volume only has an effect within its bounds.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
API_PROPERTY() FORCE_INLINE void SetIsBounded(bool value)
|
||||
{
|
||||
_isBounded = value;
|
||||
|
||||
@@ -352,7 +352,7 @@ void NavMeshRuntime::EnsureCapacity(int32 tilesToAddCount)
|
||||
// Navmesh tiles capacity growing rule
|
||||
int32 newCapacity = capacity ? capacity : 32;
|
||||
while (newCapacity < newTilesCount)
|
||||
newCapacity = Math::RoundUpToPowerOf2(newCapacity);
|
||||
newCapacity = Math::RoundUpToPowerOf2(newCapacity + 1);
|
||||
|
||||
LOG(Info, "Resizing navmesh {2} from {0} to {1} tiles capacity", capacity, newCapacity, Properties.Name);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
/// Gets the size of the box, measured in the object's local space.
|
||||
/// </summary>
|
||||
/// <remarks>The box size will be scaled by the actor's world scale. </remarks>
|
||||
API_PROPERTY(Attributes="EditorOrder(100), DefaultValue(typeof(Vector3), \"100,100,100\"), EditorDisplay(\"Collider\")")
|
||||
API_PROPERTY(Attributes="EditorOrder(100), DefaultValue(typeof(Float3), \"100,100,100\"), EditorDisplay(\"Collider\")")
|
||||
FORCE_INLINE Float3 GetSize() const
|
||||
{
|
||||
return _size;
|
||||
|
||||
@@ -50,11 +50,16 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(FileSystemBase);
|
||||
/// </summary>
|
||||
/// <param name="parentWindow">The parent window or null.</param>
|
||||
/// <param name="initialDirectory">The initial directory.</param>
|
||||
/// <param name="filter">The custom filter.</param>
|
||||
/// <param name="filter">The file filter string as null-terminated pairs of name and list of extensions. Multiple file extensions must be separated with semicolon.</param>
|
||||
/// <param name="multiSelect">True if allow multiple files to be selected, otherwise use single-file mode.</param>
|
||||
/// <param name="title">The dialog title.</param>
|
||||
/// <param name="filenames">The output names of the files picked by the user.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// Example file filters:
|
||||
/// "All Files\0*.*"
|
||||
/// "All Files\0*.*\0Image Files\0*.png;*.jpg"
|
||||
/// </remarks>
|
||||
API_FUNCTION() static bool ShowOpenFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, API_PARAM(Out) Array<String, HeapAllocation>& filenames);
|
||||
|
||||
/// <summary>
|
||||
@@ -62,11 +67,16 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(FileSystemBase);
|
||||
/// </summary>
|
||||
/// <param name="parentWindow">The parent window.</param>
|
||||
/// <param name="initialDirectory">The initial directory.</param>
|
||||
/// <param name="filter">The filter.</param>
|
||||
/// <param name="filter">The file filter string as null-terminated pairs of name and list of extensions. Multiple file extensions must be separated with semicolon.</param>
|
||||
/// <param name="multiSelect">True if allow multiple files to be selected, otherwise use single-file mode.</param>
|
||||
/// <param name="title">The title.</param>
|
||||
/// <param name="filenames">The output names of the files picked by the user.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// Example file filters:
|
||||
/// "All Files\0*.*"
|
||||
/// "All Files\0*.*\0Image Files\0*.png;*.jpg"
|
||||
/// </remarks>
|
||||
API_FUNCTION() static bool ShowSaveFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, API_PARAM(Out) Array<String, HeapAllocation>& filenames);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -528,4 +528,17 @@ String StringUtils::ToString(double value)
|
||||
return String::Format(TEXT("{}"), value);
|
||||
}
|
||||
|
||||
String StringUtils::GetZZString(const Char* str)
|
||||
{
|
||||
const Char* end = str;
|
||||
while (*end != '\0')
|
||||
{
|
||||
end++;
|
||||
if (*end == '\0')
|
||||
end++;
|
||||
}
|
||||
const int len = end - str;
|
||||
return String(str, len);
|
||||
}
|
||||
|
||||
#undef STRING_UTILS_ITOSTR_BUFFER_SIZE
|
||||
|
||||
@@ -43,7 +43,10 @@ void ThreadBase::SetPriority(ThreadPriority priority)
|
||||
void ThreadBase::Kill(bool waitForJoin)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
ClearHandleInternal();
|
||||
return;
|
||||
}
|
||||
ASSERT(GetID());
|
||||
const auto thread = static_cast<Thread*>(this);
|
||||
|
||||
@@ -105,7 +108,6 @@ int32 ThreadBase::Run()
|
||||
_callAfterWork = false;
|
||||
_runnable->AfterWork(false);
|
||||
}
|
||||
ClearHandleInternal();
|
||||
_isRunning = false;
|
||||
ThreadExiting(thread, exitCode);
|
||||
ThreadRegistry::Remove(thread);
|
||||
|
||||
@@ -12,6 +12,7 @@ class IRunnable;
|
||||
/// <summary>
|
||||
/// Base class for thread objects.
|
||||
/// </summary>
|
||||
/// <remarks>Ensure to call Kill or Join before deleting thread object.</remarks>
|
||||
class FLAXENGINE_API ThreadBase : public Object, public NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include "LinuxFileSystem.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
@@ -27,20 +29,38 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView&
|
||||
{
|
||||
const StringAsANSI<> initialDirectoryAnsi(*initialDirectory, initialDirectory.Length());
|
||||
const StringAsANSI<> titleAnsi(*title, title.Length());
|
||||
const char* initDir = initialDirectory.HasChars() ? initialDirectoryAnsi.Get() : ".";
|
||||
char cmd[2048];
|
||||
if (FileSystem::FileExists(TEXT("/usr/bin/zenity")))
|
||||
String xdgCurrentDesktop;
|
||||
StringBuilder fileFilter;
|
||||
Array<String> fileFilterEntries;
|
||||
Platform::GetEnvironmentVariable(TEXT("XDG_CURRENT_DESKTOP"), xdgCurrentDesktop);
|
||||
StringUtils::GetZZString(filter.Get()).Split('\0', fileFilterEntries);
|
||||
|
||||
const bool zenitySupported = FileSystem::FileExists(TEXT("/usr/bin/zenity"));
|
||||
const bool kdialogSupported = FileSystem::FileExists(TEXT("/usr/bin/kdialog"));
|
||||
if (zenitySupported && (xdgCurrentDesktop != TEXT("KDE") || !kdialogSupported)) // Prefer kdialog when running on KDE
|
||||
{
|
||||
// TODO: initialDirectory support
|
||||
// TODO: multiSelect support
|
||||
// TODO: filter support
|
||||
sprintf(cmd, "/usr/bin/zenity --modal --file-selection --title=\"%s\" ", titleAnsi.Get());
|
||||
for (int32 i = 1; i < fileFilterEntries.Count(); i += 2)
|
||||
{
|
||||
String extensions(fileFilterEntries[i]);
|
||||
fileFilterEntries[i].Replace(TEXT(";"), TEXT(" "));
|
||||
fileFilter.Append(String::Format(TEXT("{0}--file-filter=\"{1}|{2}\""), i > 1 ? TEXT(" ") : TEXT(""), fileFilterEntries[i-1].Get(), extensions.Get()));
|
||||
}
|
||||
|
||||
sprintf(cmd, "/usr/bin/zenity --modal --file-selection %s--filename=\"%s\" --title=\"%s\" %s ", multiSelect ? "--multiple --separator=$'\n' " : " ", initDir, titleAnsi.Get(), fileFilter.ToStringView().ToStringAnsi().GetText());
|
||||
}
|
||||
else if (FileSystem::FileExists(TEXT("/usr/bin/kdialog")))
|
||||
else if (kdialogSupported)
|
||||
{
|
||||
// TODO: multiSelect support
|
||||
// TODO: filter support
|
||||
const char* initDir = initialDirectory.HasChars() ? initialDirectoryAnsi.Get() : ".";
|
||||
sprintf(cmd, "/usr/bin/kdialog --getopenfilename \"%s\" --title \"%s\" ", initDir, titleAnsi.Get());
|
||||
for (int32 i = 1; i < fileFilterEntries.Count(); i += 2)
|
||||
{
|
||||
String extensions(fileFilterEntries[i]);
|
||||
fileFilterEntries[i].Replace(TEXT(";"), TEXT(" "));
|
||||
fileFilter.Append(String::Format(TEXT("{0}\"{1}({2})\""), i > 1 ? TEXT(" ") : TEXT(""), fileFilterEntries[i-1].Get(), extensions.Get()));
|
||||
}
|
||||
fileFilter.Append(String::Format(TEXT("{0}\"{1}({2})\""), TEXT(" "), TEXT("many things"), TEXT("*.png *.jpg")));
|
||||
|
||||
sprintf(cmd, "/usr/bin/kdialog --getopenfilename %s--title \"%s\" \"%s\" %s ", multiSelect ? "--multiple --separate-output " : " ", titleAnsi.Get(), initDir, fileFilter.ToStringView().ToStringAnsi().GetText());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace FileSystemWatchers
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
GetRootWatcher(event->wd)->OnEvent(name, FileSystemAction::Modify);
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace FileSystemWatchers
|
||||
|
||||
void AddDirWatcher(const int rootFileDesc, const String& path)
|
||||
{
|
||||
auto watcher = New<FileSystemWatcher>(path, false, rootFileDesc);
|
||||
auto watcher = New<FileSystemWatcher>(path, true, rootFileDesc);
|
||||
Pair<String, LinuxFileSystemWatcher*> subDir = Pair<String, LinuxFileSystemWatcher*>(path, watcher);
|
||||
}
|
||||
|
||||
@@ -183,8 +183,16 @@ LinuxFileSystemWatcher::LinuxFileSystemWatcher(const String& directory, bool wit
|
||||
FileSystemWatchers::Watchers[WachedDirectory] = Pair<int, Pair<String, LinuxFileSystemWatcher*>>(rootWatcher, Pair<String, LinuxFileSystemWatcher*>(directory, this));
|
||||
if (withSubDirs)
|
||||
{
|
||||
FileSystemWatchers::RootWatchers[WachedDirectory] = this;
|
||||
FileSystemWatchers::AddSubDirWatcher(WachedDirectory, directory);
|
||||
if (rootWatcher == -1)
|
||||
{
|
||||
FileSystemWatchers::RootWatchers[WachedDirectory] = this;
|
||||
FileSystemWatchers::AddSubDirWatcher(WachedDirectory, directory);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileSystemWatchers::RootWatchers[WachedDirectory] = FileSystemWatchers::RootWatchers[rootWatcher];
|
||||
FileSystemWatchers::AddSubDirWatcher(rootWatcher, directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
FileSystemWatchers::Locker.Unlock();
|
||||
|
||||
@@ -431,8 +431,11 @@ static int X11_MessageBoxCreateWindow(MessageBoxData* data)
|
||||
}
|
||||
else
|
||||
{
|
||||
x = (X11_DisplayWidth(display, data->screen) - data->dialog_width) / 2;
|
||||
y = (X11_DisplayHeight(display, data->screen) - data->dialog_height) / 3;
|
||||
int screenCount;
|
||||
X11::XineramaScreenInfo* xsi = X11::XineramaQueryScreens(xDisplay, &screenCount);
|
||||
ASSERT(data->screen < screenCount);
|
||||
x = (float)xsi[data->screen].x_org + ((float)xsi[data->screen].width - data->dialog_width) / 2;
|
||||
y = (float)xsi[data->screen].y_org + ((float)xsi[data->screen].height - data->dialog_height) / 2;
|
||||
}
|
||||
X11::XMoveWindow(display, data->window, x, y);
|
||||
|
||||
@@ -840,17 +843,17 @@ int X11ErrorHandler(X11::Display* display, X11::XErrorEvent* event)
|
||||
|
||||
int32 CalculateDpi()
|
||||
{
|
||||
// in X11 a screen is not necessarily identical to a desktop
|
||||
// so we need to stick to one type for pixel and physical size query
|
||||
int dpi = 96;
|
||||
char* resourceString = X11::XResourceManagerString(xDisplay);
|
||||
if (resourceString == NULL)
|
||||
return dpi;
|
||||
|
||||
int screenIdx = 0;
|
||||
int widthMM = X11_DisplayWidthMM(xDisplay, screenIdx);
|
||||
int heightMM = X11_DisplayHeightMM(xDisplay, screenIdx);
|
||||
double xdpi = (widthMM ? X11_DisplayWidth(xDisplay, screenIdx) / (double)widthMM * 25.4 : 0);
|
||||
double ydpi = (heightMM ? X11_DisplayHeight(xDisplay, screenIdx) / (double)heightMM * 25.4 : 0);
|
||||
if (xdpi || ydpi)
|
||||
return (int32)Math::Ceil((xdpi + ydpi) / (xdpi && ydpi ? 2 : 1));
|
||||
return 96;
|
||||
char* type = NULL;
|
||||
X11::XrmValue value;
|
||||
X11::XrmDatabase database = X11::XrmGetStringDatabase(resourceString);
|
||||
if (X11::XrmGetResource(database, "Xft.dpi", "String", &type, &value) == 1 && value.addr != NULL)
|
||||
dpi = (int)atof(value.addr);
|
||||
return dpi;
|
||||
}
|
||||
|
||||
// Maps Flax key codes to X11 names for physical key locations.
|
||||
@@ -2101,6 +2104,7 @@ bool LinuxPlatform::Init()
|
||||
xAtomWmName = X11::XInternAtom(xDisplay, "_NET_WM_NAME", 0);
|
||||
xAtomClipboard = X11::XInternAtom(xDisplay, "CLIPBOARD", 0);
|
||||
|
||||
X11::XrmInitialize();
|
||||
SystemDpi = CalculateDpi();
|
||||
|
||||
int cursorSize = X11::XcursorGetDefaultSize(xDisplay);
|
||||
@@ -2806,6 +2810,7 @@ int32 LinuxProcess(const StringView& cmdLine, const StringView& workingDir, cons
|
||||
{
|
||||
close(fildes[0]); // close the reading end of the pipe
|
||||
dup2(fildes[1], STDOUT_FILENO); // redirect stdout to pipe
|
||||
close(fildes[1]);
|
||||
dup2(STDOUT_FILENO, STDERR_FILENO); // redirect stderr to stdout
|
||||
}
|
||||
|
||||
@@ -2814,6 +2819,8 @@ int32 LinuxProcess(const StringView& cmdLine, const StringView& workingDir, cons
|
||||
{
|
||||
LOG(Warning, " failed, errno={}", errno);
|
||||
}
|
||||
fflush(stdout);
|
||||
_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2826,7 +2833,7 @@ int32 LinuxProcess(const StringView& cmdLine, const StringView& workingDir, cons
|
||||
{
|
||||
char lineBuffer[1024];
|
||||
close(fildes[1]); // close the writing end of the pipe
|
||||
FILE *stdPipe = fdopen(fildes[0], "r");
|
||||
FILE* stdPipe = fdopen(fildes[0], "r");
|
||||
while (fgets(lineBuffer, sizeof(lineBuffer), stdPipe) != NULL)
|
||||
{
|
||||
char *p = lineBuffer + strlen(lineBuffer)-1;
|
||||
@@ -2861,6 +2868,7 @@ int32 LinuxProcess(const StringView& cmdLine, const StringView& workingDir, cons
|
||||
returnCode = EPIPE;
|
||||
}
|
||||
}
|
||||
close(fildes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ static X11::Time MouseLastButtonPressTime = 0;
|
||||
LinuxWindow::LinuxWindow(const CreateWindowSettings& settings)
|
||||
: WindowBase(settings)
|
||||
{
|
||||
auto display = (X11::Display*)LinuxPlatform::GetXDisplay();
|
||||
if (!display)
|
||||
return;
|
||||
auto screen = XDefaultScreen(display);
|
||||
|
||||
// Cache data
|
||||
int32 width = Math::TruncToInt(settings.Size.X);
|
||||
int32 height = Math::TruncToInt(settings.Size.Y);
|
||||
@@ -64,9 +69,21 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings)
|
||||
break;
|
||||
case WindowStartPosition::CenterScreen:
|
||||
{
|
||||
Float2 desktopSize = Platform::GetDesktopSize();
|
||||
x = Math::TruncToInt((desktopSize.X - _clientSize.X) * 0.5f);
|
||||
y = Math::TruncToInt((desktopSize.Y - _clientSize.Y) * 0.5f);
|
||||
Rectangle desktopBounds;
|
||||
int event, err;
|
||||
const bool ok = X11::XineramaQueryExtension(display, &event, &err);
|
||||
if (X11::XineramaQueryExtension(display, &event, &err))
|
||||
{
|
||||
int count;
|
||||
X11::XineramaScreenInfo* xsi = X11::XineramaQueryScreens(display, &count);
|
||||
ASSERT(screen < count);
|
||||
desktopBounds = Rectangle(Float2((float)xsi[screen].x_org, (float)xsi[screen].y_org), Float2((float)xsi[screen].width, (float)xsi[screen].height));
|
||||
X11::XFree(xsi);
|
||||
}
|
||||
else
|
||||
desktopBounds = Rectangle(Float2::Zero, Platform::GetDesktopSize());
|
||||
x = Math::TruncToInt(desktopBounds.Location.X + (desktopBounds.Size.X - _clientSize.X) * 0.5f);
|
||||
y = Math::TruncToInt(desktopBounds.Location.Y + (desktopBounds.Size.Y - _clientSize.Y) * 0.5f);
|
||||
}
|
||||
break;
|
||||
case WindowStartPosition::Manual:
|
||||
@@ -76,11 +93,6 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings)
|
||||
}
|
||||
_resizeDisabled = !settings.HasSizingFrame;
|
||||
|
||||
auto display = (X11::Display*)LinuxPlatform::GetXDisplay();
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
auto screen = XDefaultScreen(display);
|
||||
auto rootWindow = XRootWindow(display, screen);
|
||||
|
||||
long visualMask = VisualScreenMask;
|
||||
|
||||
@@ -438,6 +438,13 @@ public:
|
||||
static String ToString(uint64 value);
|
||||
static String ToString(float value);
|
||||
static String ToString(double value);
|
||||
|
||||
public:
|
||||
|
||||
// Returns the String to double null-terminated string
|
||||
// @param str Double null-terminated string
|
||||
// @return Double null-terminated String
|
||||
static String GetZZString(const Char* str);
|
||||
};
|
||||
|
||||
inline uint32 GetHash(const char* key)
|
||||
|
||||
@@ -53,6 +53,7 @@ UnixThread* UnixThread::Setup(UnixThread* thread, uint32 stackSize)
|
||||
void UnixThread::Join()
|
||||
{
|
||||
pthread_join(_thread, nullptr);
|
||||
ClearHandleInternal();
|
||||
}
|
||||
|
||||
void UnixThread::ClearHandleInternal()
|
||||
|
||||
@@ -113,6 +113,7 @@ unsigned long Win32Thread::ThreadProc(void* pThis)
|
||||
void Win32Thread::Join()
|
||||
{
|
||||
WaitForSingleObject((HANDLE)_thread, INFINITE);
|
||||
ClearHandleInternal();
|
||||
}
|
||||
|
||||
void Win32Thread::ClearHandleInternal()
|
||||
|
||||
@@ -98,10 +98,12 @@ bool TerrainManager::GetChunkGeometry(DrawCall& drawCall, int32 chunkSize, int32
|
||||
// Prepare
|
||||
const int32 vertexCount = (chunkSize + 1) >> lodIndex;
|
||||
chunkSize = vertexCount - 1;
|
||||
const bool indexUse16bits = chunkSize * chunkSize * vertexCount < MAX_uint16;
|
||||
const int32 indexSize = indexUse16bits ? sizeof(uint16) : sizeof(uint32);
|
||||
const int32 indexCount = chunkSize * chunkSize * 2 * 3;
|
||||
const int32 vertexCount2 = vertexCount * vertexCount;
|
||||
const int32 vbSize = sizeof(TerrainVertex) * vertexCount2;
|
||||
const int32 ibSize = sizeof(uint16) * indexCount;
|
||||
const int32 ibSize = indexSize * indexCount;
|
||||
TempData.Clear();
|
||||
TempData.EnsureCapacity(Math::Max(vbSize, ibSize));
|
||||
|
||||
@@ -140,26 +142,51 @@ bool TerrainManager::GetChunkGeometry(DrawCall& drawCall, int32 chunkSize, int32
|
||||
|
||||
// Create index buffer
|
||||
auto ib = GPUDevice::Instance->CreateBuffer(TEXT("TerrainChunk.IB"));
|
||||
auto index = (uint16*)TempData.Get();
|
||||
for (int32 z = 0; z < chunkSize; z++)
|
||||
if (indexUse16bits)
|
||||
{
|
||||
for (int32 x = 0; x < chunkSize; x++)
|
||||
auto index = (uint16*)TempData.Get();
|
||||
for (int32 z = 0; z < chunkSize; z++)
|
||||
{
|
||||
const uint16 i00 = (x + 0) + (z + 0) * vertexCount;
|
||||
const uint16 i10 = (x + 1) + (z + 0) * vertexCount;
|
||||
const uint16 i11 = (x + 1) + (z + 1) * vertexCount;
|
||||
const uint16 i01 = (x + 0) + (z + 1) * vertexCount;
|
||||
for (int32 x = 0; x < chunkSize; x++)
|
||||
{
|
||||
const uint16 i00 = (x + 0) + (z + 0) * vertexCount;
|
||||
const uint16 i10 = (x + 1) + (z + 0) * vertexCount;
|
||||
const uint16 i11 = (x + 1) + (z + 1) * vertexCount;
|
||||
const uint16 i01 = (x + 0) + (z + 1) * vertexCount;
|
||||
|
||||
*index++ = i00;
|
||||
*index++ = i11;
|
||||
*index++ = i10;
|
||||
*index++ = i00;
|
||||
*index++ = i11;
|
||||
*index++ = i10;
|
||||
|
||||
*index++ = i00;
|
||||
*index++ = i01;
|
||||
*index++ = i11;
|
||||
*index++ = i00;
|
||||
*index++ = i01;
|
||||
*index++ = i11;
|
||||
}
|
||||
}
|
||||
}
|
||||
desc = GPUBufferDescription::Index(sizeof(uint16), indexCount, TempData.Get());
|
||||
else
|
||||
{
|
||||
auto index = (uint32*)TempData.Get();
|
||||
for (int32 z = 0; z < chunkSize; z++)
|
||||
{
|
||||
for (int32 x = 0; x < chunkSize; x++)
|
||||
{
|
||||
const uint32 i00 = (x + 0) + (z + 0) * vertexCount;
|
||||
const uint32 i10 = (x + 1) + (z + 0) * vertexCount;
|
||||
const uint32 i11 = (x + 1) + (z + 1) * vertexCount;
|
||||
const uint32 i01 = (x + 0) + (z + 1) * vertexCount;
|
||||
|
||||
*index++ = i00;
|
||||
*index++ = i11;
|
||||
*index++ = i10;
|
||||
|
||||
*index++ = i00;
|
||||
*index++ = i01;
|
||||
*index++ = i11;
|
||||
}
|
||||
}
|
||||
}
|
||||
desc = GPUBufferDescription::Index(indexSize, indexCount, TempData.Get());
|
||||
if (ib->Init(desc))
|
||||
{
|
||||
vb->ReleaseGPU();
|
||||
|
||||
@@ -149,8 +149,7 @@ void JobSystemService::Dispose()
|
||||
{
|
||||
if (Threads[i])
|
||||
{
|
||||
if (Threads[i]->IsRunning())
|
||||
Threads[i]->Kill(true);
|
||||
Threads[i]->Kill(true);
|
||||
Delete(Threads[i]);
|
||||
Threads[i] = nullptr;
|
||||
}
|
||||
|
||||
@@ -98,10 +98,7 @@ void ThreadPoolService::Dispose()
|
||||
// Delete threads
|
||||
for (int32 i = 0; i < ThreadPoolImpl::Threads.Count(); i++)
|
||||
{
|
||||
if (ThreadPoolImpl::Threads[i]->IsRunning())
|
||||
{
|
||||
ThreadPoolImpl::Threads[i]->Kill(true);
|
||||
}
|
||||
ThreadPoolImpl::Threads[i]->Kill(true);
|
||||
}
|
||||
ThreadPoolImpl::Threads.ClearDelete();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user