Merge branch '1.1' into 1.2

# Conflicts:
#	Source/Platforms/DotNet/Newtonsoft.Json.dll
#	Source/Platforms/DotNet/Newtonsoft.Json.pdb
#	Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll
#	Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll
This commit is contained in:
Wojtek Figat
2021-04-24 12:32:17 +02:00
43 changed files with 820 additions and 245 deletions

View File

@@ -3,7 +3,7 @@
"Version": {
"Major": 1,
"Minor": 1,
"Build": 6217
"Build": 6218
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.",

View File

@@ -43,7 +43,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
const auto uwpDataPath = platformDataPath / (isXboxOne ? TEXT("XboxOne") : TEXT("UWP")) / TEXT("Binaries");
const auto gameSettings = GameSettings::Get();
const auto platformSettings = UWPPlatformSettings::Get();
Array<byte> fileTemplate;
StringAnsi fileTemplate;
// Copy binaries
const auto binPath = data.GetGameBinariesPath();
@@ -149,12 +149,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (!FileSystem::FileExists(dstAssemblyInfoPath))
{
// Get template
if (File::ReadAllBytes(srcAssemblyInfoPath, fileTemplate))
if (File::ReadAllText(srcAssemblyInfoPath, fileTemplate))
{
data.Error(TEXT("Failed to load AssemblyInfo.cs template."));
return true;
}
fileTemplate[fileTemplate.Count() - 1] = 0;
// Write data to file
auto file = FileWriteStream::Open(dstAssemblyInfoPath);
@@ -163,7 +162,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
{
auto now = DateTime::Now();
file->WriteTextFormatted(
(char*)fileTemplate.Get()
fileTemplate.Get()
, gameSettings->ProductName.ToStringAnsi()
, gameSettings->CompanyName.ToStringAnsi()
, now.GetYear()
@@ -182,12 +181,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (!FileSystem::FileExists(dstAppPath))
{
// Get template
if (File::ReadAllBytes(srcAppPath, fileTemplate))
if (File::ReadAllText(srcAppPath, fileTemplate))
{
data.Error(TEXT("Failed to load App.cs template."));
return true;
}
fileTemplate[fileTemplate.Count() - 1] = 0;
// Write data to file
auto file = FileWriteStream::Open(dstAppPath);
@@ -195,7 +193,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (file)
{
file->WriteTextFormatted(
(char*)fileTemplate.Get()
fileTemplate.Get()
, defaultNamespace.ToStringAnsi() // {0} Default Namespace
);
hasError = file->HasError();
@@ -211,12 +209,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
const auto srcFlaxGeneratedPath = uwpDataPath / TEXT("FlaxGenerated.cs");
{
// Get template
if (File::ReadAllBytes(srcFlaxGeneratedPath, fileTemplate))
if (File::ReadAllText(srcFlaxGeneratedPath, fileTemplate))
{
data.Error(TEXT("Failed to load FlaxGenerated.cs template."));
return true;
}
fileTemplate[fileTemplate.Count() - 1] = 0;
// Prepare
StringAnsi autoRotationPreferences;
@@ -252,7 +249,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (file)
{
file->WriteTextFormatted(
(char*)fileTemplate.Get()
fileTemplate.Get()
, autoRotationPreferences.Get()
, preferredLaunchWindowingMode.Get()
);
@@ -272,12 +269,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (!FileSystem::FileExists(dstSolutionPath))
{
// Get template
if (File::ReadAllBytes(srcSolutionPath, fileTemplate))
if (File::ReadAllText(srcSolutionPath, fileTemplate))
{
data.Error(TEXT("Failed to load Solution.sln template."));
return true;
}
fileTemplate[fileTemplate.Count() - 1] = 0;
// Write data to file
auto file = FileWriteStream::Open(dstSolutionPath);
@@ -285,7 +281,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (file)
{
file->WriteTextFormatted(
(char*)fileTemplate.Get()
fileTemplate.Get()
, projectName.ToStringAnsi() // {0} Project Name
, mode // {1} Platform Mode
, projectGuid.ToStringAnsi() // {2} Project ID
@@ -305,12 +301,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
const auto srcProjectPath = uwpDataPath / TEXT("Project.csproj");
{
// Get template
if (File::ReadAllBytes(srcProjectPath, fileTemplate))
if (File::ReadAllText(srcProjectPath, fileTemplate))
{
data.Error(TEXT("Failed to load Project.csproj template."));
return true;
}
fileTemplate[fileTemplate.Count() - 1] = 0;
// Build included files data
StringBuilder filesInclude(2048);
@@ -334,7 +329,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (file)
{
file->WriteTextFormatted(
(char*)fileTemplate.Get()
fileTemplate.Get()
, projectName.ToStringAnsi() // {0} Project Name
, mode // {1} Platform Mode
, projectGuid.Get() // {2} Project ID
@@ -357,12 +352,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (!FileSystem::FileExists(dstManifestPath))
{
// Get template
if (File::ReadAllBytes(srcManifestPath, fileTemplate))
if (File::ReadAllText(srcManifestPath, fileTemplate))
{
data.Error(TEXT("Failed to load Package.appxmanifest template."));
return true;
}
fileTemplate[fileTemplate.Count() - 1] = 0;
// Build included files data
StringBuilder filesInclude(2048);
@@ -385,7 +379,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data)
if (file)
{
file->WriteTextFormatted(
(char*)fileTemplate.Get()
fileTemplate.Get()
, projectName.ToStringAnsi() // {0} Display Name
, gameSettings->CompanyName.ToStringAnsi() // {1} Company Name
, productId.ToStringAnsi() // {2} Product ID

View File

@@ -46,10 +46,7 @@ namespace FlaxEditor.CustomEditors
if (values.HasReferenceValue)
{
var v = (IList)values.ReferenceValue;
// Get the reference value if collections are the same size
if (v != null && values.Count == v.Count)
if (values.ReferenceValue is IList v && values.Count == v.Count && v.Count > index)
{
_referenceValue = v[index];
_hasReferenceValue = true;

View File

@@ -150,7 +150,10 @@ namespace FlaxEditor.Options
private void Save()
{
// Update file
Editor.SaveJsonAsset(_optionsFilePath, Options);
if (Editor.SaveJsonAsset(_optionsFilePath, Options))
{
MessageBox.Show(string.Format("Failed to save editor option to '{0}'. Ensure that directory exists and program has access to it.", _optionsFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// Special case for editor analytics
var editorAnalyticsTrackingFile = Path.Combine(Editor.LocalCachePath, "noTracking");

View File

@@ -26,6 +26,7 @@ namespace FlaxEditor.Viewport
/// <seealso cref="IGizmoOwner" />
public class PrefabWindowViewport : PrefabPreview, IEditorPrimitivesOwner
{
[HideInEditor]
private sealed class PrefabSpritesRenderer : MainEditorGizmoViewport.EditorSpritesRenderer
{
public PrefabWindowViewport Viewport;

View File

@@ -31,7 +31,7 @@ DECLARE_ENUM_OPERATORS(AssetsCacheFlags);
/// <summary>
/// Flax Game Engine assets cache container
/// </summary>
class AssetsCache
class FLAXENGINE_API AssetsCache
{
public:

View File

@@ -41,6 +41,18 @@ bool CreateJson::Create(const StringView& path, StringAnsiView& data, StringAnsi
LOG(Warning, "Asset will have different type name {0} -> {1}", typeName, String(dataTypename.Get()));
}
}
else
{
const String directory = StringUtils::GetDirectoryName(path);
if (!FileSystem::DirectoryExists(directory))
{
if (FileSystem::CreateDirectory(directory))
{
LOG(Warning, "Failed to create directory");
return true;
}
}
}
rapidjson_flax::StringBuffer buffer;

View File

@@ -27,6 +27,18 @@ bool StringView::operator!=(const String& other) const
return StringUtils::Compare(this->GetText(), *other) != 0;
}
String StringView::Left(int32 count) const
{
const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length();
return String(**this, countClamped);
}
String StringView::Right(int32 count) const
{
const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length();
return String(**this + Length() - countClamped);
}
String StringView::Substring(int32 startIndex) const
{
ASSERT(startIndex >= 0 && startIndex < Length());

View File

@@ -321,6 +321,20 @@ public:
public:
/// <summary>
/// Gets the left most given number of characters.
/// </summary>
/// <param name="count">The characters count.</param>
/// <returns>The substring.</returns>
String Left(int32 count) const;
/// <summary>
/// Gets the string of characters from the right (end of the string).
/// </summary>
/// <param name="count">The characters count.</param>
/// <returns>The substring.</returns>
String Right(int32 count) const;
/// <summary>
/// Retrieves substring created from characters starting from startIndex to the String end.
/// </summary>

View File

@@ -1040,7 +1040,7 @@ void StagingManagerVulkan::Dispose()
ScopeLock lock(_locker);
#if !BUILD_RELEASE
LOG(Info, "Vulakn staging buffers peek memory usage: {0}, allocs: {1}, frees: {2}", Utilities::BytesToText(_allBuffersPeekSize), Utilities::BytesToText(_allBuffersAllocSize), Utilities::BytesToText(_allBuffersFreeSize));
LOG(Info, "Vulkan staging buffers peek memory usage: {0}, allocs: {1}, frees: {2}", Utilities::BytesToText(_allBuffersPeekSize), Utilities::BytesToText(_allBuffersAllocSize), Utilities::BytesToText(_allBuffersFreeSize));
#endif
// Release buffers and clear memory

View File

@@ -347,6 +347,12 @@ void Actor::SetOrderInParent(int32 index)
}
}
Actor* Actor::GetChild(int32 index) const
{
CHECK_RETURN(index >= 0 && index < Children.Count(), nullptr);
return Children[index];
}
Actor* Actor::GetChild(const StringView& name) const
{
for (int32 i = 0; i < Children.Count(); i++)
@@ -354,7 +360,6 @@ Actor* Actor::GetChild(const StringView& name) const
if (Children[i]->GetName() == name)
return Children[i];
}
return nullptr;
}
@@ -482,6 +487,12 @@ void Actor::SetName(const StringView& value)
Level::callActorEvent(Level::ActorEventType::OnActorNameChanged, this, nullptr);
}
Script* Actor::GetScript(int32 index) const
{
CHECK_RETURN(index >= 0 && index < Scripts.Count(), nullptr);
return Scripts[index];
}
Script* Actor::GetScript(const MClass* type) const
{
CHECK_RETURN(type, nullptr);

View File

@@ -192,10 +192,7 @@ public:
/// </summary>
/// <param name="index">The child actor index.</param>
/// <returns>The child actor (always valid).</returns>
API_FUNCTION() FORCE_INLINE Actor* GetChild(int32 index) const
{
return Children[index];
}
API_FUNCTION() Actor* GetChild(int32 index) const;
/// <summary>
/// Gets the child actor with the given name.
@@ -266,10 +263,7 @@ public:
/// </summary>
/// <param name="index">The script index.</param>
/// <returns>The script (always valid).</returns>
API_FUNCTION() FORCE_INLINE Script* GetScript(int32 index) const
{
return Scripts[index];
}
API_FUNCTION() Script* GetScript(int32 index) const;
/// <summary>
/// Gets the script of the given type from this actor.

View File

@@ -65,22 +65,6 @@ void Game::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs
void Game::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
/*
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
// the app will be forced to exit.
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
create_task([this, deferral]()
{
m_deviceResources->Trim();
m_main->Suspend();
deferral->Complete();
});
*/
}
void Game::OnResuming(Platform::Object^ sender, Platform::Object^ args)
@@ -396,9 +380,10 @@ int PlatformImpl::GetSpecialFolderPath(const SpecialFolder type, wchar_t* buffer
path = Windows::Storage::ApplicationData::Current->LocalFolder->Path;
break;
case SpecialFolder::ProgramData:
path = Windows::Storage::ApplicationData::Current->RoamingFolder->Path;
break;
//case SpecialFolder::Temporary: path = Windows::Storage::ApplicationData::Current->TemporaryFolder->Path; break;
case SpecialFolder::Temporary:
//path = Windows::Storage::ApplicationData::Current->TemporaryFolder->Path;
path = Windows::Storage::ApplicationData::Current->LocalFolder->Path;
break;
}
@@ -409,7 +394,7 @@ int PlatformImpl::GetSpecialFolderPath(const SpecialFolder type, wchar_t* buffer
if (length >= bufferLength)
length = bufferLength - 1;
const wchar_t* data = path->Data();
for (int i = 0; i<length; i++)
for (int i = 0; i < length; i++)
buffer[i] = data[i];
buffer[length] = 0;
return length;

View File

@@ -22,9 +22,9 @@ CharacterController::CharacterController(const SpawnParams& params)
, _radius(50.0f)
, _height(150.0f)
, _minMoveDistance(0.0f)
, _upDirection(Vector3::Up)
, _isUpdatingTransform(false)
, _nonWalkableMode(CharacterController::NonWalkableModes::PreventClimbing)
, _upDirection(Vector3::Up)
, _nonWalkableMode(NonWalkableModes::PreventClimbing)
, _lastFlags(CollisionFlags::None)
{
static_assert(sizeof(_filterData) == sizeof(PxFilterData), "Invalid filter data size.");
@@ -61,7 +61,12 @@ void CharacterController::SetSlopeLimit(float value)
_slopeLimit = value;
if (_controller)
_controller->setSlopeLimit(cosf(value * DegreesToRadians));
_controller->setSlopeLimit(Math::Cos(value * DegreesToRadians));
}
CharacterController::NonWalkableModes CharacterController::GetNonWalkableMode() const
{
return _nonWalkableMode;
}
void CharacterController::SetNonWalkableMode(NonWalkableModes value)
@@ -72,6 +77,11 @@ void CharacterController::SetNonWalkableMode(NonWalkableModes value)
_controller->setNonWalkableMode(static_cast<PxControllerNonWalkableMode::Enum>(value));
}
float CharacterController::GetStepOffset() const
{
return _stepOffset;
}
void CharacterController::SetStepOffset(float value)
{
if (Math::NearEqual(value, _stepOffset))

View File

@@ -118,10 +118,7 @@ public:
/// Gets the non-walkable mode for the character controller.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(215), DefaultValue(NonWalkableModes.PreventClimbing), EditorDisplay(\"Character Controller\")")
FORCE_INLINE NonWalkableModes GetNonWalkableMode() const
{
return _nonWalkableMode;
}
NonWalkableModes GetNonWalkableMode() const;
/// <summary>
/// Sets the non-walkable mode for the character controller.
@@ -132,10 +129,7 @@ public:
/// Gets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controllers height or it will generate an error.
/// </summary>
API_PROPERTY(Attributes="EditorOrder(220), DefaultValue(30.0f), Limit(0), EditorDisplay(\"Character Controller\")")
FORCE_INLINE float GetStepOffset() const
{
return _stepOffset;
}
float GetStepOffset() const;
/// <summary>
/// Sets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controllers height or it will generate an error.

View File

@@ -289,7 +289,7 @@ void RemoveLongPathPrefix(const String& path, String& result)
result.Remove(2, 6);
}
String StringUtils::GetDirectoryName(const String& path)
String StringUtils::GetDirectoryName(const StringView& path)
{
const int32 lastFrontSlash = path.FindLast('\\');
const int32 lastBackSlash = path.FindLast('/');
@@ -297,24 +297,22 @@ String StringUtils::GetDirectoryName(const String& path)
return splitIndex != INVALID_INDEX ? path.Left(splitIndex) : String::Empty;
}
String StringUtils::GetFileName(const String& path)
String StringUtils::GetFileName(const StringView& path)
{
Char chr;
const int32 length = path.Length();
int32 num = length;
do
{
num--;
if (num < 0)
return path;
return String(path);
chr = path[num];
} while (chr != DirectorySeparatorChar && chr != AltDirectorySeparatorChar && chr != VolumeSeparatorChar);
return path.Substring(num + 1, length - num - 1);
}
String StringUtils::GetFileNameWithoutExtension(const String& path)
String StringUtils::GetFileNameWithoutExtension(const StringView& path)
{
String filename = GetFileName(path);
const int32 num = filename.FindLast('.');
@@ -325,14 +323,14 @@ String StringUtils::GetFileNameWithoutExtension(const String& path)
return filename;
}
String StringUtils::GetPathWithoutExtension(const String& path)
String StringUtils::GetPathWithoutExtension(const StringView& path)
{
const int32 num = path.FindLast('.');
if (num != -1)
{
return path.Substring(0, num);
}
return path;
return String(path);
}
void StringUtils::PathRemoveRelativeParts(String& path)

View File

@@ -20,6 +20,7 @@
#include "Engine/Platform/MessageBox.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/Clipboard.h"
#include "Engine/Platform/IGuiData.h"
#include "Engine/Utilities/StringConverter.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Engine/Engine.h"
@@ -58,6 +59,15 @@ X11::Display* xDisplay = nullptr;
X11::XIM IM = nullptr;
X11::XIC IC = nullptr;
X11::Atom xAtomDeleteWindow;
X11::Atom xAtomXdndEnter;
X11::Atom xAtomXdndPosition;
X11::Atom xAtomXdndLeave;
X11::Atom xAtomXdndDrop;
X11::Atom xAtomXdndActionCopy;
X11::Atom xAtomXdndStatus;
X11::Atom xAtomXdndSelection;
X11::Atom xAtomXdndFinished;
X11::Atom xAtomXdndAware;
X11::Atom xAtomWmState;
X11::Atom xAtomWmStateHidden;
X11::Atom xAtomWmStateMaxVert;
@@ -65,6 +75,11 @@ X11::Atom xAtomWmStateMaxHorz;
X11::Atom xAtomWmWindowOpacity;
X11::Atom xAtomWmName;
X11::Atom xAtomClipboard;
X11::Atom xDnDRequested = 0;
X11::Window xDndSourceWindow = 0;
DragDropEffect xDndResult;
Vector2 xDndPos;
int32 xDnDVersion = 0;
int32 SystemDpi = 96;
X11::Cursor Cursors[(int32)CursorType::MAX];
X11::XcursorImage* CursorsImg[(int32)CursorType::MAX];
@@ -1171,6 +1186,13 @@ public:
}
};
struct Property
{
unsigned char* data;
int format, nitems;
X11::Atom type;
};
namespace Impl
{
LinuxKeyboard Keyboard;
@@ -1222,6 +1244,407 @@ namespace Impl
}
}
}
Property ReadProperty(X11::Display* display, X11::Window window, X11::Atom property)
{
X11::Atom readType = 0;
int readFormat = 0;
unsigned long nitems = 0;
unsigned long readBytes = 0;
unsigned char* result = nullptr;
int bytesCount = 1024;
if (property != 0)
{
do
{
if (result != nullptr)
X11::XFree(result);
XGetWindowProperty(display, window, property, 0, bytesCount, 0, AnyPropertyType, &readType, &readFormat, &nitems, &readBytes, &result);
bytesCount *= 2;
} while (readBytes != 0);
}
Property p = { result, readFormat, (int)nitems, readType };
return p;
}
static X11::Atom SelectTargetFromList(X11::Display* display, const char* targetType, X11::Atom* list, int count)
{
for (int i = 0; i < count; i++)
{
X11::Atom atom = list[i];
if (atom != 0 && StringAnsi(XGetAtomName(display, atom)) == targetType)
return atom;
}
return 0;
}
static X11::Atom SelectTargetFromAtoms(X11::Display* display, const char* targetType, X11::Atom t1, X11::Atom t2, X11::Atom t3)
{
if (t1 != 0 && StringAnsi(XGetAtomName(display, t1)) == targetType)
return t1;
if (t2 != 0 && StringAnsi(XGetAtomName(display, t2)) == targetType)
return t2;
if (t3 != 0 && StringAnsi(XGetAtomName(display, t3)) == targetType)
return t3;
return 0;
}
static X11::Window FindAppWindow(X11::Display* display, X11::Window w)
{
int nprops, i = 0;
X11::Atom* a;
if (w == 0)
return 0;
a = X11::XListProperties(display, w, &nprops);
for (i = 0; i < nprops; i++)
{
if (a[i] == xAtomXdndAware)
break;
}
if (nprops)
X11::XFree(a);
if (i != nprops)
return w;
X11::Window child, wtmp;
int tmp;
unsigned int utmp;
X11::XQueryPointer(display, w, &wtmp, &child, &tmp, &tmp, &tmp, &tmp, &utmp);
return FindAppWindow(display, child);
}
}
class LinuxDropFilesData : public IGuiData
{
public:
Array<String> Files;
Type GetType() const override
{
return Type::Files;
}
String GetAsText() const override
{
return String::Empty;
}
void GetAsFiles(Array<String>* files) const override
{
files->Add(Files);
}
};
class LinuxDropTextData : public IGuiData
{
public:
StringView Text;
Type GetType() const override
{
return Type::Text;
}
String GetAsText() const override
{
return String(Text);
}
void GetAsFiles(Array<String>* files) const override
{
}
};
DragDropEffect LinuxWindow::DoDragDrop(const StringView& data)
{
auto cursorWrong = X11::XCreateFontCursor(xDisplay, 54);
auto cursorTransient = X11::XCreateFontCursor(xDisplay, 24);
auto cursorGood = X11::XCreateFontCursor(xDisplay, 4);
Array<X11::Atom, FixedAllocation<3>> formats;
formats.Add(X11::XInternAtom(xDisplay, "text/plain", 0));
formats.Add(X11::XInternAtom(xDisplay, "TEXT", 0));
formats.Add((X11::Atom)31);
StringAnsi dataAnsi(data);
LinuxDropTextData dropData;
dropData.Text = data;
// Begin dragging
auto screen = X11::XDefaultScreen(xDisplay);
auto rootWindow = X11::XRootWindow(xDisplay, screen);
if (X11::XGrabPointer(xDisplay, _window, 1, Button1MotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, rootWindow, cursorWrong, CurrentTime) != GrabSuccess)
return DragDropEffect::None;
X11::XSetSelectionOwner(xDisplay, xAtomXdndSelection, _window, CurrentTime);
// Process events
X11::XEvent event;
enum Status
{
Unaware,
Unreceptive,
CanDrop,
};
int status = Unaware, previousVersion = -1;
X11::Window previousWindow = 0;
DragDropEffect result = DragDropEffect::None;
float lastDraw = Platform::GetTimeSeconds();
float startTime = lastDraw;
while (true)
{
X11::XNextEvent(xDisplay, &event);
if (event.type == SelectionClear)
break;
if (event.type == SelectionRequest)
{
// Extract the relavent data
X11::Window owner = event.xselectionrequest.owner;
X11::Atom selection = event.xselectionrequest.selection;
X11::Atom target = event.xselectionrequest.target;
X11::Atom property = event.xselectionrequest.property;
X11::Window requestor = event.xselectionrequest.requestor;
X11::Time timestamp = event.xselectionrequest.time;
X11::Display* disp = event.xselection.display;
X11::XEvent s;
s.xselection.type = SelectionNotify;
s.xselection.requestor = requestor;
s.xselection.selection = selection;
s.xselection.target = target;
s.xselection.property = 0;
s.xselection.time = timestamp;
if (target == X11::XInternAtom(disp, "TARGETS", 0))
{
Array<X11::Atom> targets;
targets.Add(target);
targets.Add(X11::XInternAtom(disp, "MULTIPLE", 0));
targets.Add(formats.Get(), formats.Count());
X11::XChangeProperty(disp, requestor, property, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)targets.Get(), targets.Count());
s.xselection.property = property;
}
else if (formats.Contains(target))
{
s.xselection.property = property;
X11::XChangeProperty(disp, requestor, property, target, 8, PropModeReplace, reinterpret_cast<const unsigned char*>(dataAnsi.Get()), dataAnsi.Length());
}
X11::XSendEvent(event.xselection.display, event.xselectionrequest.requestor, 1, 0, &s);
}
else if (event.type == MotionNotify)
{
// Find window under mouse
auto window = Impl::FindAppWindow(xDisplay, rootWindow);
int fmt, version = -1;
X11::Atom atmp;
unsigned long nitems, bytesLeft;
unsigned char* data = nullptr;
if (window == previousWindow)
version = previousVersion;
else if(window == 0)
;
else if (X11::XGetWindowProperty(xDisplay, window, xAtomXdndAware, 0, 2, 0, AnyPropertyType, &atmp, &fmt, &nitems, &bytesLeft, &data) != Success)
continue;
else if (data == 0)
continue;
else if (fmt != 32)
continue;
else if (nitems != 1)
continue;
else
version = data[0];
if (status == Unaware && version != -1)
status = Unreceptive;
else if(version == -1)
status = Unaware;
xDndPos = Vector2((float)event.xmotion.x_root, (float)event.xmotion.y_root);
// Update mouse grab
if (status == Unaware)
X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, cursorWrong, CurrentTime);
else if(status == Unreceptive)
X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, cursorTransient, CurrentTime);
else
X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, cursorGood, CurrentTime);
if (window != previousWindow && previousVersion != -1)
{
// Send drag left event
auto ww = WindowsManager::GetByNativePtr((void*)previousWindow);
if (ww)
{
ww->_dragOver = false;
ww->OnDragLeave();
}
else
{
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = previousWindow;
m.message_type = xAtomXdndLeave;
m.format = 32;
m.data.l[0] = _window;
m.data.l[1] = 0;
m.data.l[2] = 0;
m.data.l[3] = 0;
m.data.l[4] = 0;
X11::XSendEvent(xDisplay, previousWindow, 0, NoEventMask, (X11::XEvent*)&m);
X11::XFlush(xDisplay);
}
}
if (window != previousWindow && version != -1)
{
// Send drag enter event
auto ww = WindowsManager::GetByNativePtr((void*)window);
if (ww)
{
xDndPos = ww->ScreenToClient(Platform::GetMousePosition());
xDndResult = DragDropEffect::None;
ww->OnDragEnter(&dropData, xDndPos, xDndResult);
}
else
{
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = window;
m.message_type = xAtomXdndEnter;
m.format = 32;
m.data.l[0] = _window;
m.data.l[1] = Math::Min(5, version) << 24 | (formats.Count() > 3);
m.data.l[2] = formats.Count() > 0 ? formats[0] : 0;
m.data.l[3] = formats.Count() > 1 ? formats[1] : 0;
m.data.l[4] = formats.Count() > 2 ? formats[2] : 0;
X11::XSendEvent(xDisplay, window, 0, NoEventMask, (X11::XEvent*)&m);
X11::XFlush(xDisplay);
}
}
if (version != -1)
{
// Send position event
auto ww = WindowsManager::GetByNativePtr((void*)window);
if (ww)
{
xDndPos = ww->ScreenToClient(Platform::GetMousePosition());
ww->_dragOver = true;
xDndResult = DragDropEffect::None;
ww->OnDragOver(&dropData, xDndPos, xDndResult);
status = CanDrop;
}
else
{
int x, y, tmp;
unsigned int utmp;
X11::Window wtmp;
X11::XQueryPointer(xDisplay, window, &wtmp, &wtmp, &tmp, &tmp, &x, &y, &utmp);
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = window;
m.message_type = xAtomXdndPosition;
m.format = 32;
m.data.l[0] = _window;
m.data.l[1] = 0;
m.data.l[2] = (x << 16) | y;
m.data.l[3] = CurrentTime;
m.data.l[4] = xAtomXdndActionCopy;
X11::XSendEvent(xDisplay, window, 0, NoEventMask, (X11::XEvent*)&m);
X11::XFlush(xDisplay);
}
}
previousWindow = window;
previousVersion = version;
}
else if (event.type == ClientMessage && event.xclient.message_type == xAtomXdndStatus)
{
if ((event.xclient.data.l[1]&1) && status != Unaware)
status = CanDrop;
if (!(event.xclient.data.l[1]&1) && status != Unaware)
status = Unreceptive;
}
else if (event.type == ButtonRelease && event.xbutton.button == Button1)
{
if (status == CanDrop)
{
// Send drop event
auto ww = WindowsManager::GetByNativePtr((void*)previousWindow);
if (ww)
{
xDndPos = ww->ScreenToClient(Platform::GetMousePosition());
xDndResult = DragDropEffect::None;
ww->OnDragDrop(&dropData, xDndPos, xDndResult);
ww->Focus();
result = xDndResult;
}
else
{
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = previousWindow;
m.message_type = xAtomXdndDrop;
m.format = 32;
m.data.l[0] = _window;
m.data.l[1] = 0;
m.data.l[2] = CurrentTime;
m.data.l[3] = 0;
m.data.l[4] = 0;
X11::XSendEvent(xDisplay, previousWindow, 0, NoEventMask, (X11::XEvent*)&m);
X11::XFlush(xDisplay);
result = DragDropEffect::Copy;
}
}
break;
}
// Redraw
const float time = Platform::GetTimeSeconds();
if (time - lastDraw >= 1.0f / 20.0f)
{
lastDraw = time;
Engine::OnDraw();
}
// Prevent dead-loop
if (time - startTime >= 10.0f)
{
break;
}
}
// Drag end
if (previousWindow != 0 && previousVersion != -1)
{
// Send drag left event
auto ww = WindowsManager::GetByNativePtr((void*)previousWindow);
if (ww)
{
ww->_dragOver = false;
ww->OnDragLeave();
}
else
{
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = previousWindow;
m.message_type = xAtomXdndLeave;
m.format = 32;
m.data.l[0] = _window;
m.data.l[1] = 0;
m.data.l[2] = 0;
m.data.l[3] = 0;
m.data.l[4] = 0;
X11::XSendEvent(xDisplay, previousWindow, 0, NoEventMask, (X11::XEvent*)&m);
X11::XFlush(xDisplay);
}
}
// End grabbing
X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, 0, CurrentTime);
XUngrabPointer(xDisplay, CurrentTime);
return result;
}
void LinuxClipboard::Clear()
@@ -1651,7 +2074,15 @@ bool LinuxPlatform::Init()
}
xAtomDeleteWindow = X11::XInternAtom(xDisplay, "WM_DELETE_WINDOW", 0);
xAtomWmState = X11::XInternAtom(xDisplay, "_NET_WM_STATE", 0);
xAtomXdndEnter = X11::XInternAtom(xDisplay, "XdndEnter", 0);
xAtomXdndPosition = X11::XInternAtom(xDisplay, "XdndPosition", 0);
xAtomXdndLeave = X11::XInternAtom(xDisplay, "XdndLeave", 0);
xAtomXdndDrop = X11::XInternAtom(xDisplay, "XdndDrop", 0);
xAtomXdndActionCopy = X11::XInternAtom(xDisplay, "XdndActionCopy", 0);
xAtomXdndStatus = X11::XInternAtom(xDisplay, "XdndStatus", 0);
xAtomXdndSelection = X11::XInternAtom(xDisplay, "XdndSelection", 0);
xAtomXdndFinished = X11::XInternAtom(xDisplay, "XdndFinished", 0);
xAtomXdndAware = X11::XInternAtom(xDisplay, "XdndAware", 0);
xAtomWmStateHidden = X11::XInternAtom(xDisplay, "_NET_WM_STATE_HIDDEN", 0);
xAtomWmStateMaxHorz = X11::XInternAtom(xDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
xAtomWmStateMaxVert = X11::XInternAtom(xDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
@@ -1799,6 +2230,93 @@ void LinuxPlatform::Tick()
window->Close(ClosingReason::User);
}
}
else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndEnter)
{
// Drag&drop enter
X11::Window source = event.xclient.data.l[0];
xDnDVersion = (int32)(event.xclient.data.l[1] >> 24);
const char* targetTypeFiles = "text/uri-list";
if (event.xclient.data.l[1] & 1)
{
Property p = Impl::ReadProperty(xDisplay, source, XInternAtom(xDisplay, "XdndTypeList", 0));
xDnDRequested = Impl::SelectTargetFromList(xDisplay, targetTypeFiles, (X11::Atom*)p.data, p.nitems);
X11::XFree(p.data);
}
else
{
xDnDRequested = Impl::SelectTargetFromAtoms(xDisplay, targetTypeFiles, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]);
}
}
else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndPosition)
{
// Drag&drop move
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = event.xclient.data.l[0];
m.message_type = xAtomXdndStatus;
m.format = 32;
m.data.l[0] = event.xany.window;
m.data.l[1] = (xDnDRequested != 0);
m.data.l[2] = 0;
m.data.l[3] = 0;
m.data.l[4] = xAtomXdndActionCopy;
X11::XSendEvent(xDisplay, event.xclient.data.l[0], 0, NoEventMask, (X11::XEvent*)&m);
X11::XFlush(xDisplay);
xDndPos = Vector2((float)(event.xclient.data.l[2] >> 16), (float)(event.xclient.data.l[2] & 0xffff));
window = WindowsManager::GetByNativePtr((void*)event.xany.window);
if (window)
{
LinuxDropFilesData dropData;
xDndResult = DragDropEffect::None;
if (window->_dragOver)
{
window->OnDragEnter(&dropData, xDndPos, xDndResult);
}
else
{
window->_dragOver = true;
window->OnDragOver(&dropData, xDndPos, xDndResult);
}
}
}
else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndLeave)
{
window = WindowsManager::GetByNativePtr((void*)event.xany.window);
if (window && window->_dragOver)
{
window->_dragOver = false;
window->OnDragLeave();
}
}
else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndDrop)
{
auto w = event.xany.window;
if (xDnDRequested != 0)
{
xDndSourceWindow = event.xclient.data.l[0];
auto primary = XInternAtom(xDisplay, "PRIMARY", 0);
if (xDnDVersion >= 1)
XConvertSelection(xDisplay, xAtomXdndSelection, xDnDRequested, primary, w, event.xclient.data.l[2]);
else
XConvertSelection(xDisplay, xAtomXdndSelection, xDnDRequested, primary, w, CurrentTime);
}
else
{
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = event.xclient.display;
m.window = event.xclient.data.l[0];
m.message_type = xAtomXdndFinished;
m.format = 32;
m.data.l[0] = w;
m.data.l[1] = 0;
m.data.l[2] = 0;
X11::XSendEvent(xDisplay, event.xclient.data.l[0], 0, NoEventMask, (X11::XEvent*)&m);
}
}
break;
case MapNotify:
// Auto-focus shown windows
@@ -1980,6 +2498,41 @@ void LinuxPlatform::Tick()
X11::XSendEvent(xDisplay, ev.requestor, 0, 0, (X11::XEvent*)&ev);
break;
}
case SelectionNotify:
if (event.xselection.target == xDnDRequested)
{
// Drag&drop
window = WindowsManager::GetByNativePtr((void*)event.xany.window);
if (window)
{
Property p = Impl::ReadProperty(xDisplay, event.xany.window, X11::XInternAtom(xDisplay, "PRIMARY", 0));
if (xDndResult != DragDropEffect::None)
{
LinuxDropFilesData dropData;
const String filesList((const char*)p.data);
filesList.Split('\n', dropData.Files);
for (auto& e : dropData.Files)
{
e.Replace(TEXT("file://"), TEXT(""));
e = e.TrimTrailing();
}
xDndResult = DragDropEffect::None;
window->OnDragDrop(&dropData, xDndPos, xDndResult);
}
}
X11::XClientMessageEvent m;
memset(&m, 0, sizeof(m));
m.type = ClientMessage;
m.display = xDisplay;
m.window = xDndSourceWindow;
m.message_type = xAtomXdndFinished;
m.format = 32;
m.data.l[0] = event.xany.window;
m.data.l[1] = 1;
m.data.l[2] = xAtomXdndActionCopy;
XSendEvent(xDisplay, xDndSourceWindow, 0, NoEventMask, (X11::XEvent*)&m);
}
break;
default:
break;
}

View File

@@ -103,7 +103,6 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings)
bool Fullscreen;
bool AllowMinimize;
bool AllowMaximize;
bool AllowDragAndDrop;
*/
const X11::Window window = X11::XCreateWindow(
@@ -223,6 +222,15 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings)
}
X11::XChangeProperty(display, window, wmState, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)states, statesCount);
// Drag&drop support
if (settings.AllowDragAndDrop)
{
auto xdndVersion = 5;
auto xdndAware = XInternAtom(display, "XdndAware", 0);
if (xdndAware != 0)
X11::XChangeProperty(display, window, xdndAware, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)&xdndVersion, 1);
}
// Sync
X11::XFlush(display);
X11::XSync(display, 0);
@@ -725,12 +733,6 @@ void LinuxWindow::SetTitle(const StringView& title)
_title = title;
}
DragDropEffect LinuxWindow::DoDragDrop(const StringView& data)
{
// TODO: impl drag and drop on Linux
return DragDropEffect::None;
}
void LinuxWindow::StartTrackingMouse(bool useMouseScreenOffset)
{
// TODO: impl this

View File

@@ -13,14 +13,13 @@
class LinuxWindow : public WindowBase
{
friend LinuxPlatform;
public:
typedef unsigned long HandleType;
private:
bool _resizeDisabled, _focusOnMapped = false;
bool _resizeDisabled, _focusOnMapped = false, _dragOver = false;
float _opacity = 1.0f;
HandleType _window;

View File

@@ -207,19 +207,19 @@ public:
// Returns the directory name of the specified path string
// @param path The path string from which to obtain the directory name
// @returns Directory name
static String GetDirectoryName(const String& path);
static String GetDirectoryName(const StringView& path);
// Returns the file name and extension of the specified path string
// @param path The path string from which to obtain the file name and extension
// @returns File name with extension
static String GetFileName(const String& path);
static String GetFileName(const StringView& path);
// Returns the file name without extension of the specified path string
// @param path The path string from which to obtain the file name
// @returns File name without extension
static String GetFileNameWithoutExtension(const String& path);
static String GetFileNameWithoutExtension(const StringView& path);
static String GetPathWithoutExtension(const String& path);
static String GetPathWithoutExtension(const StringView& path);
static void PathRemoveRelativeParts(String& path);

View File

@@ -318,14 +318,15 @@ void Win32Platform::Free(void* ptr)
void* Win32Platform::AllocatePages(uint64 numPages, uint64 pageSize)
{
const uint64 numBytes = numPages * pageSize;
// Use VirtualAlloc to allocate page-aligned memory
#if PLATFORM_UWP
return VirtualAllocFromApp(nullptr, (SIZE_T)numBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
return VirtualAlloc(nullptr, (SIZE_T)numBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#endif
}
void Win32Platform::FreePages(void* ptr)
{
// Free page-aligned memory
VirtualFree(ptr, 0, MEM_RELEASE);
}

View File

@@ -38,7 +38,7 @@ namespace
CriticalSection SymLocker;
bool SymInitialized = false;
bool SymModulesDirty = true;
char* SymPath = nullptr;
Array<String> SymbolsPath;
#endif
}
@@ -617,9 +617,8 @@ void WindowsPlatform::Exit()
{
SymInitialized = false;
SymCleanup(GetCurrentProcess());
free(SymPath);
SymPath = nullptr;
}
SymbolsPath.Resize(0);
SymLocker.Unlock();
#endif
@@ -1116,7 +1115,13 @@ void* WindowsPlatform::LoadLibrary(const Char* filename)
#if CRASH_LOG_ENABLE
// Refresh modules info during next stack trace collecting to have valid debug symbols information
SymLocker.Lock();
SymModulesDirty = true;
const auto folder = StringUtils::GetDirectoryName(filename);
if (!SymbolsPath.Contains(folder))
SymbolsPath.Add(folder);
if (SymInitialized)
{
SymModulesDirty = true;
}
SymLocker.Unlock();
#endif
@@ -1137,80 +1142,43 @@ Array<PlatformBase::StackFrame> WindowsPlatform::GetStackFrames(int32 skipCount,
SymInitialized = true;
// Build search path
const size_t nSymPathLen = 4096;
SymPath = (char*)malloc(nSymPathLen);
SymPath[0] = 0;
strcat_s(SymPath, nSymPathLen, ".;");
const size_t nTempLen = 1024;
char szTemp[nTempLen];
// Current directory path
if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
String symbolSearchPath;
TCHAR ModulePath[MAX_PATH] = { 0 };
if (::GetModuleFileName(::GetModuleHandle(nullptr), ModulePath, MAX_PATH))
{
szTemp[nTempLen - 1] = 0;
strcat_s(SymPath, nSymPathLen, szTemp);
strcat_s(SymPath, nSymPathLen, ";");
symbolSearchPath += StringUtils::GetDirectoryName(ModulePath);
symbolSearchPath += ";";
}
// Main module path
if (GetModuleFileNameA(nullptr, szTemp, nTempLen) > 0)
for (auto& path : SymbolsPath)
{
szTemp[nTempLen - 1] = 0;
for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p)
{
// Locate the rightmost path separator
if ((*p == '\\') || (*p == '/') || (*p == ':'))
{
*p = 0;
break;
}
}
if (strlen(szTemp) > 0)
{
strcat_s(SymPath, nSymPathLen, szTemp);
strcat_s(SymPath, nSymPathLen, ";");
}
symbolSearchPath += path;
symbolSearchPath += ";";
}
// System symbols paths
if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
String _NT_SYMBOL_PATH;
if (!Platform::GetEnvironmentVariable(TEXT("_NT_SYMBOL_PATH"), _NT_SYMBOL_PATH))
{
szTemp[nTempLen - 1] = 0;
strcat_s(SymPath, nSymPathLen, szTemp);
strcat_s(SymPath, nSymPathLen, ";");
symbolSearchPath += _NT_SYMBOL_PATH;
symbolSearchPath += ";";
}
if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
{
szTemp[nTempLen - 1] = 0;
strcat_s(SymPath, nSymPathLen, szTemp);
strcat_s(SymPath, nSymPathLen, ";");
}
if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
{
szTemp[nTempLen - 1] = 0;
strcat_s(SymPath, nSymPathLen, szTemp);
strcat_s(SymPath, nSymPathLen, ";");
strcat_s(szTemp, nTempLen, "\\system32");
strcat_s(SymPath, nSymPathLen, szTemp);
strcat_s(SymPath, nSymPathLen, ";");
}
SymInitialize(process, SymPath, FALSE);
symbolSearchPath += Platform::GetWorkingDirectory();
symbolSearchPath += ";";
DWORD options = SymGetOptions();
options |= SYMOPT_LOAD_LINES;
options |= SYMOPT_FAIL_CRITICAL_ERRORS;
options |= SYMOPT_DEFERRED_LOADS;
options |= SYMOPT_EXACT_SYMBOLS;
SymSetOptions(options);
SymInitializeW(process, *symbolSearchPath, TRUE);
}
// Load modules
// Refresh modules if needed
if (SymModulesDirty)
{
SymModulesDirty = false;
GetModuleListPSAPI(process);
SymRefreshModuleList(process);
}
SymRefreshModuleList(process);
// Capture the context if missing
/*EXCEPTION_POINTERS exceptionPointers;

View File

@@ -34,6 +34,8 @@ bool DepthOfFieldPass::Init()
_platformSupportsDoF = limits.HasCompute;
_platformSupportsBokeh = _platformSupportsDoF && limits.HasGeometryShaders && limits.HasDrawIndirect && limits.HasAppendConsumeBuffers;
_platformSupportsBokeh &= GPUDevice::Instance->GetRendererType() != RendererType::DirectX12; // TODO: fix bokeh crash on d3d12 (driver issue probably - started to happen recently)
// Create pipeline states
if (_platformSupportsDoF)
{

View File

@@ -326,6 +326,24 @@ bool MAssembly::LoadWithImage(const String& assemblyPath)
mono_debug_open_image_from_memory(assemblyImage, _debugData.Get(), _debugData.Count());
}
}
#if 0
// Hack to load debug information for Newtonsoft.Json (enable it to debug C# code of json lib)
if (assemblyPath.EndsWith(TEXT("FlaxEngine.CSharp.dll")))
{
static Array<byte> NewtonsoftJsonDebugData;
File::ReadAllBytes(StringUtils::GetDirectoryName(assemblyPath) / TEXT("Newtonsoft.Json.pdb"), NewtonsoftJsonDebugData);
if (NewtonsoftJsonDebugData.HasItems())
{
StringAnsi tmp(StringUtils::GetDirectoryName(assemblyPath) / TEXT("Newtonsoft.Json.dll"));
MonoAssembly* a = mono_assembly_open(tmp.Get(), &status);
if (a)
{
mono_debug_open_image_from_memory(mono_assembly_get_image(a), NewtonsoftJsonDebugData.Get(), NewtonsoftJsonDebugData.Count());
}
}
}
#endif
#endif
// Set state

View File

@@ -178,13 +178,15 @@ void Script::SetupType()
{
// Enable tick functions based on the method overriden in C# or Visual Script
ScriptingTypeHandle typeHandle = GetTypeHandle();
_tickUpdate = _tickLateUpdate = _tickFixedUpdate = 0;
while (typeHandle != Script::TypeInitializer)
{
auto& type = typeHandle.GetType();
_tickUpdate |= type.Script.ScriptVTable[8] != nullptr;
_tickLateUpdate |= type.Script.ScriptVTable[9] != nullptr;
_tickFixedUpdate |= type.Script.ScriptVTable[10] != nullptr;
if (type.Script.ScriptVTable)
{
_tickUpdate |= type.Script.ScriptVTable[8] != nullptr;
_tickLateUpdate |= type.Script.ScriptVTable[9] != nullptr;
_tickFixedUpdate |= type.Script.ScriptVTable[10] != nullptr;
}
typeHandle = type.GetBaseType();
}
}

View File

@@ -27,7 +27,6 @@
#include "Engine/Engine/EngineService.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Utilities/StringConverter.h"
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
#include <ThirdParty/mono-2.0/mono/metadata/object.h>

View File

@@ -154,8 +154,7 @@ public:
// @param length Text length
void WriteText(const char* text, int32 length)
{
for (int32 i = 0; i < length; i++)
WriteChar(text[i]);
WriteBytes((const void*)text, sizeof(char) * length);
}
// Writes text to the stream
@@ -163,8 +162,7 @@ public:
// @param length Text length
void WriteText(const Char* text, int32 length)
{
for (int32 i = 0; i < length; i++)
WriteChar(text[i]);
WriteBytes((const void*)text, sizeof(Char) * length);
}
template<typename... Args>

View File

@@ -39,9 +39,6 @@ namespace FlaxEngine.GUI
/// <summary>
/// Gets a value indicating whether use progress value smoothing.
/// </summary>
/// <value>
/// <c>true</c> if use progress value smoothing; otherwise, <c>false</c>.
/// </value>
public bool UseSmoothing => !Mathf.IsZero(SmoothingScale);
/// <summary>
@@ -91,8 +88,6 @@ namespace FlaxEngine.GUI
if (!Mathf.NearEqual(value, _value))
{
_value = value;
// Check if skip smoothing
if (!UseSmoothing)
{
_current = _value;
@@ -138,22 +133,22 @@ namespace FlaxEngine.GUI
/// <inheritdoc />
public override void Update(float deltaTime)
{
bool isDeltaSlow = deltaTime > (1 / 20.0f);
// Ensure progress bar is visible
if (Visible)
{
// Value smoothing
var value = _value;
if (Mathf.Abs(_current - _value) > 0.01f)
{
// Lerp or not if running slow
float value;
bool isDeltaSlow = deltaTime > (1 / 20.0f);
if (!isDeltaSlow && UseSmoothing)
value = Mathf.Lerp(_current, _value, Mathf.Saturate(deltaTime * 5.0f * SmoothingScale));
else
value = _value;
_current = value;
}
else
{
_current = _value;
}
}
base.Update(deltaTime);

View File

@@ -274,7 +274,7 @@ namespace FlaxEngine.GUI
public int GetChildIndexAt(Vector2 point)
{
int result = -1;
for (int i = 0; i < _children.Count; i++)
for (int i = _children.Count - 1; i >= 0; i--)
{
var child = _children[i];
@@ -296,7 +296,7 @@ namespace FlaxEngine.GUI
public Control GetChildAt(Vector2 point)
{
Control result = null;
for (int i = 0; i < _children.Count; i++)
for (int i = _children.Count - 1; i >= 0; i--)
{
var child = _children[i];
@@ -322,7 +322,7 @@ namespace FlaxEngine.GUI
throw new ArgumentNullException(nameof(isValid));
Control result = null;
for (int i = 0; i < _children.Count; i++)
for (int i = _children.Count - 1; i >= 0; i--)
{
var child = _children[i];
@@ -344,7 +344,7 @@ namespace FlaxEngine.GUI
public Control GetChildAtRecursive(Vector2 point)
{
Control result = null;
for (int i = 0; i < _children.Count; i++)
for (int i = _children.Count - 1; i >= 0; i--)
{
var child = _children[i];

View File

@@ -73,13 +73,18 @@ namespace FlaxEngine.GUI
Vector2 locationWS = target.PointToWindow(location);
Vector2 locationSS = parentWin.PointToScreen(locationWS);
Vector2 screenSize = Platform.VirtualDesktopSize;
Vector2 parentWinLocationSS = parentWin.PointToScreen(Vector2.Zero);
float parentWinRightSS = parentWinLocationSS.Y + parentWin.Size.Y;
float parentWinBottomSS = parentWinLocationSS.X + parentWin.Size.X;
Vector2 rightBottomLocationSS = locationSS + dpiSize;
if (screenSize.Y < rightBottomLocationSS.Y)
// Prioritize tooltip placement within parent window, fall back to virtual desktop
if (parentWinRightSS < rightBottomLocationSS.Y || screenSize.Y < rightBottomLocationSS.Y)
{
// Direction: up
locationSS.Y -= dpiSize.Y;
}
if (screenSize.X < rightBottomLocationSS.X)
if (parentWinBottomSS < rightBottomLocationSS.X || screenSize.X < rightBottomLocationSS.X)
{
// Direction: left
locationSS.X -= dpiSize.X;
@@ -155,7 +160,7 @@ namespace FlaxEngine.GUI
/// <param name="dt">The delta time.</param>
public void OnMouseOverControl(Control target, float dt)
{
if (!Visible)
if (!Visible && _timeToPopupLeft > 0.0f)
{
_lastTarget = target;
_timeToPopupLeft -= dt;

View File

@@ -13,5 +13,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("b8442186-4a70-7c85-704a-857c262d00f6")]
[assembly: AssemblyVersion("1.1.6217")]
[assembly: AssemblyFileVersion("1.1.6217")]
[assembly: AssemblyVersion("1.1.6218")]
[assembly: AssemblyFileVersion("1.1.6218")]

View File

@@ -3,11 +3,11 @@
#pragma once
#define FLAXENGINE_NAME "FlaxEngine"
#define FLAXENGINE_VERSION Version(1, 1, 6217)
#define FLAXENGINE_VERSION_TEXT "1.1.6217"
#define FLAXENGINE_VERSION Version(1, 1, 6218)
#define FLAXENGINE_VERSION_TEXT "1.1.6218"
#define FLAXENGINE_VERSION_MAJOR 1
#define FLAXENGINE_VERSION_MINOR 1
#define FLAXENGINE_VERSION_BUILD 6217
#define FLAXENGINE_VERSION_BUILD 6218
#define FLAXENGINE_COMPANY "Flax"
#define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved."

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -54,6 +54,7 @@
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="Game.Build.json" />
<None Include="WSACertificate.pfx" />
</ItemGroup>
<ItemGroup>{3}
@@ -70,7 +71,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="Content\**" />
<MonoDataFiles Include="Mono\**" />
<MonoDataFiles Include="$(ProjectDir)Mono\**" />
<DataSecondary Include="DataSecondary\**" />
</ItemGroup>
<ItemGroup>

Binary file not shown.

View File

@@ -54,6 +54,7 @@
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="Game.Build.json" />
<None Include="WSACertificate.pfx" />
</ItemGroup>
<ItemGroup>{3}
@@ -70,7 +71,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="Content\**" />
<MonoDataFiles Include="Mono\**" />
<MonoDataFiles Include="$(ProjectDir)Mono\**" />
<DataSecondary Include="DataSecondary\**" />
</ItemGroup>
<ItemGroup>

View File

@@ -250,66 +250,66 @@ namespace Flax.Build.Bindings
var path = GetCachePath(moduleInfo.Module, moduleOptions);
if (!File.Exists(path))
return false;
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var reader = new BinaryReader(stream, Encoding.UTF8))
try
{
// Version
var version = reader.ReadInt32();
if (version != CacheVersion)
return false;
if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64())
return false;
// Build options
if (reader.ReadString() != moduleOptions.IntermediateFolder ||
reader.ReadInt32() != (int)moduleOptions.Platform.Target ||
reader.ReadInt32() != (int)moduleOptions.Architecture ||
reader.ReadInt32() != (int)moduleOptions.Configuration)
return false;
var publicDefinitions = Read(reader, Utilities.GetEmptyArray<string>());
if (publicDefinitions.Length != moduleOptions.PublicDefinitions.Count || publicDefinitions.Any(x => !moduleOptions.PublicDefinitions.Contains(x)))
return false;
var privateDefinitions = Read(reader, Utilities.GetEmptyArray<string>());
if (privateDefinitions.Length != moduleOptions.PrivateDefinitions.Count || privateDefinitions.Any(x => !moduleOptions.PrivateDefinitions.Contains(x)))
return false;
var preprocessorDefinitions = Read(reader, Utilities.GetEmptyArray<string>());
if (preprocessorDefinitions.Length != moduleOptions.CompileEnv.PreprocessorDefinitions.Count || preprocessorDefinitions.Any(x => !moduleOptions.CompileEnv.PreprocessorDefinitions.Contains(x)))
return false;
// Header files
var headerFilesCount = reader.ReadInt32();
if (headerFilesCount != headerFiles.Count)
return false;
for (int i = 0; i < headerFilesCount; i++)
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var reader = new BinaryReader(stream, Encoding.UTF8))
{
var headerFile = headerFiles[i];
if (headerFile != reader.ReadString())
// Version
var version = reader.ReadInt32();
if (version != CacheVersion)
return false;
if (File.GetLastWriteTime(headerFile).Ticks > reader.ReadInt64())
if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64())
return false;
}
// Info
var newModuleInfo = new ModuleInfo
{
Module = moduleInfo.Module,
Name = moduleInfo.Name,
Namespace = moduleInfo.Namespace,
IsFromCache = true,
};
try
{
// Build options
if (reader.ReadString() != moduleOptions.IntermediateFolder ||
reader.ReadInt32() != (int)moduleOptions.Platform.Target ||
reader.ReadInt32() != (int)moduleOptions.Architecture ||
reader.ReadInt32() != (int)moduleOptions.Configuration)
return false;
var publicDefinitions = Read(reader, Utilities.GetEmptyArray<string>());
if (publicDefinitions.Length != moduleOptions.PublicDefinitions.Count || publicDefinitions.Any(x => !moduleOptions.PublicDefinitions.Contains(x)))
return false;
var privateDefinitions = Read(reader, Utilities.GetEmptyArray<string>());
if (privateDefinitions.Length != moduleOptions.PrivateDefinitions.Count || privateDefinitions.Any(x => !moduleOptions.PrivateDefinitions.Contains(x)))
return false;
var preprocessorDefinitions = Read(reader, Utilities.GetEmptyArray<string>());
if (preprocessorDefinitions.Length != moduleOptions.CompileEnv.PreprocessorDefinitions.Count || preprocessorDefinitions.Any(x => !moduleOptions.CompileEnv.PreprocessorDefinitions.Contains(x)))
return false;
// Header files
var headerFilesCount = reader.ReadInt32();
if (headerFilesCount != headerFiles.Count)
return false;
for (int i = 0; i < headerFilesCount; i++)
{
var headerFile = headerFiles[i];
if (headerFile != reader.ReadString())
return false;
if (File.GetLastWriteTime(headerFile).Ticks > reader.ReadInt64())
return false;
}
// Info
var newModuleInfo = new ModuleInfo
{
Module = moduleInfo.Module,
Name = moduleInfo.Name,
Namespace = moduleInfo.Namespace,
IsFromCache = true,
};
newModuleInfo.Read(reader);
// Skip parsing and use data loaded from cache
moduleInfo = newModuleInfo;
return true;
}
catch
{
// Skip loading cache
return false;
}
}
catch
{
// Skip loading cache
return false;
}
}
}

View File

@@ -1129,6 +1129,7 @@ namespace Flax.Build.Bindings
var paramsCount = eventInfo.Type.GenericArgs?.Count ?? 0;
// C# event invoking wrapper (calls C# event from C++ delegate)
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MEvent.h");
contents.Append(" ");
if (eventInfo.IsStatic)
@@ -1251,7 +1252,13 @@ namespace Flax.Build.Bindings
if (fieldInfo.Getter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Getter, "{0}");
if (fieldInfo.Setter != null)
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Setter, "{0} = {1}");
{
var callFormat = "{0} = {1}";
var type = fieldInfo.Setter.Parameters[0].Type;
if (type.IsArray)
callFormat = $"auto __tmp = {{1}}; for (int32 i = 0; i < {type.ArraySize}; i++) {{0}}[i] = __tmp[i]";
GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Setter, callFormat);
}
}
// Properties

View File

@@ -623,9 +623,6 @@ namespace Flax.Build.Bindings
if (!fieldInfo.IsReadOnly)
{
if (fieldInfo.Type.IsArray)
throw new NotImplementedException("Use ReadOnly on field. TODO: add support for setter for fixed-array fields.");
fieldInfo.Setter = new FunctionInfo
{
Name = "Set" + fieldInfo.Name,

View File

@@ -67,10 +67,10 @@ namespace Flax.Build.Platforms
options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_UWP");
options.CompileEnv.PreprocessorDefinitions.Add("WINAPI_FAMILY=WINAPI_FAMILY_PC_APP");
options.CompileEnv.PreprocessorDefinitions.Add("_WINRT_DLL");
options.CompileEnv.PreprocessorDefinitions.Add("_WINDLL");
options.CompileEnv.PreprocessorDefinitions.Add("__WRL_NO_DEFAULT_LIB__");
options.LinkEnv.InputLibraries.Add("WindowsApp.lib");
options.LinkEnv.InputLibraries.Add("dloadhelper.lib");
}
}
}

View File

@@ -680,6 +680,8 @@ namespace Flax.Build.Platforms
args.Add("/WINMD");
args.Add(string.Format("/WINMDFILE:\"{0}\"", Path.ChangeExtension(outputFilePath, "winmd")));
args.Add("/APPCONTAINER");
if (linkEnvironment.Output == LinkerOutput.SharedLibrary)
args.Add("/DYNAMICBASE");
}
if (linkEnvironment.LinkTimeCodeGeneration)
@@ -937,7 +939,7 @@ namespace Flax.Build.Platforms
xmlTextWriter.WriteStartElement("Properties");
// TODO: better logo handling
var logoSrcPath = Path.Combine(Environment.CurrentDirectory, "Source", "Logo.png");
var logoSrcPath = Path.Combine(Globals.EngineRoot, "Source", "Logo.png");
var logoDstPath = Path.Combine(options.IntermediateFolder, "Logo.png");
if (!File.Exists(logoDstPath))
Utilities.FileCopy(logoSrcPath, logoDstPath);