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:
@@ -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.",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -31,7 +31,7 @@ DECLARE_ENUM_OPERATORS(AssetsCacheFlags);
|
||||
/// <summary>
|
||||
/// Flax Game Engine assets cache container
|
||||
/// </summary>
|
||||
class AssetsCache
|
||||
class FLAXENGINE_API AssetsCache
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 Controller’s 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 Controller’s height or it will generate an error.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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."
|
||||
|
||||
|
||||
BIN
Source/Platforms/DotNet/Newtonsoft.Json.dll
(Stored with Git LFS)
BIN
Source/Platforms/DotNet/Newtonsoft.Json.dll
(Stored with Git LFS)
Binary file not shown.
BIN
Source/Platforms/DotNet/Newtonsoft.Json.pdb
(Stored with Git LFS)
BIN
Source/Platforms/DotNet/Newtonsoft.Json.pdb
(Stored with Git LFS)
Binary file not shown.
BIN
Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll
(Stored with Git LFS)
BIN
Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll
(Stored with Git LFS)
Binary file not shown.
@@ -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>
|
||||
|
||||
BIN
Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll
(Stored with Git LFS)
BIN
Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll
(Stored with Git LFS)
Binary file not shown.
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user