UWP: Remove platform port, needs to be redone from scratch for 4.x
The UWP platform port was never ported to the Godot 4.0+ API, and it's now accumulating bitrot as it doesn't compile, and thus we no longer propagate platform changes in it. So we finally remove to acknowledge this state. There's still some interest in reviving the UWP port eventually, especially as support for Direct3D 12 will soon be merged, but when that happens it will be easiest to redo it from scratch.
|
@ -33,6 +33,3 @@ Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1
|
||||||
Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
||||||
Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
|
Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
|
||||||
Linux054c0268,054c-0268-Sony PLAYSTATION(R)3 Controller,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
Linux054c0268,054c-0268-Sony PLAYSTATION(R)3 Controller,a:b0,b:b1,y:b2,x:b3,start:b9,guide:b10,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
|
||||||
|
|
||||||
# UWP
|
|
||||||
__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP,
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ def make_default_controller_mappings(target, source, env):
|
||||||
"Android": "#if defined(__ANDROID__)",
|
"Android": "#if defined(__ANDROID__)",
|
||||||
"iOS": "#ifdef IOS_ENABLED",
|
"iOS": "#ifdef IOS_ENABLED",
|
||||||
"Web": "#ifdef WEB_ENABLED",
|
"Web": "#ifdef WEB_ENABLED",
|
||||||
"UWP": "#ifdef UWP_ENABLED",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g.write("const char* DefaultControllerMappings::mappings[] = {\n")
|
g.write("const char* DefaultControllerMappings::mappings[] = {\n")
|
||||||
|
|
|
@ -190,7 +190,7 @@
|
||||||
<method name="get_swap_cancel_ok">
|
<method name="get_swap_cancel_ok">
|
||||||
<return type="bool" />
|
<return type="bool" />
|
||||||
<description>
|
<description>
|
||||||
Returns [code]true[/code] if positions of [b]OK[/b] and [b]Cancel[/b] buttons are swapped in dialogs. This is enabled by default on Windows and UWP to follow interface conventions, and be toggled by changing [member ProjectSettings.gui/common/swap_cancel_ok].
|
Returns [code]true[/code] if positions of [b]OK[/b] and [b]Cancel[/b] buttons are swapped in dialogs. This is enabled by default on Windows to follow interface conventions, and be toggled by changing [member ProjectSettings.gui/common/swap_cancel_ok].
|
||||||
[b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
|
[b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
<description>
|
<description>
|
||||||
Returns the acceleration in m/s² of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
|
Returns the acceleration in m/s² of the device's accelerometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
|
||||||
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
|
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
|
||||||
[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
|
[b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_action_raw_strength" qualifiers="const">
|
<method name="get_action_raw_strength" qualifiers="const">
|
||||||
|
@ -166,7 +166,7 @@
|
||||||
<return type="Vector3" />
|
<return type="Vector3" />
|
||||||
<description>
|
<description>
|
||||||
Returns the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
|
Returns the magnetic field strength in micro-Tesla for all axes of the device's magnetometer sensor, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
|
||||||
[b]Note:[/b] This method only works on Android, iOS and UWP. On other platforms, it always returns [constant Vector3.ZERO].
|
[b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_mouse_button_mask" qualifiers="const">
|
<method name="get_mouse_button_mask" qualifiers="const">
|
||||||
|
|
|
@ -298,7 +298,7 @@
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
Returns the name of the host OS.
|
Returns the name of the host OS.
|
||||||
On Windows, this is [code]"Windows"[/code] or [code]"UWP"[/code] if exported on Universal Windows Platform.
|
On Windows, this is [code]"Windows"[/code].
|
||||||
On macOS, this is [code]"macOS"[/code].
|
On macOS, this is [code]"macOS"[/code].
|
||||||
On Linux-based operating systems, this is [code]"Linux"[/code].
|
On Linux-based operating systems, this is [code]"Linux"[/code].
|
||||||
On BSD-based operating systems, this is [code]"FreeBSD"[/code], [code]"NetBSD"[/code], [code]"OpenBSD"[/code], or [code]"BSD"[/code] as a fallback.
|
On BSD-based operating systems, this is [code]"FreeBSD"[/code], [code]"NetBSD"[/code], [code]"OpenBSD"[/code], or [code]"BSD"[/code] as a fallback.
|
||||||
|
@ -309,7 +309,7 @@
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
match OS.get_name():
|
match OS.get_name():
|
||||||
"Windows", "UWP":
|
"Windows":
|
||||||
print("Windows")
|
print("Windows")
|
||||||
"macOS":
|
"macOS":
|
||||||
print("macOS")
|
print("macOS")
|
||||||
|
@ -326,7 +326,6 @@
|
||||||
switch (OS.GetName())
|
switch (OS.GetName())
|
||||||
{
|
{
|
||||||
case "Windows":
|
case "Windows":
|
||||||
case "UWP":
|
|
||||||
GD.Print("Windows");
|
GD.Print("Windows");
|
||||||
break;
|
break;
|
||||||
case "macOS":
|
case "macOS":
|
||||||
|
@ -370,7 +369,7 @@
|
||||||
<return type="String" />
|
<return type="String" />
|
||||||
<description>
|
<description>
|
||||||
Returns the name of the CPU model on the host machine (e.g. "Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz").
|
Returns the name of the CPU model on the host machine (e.g. "Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz").
|
||||||
[b]Note:[/b] This method is only implemented on Windows, macOS, Linux and iOS. On Android, Web and UWP, [method get_processor_name] returns an empty string.
|
[b]Note:[/b] This method is only implemented on Windows, macOS, Linux and iOS. On Android and Web, [method get_processor_name] returns an empty string.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_restart_on_exit_arguments" qualifiers="const">
|
<method name="get_restart_on_exit_arguments" qualifiers="const">
|
||||||
|
@ -450,7 +449,7 @@
|
||||||
<description>
|
<description>
|
||||||
Returns a string that is unique to the device.
|
Returns a string that is unique to the device.
|
||||||
[b]Note:[/b] This string may change without notice if the user reinstalls/upgrades their operating system or changes their hardware. This means it should generally not be used to encrypt persistent data as the data saved before an unexpected ID change would become inaccessible. The returned string may also be falsified using external programs, so do not rely on the string returned by [method get_unique_id] for security purposes.
|
[b]Note:[/b] This string may change without notice if the user reinstalls/upgrades their operating system or changes their hardware. This means it should generally not be used to encrypt persistent data as the data saved before an unexpected ID change would become inaccessible. The returned string may also be falsified using external programs, so do not rely on the string returned by [method get_unique_id] for security purposes.
|
||||||
[b]Note:[/b] Returns an empty string on Web and UWP, as this method isn't implemented on those platforms yet.
|
[b]Note:[/b] Returns an empty string on Web, as this method isn't implemented on this platform yet.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_user_data_dir" qualifiers="const">
|
<method name="get_user_data_dir" qualifiers="const">
|
||||||
|
@ -473,7 +472,6 @@
|
||||||
For Windows, the major and minor version are returned, as well as the build number. For example, the returned string can look like [code]10.0.9926[/code] for a build of Windows 10, and it can look like [code]6.1.7601[/code] for a build of Windows 7 SP1.
|
For Windows, the major and minor version are returned, as well as the build number. For example, the returned string can look like [code]10.0.9926[/code] for a build of Windows 10, and it can look like [code]6.1.7601[/code] for a build of Windows 7 SP1.
|
||||||
For rolling distributions, such as Arch Linux, an empty string is returned.
|
For rolling distributions, such as Arch Linux, an empty string is returned.
|
||||||
For macOS and iOS, the major and minor version are returned, as well as the patch number.
|
For macOS and iOS, the major and minor version are returned, as well as the patch number.
|
||||||
For UWP, the device family version is returned.
|
|
||||||
For Android, the SDK version and the incremental build number are returned. If it's a custom ROM, it attempts to return its version instead.
|
For Android, the SDK version and the incremental build number are returned. If it's a custom ROM, it attempts to return its version instead.
|
||||||
[b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
|
[b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
|
||||||
</description>
|
</description>
|
||||||
|
|
|
@ -938,7 +938,7 @@
|
||||||
If [code]true[/code], snaps [Control] node vertices to the nearest pixel to ensure they remain crisp even when the camera moves or zooms.
|
If [code]true[/code], snaps [Control] node vertices to the nearest pixel to ensure they remain crisp even when the camera moves or zooms.
|
||||||
</member>
|
</member>
|
||||||
<member name="gui/common/swap_cancel_ok" type="bool" setter="" getter="">
|
<member name="gui/common/swap_cancel_ok" type="bool" setter="" getter="">
|
||||||
If [code]true[/code], swaps [b]Cancel[/b] and [b]OK[/b] buttons in dialogs on Windows and UWP to follow interface conventions. [method DisplayServer.get_swap_cancel_ok] can be used to query whether buttons are swapped at run-time.
|
If [code]true[/code], swaps [b]Cancel[/b] and [b]OK[/b] buttons in dialogs on Windows to follow interface conventions. [method DisplayServer.get_swap_cancel_ok] can be used to query whether buttons are swapped at run-time.
|
||||||
[b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
|
[b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
|
||||||
</member>
|
</member>
|
||||||
<member name="gui/common/text_edit_undo_stack_max_size" type="int" setter="" getter="" default="1024">
|
<member name="gui/common/text_edit_undo_stack_max_size" type="int" setter="" getter="" default="1024">
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
#define _EXT_DEBUG_OUTPUT 0x92E0
|
#define _EXT_DEBUG_OUTPUT 0x92E0
|
||||||
|
|
||||||
#ifndef GLAPIENTRY
|
#ifndef GLAPIENTRY
|
||||||
#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
#define GLAPIENTRY APIENTRY
|
#define GLAPIENTRY APIENTRY
|
||||||
#else
|
#else
|
||||||
#define GLAPIENTRY
|
#define GLAPIENTRY
|
||||||
|
|
|
@ -32,19 +32,21 @@
|
||||||
|
|
||||||
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
|
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
#include <stdio.h>
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#ifndef UWP_ENABLED
|
|
||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#endif
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#else // UNIX
|
#else // UNIX
|
||||||
|
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
#ifdef ANDROID_ENABLED
|
#ifdef ANDROID_ENABLED
|
||||||
// We could drop this file once we up our API level to 24,
|
// We could drop this file once we up our API level to 24,
|
||||||
// where the NDK's ifaddrs.h supports to needed getifaddrs.
|
// where the NDK's ifaddrs.h supports to needed getifaddrs.
|
||||||
|
@ -55,13 +57,19 @@
|
||||||
#endif
|
#endif
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
#include <net/if.h> // Order is important on OpenBSD, leave as last
|
|
||||||
#endif
|
#include <net/if.h> // Order is important on OpenBSD, leave as last.
|
||||||
|
|
||||||
|
#endif // UNIX
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
|
static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
|
||||||
IPAddress ip;
|
IPAddress ip;
|
||||||
|
@ -126,42 +134,6 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
|
||||||
|
|
||||||
#if defined(WINDOWS_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
|
|
||||||
#if defined(UWP_ENABLED)
|
|
||||||
|
|
||||||
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
|
||||||
using namespace Windows::Networking;
|
|
||||||
using namespace Windows::Networking::Connectivity;
|
|
||||||
|
|
||||||
// Returns addresses, not interfaces.
|
|
||||||
auto hostnames = NetworkInformation::GetHostNames();
|
|
||||||
|
|
||||||
for (int i = 0; i < hostnames->Size; i++) {
|
|
||||||
auto hostname = hostnames->GetAt(i);
|
|
||||||
|
|
||||||
if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = hostname->RawName->Data();
|
|
||||||
HashMap<String, Interface_Info>::Element *E = r_interfaces->find(name);
|
|
||||||
if (!E) {
|
|
||||||
Interface_Info info;
|
|
||||||
info.name = name;
|
|
||||||
info.name_friendly = hostname->DisplayName->Data();
|
|
||||||
info.index = String::num_uint64(0);
|
|
||||||
E = r_interfaces->insert(name, info);
|
|
||||||
ERR_CONTINUE(!E);
|
|
||||||
}
|
|
||||||
|
|
||||||
Interface_Info &info = E->get();
|
|
||||||
|
|
||||||
IPAddress ip = IPAddress(hostname->CanonicalName->Data());
|
|
||||||
info.ip_addresses.push_front(ip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
||||||
ULONG buf_size = 1024;
|
ULONG buf_size = 1024;
|
||||||
IP_ADAPTER_ADDRESSES *addrs;
|
IP_ADAPTER_ADDRESSES *addrs;
|
||||||
|
@ -208,8 +180,6 @@ void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces)
|
||||||
memfree(addrs);
|
memfree(addrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else // UNIX
|
#else // UNIX
|
||||||
|
|
||||||
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
|
||||||
|
@ -248,7 +218,8 @@ void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces)
|
||||||
freeifaddrs(ifAddrStruct);
|
freeifaddrs(ifAddrStruct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
#endif // UNIX
|
||||||
|
|
||||||
void IPUnix::make_default() {
|
void IPUnix::make_default() {
|
||||||
_create = _create_unix;
|
_create = _create_unix;
|
||||||
|
@ -261,4 +232,4 @@ IP *IPUnix::_create_unix() {
|
||||||
IPUnix::IPUnix() {
|
IPUnix::IPUnix() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // UNIX_ENABLED || WINDOWS_ENABLED
|
||||||
|
|
|
@ -40,23 +40,10 @@
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
[03:57] <reduz> yessopie, so i don't havemak to rely on unicows
|
|
||||||
[03:58] <yessopie> reduz- yeah, all of the functions fail, and then you can call GetLastError () which will return 120
|
|
||||||
[03:58] <drumstick> CategoryApl, hehe, what? :)
|
|
||||||
[03:59] <CategoryApl> didn't Verona lead to some trouble
|
|
||||||
[03:59] <yessopie> 120 = ERROR_CALL_NOT_IMPLEMENTED
|
|
||||||
[03:59] <yessopie> (you can use that constant if you include winerr.h)
|
|
||||||
[03:59] <CategoryApl> well answer with winning a compo
|
|
||||||
|
|
||||||
[04:02] <yessopie> if ( SetCurrentDirectoryW ( L"." ) == FALSE && GetLastError () == ERROR_CALL_NOT_IMPLEMENTED ) { use ANSI }
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct DirAccessWindowsPrivate {
|
struct DirAccessWindowsPrivate {
|
||||||
HANDLE h; //handle for findfirstfile
|
HANDLE h; // handle for FindFirstFile.
|
||||||
WIN32_FIND_DATA f;
|
WIN32_FIND_DATA f;
|
||||||
WIN32_FIND_DATAW fu; //unicode version
|
WIN32_FIND_DATAW fu; // Unicode version.
|
||||||
};
|
};
|
||||||
|
|
||||||
String DirAccessWindows::fix_path(String p_path) const {
|
String DirAccessWindows::fix_path(String p_path) const {
|
||||||
|
@ -358,12 +345,6 @@ DirAccessWindows::DirAccessWindows() {
|
||||||
p->h = INVALID_HANDLE_VALUE;
|
p->h = INVALID_HANDLE_VALUE;
|
||||||
current_dir = ".";
|
current_dir = ".";
|
||||||
|
|
||||||
#ifdef UWP_ENABLED
|
|
||||||
Windows::Storage::StorageFolder ^ install_folder = Windows::ApplicationModel::Package::Current->InstalledLocation;
|
|
||||||
change_dir(install_folder->Path->Data());
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
DWORD mask = GetLogicalDrives();
|
DWORD mask = GetLogicalDrives();
|
||||||
|
|
||||||
for (int i = 0; i < MAX_DRIVES; i++) {
|
for (int i = 0; i < MAX_DRIVES; i++) {
|
||||||
|
@ -375,7 +356,6 @@ DirAccessWindows::DirAccessWindows() {
|
||||||
}
|
}
|
||||||
|
|
||||||
change_dir(".");
|
change_dir(".");
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirAccessWindows::~DirAccessWindows() {
|
DirAccessWindows::~DirAccessWindows() {
|
||||||
|
@ -384,4 +364,4 @@ DirAccessWindows::~DirAccessWindows() {
|
||||||
memdelete(p);
|
memdelete(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //windows DirAccess support
|
#endif // WINDOWS_ENABLED
|
||||||
|
|
|
@ -276,7 +276,6 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
|
||||||
capitalize_string_remaps["uv"] = "UV";
|
capitalize_string_remaps["uv"] = "UV";
|
||||||
capitalize_string_remaps["uv1"] = "UV1";
|
capitalize_string_remaps["uv1"] = "UV1";
|
||||||
capitalize_string_remaps["uv2"] = "UV2";
|
capitalize_string_remaps["uv2"] = "UV2";
|
||||||
capitalize_string_remaps["uwp"] = "UWP";
|
|
||||||
capitalize_string_remaps["vector2"] = "Vector2";
|
capitalize_string_remaps["vector2"] = "Vector2";
|
||||||
capitalize_string_remaps["vpn"] = "VPN";
|
capitalize_string_remaps["vpn"] = "VPN";
|
||||||
capitalize_string_remaps["vram"] = "VRAM";
|
capitalize_string_remaps["vram"] = "VRAM";
|
||||||
|
|
|
@ -1777,7 +1777,7 @@ void FileSystemDock::_rename_operation_confirm() {
|
||||||
|
|
||||||
// Present a more user friendly warning for name conflict.
|
// Present a more user friendly warning for name conflict.
|
||||||
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||||
#if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
// Workaround case insensitivity on Windows.
|
// Workaround case insensitivity on Windows.
|
||||||
if ((da->file_exists(new_path) || da->dir_exists(new_path)) && new_path.to_lower() != old_path.to_lower()) {
|
if ((da->file_exists(new_path) || da->dir_exists(new_path)) && new_path.to_lower() != old_path.to_lower()) {
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -727,8 +727,7 @@ int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) {
|
||||||
* responsible for the initialization of all low level singletons and core types, and parsing
|
* responsible for the initialization of all low level singletons and core types, and parsing
|
||||||
* command line arguments to configure things accordingly.
|
* command line arguments to configure things accordingly.
|
||||||
* If p_second_phase is true, it will chain into setup2() (default behavior). This is
|
* If p_second_phase is true, it will chain into setup2() (default behavior). This is
|
||||||
* disabled on some platforms (Android, iOS, UWP) which trigger the second step in their
|
* disabled on some platforms (Android, iOS) which trigger the second step in their own time.
|
||||||
* own time.
|
|
||||||
*
|
*
|
||||||
* - setup2(p_main_tid_override) registers high level servers and singletons, displays the
|
* - setup2(p_main_tid_override) registers high level servers and singletons, displays the
|
||||||
* boot splash, then registers higher level types (scene, editor, etc.).
|
* boot splash, then registers higher level types (scene, editor, etc.).
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp build" xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build">
|
|
||||||
<Identity Name="$identity_name$" Publisher="$publisher$" Version="$version_string$" ProcessorArchitecture="$architecture$" />
|
|
||||||
<mp:PhoneIdentity PhoneProductId="$product_guid$" PhonePublisherId="$publisher_guid$" />
|
|
||||||
<Properties>
|
|
||||||
<DisplayName>$display_name$</DisplayName>
|
|
||||||
<PublisherDisplayName>$publisher_display_name$</PublisherDisplayName>
|
|
||||||
<Logo>Assets\StoreLogo.png</Logo>
|
|
||||||
</Properties>
|
|
||||||
<Dependencies>
|
|
||||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.14393.0" />
|
|
||||||
<PackageDependency Name="Microsoft.VCLibs.140.00" MinVersion="14.0.24123.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
|
||||||
</Dependencies>
|
|
||||||
<Resources>
|
|
||||||
<Resource Language="EN-US" />
|
|
||||||
</Resources>
|
|
||||||
<Applications>
|
|
||||||
<Application Id="App" Executable="godot.uwp.exe" EntryPoint="GodotUWP.App">
|
|
||||||
<uap:VisualElements DisplayName="$display_name$" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="$app_description$" BackgroundColor="$bg_color$">
|
|
||||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" Square310x310Logo="Assets\Square310x310Logo.png" Square71x71Logo="Assets\Square71x71Logo.png" ShortName="$short_name$">
|
|
||||||
$name_on_tiles$
|
|
||||||
</uap:DefaultTile>
|
|
||||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
|
||||||
$rotation_preference$
|
|
||||||
</uap:VisualElements>
|
|
||||||
</Application>
|
|
||||||
</Applications>
|
|
||||||
$capabilities_place$
|
|
||||||
<build:Metadata>
|
|
||||||
<build:Item Name="GodotEngine" Version="$godot_version$" />
|
|
||||||
</build:Metadata>
|
|
||||||
</Package>
|
|
Before Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 848 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 883 B |
Before Width: | Height: | Size: 3.4 KiB |
|
@ -61,12 +61,6 @@ if env["builtin_freetype"]:
|
||||||
if env["brotli"]:
|
if env["brotli"]:
|
||||||
env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
|
env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
|
||||||
|
|
||||||
if env["platform"] == "uwp":
|
|
||||||
# Include header for UWP to fix build issues
|
|
||||||
env_freetype.Append(CCFLAGS=["/FI", '"modules/freetype/uwpdef.h"'])
|
|
||||||
# Globally too, as freetype is used in scene (see bottom)
|
|
||||||
env.Append(CCFLAGS=["/FI", '"modules/freetype/uwpdef.h"'])
|
|
||||||
|
|
||||||
env_freetype.Prepend(CPPPATH=[thirdparty_dir + "/include"])
|
env_freetype.Prepend(CPPPATH=[thirdparty_dir + "/include"])
|
||||||
# Also needed in main env for scene/
|
# Also needed in main env for scene/
|
||||||
env.Prepend(CPPPATH=[thirdparty_dir + "/include"])
|
env.Prepend(CPPPATH=[thirdparty_dir + "/include"])
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* uwpdef.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef UWPDEF_H
|
|
||||||
#define UWPDEF_H
|
|
||||||
|
|
||||||
// "generic" is a reserved keyword in C++/CX code
|
|
||||||
// this avoids the errors in the variable name from Freetype code
|
|
||||||
#define generic freetype_generic
|
|
||||||
|
|
||||||
#endif // UWPDEF_H
|
|
|
@ -3,7 +3,7 @@ import os.path
|
||||||
|
|
||||||
|
|
||||||
def is_desktop(platform):
|
def is_desktop(platform):
|
||||||
return platform in ["windows", "macos", "linuxbsd", "uwp", "haiku"]
|
return platform in ["windows", "macos", "linuxbsd", "haiku"]
|
||||||
|
|
||||||
|
|
||||||
def is_unix_like(platform):
|
def is_unix_like(platform):
|
||||||
|
|
|
@ -84,7 +84,6 @@
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants>
|
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants>
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants>
|
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants>
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'macos' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants>
|
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'macos' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants>
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'uwp' ">GODOT_UWP;GODOT_PC</GodotPlatformConstants>
|
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants>
|
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants>
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants>
|
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants>
|
||||||
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'ios' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants>
|
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'ios' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants>
|
||||||
|
|
|
@ -592,7 +592,6 @@ MONO_AOT_MODE_LAST = 1000,
|
||||||
switch (platform)
|
switch (platform)
|
||||||
{
|
{
|
||||||
case OS.Platforms.Windows:
|
case OS.Platforms.Windows:
|
||||||
case OS.Platforms.UWP:
|
|
||||||
{
|
{
|
||||||
return $"windows-{arch}";
|
return $"windows-{arch}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ namespace GodotTools.Utils
|
||||||
public const string FreeBSD = "FreeBSD";
|
public const string FreeBSD = "FreeBSD";
|
||||||
public const string NetBSD = "NetBSD";
|
public const string NetBSD = "NetBSD";
|
||||||
public const string BSD = "BSD";
|
public const string BSD = "BSD";
|
||||||
public const string UWP = "UWP";
|
|
||||||
public const string Haiku = "Haiku";
|
public const string Haiku = "Haiku";
|
||||||
public const string Android = "Android";
|
public const string Android = "Android";
|
||||||
public const string iOS = "iOS";
|
public const string iOS = "iOS";
|
||||||
|
@ -41,7 +40,6 @@ namespace GodotTools.Utils
|
||||||
public const string Windows = "windows";
|
public const string Windows = "windows";
|
||||||
public const string MacOS = "macos";
|
public const string MacOS = "macos";
|
||||||
public const string LinuxBSD = "linuxbsd";
|
public const string LinuxBSD = "linuxbsd";
|
||||||
public const string UWP = "uwp";
|
|
||||||
public const string Haiku = "haiku";
|
public const string Haiku = "haiku";
|
||||||
public const string Android = "android";
|
public const string Android = "android";
|
||||||
public const string iOS = "ios";
|
public const string iOS = "ios";
|
||||||
|
@ -71,7 +69,6 @@ namespace GodotTools.Utils
|
||||||
["Windows"] = Platforms.Windows,
|
["Windows"] = Platforms.Windows,
|
||||||
["macOS"] = Platforms.MacOS,
|
["macOS"] = Platforms.MacOS,
|
||||||
["Linux"] = Platforms.LinuxBSD,
|
["Linux"] = Platforms.LinuxBSD,
|
||||||
["UWP"] = Platforms.UWP,
|
|
||||||
["Haiku"] = Platforms.Haiku,
|
["Haiku"] = Platforms.Haiku,
|
||||||
["Android"] = Platforms.Android,
|
["Android"] = Platforms.Android,
|
||||||
["iOS"] = Platforms.iOS,
|
["iOS"] = Platforms.iOS,
|
||||||
|
@ -86,7 +83,6 @@ namespace GodotTools.Utils
|
||||||
[Names.FreeBSD] = Platforms.LinuxBSD,
|
[Names.FreeBSD] = Platforms.LinuxBSD,
|
||||||
[Names.NetBSD] = Platforms.LinuxBSD,
|
[Names.NetBSD] = Platforms.LinuxBSD,
|
||||||
[Names.BSD] = Platforms.LinuxBSD,
|
[Names.BSD] = Platforms.LinuxBSD,
|
||||||
[Names.UWP] = Platforms.UWP,
|
|
||||||
[Names.Haiku] = Platforms.Haiku,
|
[Names.Haiku] = Platforms.Haiku,
|
||||||
[Names.Android] = Platforms.Android,
|
[Names.Android] = Platforms.Android,
|
||||||
[Names.iOS] = Platforms.iOS,
|
[Names.iOS] = Platforms.iOS,
|
||||||
|
@ -102,7 +98,6 @@ namespace GodotTools.Utils
|
||||||
// instead of `linux` in the runtime identifier. This would be a problem as
|
// instead of `linux` in the runtime identifier. This would be a problem as
|
||||||
// Godot has a single export profile for both, named LinuxBSD.
|
// Godot has a single export profile for both, named LinuxBSD.
|
||||||
[Platforms.LinuxBSD] = DotNetOS.Linux,
|
[Platforms.LinuxBSD] = DotNetOS.Linux,
|
||||||
[Platforms.UWP] = DotNetOS.Win10,
|
|
||||||
[Platforms.Android] = DotNetOS.Android,
|
[Platforms.Android] = DotNetOS.Android,
|
||||||
[Platforms.iOS] = DotNetOS.iOS,
|
[Platforms.iOS] = DotNetOS.iOS,
|
||||||
[Platforms.Web] = DotNetOS.Browser
|
[Platforms.Web] = DotNetOS.Browser
|
||||||
|
@ -138,21 +133,18 @@ namespace GodotTools.Utils
|
||||||
private static readonly Lazy<bool> _isWindows = new(() => IsOS(Names.Windows));
|
private static readonly Lazy<bool> _isWindows = new(() => IsOS(Names.Windows));
|
||||||
private static readonly Lazy<bool> _isMacOS = new(() => IsOS(Names.MacOS));
|
private static readonly Lazy<bool> _isMacOS = new(() => IsOS(Names.MacOS));
|
||||||
private static readonly Lazy<bool> _isLinuxBSD = new(() => IsAnyOS(LinuxBSDPlatforms));
|
private static readonly Lazy<bool> _isLinuxBSD = new(() => IsAnyOS(LinuxBSDPlatforms));
|
||||||
private static readonly Lazy<bool> _isUWP = new(() => IsOS(Names.UWP));
|
|
||||||
private static readonly Lazy<bool> _isHaiku = new(() => IsOS(Names.Haiku));
|
private static readonly Lazy<bool> _isHaiku = new(() => IsOS(Names.Haiku));
|
||||||
private static readonly Lazy<bool> _isAndroid = new(() => IsOS(Names.Android));
|
private static readonly Lazy<bool> _isAndroid = new(() => IsOS(Names.Android));
|
||||||
private static readonly Lazy<bool> _isiOS = new(() => IsOS(Names.iOS));
|
private static readonly Lazy<bool> _isiOS = new(() => IsOS(Names.iOS));
|
||||||
private static readonly Lazy<bool> _isWeb = new(() => IsOS(Names.Web));
|
private static readonly Lazy<bool> _isWeb = new(() => IsOS(Names.Web));
|
||||||
private static readonly Lazy<bool> _isUnixLike = new(() => IsAnyOS(UnixLikePlatforms));
|
private static readonly Lazy<bool> _isUnixLike = new(() => IsAnyOS(UnixLikePlatforms));
|
||||||
|
|
||||||
[SupportedOSPlatformGuard("windows")] public static bool IsWindows => _isWindows.Value || IsUWP;
|
[SupportedOSPlatformGuard("windows")] public static bool IsWindows => _isWindows.Value;
|
||||||
|
|
||||||
[SupportedOSPlatformGuard("osx")] public static bool IsMacOS => _isMacOS.Value;
|
[SupportedOSPlatformGuard("osx")] public static bool IsMacOS => _isMacOS.Value;
|
||||||
|
|
||||||
[SupportedOSPlatformGuard("linux")] public static bool IsLinuxBSD => _isLinuxBSD.Value;
|
[SupportedOSPlatformGuard("linux")] public static bool IsLinuxBSD => _isLinuxBSD.Value;
|
||||||
|
|
||||||
[SupportedOSPlatformGuard("windows")] public static bool IsUWP => _isUWP.Value;
|
|
||||||
|
|
||||||
public static bool IsHaiku => _isHaiku.Value;
|
public static bool IsHaiku => _isHaiku.Value;
|
||||||
|
|
||||||
[SupportedOSPlatformGuard("android")] public static bool IsAndroid => _isAndroid.Value;
|
[SupportedOSPlatformGuard("android")] public static bool IsAndroid => _isAndroid.Value;
|
||||||
|
|
|
@ -80,7 +80,7 @@ SOFTWARE.
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
String get_hostfxr_file_name() {
|
String get_hostfxr_file_name() {
|
||||||
#if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED)
|
#if defined(WINDOWS_ENABLED)
|
||||||
return "hostfxr.dll";
|
return "hostfxr.dll";
|
||||||
#elif defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
#elif defined(MACOS_ENABLED) || defined(IOS_ENABLED)
|
||||||
return "libhostfxr.dylib";
|
return "libhostfxr.dylib";
|
||||||
|
|
|
@ -100,7 +100,6 @@ static const char *platform_name_map[][2] = {
|
||||||
{ "FreeBSD", "linuxbsd" },
|
{ "FreeBSD", "linuxbsd" },
|
||||||
{ "NetBSD", "linuxbsd" },
|
{ "NetBSD", "linuxbsd" },
|
||||||
{ "BSD", "linuxbsd" },
|
{ "BSD", "linuxbsd" },
|
||||||
{ "UWP", "uwp" },
|
|
||||||
{ "Haiku", "haiku" },
|
{ "Haiku", "haiku" },
|
||||||
{ "Android", "android" },
|
{ "Android", "android" },
|
||||||
{ "iOS", "ios" },
|
{ "iOS", "ios" },
|
||||||
|
|
|
@ -25,7 +25,7 @@ elif env["builtin_wslay"]:
|
||||||
env_ws.Prepend(CPPPATH=[thirdparty_dir])
|
env_ws.Prepend(CPPPATH=[thirdparty_dir])
|
||||||
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
|
env_ws.Append(CPPDEFINES=["HAVE_CONFIG_H"])
|
||||||
|
|
||||||
if env["platform"] == "windows" or env["platform"] == "uwp":
|
if env["platform"] == "windows":
|
||||||
env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
|
env_ws.Append(CPPDEFINES=["HAVE_WINSOCK2_H"])
|
||||||
else:
|
else:
|
||||||
env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
|
env_ws.Append(CPPDEFINES=["HAVE_NETINET_IN_H"])
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# UWP platform port
|
|
||||||
|
|
||||||
> **Warning**
|
|
||||||
>
|
|
||||||
> The UWP platform port is not currently in a working state for the `master`
|
|
||||||
> branch, and may be dropped in the future.
|
|
||||||
|
|
||||||
This folder contains the C++ code for the Universal Windows Platform (UWP)
|
|
||||||
platform port. **This is not to be confused with the "standard" Win32 port**,
|
|
||||||
which is available in [`platform/windows`](/platform/windows).
|
|
||||||
|
|
||||||
See also [`misc/dist/uwp_template`](/misc/dist/uwp_template) folder for the UWP
|
|
||||||
project template used for packaging the UWP export templates.
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_uwp.html)
|
|
||||||
- Instructions on building this platform port from source.
|
|
||||||
- [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html)
|
|
||||||
- Instructions on using the compiled export templates to export a project.
|
|
|
@ -1,20 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
Import("env")
|
|
||||||
|
|
||||||
files = [
|
|
||||||
"#platform/windows/key_mapping_windows.cpp",
|
|
||||||
"#platform/windows/windows_terminal_logger.cpp",
|
|
||||||
"joypad_uwp.cpp",
|
|
||||||
"context_egl_uwp.cpp",
|
|
||||||
"app_uwp.cpp",
|
|
||||||
"os_uwp.cpp",
|
|
||||||
]
|
|
||||||
|
|
||||||
if "build_angle" in env and env["build_angle"]:
|
|
||||||
cmd = env.AlwaysBuild(env.ANGLE("libANGLE.lib", None))
|
|
||||||
|
|
||||||
prog = env.add_program("#bin/godot", files)
|
|
||||||
|
|
||||||
if "build_angle" in env and env["build_angle"]:
|
|
||||||
env.Depends(prog, [cmd])
|
|
|
@ -1,560 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* app_uwp.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "app_uwp.h"
|
|
||||||
|
|
||||||
#include "core/io/dir_access.h"
|
|
||||||
#include "core/io/file_access.h"
|
|
||||||
#include "core/os/keyboard.h"
|
|
||||||
#include "main/main.h"
|
|
||||||
#include "platform/windows/key_mapping_windows.h"
|
|
||||||
|
|
||||||
#include <collection.h>
|
|
||||||
|
|
||||||
using namespace Windows::ApplicationModel::Core;
|
|
||||||
using namespace Windows::ApplicationModel::Activation;
|
|
||||||
using namespace Windows::UI::Core;
|
|
||||||
using namespace Windows::UI::Input;
|
|
||||||
using namespace Windows::Devices::Input;
|
|
||||||
using namespace Windows::UI::Xaml::Input;
|
|
||||||
using namespace Windows::Foundation;
|
|
||||||
using namespace Windows::Graphics::Display;
|
|
||||||
using namespace Windows::System;
|
|
||||||
using namespace Windows::System::Threading::Core;
|
|
||||||
using namespace Microsoft::WRL;
|
|
||||||
|
|
||||||
using namespace GodotUWP;
|
|
||||||
|
|
||||||
// Helper to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
|
|
||||||
inline float ConvertDipsToPixels(float dips, float dpi) {
|
|
||||||
static const float dipsPerInch = 96.0f;
|
|
||||||
return floor(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of the IFrameworkViewSource interface, necessary to run our app.
|
|
||||||
ref class GodotUWPViewSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource {
|
|
||||||
public:
|
|
||||||
virtual Windows::ApplicationModel::Core::IFrameworkView ^ CreateView() {
|
|
||||||
return ref new App();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The main function creates an IFrameworkViewSource for our app, and runs the app.
|
|
||||||
[Platform::MTAThread] int main(Platform::Array<Platform::String ^> ^) {
|
|
||||||
auto godotApplicationSource = ref new GodotUWPViewSource();
|
|
||||||
CoreApplication::Run(godotApplicationSource);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The first method called when the IFrameworkView is being created.
|
|
||||||
void App::Initialize(CoreApplicationView ^ applicationView) {
|
|
||||||
// Register event handlers for app lifecycle. This example includes Activated, so that we
|
|
||||||
// can make the CoreWindow active and start rendering on the window.
|
|
||||||
applicationView->Activated +=
|
|
||||||
ref new TypedEventHandler<CoreApplicationView ^, IActivatedEventArgs ^>(this, &App::OnActivated);
|
|
||||||
|
|
||||||
// Logic for other event handlers could go here.
|
|
||||||
// Information about the Suspending and Resuming event handlers can be found here:
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh994930.aspx
|
|
||||||
|
|
||||||
os = new OS_UWP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when the CoreWindow object is created (or re-created).
|
|
||||||
void App::SetWindow(CoreWindow ^ p_window) {
|
|
||||||
window = p_window;
|
|
||||||
window->VisibilityChanged +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, VisibilityChangedEventArgs ^>(this, &App::OnVisibilityChanged);
|
|
||||||
|
|
||||||
window->Closed +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, CoreWindowEventArgs ^>(this, &App::OnWindowClosed);
|
|
||||||
|
|
||||||
window->SizeChanged +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, WindowSizeChangedEventArgs ^>(this, &App::OnWindowSizeChanged);
|
|
||||||
|
|
||||||
#if !(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
|
||||||
// Disable all pointer visual feedback for better performance when touching.
|
|
||||||
// This is not supported on Windows Phone applications.
|
|
||||||
auto pointerVisualizationSettings = PointerVisualizationSettings::GetForCurrentView();
|
|
||||||
pointerVisualizationSettings->IsContactFeedbackEnabled = false;
|
|
||||||
pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
window->PointerPressed +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &App::OnPointerPressed);
|
|
||||||
window->PointerMoved +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &App::OnPointerMoved);
|
|
||||||
window->PointerReleased +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &App::OnPointerReleased);
|
|
||||||
window->PointerWheelChanged +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, PointerEventArgs ^>(this, &App::OnPointerWheelChanged);
|
|
||||||
|
|
||||||
mouseChangedNotifier = SignalNotifier::AttachToEvent(L"os_mouse_mode_changed", ref new SignalHandler(this, &App::OnMouseModeChanged));
|
|
||||||
|
|
||||||
mouseChangedNotifier->Enable();
|
|
||||||
|
|
||||||
window->CharacterReceived +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, CharacterReceivedEventArgs ^>(this, &App::OnCharacterReceived);
|
|
||||||
window->KeyDown +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &App::OnKeyDown);
|
|
||||||
window->KeyUp +=
|
|
||||||
ref new TypedEventHandler<CoreWindow ^, KeyEventArgs ^>(this, &App::OnKeyUp);
|
|
||||||
|
|
||||||
os->set_window(window);
|
|
||||||
|
|
||||||
unsigned int argc;
|
|
||||||
char **argv = get_command_line(&argc);
|
|
||||||
|
|
||||||
Main::setup("uwp", argc, argv, false);
|
|
||||||
|
|
||||||
UpdateWindowSize(Size(window->Bounds.Width, window->Bounds.Height));
|
|
||||||
|
|
||||||
Main::setup2();
|
|
||||||
}
|
|
||||||
|
|
||||||
static MouseButton _get_button(Windows::UI::Input::PointerPoint ^ pt) {
|
|
||||||
using namespace Windows::UI::Input;
|
|
||||||
|
|
||||||
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
|
||||||
return MOUSE_BUTTON_LEFT;
|
|
||||||
#else
|
|
||||||
switch (pt->Properties->PointerUpdateKind) {
|
|
||||||
case PointerUpdateKind::LeftButtonPressed:
|
|
||||||
case PointerUpdateKind::LeftButtonReleased:
|
|
||||||
return MOUSE_BUTTON_LEFT;
|
|
||||||
|
|
||||||
case PointerUpdateKind::RightButtonPressed:
|
|
||||||
case PointerUpdateKind::RightButtonReleased:
|
|
||||||
return MOUSE_BUTTON_RIGHT;
|
|
||||||
|
|
||||||
case PointerUpdateKind::MiddleButtonPressed:
|
|
||||||
case PointerUpdateKind::MiddleButtonReleased:
|
|
||||||
return MOUSE_BUTTON_MIDDLE;
|
|
||||||
|
|
||||||
case PointerUpdateKind::XButton1Pressed:
|
|
||||||
case PointerUpdateKind::XButton1Released:
|
|
||||||
return MOUSE_BUTTON_WHEEL_UP;
|
|
||||||
|
|
||||||
case PointerUpdateKind::XButton2Pressed:
|
|
||||||
case PointerUpdateKind::XButton2Released:
|
|
||||||
return MOUSE_BUTTON_WHEEL_DOWN;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return MOUSE_BUTTON_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _is_touch(Windows::UI::Input::PointerPoint ^ pointerPoint) {
|
|
||||||
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
using namespace Windows::Devices::Input;
|
|
||||||
switch (pointerPoint->PointerDevice->PointerDeviceType) {
|
|
||||||
case PointerDeviceType::Touch:
|
|
||||||
case PointerDeviceType::Pen:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Foundation::Point _get_pixel_position(CoreWindow ^ window, Windows::Foundation::Point rawPosition, OS *os) {
|
|
||||||
Windows::Foundation::Point outputPosition;
|
|
||||||
|
|
||||||
// Compute coordinates normalized from 0..1.
|
|
||||||
// If the coordinates need to be sized to the SDL window,
|
|
||||||
// we'll do that after.
|
|
||||||
#if 1 || WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
|
|
||||||
outputPosition.X = rawPosition.X / window->Bounds.Width;
|
|
||||||
outputPosition.Y = rawPosition.Y / window->Bounds.Height;
|
|
||||||
#else
|
|
||||||
switch (DisplayProperties::CurrentOrientation) {
|
|
||||||
case DisplayOrientations::Portrait:
|
|
||||||
outputPosition.X = rawPosition.X / window->Bounds.Width;
|
|
||||||
outputPosition.Y = rawPosition.Y / window->Bounds.Height;
|
|
||||||
break;
|
|
||||||
case DisplayOrientations::PortraitFlipped:
|
|
||||||
outputPosition.X = 1.0f - (rawPosition.X / window->Bounds.Width);
|
|
||||||
outputPosition.Y = 1.0f - (rawPosition.Y / window->Bounds.Height);
|
|
||||||
break;
|
|
||||||
case DisplayOrientations::Landscape:
|
|
||||||
outputPosition.X = rawPosition.Y / window->Bounds.Height;
|
|
||||||
outputPosition.Y = 1.0f - (rawPosition.X / window->Bounds.Width);
|
|
||||||
break;
|
|
||||||
case DisplayOrientations::LandscapeFlipped:
|
|
||||||
outputPosition.X = 1.0f - (rawPosition.Y / window->Bounds.Height);
|
|
||||||
outputPosition.Y = rawPosition.X / window->Bounds.Width;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OS::VideoMode vm = os->get_video_mode();
|
|
||||||
outputPosition.X *= vm.width;
|
|
||||||
outputPosition.Y *= vm.height;
|
|
||||||
|
|
||||||
return outputPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _get_finger(uint32_t p_touch_id) {
|
|
||||||
return p_touch_id % 31; // for now
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args, bool p_pressed, bool p_is_wheel) {
|
|
||||||
Windows::UI::Input::PointerPoint ^ point = args->CurrentPoint;
|
|
||||||
Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
|
|
||||||
MouseButton but = _get_button(point);
|
|
||||||
if (_is_touch(point)) {
|
|
||||||
Ref<InputEventScreenTouch> screen_touch;
|
|
||||||
screen_touch.instantiate();
|
|
||||||
screen_touch->set_device(0);
|
|
||||||
screen_touch->set_pressed(p_pressed);
|
|
||||||
screen_touch->set_position(Vector2(pos.X, pos.Y));
|
|
||||||
screen_touch->set_index(_get_finger(point->PointerId));
|
|
||||||
|
|
||||||
last_touch_x[screen_touch->get_index()] = pos.X;
|
|
||||||
last_touch_y[screen_touch->get_index()] = pos.Y;
|
|
||||||
|
|
||||||
os->input_event(screen_touch);
|
|
||||||
} else {
|
|
||||||
Ref<InputEventMouseButton> mouse_button;
|
|
||||||
mouse_button.instantiate();
|
|
||||||
mouse_button->set_device(0);
|
|
||||||
mouse_button->set_pressed(p_pressed);
|
|
||||||
mouse_button->set_button_index(but);
|
|
||||||
mouse_button->set_position(Vector2(pos.X, pos.Y));
|
|
||||||
mouse_button->set_global_position(Vector2(pos.X, pos.Y));
|
|
||||||
|
|
||||||
if (p_is_wheel) {
|
|
||||||
if (point->Properties->MouseWheelDelta > 0) {
|
|
||||||
mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? MOUSE_BUTTON_WHEEL_RIGHT : MOUSE_BUTTON_WHEEL_UP);
|
|
||||||
} else if (point->Properties->MouseWheelDelta < 0) {
|
|
||||||
mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? MOUSE_BUTTON_WHEEL_LEFT : MOUSE_BUTTON_WHEEL_DOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_touch_x[31] = pos.X;
|
|
||||||
last_touch_y[31] = pos.Y;
|
|
||||||
|
|
||||||
os->input_event(mouse_button);
|
|
||||||
|
|
||||||
if (p_is_wheel) {
|
|
||||||
// Send release for mouse wheel
|
|
||||||
mouse_button->set_pressed(false);
|
|
||||||
os->input_event(mouse_button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnPointerPressed(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
|
|
||||||
pointer_event(sender, args, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnPointerReleased(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
|
|
||||||
pointer_event(sender, args, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnPointerWheelChanged(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
|
|
||||||
pointer_event(sender, args, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnMouseModeChanged(Windows::System::Threading::Core::SignalNotifier ^ signalNotifier, bool timedOut) {
|
|
||||||
OS::MouseMode mode = os->get_mouse_mode();
|
|
||||||
SignalNotifier ^ notifier = mouseChangedNotifier;
|
|
||||||
|
|
||||||
window->Dispatcher->RunAsync(
|
|
||||||
CoreDispatcherPriority::High,
|
|
||||||
ref new DispatchedHandler(
|
|
||||||
[mode, notifier, this]() {
|
|
||||||
if (mode == OS::MOUSE_MODE_CAPTURED) {
|
|
||||||
this->MouseMovedToken = MouseDevice::GetForCurrentView()->MouseMoved +=
|
|
||||||
ref new TypedEventHandler<MouseDevice ^, MouseEventArgs ^>(this, &App::OnMouseMoved);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
MouseDevice::GetForCurrentView()->MouseMoved -= MouseMovedToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
notifier->Enable();
|
|
||||||
}));
|
|
||||||
|
|
||||||
ResetEvent(os->mouse_mode_changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args) {
|
|
||||||
Windows::UI::Input::PointerPoint ^ point = args->CurrentPoint;
|
|
||||||
Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
|
|
||||||
|
|
||||||
if (_is_touch(point)) {
|
|
||||||
Ref<InputEventScreenDrag> screen_drag;
|
|
||||||
screen_drag.instantiate();
|
|
||||||
screen_drag->set_device(0);
|
|
||||||
screen_drag->set_position(Vector2(pos.X, pos.Y));
|
|
||||||
screen_drag->set_index(_get_finger(point->PointerId));
|
|
||||||
screen_drag->set_relative(Vector2(screen_drag->get_position().x - last_touch_x[screen_drag->get_index()], screen_drag->get_position().y - last_touch_y[screen_drag->get_index()]));
|
|
||||||
|
|
||||||
os->input_event(screen_drag);
|
|
||||||
} else {
|
|
||||||
// In case the mouse grabbed, MouseMoved will handle this
|
|
||||||
if (os->get_mouse_mode() == OS::MouseMode::MOUSE_MODE_CAPTURED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<InputEventMouseMotion> mouse_motion;
|
|
||||||
mouse_motion.instantiate();
|
|
||||||
mouse_motion->set_device(0);
|
|
||||||
mouse_motion->set_position(Vector2(pos.X, pos.Y));
|
|
||||||
mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
|
|
||||||
mouse_motion->set_relative(Vector2(pos.X - last_touch_x[31], pos.Y - last_touch_y[31]));
|
|
||||||
|
|
||||||
last_mouse_pos = pos;
|
|
||||||
|
|
||||||
os->input_event(mouse_motion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) {
|
|
||||||
// In case the mouse isn't grabbed, PointerMoved will handle this
|
|
||||||
if (os->get_mouse_mode() != OS::MouseMode::MOUSE_MODE_CAPTURED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Windows::Foundation::Point pos;
|
|
||||||
pos.X = last_mouse_pos.X + args->MouseDelta.X;
|
|
||||||
pos.Y = last_mouse_pos.Y + args->MouseDelta.Y;
|
|
||||||
|
|
||||||
Ref<InputEventMouseMotion> mouse_motion;
|
|
||||||
mouse_motion.instantiate();
|
|
||||||
mouse_motion->set_device(0);
|
|
||||||
mouse_motion->set_position(Vector2(pos.X, pos.Y));
|
|
||||||
mouse_motion->set_global_position(Vector2(pos.X, pos.Y));
|
|
||||||
mouse_motion->set_relative(Vector2(args->MouseDelta.X, args->MouseDelta.Y));
|
|
||||||
|
|
||||||
last_mouse_pos = pos;
|
|
||||||
|
|
||||||
os->input_event(mouse_motion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::key_event(Windows::UI::Core::CoreWindow ^ sender, bool p_pressed, Windows::UI::Core::KeyEventArgs ^ key_args, Windows::UI::Core::CharacterReceivedEventArgs ^ char_args) {
|
|
||||||
OS_UWP::KeyEvent ke;
|
|
||||||
|
|
||||||
ke.control = sender->GetAsyncKeyState(VirtualKey::Control) == CoreVirtualKeyStates::Down;
|
|
||||||
ke.alt = sender->GetAsyncKeyState(VirtualKey::Menu) == CoreVirtualKeyStates::Down;
|
|
||||||
ke.shift = sender->GetAsyncKeyState(VirtualKey::Shift) == CoreVirtualKeyStates::Down;
|
|
||||||
|
|
||||||
ke.pressed = p_pressed;
|
|
||||||
|
|
||||||
if (key_args != nullptr) {
|
|
||||||
ke.type = OS_UWP::KeyEvent::MessageType::KEY_EVENT_MESSAGE;
|
|
||||||
ke.unicode = 0;
|
|
||||||
ke.keycode = KeyMappingWindows::get_keysym((unsigned int)key_args->VirtualKey);
|
|
||||||
ke.physical_keycode = KeyMappingWindows::get_scansym((unsigned int)key_args->KeyStatus.ScanCode, key_args->KeyStatus.IsExtendedKey);
|
|
||||||
ke.echo = (!p_pressed && !key_args->KeyStatus.IsKeyReleased) || (p_pressed && key_args->KeyStatus.WasKeyDown);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
ke.type = OS_UWP::KeyEvent::MessageType::CHAR_EVENT_MESSAGE;
|
|
||||||
ke.unicode = char_args->KeyCode;
|
|
||||||
ke.keycode = 0;
|
|
||||||
ke.physical_keycode = 0;
|
|
||||||
ke.echo = (!p_pressed && !char_args->KeyStatus.IsKeyReleased) || (p_pressed && char_args->KeyStatus.WasKeyDown);
|
|
||||||
}
|
|
||||||
|
|
||||||
os->queue_key_event(ke);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnKeyDown(CoreWindow ^ sender, KeyEventArgs ^ args) {
|
|
||||||
key_event(sender, true, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnKeyUp(CoreWindow ^ sender, KeyEventArgs ^ args) {
|
|
||||||
key_event(sender, false, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnCharacterReceived(CoreWindow ^ sender, CharacterReceivedEventArgs ^ args) {
|
|
||||||
key_event(sender, true, nullptr, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes scene resources
|
|
||||||
void App::Load(Platform::String ^ entryPoint) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is called after the window becomes active.
|
|
||||||
void App::Run() {
|
|
||||||
if (Main::start()) {
|
|
||||||
os->run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView
|
|
||||||
// class is torn down while the app is in the foreground.
|
|
||||||
void App::Uninitialize() {
|
|
||||||
Main::cleanup();
|
|
||||||
delete os;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Application lifecycle event handler.
|
|
||||||
void App::OnActivated(CoreApplicationView ^ applicationView, IActivatedEventArgs ^ args) {
|
|
||||||
// Run() won't start until the CoreWindow is activated.
|
|
||||||
CoreWindow::GetForCurrentThread()->Activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Window event handlers.
|
|
||||||
void App::OnVisibilityChanged(CoreWindow ^ sender, VisibilityChangedEventArgs ^ args) {
|
|
||||||
mWindowVisible = args->Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnWindowClosed(CoreWindow ^ sender, CoreWindowEventArgs ^ args) {
|
|
||||||
mWindowClosed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::OnWindowSizeChanged(CoreWindow ^ sender, WindowSizeChangedEventArgs ^ args) {
|
|
||||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
|
|
||||||
// On Windows 8.1, apps are resized when they are snapped alongside other apps, or when the device is rotated.
|
|
||||||
// The default framebuffer will be automatically resized when either of these occur.
|
|
||||||
// In particular, on a 90 degree rotation, the default framebuffer's width and height will switch.
|
|
||||||
UpdateWindowSize(args->Size);
|
|
||||||
#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
|
||||||
// On Windows Phone 8.1, the window size changes when the device is rotated.
|
|
||||||
// The default framebuffer will not be automatically resized when this occurs.
|
|
||||||
// It is therefore up to the app to handle rotation-specific logic in its rendering code.
|
|
||||||
//os->screen_size_changed();
|
|
||||||
UpdateWindowSize(args->Size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::UpdateWindowSize(Size size) {
|
|
||||||
float dpi;
|
|
||||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
|
|
||||||
DisplayInformation ^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
|
|
||||||
dpi = currentDisplayInformation->LogicalDpi;
|
|
||||||
#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
|
||||||
dpi = DisplayProperties::LogicalDpi;
|
|
||||||
#endif
|
|
||||||
Size pixelSize(ConvertDipsToPixels(size.Width, dpi), ConvertDipsToPixels(size.Height, dpi));
|
|
||||||
|
|
||||||
mWindowWidth = static_cast<GLsizei>(pixelSize.Width);
|
|
||||||
mWindowHeight = static_cast<GLsizei>(pixelSize.Height);
|
|
||||||
|
|
||||||
OS::VideoMode vm;
|
|
||||||
vm.width = mWindowWidth;
|
|
||||||
vm.height = mWindowHeight;
|
|
||||||
vm.fullscreen = true;
|
|
||||||
vm.resizable = false;
|
|
||||||
os->set_video_mode(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
char **App::get_command_line(unsigned int *out_argc) {
|
|
||||||
static char *fail_cl[] = { "--path", "game", nullptr };
|
|
||||||
*out_argc = 2;
|
|
||||||
|
|
||||||
FILE *f = _wfopen(L"__cl__.cl", L"rb");
|
|
||||||
|
|
||||||
if (f == nullptr) {
|
|
||||||
wprintf(L"Couldn't open command line file.\n");
|
|
||||||
return fail_cl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define READ_LE_4(v) ((int)(##v[3] & 0xFF) << 24) | ((int)(##v[2] & 0xFF) << 16) | ((int)(##v[1] & 0xFF) << 8) | ((int)(##v[0] & 0xFF))
|
|
||||||
#define CMD_MAX_LEN 65535
|
|
||||||
|
|
||||||
uint8_t len[4];
|
|
||||||
int r = fread(len, sizeof(uint8_t), 4, f);
|
|
||||||
|
|
||||||
Platform::Collections::Vector<Platform::String ^> cl;
|
|
||||||
|
|
||||||
if (r < 4) {
|
|
||||||
fclose(f);
|
|
||||||
wprintf(L"Wrong cmdline length.\n");
|
|
||||||
return (fail_cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int argc = READ_LE_4(len);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
r = fread(len, sizeof(uint8_t), 4, f);
|
|
||||||
|
|
||||||
if (r < 4) {
|
|
||||||
fclose(f);
|
|
||||||
wprintf(L"Wrong cmdline param length.\n");
|
|
||||||
return (fail_cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
int strlen = READ_LE_4(len);
|
|
||||||
|
|
||||||
if (strlen > CMD_MAX_LEN) {
|
|
||||||
fclose(f);
|
|
||||||
wprintf(L"Wrong command length.\n");
|
|
||||||
return (fail_cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *arg = new char[strlen + 1];
|
|
||||||
r = fread(arg, sizeof(char), strlen, f);
|
|
||||||
arg[strlen] = '\0';
|
|
||||||
|
|
||||||
if (r == strlen) {
|
|
||||||
int warg_size = MultiByteToWideChar(CP_UTF8, 0, arg, -1, nullptr, 0);
|
|
||||||
wchar_t *warg = new wchar_t[warg_size];
|
|
||||||
|
|
||||||
MultiByteToWideChar(CP_UTF8, 0, arg, -1, warg, warg_size);
|
|
||||||
|
|
||||||
cl.Append(ref new Platform::String(warg, warg_size));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
delete[] arg;
|
|
||||||
fclose(f);
|
|
||||||
wprintf(L"Error reading command.\n");
|
|
||||||
return (fail_cl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef READ_LE_4
|
|
||||||
#undef CMD_MAX_LEN
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
char **ret = new char *[cl.Size + 1];
|
|
||||||
|
|
||||||
for (int i = 0; i < cl.Size; i++) {
|
|
||||||
int arg_size = WideCharToMultiByte(CP_UTF8, 0, cl.GetAt(i)->Data(), -1, nullptr, 0, nullptr, nullptr);
|
|
||||||
char *arg = new char[arg_size];
|
|
||||||
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, cl.GetAt(i)->Data(), -1, arg, arg_size, nullptr, nullptr);
|
|
||||||
|
|
||||||
ret[i] = arg;
|
|
||||||
}
|
|
||||||
ret[cl.Size] = nullptr;
|
|
||||||
*out_argc = cl.Size;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* app_uwp.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef APP_UWP_H
|
|
||||||
#define APP_UWP_H
|
|
||||||
|
|
||||||
#include "os_uwp.h"
|
|
||||||
|
|
||||||
#include <GLES2/gl2.h>
|
|
||||||
#include <wrl.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
/** clang-format does not play nice with this C++/CX hybrid, needs investigation. */
|
|
||||||
/* clang-format off */
|
|
||||||
|
|
||||||
namespace GodotUWP
|
|
||||||
{
|
|
||||||
ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
App() {}
|
|
||||||
|
|
||||||
// IFrameworkView Methods.
|
|
||||||
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
|
|
||||||
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
|
|
||||||
virtual void Load(Platform::String^ entryPoint);
|
|
||||||
virtual void Run();
|
|
||||||
virtual void Uninitialize();
|
|
||||||
|
|
||||||
property Windows::Foundation::EventRegistrationToken MouseMovedToken {
|
|
||||||
Windows::Foundation::EventRegistrationToken get() { return this->mouseMovedToken; }
|
|
||||||
void set(Windows::Foundation::EventRegistrationToken p_token) { this->mouseMovedToken = p_token; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RecreateRenderer();
|
|
||||||
|
|
||||||
// Application lifecycle event handlers.
|
|
||||||
void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
|
|
||||||
|
|
||||||
// Window event handlers.
|
|
||||||
void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
|
|
||||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
|
|
||||||
void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
|
|
||||||
|
|
||||||
void pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed, bool p_is_wheel = false);
|
|
||||||
void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
|
|
||||||
void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
|
|
||||||
void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
|
|
||||||
void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouse_device, Windows::Devices::Input::MouseEventArgs^ args);
|
|
||||||
void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
|
|
||||||
|
|
||||||
Windows::System::Threading::Core::SignalNotifier^ mouseChangedNotifier;
|
|
||||||
Windows::Foundation::EventRegistrationToken mouseMovedToken;
|
|
||||||
void OnMouseModeChanged(Windows::System::Threading::Core::SignalNotifier^ signalNotifier, bool timedOut);
|
|
||||||
|
|
||||||
void key_event(Windows::UI::Core::CoreWindow^ sender, bool p_pressed, Windows::UI::Core::KeyEventArgs^ key_args = nullptr, Windows::UI::Core::CharacterReceivedEventArgs^ char_args = nullptr);
|
|
||||||
void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
|
|
||||||
void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
|
|
||||||
void OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args);
|
|
||||||
|
|
||||||
void UpdateWindowSize(Windows::Foundation::Size size);
|
|
||||||
void InitializeEGL(Windows::UI::Core::CoreWindow^ window);
|
|
||||||
void CleanupEGL();
|
|
||||||
|
|
||||||
char** get_command_line(unsigned int* out_argc);
|
|
||||||
|
|
||||||
bool mWindowClosed = false;
|
|
||||||
bool mWindowVisible = true;
|
|
||||||
GLsizei mWindowWidth = 0;
|
|
||||||
GLsizei mWindowHeight = 0;
|
|
||||||
|
|
||||||
EGLDisplay mEglDisplay = EGL_NO_DISPLAY;
|
|
||||||
EGLContext mEglContext = EGL_NO_CONTEXT;
|
|
||||||
EGLSurface mEglSurface = EGL_NO_SURFACE;
|
|
||||||
|
|
||||||
CoreWindow^ window;
|
|
||||||
OS_UWP* os;
|
|
||||||
|
|
||||||
int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
|
|
||||||
int last_touch_y[32];
|
|
||||||
Windows::Foundation::Point last_mouse_pos;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clang-format on */
|
|
||||||
|
|
||||||
#endif // APP_UWP_H
|
|
|
@ -1,212 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* context_egl_uwp.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "context_egl_uwp.h"
|
|
||||||
|
|
||||||
#include <EGL/eglext.h>
|
|
||||||
|
|
||||||
using Platform::Exception;
|
|
||||||
|
|
||||||
void ContextEGL_UWP::release_current() {
|
|
||||||
eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, mEglContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextEGL_UWP::make_current() {
|
|
||||||
eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ContextEGL_UWP::get_window_width() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ContextEGL_UWP::get_window_height() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextEGL_UWP::reset() {
|
|
||||||
cleanup();
|
|
||||||
|
|
||||||
window = CoreWindow::GetForCurrentThread();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextEGL_UWP::swap_buffers() {
|
|
||||||
if (eglSwapBuffers(mEglDisplay, mEglSurface) != EGL_TRUE) {
|
|
||||||
cleanup();
|
|
||||||
|
|
||||||
window = CoreWindow::GetForCurrentThread();
|
|
||||||
initialize();
|
|
||||||
|
|
||||||
// tell rasterizer to reload textures and stuff?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Error ContextEGL_UWP::initialize() {
|
|
||||||
EGLint configAttribList[] = {
|
|
||||||
EGL_RED_SIZE, 8,
|
|
||||||
EGL_GREEN_SIZE, 8,
|
|
||||||
EGL_BLUE_SIZE, 8,
|
|
||||||
EGL_ALPHA_SIZE, 8,
|
|
||||||
EGL_DEPTH_SIZE, 8,
|
|
||||||
EGL_STENCIL_SIZE, 8,
|
|
||||||
EGL_SAMPLE_BUFFERS, 0,
|
|
||||||
EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
EGLint surfaceAttribList[] = {
|
|
||||||
EGL_NONE, EGL_NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
EGLint numConfigs = 0;
|
|
||||||
EGLint majorVersion = 1;
|
|
||||||
EGLint minorVersion;
|
|
||||||
if (driver == GLES_2_0) {
|
|
||||||
minorVersion = 0;
|
|
||||||
} else {
|
|
||||||
minorVersion = 5;
|
|
||||||
}
|
|
||||||
EGLDisplay display = EGL_NO_DISPLAY;
|
|
||||||
EGLContext context = EGL_NO_CONTEXT;
|
|
||||||
EGLSurface surface = EGL_NO_SURFACE;
|
|
||||||
EGLConfig config = nullptr;
|
|
||||||
EGLint contextAttribs[3];
|
|
||||||
if (driver == GLES_2_0) {
|
|
||||||
contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION;
|
|
||||||
contextAttribs[1] = 2;
|
|
||||||
contextAttribs[2] = EGL_NONE;
|
|
||||||
} else {
|
|
||||||
contextAttribs[0] = EGL_CONTEXT_CLIENT_VERSION;
|
|
||||||
contextAttribs[1] = 3;
|
|
||||||
contextAttribs[2] = EGL_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const EGLint displayAttributes[] = {
|
|
||||||
/*EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
|
|
||||||
EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
|
|
||||||
EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
|
|
||||||
EGL_NONE,*/
|
|
||||||
// These are the default display attributes, used to request ANGLE's D3D11 renderer.
|
|
||||||
// eglInitialize will only succeed with these attributes if the hardware supports D3D11 Feature Level 10_0+.
|
|
||||||
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
|
|
||||||
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
|
|
||||||
|
|
||||||
// EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER is an optimization that can have large performance benefits on mobile devices.
|
|
||||||
// Its syntax is subject to change, though. Please update your Visual Studio templates if you experience compilation issues with it.
|
|
||||||
EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER,
|
|
||||||
EGL_TRUE,
|
|
||||||
|
|
||||||
// EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that enables ANGLE to automatically call
|
|
||||||
// the IDXGIDevice3::Trim method on behalf of the application when it gets suspended.
|
|
||||||
// Calling IDXGIDevice3::Trim when an application is suspended is a Windows Store application certification requirement.
|
|
||||||
EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE,
|
|
||||||
EGL_TRUE,
|
|
||||||
EGL_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
|
|
||||||
|
|
||||||
if (!eglGetPlatformDisplayEXT) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT");
|
|
||||||
}
|
|
||||||
|
|
||||||
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes);
|
|
||||||
|
|
||||||
if (display == EGL_NO_DISPLAY) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to get default EGL display");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eglInitialize(display, &majorVersion, &minorVersion) == EGL_FALSE) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to initialize EGL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eglGetConfigs(display, nullptr, 0, &numConfigs) == EGL_FALSE) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to get EGLConfig count");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eglChooseConfig(display, configAttribList, &config, 1, &numConfigs) == EGL_FALSE) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to choose first EGLConfig count");
|
|
||||||
}
|
|
||||||
|
|
||||||
surface = eglCreateWindowSurface(display, config, reinterpret_cast<IInspectable *>(window), surfaceAttribList);
|
|
||||||
if (surface == EGL_NO_SURFACE) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to create EGL fullscreen surface");
|
|
||||||
}
|
|
||||||
|
|
||||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
|
|
||||||
if (context == EGL_NO_CONTEXT) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to create EGL context");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
|
|
||||||
throw Exception::CreateException(E_FAIL, L"Failed to make fullscreen EGLSurface current");
|
|
||||||
}
|
|
||||||
} catch (...) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
mEglDisplay = display;
|
|
||||||
mEglSurface = surface;
|
|
||||||
mEglContext = context;
|
|
||||||
|
|
||||||
eglQuerySurface(display, surface, EGL_WIDTH, &width);
|
|
||||||
eglQuerySurface(display, surface, EGL_HEIGHT, &height);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ContextEGL_UWP::cleanup() {
|
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE) {
|
|
||||||
eglDestroySurface(mEglDisplay, mEglSurface);
|
|
||||||
mEglSurface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT) {
|
|
||||||
eglDestroyContext(mEglDisplay, mEglContext);
|
|
||||||
mEglContext = EGL_NO_CONTEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mEglDisplay != EGL_NO_DISPLAY) {
|
|
||||||
eglTerminate(mEglDisplay);
|
|
||||||
mEglDisplay = EGL_NO_DISPLAY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextEGL_UWP::ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver) :
|
|
||||||
mEglDisplay(EGL_NO_DISPLAY),
|
|
||||||
mEglContext(EGL_NO_CONTEXT),
|
|
||||||
mEglSurface(EGL_NO_SURFACE),
|
|
||||||
driver(p_driver),
|
|
||||||
window(p_window),
|
|
||||||
vsync(false) {}
|
|
||||||
|
|
||||||
ContextEGL_UWP::~ContextEGL_UWP() {
|
|
||||||
cleanup();
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* context_egl_uwp.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef CONTEXT_EGL_UWP_H
|
|
||||||
#define CONTEXT_EGL_UWP_H
|
|
||||||
|
|
||||||
#include "core/error/error_list.h"
|
|
||||||
#include "core/os/os.h"
|
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
|
||||||
#include <wrl.h>
|
|
||||||
|
|
||||||
using namespace Windows::UI::Core;
|
|
||||||
|
|
||||||
class ContextEGL_UWP {
|
|
||||||
public:
|
|
||||||
enum Driver {
|
|
||||||
GLES_2_0,
|
|
||||||
VULKAN, // FIXME: Add Vulkan support.
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
CoreWindow ^ window;
|
|
||||||
|
|
||||||
EGLDisplay mEglDisplay;
|
|
||||||
EGLContext mEglContext;
|
|
||||||
EGLSurface mEglSurface;
|
|
||||||
|
|
||||||
EGLint width;
|
|
||||||
EGLint height;
|
|
||||||
|
|
||||||
bool vsync;
|
|
||||||
|
|
||||||
Driver driver;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void release_current();
|
|
||||||
|
|
||||||
void make_current();
|
|
||||||
|
|
||||||
int get_window_width();
|
|
||||||
int get_window_height();
|
|
||||||
void swap_buffers();
|
|
||||||
|
|
||||||
void set_use_vsync(bool use) { vsync = use; }
|
|
||||||
bool is_using_vsync() const { return vsync; }
|
|
||||||
|
|
||||||
Error initialize();
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void cleanup();
|
|
||||||
|
|
||||||
ContextEGL_UWP(CoreWindow ^ p_window, Driver p_driver);
|
|
||||||
~ContextEGL_UWP();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTEXT_EGL_UWP_H
|
|
|
@ -1,216 +0,0 @@
|
||||||
import methods
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from platform_methods import detect_arch
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from SCons import Environment
|
|
||||||
|
|
||||||
|
|
||||||
def get_name():
|
|
||||||
return "UWP"
|
|
||||||
|
|
||||||
|
|
||||||
def can_build():
|
|
||||||
if os.name == "nt":
|
|
||||||
# building natively on windows!
|
|
||||||
if os.getenv("VSINSTALLDIR"):
|
|
||||||
if os.getenv("ANGLE_SRC_PATH") is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_opts():
|
|
||||||
return [
|
|
||||||
("msvc_version", "MSVC version to use (ignored if the VCINSTALLDIR environment variable is set)", None),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_flags():
|
|
||||||
return [
|
|
||||||
("arch", detect_arch()),
|
|
||||||
("tools", False),
|
|
||||||
("xaudio2", True),
|
|
||||||
("builtin_pcre2_with_jit", False),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def configure(env: "Environment"):
|
|
||||||
# Validate arch.
|
|
||||||
supported_arches = ["x86_32", "x86_64", "arm32"]
|
|
||||||
if env["arch"] not in supported_arches:
|
|
||||||
print(
|
|
||||||
'Unsupported CPU architecture "%s" for UWP. Supported architectures are: %s.'
|
|
||||||
% (env["arch"], ", ".join(supported_arches))
|
|
||||||
)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
env.msvc = True
|
|
||||||
|
|
||||||
## Build type
|
|
||||||
|
|
||||||
if env["target"] == "release":
|
|
||||||
env.Append(CCFLAGS=["/MD"])
|
|
||||||
env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
|
|
||||||
if env["optimize"] != "none":
|
|
||||||
env.Append(CCFLAGS=["/O2", "/GL"])
|
|
||||||
env.Append(LINKFLAGS=["/LTCG"])
|
|
||||||
|
|
||||||
elif env["target"] == "release_debug":
|
|
||||||
env.Append(CCFLAGS=["/MD"])
|
|
||||||
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
|
|
||||||
env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
|
|
||||||
if env["optimize"] != "none":
|
|
||||||
env.Append(CCFLAGS=["/O2", "/Zi"])
|
|
||||||
|
|
||||||
elif env["target"] == "debug":
|
|
||||||
env.Append(CCFLAGS=["/Zi"])
|
|
||||||
env.Append(CCFLAGS=["/MDd"])
|
|
||||||
env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
|
|
||||||
env.AppendUnique(CPPDEFINES=["WINDOWS_SUBSYSTEM_CONSOLE"])
|
|
||||||
env.Append(LINKFLAGS=["/DEBUG"])
|
|
||||||
|
|
||||||
## Compiler configuration
|
|
||||||
|
|
||||||
env["ENV"] = os.environ
|
|
||||||
vc_base_path = os.environ["VCTOOLSINSTALLDIR"] if "VCTOOLSINSTALLDIR" in os.environ else os.environ["VCINSTALLDIR"]
|
|
||||||
|
|
||||||
# Force to use Unicode encoding
|
|
||||||
env.AppendUnique(CCFLAGS=["/utf-8"])
|
|
||||||
|
|
||||||
# ANGLE
|
|
||||||
angle_root = os.environ["ANGLE_SRC_PATH"]
|
|
||||||
env.Prepend(CPPPATH=[angle_root + "/include"])
|
|
||||||
jobs = str(env.GetOption("num_jobs"))
|
|
||||||
angle_build_cmd = (
|
|
||||||
"msbuild.exe "
|
|
||||||
+ angle_root
|
|
||||||
+ "/winrt/10/src/angle.sln /nologo /v:m /m:"
|
|
||||||
+ jobs
|
|
||||||
+ " /p:Configuration=Release /p:Platform="
|
|
||||||
)
|
|
||||||
|
|
||||||
if os.path.isfile(f"{angle_root}/winrt/10/src/angle.sln"):
|
|
||||||
env["build_angle"] = True
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
arch = ""
|
|
||||||
if str(os.getenv("Platform")).lower() == "arm":
|
|
||||||
print("Compiled program architecture will be an ARM executable (forcing arch=arm32).")
|
|
||||||
|
|
||||||
arch = "arm"
|
|
||||||
env["arch"] = "arm32"
|
|
||||||
env.Append(LINKFLAGS=["/MACHINE:ARM"])
|
|
||||||
env.Append(LIBPATH=[vc_base_path + "lib/store/arm"])
|
|
||||||
|
|
||||||
angle_build_cmd += "ARM"
|
|
||||||
|
|
||||||
env.Append(LIBPATH=[angle_root + "/winrt/10/src/Release_ARM/lib"])
|
|
||||||
|
|
||||||
else:
|
|
||||||
compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"])
|
|
||||||
|
|
||||||
if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64":
|
|
||||||
env["arch"] = "x86_64"
|
|
||||||
print("Compiled program architecture will be a x64 executable (forcing arch=x86_64).")
|
|
||||||
elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86":
|
|
||||||
env["arch"] = "x86_32"
|
|
||||||
print("Compiled program architecture will be a x86 executable (forcing arch=x86_32).")
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
"Failed to detect MSVC compiler architecture version... Defaulting to x86 32-bit executable settings"
|
|
||||||
" (forcing arch=x86_32). Compilation attempt will continue, but SCons can not detect for what architecture"
|
|
||||||
" this build is compiled for. You should check your settings/compilation setup."
|
|
||||||
)
|
|
||||||
env["arch"] = "x86_32"
|
|
||||||
|
|
||||||
if env["arch"] == "x86_32":
|
|
||||||
arch = "x86"
|
|
||||||
|
|
||||||
angle_build_cmd += "Win32"
|
|
||||||
|
|
||||||
env.Append(LINKFLAGS=["/MACHINE:X86"])
|
|
||||||
env.Append(LIBPATH=[vc_base_path + "lib/store"])
|
|
||||||
env.Append(LIBPATH=[angle_root + "/winrt/10/src/Release_Win32/lib"])
|
|
||||||
|
|
||||||
else:
|
|
||||||
arch = "x64"
|
|
||||||
|
|
||||||
angle_build_cmd += "x64"
|
|
||||||
|
|
||||||
env.Append(LINKFLAGS=["/MACHINE:X64"])
|
|
||||||
env.Append(LIBPATH=[os.environ["VCINSTALLDIR"] + "lib/store/amd64"])
|
|
||||||
env.Append(LIBPATH=[angle_root + "/winrt/10/src/Release_x64/lib"])
|
|
||||||
|
|
||||||
env["PROGSUFFIX"] = "." + arch + env["PROGSUFFIX"]
|
|
||||||
env["OBJSUFFIX"] = "." + arch + env["OBJSUFFIX"]
|
|
||||||
env["LIBSUFFIX"] = "." + arch + env["LIBSUFFIX"]
|
|
||||||
|
|
||||||
## Compile flags
|
|
||||||
|
|
||||||
env.Prepend(CPPPATH=["#platform/uwp", "#drivers/windows"])
|
|
||||||
env.Append(CPPDEFINES=["UWP_ENABLED", "WINDOWS_ENABLED", "TYPED_METHOD_BIND"])
|
|
||||||
env.Append(CPPDEFINES=["GLES_ENABLED", "GL_GLEXT_PROTOTYPES", "EGL_EGLEXT_PROTOTYPES", "ANGLE_ENABLED"])
|
|
||||||
winver = "0x0602" # Windows 8 is the minimum target for UWP build
|
|
||||||
env.Append(CPPDEFINES=[("WINVER", winver), ("_WIN32_WINNT", winver), "WIN32"])
|
|
||||||
|
|
||||||
env.Append(CPPDEFINES=["__WRL_NO_DEFAULT_LIB__", ("PNG_ABORT", "abort")])
|
|
||||||
|
|
||||||
env.Append(CPPFLAGS=["/AI", vc_base_path + "lib/store/references"])
|
|
||||||
env.Append(CPPFLAGS=["/AI", vc_base_path + "lib/x86/store/references"])
|
|
||||||
|
|
||||||
env.Append(
|
|
||||||
CCFLAGS=(
|
|
||||||
'/FS /MP /GS /wd"4453" /wd"28204" /wd"4291" /Zc:wchar_t /Gm- /fp:precise /errorReport:prompt /WX-'
|
|
||||||
" /Zc:forScope /Gd /EHsc /nologo".split()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
env.Append(CPPDEFINES=["_UNICODE", "UNICODE", ("WINAPI_FAMILY", "WINAPI_FAMILY_APP")])
|
|
||||||
env.Append(CXXFLAGS=["/ZW"])
|
|
||||||
env.Append(
|
|
||||||
CCFLAGS=[
|
|
||||||
"/AI",
|
|
||||||
vc_base_path + "\\vcpackages",
|
|
||||||
"/AI",
|
|
||||||
os.environ["WINDOWSSDKDIR"] + "\\References\\CommonConfiguration\\Neutral",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
## Link flags
|
|
||||||
|
|
||||||
env.Append(
|
|
||||||
LINKFLAGS=[
|
|
||||||
"/MANIFEST:NO",
|
|
||||||
"/NXCOMPAT",
|
|
||||||
"/DYNAMICBASE",
|
|
||||||
"/WINMD",
|
|
||||||
"/APPCONTAINER",
|
|
||||||
"/ERRORREPORT:PROMPT",
|
|
||||||
"/NOLOGO",
|
|
||||||
"/TLBID:1",
|
|
||||||
'/NODEFAULTLIB:"kernel32.lib"',
|
|
||||||
'/NODEFAULTLIB:"ole32.lib"',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
LIBS = [
|
|
||||||
"WindowsApp",
|
|
||||||
"mincore",
|
|
||||||
"ws2_32",
|
|
||||||
"libANGLE",
|
|
||||||
"libEGL",
|
|
||||||
"libGLESv2",
|
|
||||||
"bcrypt",
|
|
||||||
]
|
|
||||||
env.Append(LINKFLAGS=[p + ".lib" for p in LIBS])
|
|
||||||
|
|
||||||
# Incremental linking fix
|
|
||||||
env["BUILDERS"]["ProgramOriginal"] = env["BUILDERS"]["Program"]
|
|
||||||
env["BUILDERS"]["Program"] = methods.precious_program
|
|
||||||
|
|
||||||
env.Append(BUILDERS={"ANGLE": env.Builder(action=angle_build_cmd)})
|
|
|
@ -1,465 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* app_packager.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "app_packager.h"
|
|
||||||
|
|
||||||
#include "editor/editor_node.h"
|
|
||||||
#include "editor/editor_paths.h"
|
|
||||||
|
|
||||||
String AppxPackager::hash_block(const uint8_t *p_block_data, size_t p_block_len) {
|
|
||||||
unsigned char hash[32];
|
|
||||||
char base64[45];
|
|
||||||
|
|
||||||
CryptoCore::sha256(p_block_data, p_block_len, hash);
|
|
||||||
size_t len = 0;
|
|
||||||
CryptoCore::b64_encode((unsigned char *)base64, 45, &len, (unsigned char *)hash, 32);
|
|
||||||
base64[44] = '\0';
|
|
||||||
|
|
||||||
return String(base64);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppxPackager::make_block_map(const String &p_path) {
|
|
||||||
Ref<FileAccess> tmp_file = FileAccess::open(p_path, FileAccess::WRITE);
|
|
||||||
|
|
||||||
tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>");
|
|
||||||
tmp_file->store_string("<BlockMap xmlns=\"http://schemas.microsoft.com/appx/2010/blockmap\" HashMethod=\"http://www.w3.org/2001/04/xmlenc#sha256\">");
|
|
||||||
|
|
||||||
for (int i = 0; i < file_metadata.size(); i++) {
|
|
||||||
FileMeta file = file_metadata[i];
|
|
||||||
|
|
||||||
tmp_file->store_string(
|
|
||||||
"<File Name=\"" + file.name.replace("/", "\\") + "\" Size=\"" + itos(file.uncompressed_size) + "\" LfhSize=\"" + itos(file.lfh_size) + "\">");
|
|
||||||
|
|
||||||
for (int j = 0; j < file.hashes.size(); j++) {
|
|
||||||
tmp_file->store_string("<Block Hash=\"" + file.hashes[j].base64_hash + "\" ");
|
|
||||||
if (file.compressed) {
|
|
||||||
tmp_file->store_string("Size=\"" + itos(file.hashes[j].compressed_size) + "\" ");
|
|
||||||
}
|
|
||||||
tmp_file->store_string("/>");
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_file->store_string("</File>");
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_file->store_string("</BlockMap>");
|
|
||||||
}
|
|
||||||
|
|
||||||
String AppxPackager::content_type(String p_extension) {
|
|
||||||
if (p_extension == "png") {
|
|
||||||
return "image/png";
|
|
||||||
} else if (p_extension == "jpg") {
|
|
||||||
return "image/jpg";
|
|
||||||
} else if (p_extension == "xml") {
|
|
||||||
return "application/xml";
|
|
||||||
} else if (p_extension == "exe" || p_extension == "dll") {
|
|
||||||
return "application/x-msdownload";
|
|
||||||
} else {
|
|
||||||
return "application/octet-stream";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppxPackager::make_content_types(const String &p_path) {
|
|
||||||
Ref<FileAccess> tmp_file = FileAccess::open(p_path, FileAccess::WRITE);
|
|
||||||
|
|
||||||
tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
|
||||||
tmp_file->store_string("<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
|
|
||||||
|
|
||||||
HashMap<String, String> types;
|
|
||||||
|
|
||||||
for (int i = 0; i < file_metadata.size(); i++) {
|
|
||||||
String ext = file_metadata[i].name.get_extension().to_lower();
|
|
||||||
|
|
||||||
if (types.has(ext)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
types[ext] = content_type(ext);
|
|
||||||
|
|
||||||
tmp_file->store_string("<Default Extension=\"" + ext + "\" ContentType=\"" + types[ext] + "\" />");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appx signature file
|
|
||||||
tmp_file->store_string("<Default Extension=\"p7x\" ContentType=\"application/octet-stream\" />");
|
|
||||||
|
|
||||||
// Override for package files
|
|
||||||
tmp_file->store_string("<Override PartName=\"/AppxManifest.xml\" ContentType=\"application/vnd.ms-appx.manifest+xml\" />");
|
|
||||||
tmp_file->store_string("<Override PartName=\"/AppxBlockMap.xml\" ContentType=\"application/vnd.ms-appx.blockmap+xml\" />");
|
|
||||||
tmp_file->store_string("<Override PartName=\"/AppxSignature.p7x\" ContentType=\"application/vnd.ms-appx.signature\" />");
|
|
||||||
tmp_file->store_string("<Override PartName=\"/AppxMetadata/CodeIntegrity.cat\" ContentType=\"application/vnd.ms-pkiseccat\" />");
|
|
||||||
|
|
||||||
tmp_file->store_string("</Types>");
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) {
|
|
||||||
Vector<uint8_t> buf;
|
|
||||||
buf.resize(BASE_FILE_HEADER_SIZE + p_file_meta.name.length());
|
|
||||||
|
|
||||||
int offs = 0;
|
|
||||||
// Write magic
|
|
||||||
offs += buf_put_int32(FILE_HEADER_MAGIC, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Version
|
|
||||||
offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Special flag
|
|
||||||
offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Compression
|
|
||||||
offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// File date and time
|
|
||||||
offs += buf_put_int32(0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// CRC-32
|
|
||||||
offs += buf_put_int32(p_file_meta.file_crc32, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Compressed size
|
|
||||||
offs += buf_put_int32(p_file_meta.compressed_size, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Uncompressed size
|
|
||||||
offs += buf_put_int32(p_file_meta.uncompressed_size, &buf.write[offs]);
|
|
||||||
|
|
||||||
// File name length
|
|
||||||
offs += buf_put_int16(p_file_meta.name.length(), &buf.write[offs]);
|
|
||||||
|
|
||||||
// Extra data length
|
|
||||||
offs += buf_put_int16(0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// File name
|
|
||||||
offs += buf_put_string(p_file_meta.name, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Done!
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppxPackager::store_central_dir_header(const FileMeta &p_file, bool p_do_hash) {
|
|
||||||
Vector<uint8_t> &buf = central_dir_data;
|
|
||||||
int offs = buf.size();
|
|
||||||
buf.resize(buf.size() + BASE_CENTRAL_DIR_SIZE + p_file.name.length());
|
|
||||||
|
|
||||||
// Write magic
|
|
||||||
offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf.write[offs]);
|
|
||||||
|
|
||||||
// ZIP versions
|
|
||||||
offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
|
|
||||||
offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]);
|
|
||||||
|
|
||||||
// General purpose flag
|
|
||||||
offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Compression
|
|
||||||
offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Modification date/time
|
|
||||||
offs += buf_put_int32(0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Crc-32
|
|
||||||
offs += buf_put_int32(p_file.file_crc32, &buf.write[offs]);
|
|
||||||
|
|
||||||
// File sizes
|
|
||||||
offs += buf_put_int32(p_file.compressed_size, &buf.write[offs]);
|
|
||||||
offs += buf_put_int32(p_file.uncompressed_size, &buf.write[offs]);
|
|
||||||
|
|
||||||
// File name length
|
|
||||||
offs += buf_put_int16(p_file.name.length(), &buf.write[offs]);
|
|
||||||
|
|
||||||
// Extra field length
|
|
||||||
offs += buf_put_int16(0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Comment length
|
|
||||||
offs += buf_put_int16(0, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Disk number start, internal/external file attributes
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
buf.write[offs++] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relative offset
|
|
||||||
offs += buf_put_int32(p_file.zip_offset, &buf.write[offs]);
|
|
||||||
|
|
||||||
// File name
|
|
||||||
offs += buf_put_string(p_file.name, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Done!
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<uint8_t> AppxPackager::make_end_of_central_record() {
|
|
||||||
Vector<uint8_t> buf;
|
|
||||||
buf.resize(ZIP64_END_OF_CENTRAL_DIR_SIZE + 12 + END_OF_CENTRAL_DIR_SIZE); // Size plus magic
|
|
||||||
|
|
||||||
int offs = 0;
|
|
||||||
|
|
||||||
// Write magic
|
|
||||||
offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Size of this record
|
|
||||||
offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Version (yes, twice)
|
|
||||||
offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
|
|
||||||
offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Disk number
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
buf.write[offs++] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number of entries (total and per disk)
|
|
||||||
offs += buf_put_int64(file_metadata.size(), &buf.write[offs]);
|
|
||||||
offs += buf_put_int64(file_metadata.size(), &buf.write[offs]);
|
|
||||||
|
|
||||||
// Size of central dir
|
|
||||||
offs += buf_put_int64(central_dir_data.size(), &buf.write[offs]);
|
|
||||||
|
|
||||||
// Central dir offset
|
|
||||||
offs += buf_put_int64(central_dir_offset, &buf.write[offs]);
|
|
||||||
|
|
||||||
////// ZIP64 locator
|
|
||||||
|
|
||||||
// Write magic for zip64 central dir locator
|
|
||||||
offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Disk number
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
buf.write[offs++] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relative offset
|
|
||||||
offs += buf_put_int64(end_of_central_dir_offset, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Number of disks
|
|
||||||
offs += buf_put_int32(1, &buf.write[offs]);
|
|
||||||
|
|
||||||
/////// End of zip directory
|
|
||||||
|
|
||||||
// Write magic for end central dir
|
|
||||||
offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]);
|
|
||||||
|
|
||||||
// Dummy stuff for Zip64
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
buf.write[offs++] = 0x0;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 12; i++) {
|
|
||||||
buf.write[offs++] = 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size of comments
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
buf.write[offs++] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done!
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppxPackager::init(Ref<FileAccess> p_fa) {
|
|
||||||
package = p_fa;
|
|
||||||
central_dir_offset = 0;
|
|
||||||
end_of_central_dir_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress) {
|
|
||||||
if (p_file_no >= 1 && p_total_files >= 1) {
|
|
||||||
if (EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files)) {
|
|
||||||
return ERR_SKIP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileMeta meta;
|
|
||||||
meta.name = p_file_name;
|
|
||||||
meta.uncompressed_size = p_len;
|
|
||||||
meta.compressed = p_compress;
|
|
||||||
meta.zip_offset = package->get_position();
|
|
||||||
|
|
||||||
Vector<uint8_t> file_buffer;
|
|
||||||
|
|
||||||
// Data for compression
|
|
||||||
z_stream strm{};
|
|
||||||
Vector<uint8_t> strm_in;
|
|
||||||
strm_in.resize(BLOCK_SIZE);
|
|
||||||
Vector<uint8_t> strm_out;
|
|
||||||
|
|
||||||
if (p_compress) {
|
|
||||||
strm.zalloc = zipio_alloc;
|
|
||||||
strm.zfree = zipio_free;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
|
|
||||||
strm_out.resize(BLOCK_SIZE + 8);
|
|
||||||
|
|
||||||
deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
|
||||||
}
|
|
||||||
|
|
||||||
int step = 0;
|
|
||||||
|
|
||||||
while (p_len - step > 0) {
|
|
||||||
size_t block_size = (p_len - step) > BLOCK_SIZE ? (size_t)BLOCK_SIZE : (p_len - step);
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < block_size; i++) {
|
|
||||||
strm_in.write[i] = p_buffer[step + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockHash bh;
|
|
||||||
bh.base64_hash = hash_block(strm_in.ptr(), block_size);
|
|
||||||
|
|
||||||
if (p_compress) {
|
|
||||||
strm.avail_in = block_size;
|
|
||||||
strm.avail_out = strm_out.size();
|
|
||||||
strm.next_in = (uint8_t *)strm_in.ptr();
|
|
||||||
strm.next_out = strm_out.ptrw();
|
|
||||||
|
|
||||||
int total_out_before = strm.total_out;
|
|
||||||
|
|
||||||
int err = deflate(&strm, Z_FULL_FLUSH);
|
|
||||||
ERR_FAIL_COND_V(err < 0, ERR_BUG); // Negative means bug
|
|
||||||
|
|
||||||
bh.compressed_size = strm.total_out - total_out_before;
|
|
||||||
|
|
||||||
//package->store_buffer(strm_out.ptr(), strm.total_out - total_out_before);
|
|
||||||
int start = file_buffer.size();
|
|
||||||
file_buffer.resize(file_buffer.size() + bh.compressed_size);
|
|
||||||
for (uint64_t i = 0; i < bh.compressed_size; i++) {
|
|
||||||
file_buffer.write[start + i] = strm_out[i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bh.compressed_size = block_size;
|
|
||||||
//package->store_buffer(strm_in.ptr(), block_size);
|
|
||||||
int start = file_buffer.size();
|
|
||||||
file_buffer.resize(file_buffer.size() + block_size);
|
|
||||||
for (uint64_t i = 0; i < bh.compressed_size; i++) {
|
|
||||||
file_buffer.write[start + i] = strm_in[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
meta.hashes.push_back(bh);
|
|
||||||
|
|
||||||
step += block_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_compress) {
|
|
||||||
strm.avail_in = 0;
|
|
||||||
strm.avail_out = strm_out.size();
|
|
||||||
strm.next_in = (uint8_t *)strm_in.ptr();
|
|
||||||
strm.next_out = strm_out.ptrw();
|
|
||||||
|
|
||||||
int total_out_before = strm.total_out;
|
|
||||||
|
|
||||||
deflate(&strm, Z_FINISH);
|
|
||||||
|
|
||||||
//package->store_buffer(strm_out.ptr(), strm.total_out - total_out_before);
|
|
||||||
int start = file_buffer.size();
|
|
||||||
file_buffer.resize(file_buffer.size() + (strm.total_out - total_out_before));
|
|
||||||
for (uint64_t i = 0; i < (strm.total_out - total_out_before); i++) {
|
|
||||||
file_buffer.write[start + i] = strm_out[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
deflateEnd(&strm);
|
|
||||||
meta.compressed_size = strm.total_out;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
meta.compressed_size = p_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate file CRC-32
|
|
||||||
uLong crc = crc32(0L, Z_NULL, 0);
|
|
||||||
crc = crc32(crc, p_buffer, p_len);
|
|
||||||
meta.file_crc32 = crc;
|
|
||||||
|
|
||||||
// Create file header
|
|
||||||
Vector<uint8_t> file_header = make_file_header(meta);
|
|
||||||
meta.lfh_size = file_header.size();
|
|
||||||
|
|
||||||
// Store the header and file;
|
|
||||||
package->store_buffer(file_header.ptr(), file_header.size());
|
|
||||||
package->store_buffer(file_buffer.ptr(), file_buffer.size());
|
|
||||||
|
|
||||||
file_metadata.push_back(meta);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppxPackager::finish() {
|
|
||||||
// Create and add block map file
|
|
||||||
EditorNode::progress_task_step("export", "Creating block map...", 4);
|
|
||||||
|
|
||||||
const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpblockmap.xml");
|
|
||||||
make_block_map(tmp_blockmap_file_path);
|
|
||||||
|
|
||||||
{
|
|
||||||
Ref<FileAccess> blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ);
|
|
||||||
Vector<uint8_t> blockmap_buffer;
|
|
||||||
blockmap_buffer.resize(blockmap_file->get_length());
|
|
||||||
|
|
||||||
blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size());
|
|
||||||
|
|
||||||
add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add content types
|
|
||||||
|
|
||||||
EditorNode::progress_task_step("export", "Setting content types...", 5);
|
|
||||||
|
|
||||||
const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpcontenttypes.xml");
|
|
||||||
make_content_types(tmp_content_types_file_path);
|
|
||||||
|
|
||||||
{
|
|
||||||
Ref<FileAccess> types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ);
|
|
||||||
Vector<uint8_t> types_buffer;
|
|
||||||
types_buffer.resize(types_file->get_length());
|
|
||||||
|
|
||||||
types_file->get_buffer(types_buffer.ptrw(), types_buffer.size());
|
|
||||||
|
|
||||||
add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup generated files.
|
|
||||||
DirAccess::remove_file_or_error(tmp_blockmap_file_path);
|
|
||||||
DirAccess::remove_file_or_error(tmp_content_types_file_path);
|
|
||||||
|
|
||||||
// Pre-process central directory before signing
|
|
||||||
for (int i = 0; i < file_metadata.size(); i++) {
|
|
||||||
store_central_dir_header(file_metadata[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write central directory
|
|
||||||
EditorNode::progress_task_step("export", "Finishing package...", 6);
|
|
||||||
central_dir_offset = package->get_position();
|
|
||||||
package->store_buffer(central_dir_data.ptr(), central_dir_data.size());
|
|
||||||
|
|
||||||
// End record
|
|
||||||
end_of_central_dir_offset = package->get_position();
|
|
||||||
Vector<uint8_t> end_record = make_end_of_central_record();
|
|
||||||
package->store_buffer(end_record.ptr(), end_record.size());
|
|
||||||
|
|
||||||
package.unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
AppxPackager::AppxPackager() {}
|
|
||||||
|
|
||||||
AppxPackager::~AppxPackager() {}
|
|
|
@ -1,149 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* app_packager.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef UWP_APP_PACKAGER_H
|
|
||||||
#define UWP_APP_PACKAGER_H
|
|
||||||
|
|
||||||
#include "core/config/project_settings.h"
|
|
||||||
#include "core/core_bind.h"
|
|
||||||
#include "core/crypto/crypto_core.h"
|
|
||||||
#include "core/io/dir_access.h"
|
|
||||||
#include "core/io/file_access.h"
|
|
||||||
#include "core/io/marshalls.h"
|
|
||||||
#include "core/io/zip_io.h"
|
|
||||||
#include "core/object/class_db.h"
|
|
||||||
#include "core/version.h"
|
|
||||||
#include "editor/export/editor_export_platform.h"
|
|
||||||
|
|
||||||
#include "thirdparty/minizip/unzip.h"
|
|
||||||
#include "thirdparty/minizip/zip.h"
|
|
||||||
|
|
||||||
#include <zlib.h>
|
|
||||||
|
|
||||||
class AppxPackager {
|
|
||||||
enum {
|
|
||||||
FILE_HEADER_MAGIC = 0x04034b50,
|
|
||||||
DATA_DESCRIPTOR_MAGIC = 0x08074b50,
|
|
||||||
CENTRAL_DIR_MAGIC = 0x02014b50,
|
|
||||||
END_OF_CENTRAL_DIR_MAGIC = 0x06054b50,
|
|
||||||
ZIP64_END_OF_CENTRAL_DIR_MAGIC = 0x06064b50,
|
|
||||||
ZIP64_END_DIR_LOCATOR_MAGIC = 0x07064b50,
|
|
||||||
P7X_SIGNATURE = 0x58434b50,
|
|
||||||
ZIP64_HEADER_ID = 0x0001,
|
|
||||||
ZIP_VERSION = 20,
|
|
||||||
ZIP_ARCHIVE_VERSION = 45,
|
|
||||||
GENERAL_PURPOSE = 0x00,
|
|
||||||
BASE_FILE_HEADER_SIZE = 30,
|
|
||||||
DATA_DESCRIPTOR_SIZE = 24,
|
|
||||||
BASE_CENTRAL_DIR_SIZE = 46,
|
|
||||||
EXTRA_FIELD_LENGTH = 28,
|
|
||||||
ZIP64_HEADER_SIZE = 24,
|
|
||||||
ZIP64_END_OF_CENTRAL_DIR_SIZE = (56 - 12),
|
|
||||||
END_OF_CENTRAL_DIR_SIZE = 42,
|
|
||||||
BLOCK_SIZE = 65536,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BlockHash {
|
|
||||||
String base64_hash;
|
|
||||||
size_t compressed_size = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileMeta {
|
|
||||||
String name;
|
|
||||||
int lfh_size = 0;
|
|
||||||
bool compressed = false;
|
|
||||||
size_t compressed_size = 0;
|
|
||||||
size_t uncompressed_size = 0;
|
|
||||||
Vector<BlockHash> hashes;
|
|
||||||
uLong file_crc32 = 0;
|
|
||||||
ZPOS64_T zip_offset = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
String progress_task;
|
|
||||||
Ref<FileAccess> package;
|
|
||||||
|
|
||||||
HashSet<String> mime_types;
|
|
||||||
|
|
||||||
Vector<FileMeta> file_metadata;
|
|
||||||
|
|
||||||
ZPOS64_T central_dir_offset = 0;
|
|
||||||
ZPOS64_T end_of_central_dir_offset = 0;
|
|
||||||
Vector<uint8_t> central_dir_data;
|
|
||||||
|
|
||||||
String hash_block(const uint8_t *p_block_data, size_t p_block_len);
|
|
||||||
|
|
||||||
void make_block_map(const String &p_path);
|
|
||||||
void make_content_types(const String &p_path);
|
|
||||||
|
|
||||||
_FORCE_INLINE_ unsigned int buf_put_int16(uint16_t p_val, uint8_t *p_buf) {
|
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
*p_buf++ = (p_val >> (i * 8)) & 0xFF;
|
|
||||||
}
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
_FORCE_INLINE_ unsigned int buf_put_int32(uint32_t p_val, uint8_t *p_buf) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
*p_buf++ = (p_val >> (i * 8)) & 0xFF;
|
|
||||||
}
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
_FORCE_INLINE_ unsigned int buf_put_int64(uint64_t p_val, uint8_t *p_buf) {
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
*p_buf++ = (p_val >> (i * 8)) & 0xFF;
|
|
||||||
}
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
_FORCE_INLINE_ unsigned int buf_put_string(String p_val, uint8_t *p_buf) {
|
|
||||||
for (int i = 0; i < p_val.length(); i++) {
|
|
||||||
*p_buf++ = p_val.utf8().get(i);
|
|
||||||
}
|
|
||||||
return p_val.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<uint8_t> make_file_header(FileMeta p_file_meta);
|
|
||||||
void store_central_dir_header(const FileMeta &p_file, bool p_do_hash = true);
|
|
||||||
Vector<uint8_t> make_end_of_central_record();
|
|
||||||
|
|
||||||
String content_type(String p_extension);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void set_progress_task(String p_task) { progress_task = p_task; }
|
|
||||||
void init(Ref<FileAccess> p_fa);
|
|
||||||
Error add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false);
|
|
||||||
void finish();
|
|
||||||
|
|
||||||
AppxPackager();
|
|
||||||
~AppxPackager();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // UWP_APP_PACKAGER_H
|
|
|
@ -1,56 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* export.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "export.h"
|
|
||||||
|
|
||||||
#include "export_plugin.h"
|
|
||||||
|
|
||||||
#include "editor/editor_settings.h"
|
|
||||||
#include "editor/export/editor_export.h"
|
|
||||||
|
|
||||||
void register_uwp_exporter_types() {
|
|
||||||
// GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformUWP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void register_uwp_exporter() {
|
|
||||||
#ifdef WINDOWS_ENABLED
|
|
||||||
EDITOR_DEF("export/uwp/signtool", "");
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/uwp/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
|
|
||||||
EDITOR_DEF("export/uwp/debug_certificate", "");
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/uwp/debug_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx"));
|
|
||||||
EDITOR_DEF("export/uwp/debug_password", "");
|
|
||||||
EDITOR_DEF("export/uwp/debug_algorithm", 2); // SHA256 is the default
|
|
||||||
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "export/uwp/debug_algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"));
|
|
||||||
#endif // WINDOWS_ENABLED
|
|
||||||
|
|
||||||
Ref<EditorExportPlatformUWP> exporter;
|
|
||||||
exporter.instantiate();
|
|
||||||
EditorExport::get_singleton()->add_export_platform(exporter);
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* export.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef UWP_EXPORT_H
|
|
||||||
#define UWP_EXPORT_H
|
|
||||||
|
|
||||||
void register_uwp_exporter_types();
|
|
||||||
void register_uwp_exporter();
|
|
||||||
|
|
||||||
#endif // UWP_EXPORT_H
|
|
|
@ -1,525 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* export_plugin.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "export_plugin.h"
|
|
||||||
|
|
||||||
#include "logo_svg.gen.h"
|
|
||||||
|
|
||||||
#include "editor/editor_scale.h"
|
|
||||||
#include "editor/editor_settings.h"
|
|
||||||
#include "scene/resources/image_texture.h"
|
|
||||||
|
|
||||||
#include "modules/modules_enabled.gen.h" // For svg and regex.
|
|
||||||
#ifdef MODULE_SVG_ENABLED
|
|
||||||
#include "modules/svg/image_loader_svg.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String EditorExportPlatformUWP::get_name() const {
|
|
||||||
return "UWP";
|
|
||||||
}
|
|
||||||
String EditorExportPlatformUWP::get_os_name() const {
|
|
||||||
return "UWP";
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> EditorExportPlatformUWP::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
|
|
||||||
List<String> list;
|
|
||||||
list.push_back("appx");
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Texture2D> EditorExportPlatformUWP::get_logo() const {
|
|
||||||
return logo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorExportPlatformUWP::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
|
|
||||||
r_features->push_back("s3tc");
|
|
||||||
r_features->push_back("etc");
|
|
||||||
r_features->push_back(p_preset->get("binary_format/architecture"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options) const {
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm32"), "x86_64"));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/display_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/short_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game.Name"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/description"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher", PROPERTY_HINT_PLACEHOLDER_TEXT, "CN=CompanyName"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/publisher_display_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/product_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "identity/publisher_guid", PROPERTY_HINT_PLACEHOLDER_TEXT, "00000000-0000-0000-0000-000000000000"), ""));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/certificate", PROPERTY_HINT_GLOBAL_FILE, "*.pfx", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "signing/password", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SECRET), ""));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "signing/algorithm", PROPERTY_HINT_ENUM, "MD5,SHA1,SHA256"), 2));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/major"), 1));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/minor"), 0));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/build"), 0));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/revision"), 0));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape"), true));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_flipped"), true));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_flipped"), true));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "images/background_color"), "transparent"));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/store_logo", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square44x44_logo", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square71x71_logo", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square150x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/square310x310_logo", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/wide310x150_logo", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::OBJECT, "images/splash_screen", PROPERTY_HINT_RESOURCE_TYPE, "CompressedTexture2D"), Variant()));
|
|
||||||
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square150x150"), false));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_wide310x150"), false));
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "tiles/show_name_on_square310x310"), false));
|
|
||||||
|
|
||||||
// Capabilities
|
|
||||||
const char **basic = uwp_capabilities;
|
|
||||||
while (*basic) {
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic)), false));
|
|
||||||
basic++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char **uap = uwp_uap_capabilities;
|
|
||||||
while (*uap) {
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap)), false));
|
|
||||||
uap++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char **device = uwp_device_capabilities;
|
|
||||||
while (*device) {
|
|
||||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device)), false));
|
|
||||||
device++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const {
|
|
||||||
#ifndef DEV_ENABLED
|
|
||||||
// We don't provide export templates for the UWP platform currently as it
|
|
||||||
// has not been ported for Godot 4. This is skipped in DEV_ENABLED so that
|
|
||||||
// contributors can still test the pipeline if/when we can build it again.
|
|
||||||
r_error = "The UWP platform is currently not supported in Godot 4.\n";
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
|
|
||||||
String err;
|
|
||||||
bool valid = false;
|
|
||||||
|
|
||||||
// Look for export templates (first official, and if defined custom templates).
|
|
||||||
String arch = p_preset->get("binary_format/architecture");
|
|
||||||
String arch_infix;
|
|
||||||
if (arch == "arm32") {
|
|
||||||
arch_infix = "arm";
|
|
||||||
} else if (arch == "x86_32") {
|
|
||||||
arch_infix = "x86";
|
|
||||||
} else if (arch == "x86_64") {
|
|
||||||
arch_infix = "x64";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dvalid = exists_export_template("uwp_" + arch_infix + "_debug.zip", &err);
|
|
||||||
bool rvalid = exists_export_template("uwp_" + arch_infix + "_release.zip", &err);
|
|
||||||
|
|
||||||
if (p_preset->get("custom_template/debug") != "") {
|
|
||||||
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
|
|
||||||
if (!dvalid) {
|
|
||||||
err += TTR("Custom debug template not found.") + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p_preset->get("custom_template/release") != "") {
|
|
||||||
rvalid = FileAccess::exists(p_preset->get("custom_template/release"));
|
|
||||||
if (!rvalid) {
|
|
||||||
err += TTR("Custom release template not found.") + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
valid = dvalid || rvalid;
|
|
||||||
r_missing_templates = !valid;
|
|
||||||
|
|
||||||
if (!err.is_empty()) {
|
|
||||||
r_error = err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
#endif // DEV_ENABLED
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EditorExportPlatformUWP::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
|
|
||||||
#ifndef DEV_ENABLED
|
|
||||||
// We don't provide export templates for the UWP platform currently as it
|
|
||||||
// has not been ported for Godot 4. This is skipped in DEV_ENABLED so that
|
|
||||||
// contributors can still test the pipeline if/when we can build it again.
|
|
||||||
r_error = "The UWP platform is currently not supported in Godot 4.\n";
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
|
|
||||||
String err;
|
|
||||||
bool valid = true;
|
|
||||||
|
|
||||||
// Validate the project configuration.
|
|
||||||
|
|
||||||
if (!_valid_resource_name(p_preset->get("package/short_name"))) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid package short name.") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_valid_resource_name(p_preset->get("package/unique_name"))) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid package unique name.") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_valid_resource_name(p_preset->get("package/publisher_display_name"))) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid package publisher display name.") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_valid_guid(p_preset->get("identity/product_guid"))) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid product GUID.") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_valid_guid(p_preset->get("identity/publisher_guid"))) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid publisher GUID.") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_valid_bgcolor(p_preset->get("images/background_color"))) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid background color.") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/store_logo").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/store_logo"))), 50, 50)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid Store Logo image dimensions (should be 50x50).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/square44x44_logo").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/square44x44_logo"))), 44, 44)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid square 44x44 logo image dimensions (should be 44x44).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/square71x71_logo").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/square71x71_logo"))), 71, 71)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid square 71x71 logo image dimensions (should be 71x71).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/square150x150_logo").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/square150x150_logo"))), 150, 150)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid square 150x150 logo image dimensions (should be 150x150).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/square310x310_logo").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/square310x310_logo"))), 310, 310)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid square 310x310 logo image dimensions (should be 310x310).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/wide310x150_logo").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/wide310x150_logo"))), 310, 150)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid wide 310x150 logo image dimensions (should be 310x150).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p_preset->get("images/splash_screen").is_zero() && !_valid_image((Object::cast_to<CompressedTexture2D>((Object *)p_preset->get("images/splash_screen"))), 620, 300)) {
|
|
||||||
valid = false;
|
|
||||||
err += TTR("Invalid splash screen image dimensions (should be 620x300).") + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
r_error = err;
|
|
||||||
return valid;
|
|
||||||
#endif // DEV_ENABLED
|
|
||||||
}
|
|
||||||
|
|
||||||
Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
|
|
||||||
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
|
|
||||||
|
|
||||||
String src_appx;
|
|
||||||
|
|
||||||
EditorProgress ep("export", TTR("Exporting for UWP"), 7, true);
|
|
||||||
|
|
||||||
if (p_debug) {
|
|
||||||
src_appx = p_preset->get("custom_template/debug");
|
|
||||||
} else {
|
|
||||||
src_appx = p_preset->get("custom_template/release");
|
|
||||||
}
|
|
||||||
|
|
||||||
src_appx = src_appx.strip_edges();
|
|
||||||
|
|
||||||
String arch = p_preset->get("binary_format/architecture");
|
|
||||||
|
|
||||||
if (src_appx.is_empty()) {
|
|
||||||
String err, arch_infix;
|
|
||||||
if (arch == "arm32") {
|
|
||||||
arch_infix = "arm";
|
|
||||||
} else if (arch == "x86_32") {
|
|
||||||
arch_infix = "x86";
|
|
||||||
} else if (arch == "x86_64") {
|
|
||||||
arch_infix = "x64";
|
|
||||||
}
|
|
||||||
if (p_debug) {
|
|
||||||
src_appx = find_export_template("uwp_" + arch_infix + "_debug.zip", &err);
|
|
||||||
} else {
|
|
||||||
src_appx = find_export_template("uwp_" + arch_infix + "_release.zip", &err);
|
|
||||||
}
|
|
||||||
if (src_appx.is_empty()) {
|
|
||||||
EditorNode::add_io_error(err);
|
|
||||||
return ERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DirAccess::exists(p_path.get_base_dir())) {
|
|
||||||
return ERR_FILE_BAD_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error err = OK;
|
|
||||||
|
|
||||||
Ref<FileAccess> fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err);
|
|
||||||
ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
|
|
||||||
|
|
||||||
AppxPackager packager;
|
|
||||||
packager.init(fa_pack);
|
|
||||||
|
|
||||||
Ref<FileAccess> io_fa;
|
|
||||||
zlib_filefunc_def io = zipio_create_io(&io_fa);
|
|
||||||
|
|
||||||
if (ep.step("Creating package...", 0)) {
|
|
||||||
return ERR_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
unzFile pkg = unzOpen2(src_appx.utf8().get_data(), &io);
|
|
||||||
|
|
||||||
if (!pkg) {
|
|
||||||
EditorNode::add_io_error("Could not find template appx to export:\n" + src_appx);
|
|
||||||
return ERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = unzGoToFirstFile(pkg);
|
|
||||||
|
|
||||||
if (ep.step("Copying template files...", 1)) {
|
|
||||||
return ERR_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorNode::progress_add_task("template_files", "Template files", 100);
|
|
||||||
packager.set_progress_task("template_files");
|
|
||||||
|
|
||||||
int template_files_amount = 9;
|
|
||||||
int template_file_no = 1;
|
|
||||||
|
|
||||||
while (ret == UNZ_OK) {
|
|
||||||
// get file name
|
|
||||||
unz_file_info info;
|
|
||||||
char fname[16834];
|
|
||||||
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16834, nullptr, 0, nullptr, 0);
|
|
||||||
if (ret != UNZ_OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
String path = String::utf8(fname);
|
|
||||||
|
|
||||||
if (path.ends_with("/")) {
|
|
||||||
// Ignore directories
|
|
||||||
ret = unzGoToNextFile(pkg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<uint8_t> data;
|
|
||||||
bool do_read = true;
|
|
||||||
|
|
||||||
if (path.begins_with("Assets/")) {
|
|
||||||
path = path.replace(".scale-100", "");
|
|
||||||
|
|
||||||
data = _get_image_data(p_preset, path);
|
|
||||||
if (data.size() > 0) {
|
|
||||||
do_read = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//read
|
|
||||||
if (do_read) {
|
|
||||||
data.resize(info.uncompressed_size);
|
|
||||||
unzOpenCurrentFile(pkg);
|
|
||||||
unzReadCurrentFile(pkg, data.ptrw(), data.size());
|
|
||||||
unzCloseCurrentFile(pkg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == "AppxManifest.xml") {
|
|
||||||
data = _fix_manifest(p_preset, data, p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG));
|
|
||||||
}
|
|
||||||
|
|
||||||
print_line("ADDING: " + path);
|
|
||||||
|
|
||||||
err = packager.add_file(path, data.ptr(), data.size(), template_file_no++, template_files_amount, _should_compress_asset(path, data));
|
|
||||||
if (err != OK) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = unzGoToNextFile(pkg);
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorNode::progress_end_task("template_files");
|
|
||||||
|
|
||||||
if (ep.step("Creating command line...", 2)) {
|
|
||||||
return ERR_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" ");
|
|
||||||
for (int i = 0; i < cl.size(); i++) {
|
|
||||||
if (cl[i].strip_edges().length() == 0) {
|
|
||||||
cl.remove_at(i);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(p_flags & DEBUG_FLAG_DUMB_CLIENT)) {
|
|
||||||
cl.push_back("--path");
|
|
||||||
cl.push_back("game");
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_export_flags(cl, p_flags);
|
|
||||||
|
|
||||||
// Command line file
|
|
||||||
Vector<uint8_t> clf;
|
|
||||||
|
|
||||||
// Argc
|
|
||||||
clf.resize(4);
|
|
||||||
encode_uint32(cl.size(), clf.ptrw());
|
|
||||||
|
|
||||||
for (int i = 0; i < cl.size(); i++) {
|
|
||||||
CharString txt = cl[i].utf8();
|
|
||||||
int base = clf.size();
|
|
||||||
clf.resize(base + 4 + txt.length());
|
|
||||||
encode_uint32(txt.length(), &clf.write[base]);
|
|
||||||
memcpy(&clf.write[base + 4], txt.ptr(), txt.length());
|
|
||||||
print_line(itos(i) + " param: " + cl[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = packager.add_file("__cl__.cl", clf.ptr(), clf.size(), -1, -1, false);
|
|
||||||
if (err != OK) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ep.step("Adding project files...", 3)) {
|
|
||||||
return ERR_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorNode::progress_add_task("project_files", "Project Files", 100);
|
|
||||||
packager.set_progress_task("project_files");
|
|
||||||
|
|
||||||
err = export_project_files(p_preset, p_debug, save_appx_file, &packager);
|
|
||||||
|
|
||||||
EditorNode::progress_end_task("project_files");
|
|
||||||
|
|
||||||
if (ep.step("Closing package...", 7)) {
|
|
||||||
return ERR_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
unzClose(pkg);
|
|
||||||
|
|
||||||
packager.finish();
|
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
|
||||||
// Sign with signtool
|
|
||||||
String signtool_path = EDITOR_GET("export/uwp/signtool");
|
|
||||||
if (signtool_path.is_empty()) {
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FileAccess::exists(signtool_path)) {
|
|
||||||
ERR_PRINT("Could not find signtool executable at " + signtool_path + ", aborting.");
|
|
||||||
return ERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String algs[] = { "MD5", "SHA1", "SHA256" };
|
|
||||||
|
|
||||||
String cert_path = EDITOR_GET("export/uwp/debug_certificate");
|
|
||||||
String cert_pass = EDITOR_GET("export/uwp/debug_password");
|
|
||||||
int cert_alg = EDITOR_GET("export/uwp/debug_algorithm");
|
|
||||||
|
|
||||||
if (!p_debug) {
|
|
||||||
cert_path = p_preset->get_or_env("signing/certificate", ENV_UWP_SIGNING_CERT);
|
|
||||||
cert_pass = p_preset->get_or_env("signing/password", ENV_UWP_SIGNING_PASS);
|
|
||||||
cert_alg = p_preset->get("signing/algorithm");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cert_path.is_empty()) {
|
|
||||||
return OK; // Certificate missing, don't try to sign
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FileAccess::exists(cert_path)) {
|
|
||||||
ERR_PRINT("Could not find certificate file at " + cert_path + ", aborting.");
|
|
||||||
return ERR_FILE_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cert_alg < 0 || cert_alg > 2) {
|
|
||||||
ERR_PRINT("Invalid certificate algorithm " + itos(cert_alg) + ", aborting.");
|
|
||||||
return ERR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> args;
|
|
||||||
args.push_back("sign");
|
|
||||||
args.push_back("/fd");
|
|
||||||
args.push_back(algs[cert_alg]);
|
|
||||||
args.push_back("/a");
|
|
||||||
args.push_back("/f");
|
|
||||||
args.push_back(cert_path);
|
|
||||||
args.push_back("/p");
|
|
||||||
args.push_back(cert_pass);
|
|
||||||
args.push_back(p_path);
|
|
||||||
|
|
||||||
OS::get_singleton()->execute(signtool_path, args);
|
|
||||||
#endif // WINDOWS_ENABLED
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorExportPlatformUWP::get_platform_features(List<String> *r_features) const {
|
|
||||||
r_features->push_back("pc");
|
|
||||||
r_features->push_back("uwp");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) {
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorExportPlatformUWP::EditorExportPlatformUWP() {
|
|
||||||
#ifdef MODULE_SVG_ENABLED
|
|
||||||
Ref<Image> img = memnew(Image);
|
|
||||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
|
||||||
|
|
||||||
ImageLoaderSVG::create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false);
|
|
||||||
|
|
||||||
logo = ImageTexture::create_from_image(img);
|
|
||||||
#endif
|
|
||||||
}
|
|
|
@ -1,450 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* export_plugin.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef UWP_EXPORT_PLUGIN_H
|
|
||||||
#define UWP_EXPORT_PLUGIN_H
|
|
||||||
|
|
||||||
#include "app_packager.h"
|
|
||||||
|
|
||||||
#include "core/config/project_settings.h"
|
|
||||||
#include "core/crypto/crypto_core.h"
|
|
||||||
#include "core/io/dir_access.h"
|
|
||||||
#include "core/io/file_access.h"
|
|
||||||
#include "core/io/marshalls.h"
|
|
||||||
#include "core/io/zip_io.h"
|
|
||||||
#include "core/object/class_db.h"
|
|
||||||
#include "core/version.h"
|
|
||||||
#include "editor/editor_node.h"
|
|
||||||
#include "editor/editor_paths.h"
|
|
||||||
#include "editor/export/editor_export_platform.h"
|
|
||||||
#include "scene/resources/compressed_texture.h"
|
|
||||||
|
|
||||||
#include "thirdparty/minizip/unzip.h"
|
|
||||||
#include "thirdparty/minizip/zip.h"
|
|
||||||
|
|
||||||
#include <zlib.h>
|
|
||||||
|
|
||||||
// Capabilities
|
|
||||||
static const char *uwp_capabilities[] = {
|
|
||||||
"allJoyn",
|
|
||||||
"codeGeneration",
|
|
||||||
"internetClient",
|
|
||||||
"internetClientServer",
|
|
||||||
"privateNetworkClientServer",
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
static const char *uwp_uap_capabilities[] = {
|
|
||||||
"appointments",
|
|
||||||
"blockedChatMessages",
|
|
||||||
"chat",
|
|
||||||
"contacts",
|
|
||||||
"enterpriseAuthentication",
|
|
||||||
"musicLibrary",
|
|
||||||
"objects3D",
|
|
||||||
"picturesLibrary",
|
|
||||||
"phoneCall",
|
|
||||||
"removableStorage",
|
|
||||||
"sharedUserCertificates",
|
|
||||||
"userAccountInformation",
|
|
||||||
"videosLibrary",
|
|
||||||
"voipCall",
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
static const char *uwp_device_capabilities[] = {
|
|
||||||
"bluetooth",
|
|
||||||
"location",
|
|
||||||
"microphone",
|
|
||||||
"proximity",
|
|
||||||
"webcam",
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
// Optional environment variables for defining confidential information. If any
|
|
||||||
// of these is set, they will override the values set in the credentials file.
|
|
||||||
const String ENV_UWP_SIGNING_CERT = "GODOT_UWP_SIGNING_CERTIFICATE";
|
|
||||||
const String ENV_UWP_SIGNING_PASS = "GODOT_UWP_SIGNING_PASSWORD";
|
|
||||||
|
|
||||||
class EditorExportPlatformUWP : public EditorExportPlatform {
|
|
||||||
GDCLASS(EditorExportPlatformUWP, EditorExportPlatform);
|
|
||||||
|
|
||||||
Ref<ImageTexture> logo;
|
|
||||||
|
|
||||||
bool _valid_resource_name(const String &p_name) const {
|
|
||||||
if (p_name.is_empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (p_name.ends_with(".")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *invalid_names[] = {
|
|
||||||
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7",
|
|
||||||
"COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
const char **t = invalid_names;
|
|
||||||
while (*t) {
|
|
||||||
if (p_name == *t) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
t++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _valid_guid(const String &p_guid) const {
|
|
||||||
Vector<String> parts = p_guid.split("-");
|
|
||||||
|
|
||||||
if (parts.size() != 5) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (parts[0].length() != 8) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int i = 1; i < 4; i++) {
|
|
||||||
if (parts[i].length() != 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parts[4].length() != 12) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _valid_bgcolor(const String &p_color) const {
|
|
||||||
if (p_color.is_empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (p_color.begins_with("#") && p_color.is_valid_html_color()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Colors from https://msdn.microsoft.com/en-us/library/windows/apps/dn934817.aspx
|
|
||||||
static const char *valid_colors[] = {
|
|
||||||
"aliceBlue", "antiqueWhite", "aqua", "aquamarine", "azure", "beige",
|
|
||||||
"bisque", "black", "blanchedAlmond", "blue", "blueViolet", "brown",
|
|
||||||
"burlyWood", "cadetBlue", "chartreuse", "chocolate", "coral", "cornflowerBlue",
|
|
||||||
"cornsilk", "crimson", "cyan", "darkBlue", "darkCyan", "darkGoldenrod",
|
|
||||||
"darkGray", "darkGreen", "darkKhaki", "darkMagenta", "darkOliveGreen", "darkOrange",
|
|
||||||
"darkOrchid", "darkRed", "darkSalmon", "darkSeaGreen", "darkSlateBlue", "darkSlateGray",
|
|
||||||
"darkTurquoise", "darkViolet", "deepPink", "deepSkyBlue", "dimGray", "dodgerBlue",
|
|
||||||
"firebrick", "floralWhite", "forestGreen", "fuchsia", "gainsboro", "ghostWhite",
|
|
||||||
"gold", "goldenrod", "gray", "green", "greenYellow", "honeydew",
|
|
||||||
"hotPink", "indianRed", "indigo", "ivory", "khaki", "lavender",
|
|
||||||
"lavenderBlush", "lawnGreen", "lemonChiffon", "lightBlue", "lightCoral", "lightCyan",
|
|
||||||
"lightGoldenrodYellow", "lightGreen", "lightGray", "lightPink", "lightSalmon", "lightSeaGreen",
|
|
||||||
"lightSkyBlue", "lightSlateGray", "lightSteelBlue", "lightYellow", "lime", "limeGreen",
|
|
||||||
"linen", "magenta", "maroon", "mediumAquamarine", "mediumBlue", "mediumOrchid",
|
|
||||||
"mediumPurple", "mediumSeaGreen", "mediumSlateBlue", "mediumSpringGreen", "mediumTurquoise", "mediumVioletRed",
|
|
||||||
"midnightBlue", "mintCream", "mistyRose", "moccasin", "navajoWhite", "navy",
|
|
||||||
"oldLace", "olive", "oliveDrab", "orange", "orangeRed", "orchid",
|
|
||||||
"paleGoldenrod", "paleGreen", "paleTurquoise", "paleVioletRed", "papayaWhip", "peachPuff",
|
|
||||||
"peru", "pink", "plum", "powderBlue", "purple", "red",
|
|
||||||
"rosyBrown", "royalBlue", "saddleBrown", "salmon", "sandyBrown", "seaGreen",
|
|
||||||
"seaShell", "sienna", "silver", "skyBlue", "slateBlue", "slateGray",
|
|
||||||
"snow", "springGreen", "steelBlue", "tan", "teal", "thistle",
|
|
||||||
"tomato", "transparent", "turquoise", "violet", "wheat", "white",
|
|
||||||
"whiteSmoke", "yellow", "yellowGreen",
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
const char **color = valid_colors;
|
|
||||||
|
|
||||||
while (*color) {
|
|
||||||
if (p_color == *color) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
color++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _valid_image(const CompressedTexture2D *p_image, int p_width, int p_height) const {
|
|
||||||
if (!p_image) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add resource creation or image rescaling to enable other scales:
|
|
||||||
// 1.25, 1.5, 2.0
|
|
||||||
return p_width == p_image->get_width() && p_height == p_image->get_height();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<uint8_t> _fix_manifest(const Ref<EditorExportPreset> &p_preset, const Vector<uint8_t> &p_template, bool p_give_internet) const {
|
|
||||||
String result = String::utf8((const char *)p_template.ptr(), p_template.size());
|
|
||||||
|
|
||||||
result = result.replace("$godot_version$", VERSION_FULL_NAME);
|
|
||||||
|
|
||||||
result = result.replace("$identity_name$", p_preset->get("package/unique_name"));
|
|
||||||
result = result.replace("$publisher$", p_preset->get("package/publisher"));
|
|
||||||
|
|
||||||
result = result.replace("$product_guid$", p_preset->get("identity/product_guid"));
|
|
||||||
result = result.replace("$publisher_guid$", p_preset->get("identity/publisher_guid"));
|
|
||||||
|
|
||||||
String version = itos(p_preset->get("version/major")) + "." + itos(p_preset->get("version/minor")) + "." + itos(p_preset->get("version/build")) + "." + itos(p_preset->get("version/revision"));
|
|
||||||
result = result.replace("$version_string$", version);
|
|
||||||
|
|
||||||
String arch = p_preset->get("binary_format/architecture");
|
|
||||||
String architecture = arch == "arm32" ? "arm" : (arch == "x86_32" ? "x86" : "x64");
|
|
||||||
result = result.replace("$architecture$", architecture);
|
|
||||||
|
|
||||||
result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)GLOBAL_GET("application/config/name") : String(p_preset->get("package/display_name")));
|
|
||||||
|
|
||||||
result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name"));
|
|
||||||
result = result.replace("$app_description$", p_preset->get("package/description"));
|
|
||||||
result = result.replace("$bg_color$", p_preset->get("images/background_color"));
|
|
||||||
result = result.replace("$short_name$", p_preset->get("package/short_name"));
|
|
||||||
|
|
||||||
String name_on_tiles = "";
|
|
||||||
if ((bool)p_preset->get("tiles/show_name_on_square150x150")) {
|
|
||||||
name_on_tiles += " <uap:ShowOn Tile=\"square150x150Logo\" />\n";
|
|
||||||
}
|
|
||||||
if ((bool)p_preset->get("tiles/show_name_on_wide310x150")) {
|
|
||||||
name_on_tiles += " <uap:ShowOn Tile=\"wide310x150Logo\" />\n";
|
|
||||||
}
|
|
||||||
if ((bool)p_preset->get("tiles/show_name_on_square310x310")) {
|
|
||||||
name_on_tiles += " <uap:ShowOn Tile=\"square310x310Logo\" />\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
String show_name_on_tiles = "";
|
|
||||||
if (!name_on_tiles.is_empty()) {
|
|
||||||
show_name_on_tiles = "<uap:ShowNameOnTiles>\n" + name_on_tiles + " </uap:ShowNameOnTiles>";
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result.replace("$name_on_tiles$", name_on_tiles);
|
|
||||||
|
|
||||||
String rotations = "";
|
|
||||||
if ((bool)p_preset->get("orientation/landscape")) {
|
|
||||||
rotations += " <uap:Rotation Preference=\"landscape\" />\n";
|
|
||||||
}
|
|
||||||
if ((bool)p_preset->get("orientation/portrait")) {
|
|
||||||
rotations += " <uap:Rotation Preference=\"portrait\" />\n";
|
|
||||||
}
|
|
||||||
if ((bool)p_preset->get("orientation/landscape_flipped")) {
|
|
||||||
rotations += " <uap:Rotation Preference=\"landscapeFlipped\" />\n";
|
|
||||||
}
|
|
||||||
if ((bool)p_preset->get("orientation/portrait_flipped")) {
|
|
||||||
rotations += " <uap:Rotation Preference=\"portraitFlipped\" />\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
String rotation_preference = "";
|
|
||||||
if (!rotations.is_empty()) {
|
|
||||||
rotation_preference = "<uap:InitialRotationPreference>\n" + rotations + " </uap:InitialRotationPreference>";
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result.replace("$rotation_preference$", rotation_preference);
|
|
||||||
|
|
||||||
String capabilities_elements = "";
|
|
||||||
const char **basic = uwp_capabilities;
|
|
||||||
while (*basic) {
|
|
||||||
if ((bool)p_preset->get("capabilities/" + String(*basic))) {
|
|
||||||
capabilities_elements += " <Capability Name=\"" + String(*basic) + "\" />\n";
|
|
||||||
}
|
|
||||||
basic++;
|
|
||||||
}
|
|
||||||
const char **uap = uwp_uap_capabilities;
|
|
||||||
while (*uap) {
|
|
||||||
if ((bool)p_preset->get("capabilities/" + String(*uap))) {
|
|
||||||
capabilities_elements += " <uap:Capability Name=\"" + String(*uap) + "\" />\n";
|
|
||||||
}
|
|
||||||
uap++;
|
|
||||||
}
|
|
||||||
const char **device = uwp_device_capabilities;
|
|
||||||
while (*device) {
|
|
||||||
if ((bool)p_preset->get("capabilities/" + String(*device))) {
|
|
||||||
capabilities_elements += " <DeviceCapability Name=\"" + String(*device) + "\" />\n";
|
|
||||||
}
|
|
||||||
device++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!((bool)p_preset->get("capabilities/internetClient")) && p_give_internet) {
|
|
||||||
capabilities_elements += " <Capability Name=\"internetClient\" />\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
String capabilities_string = "<Capabilities />";
|
|
||||||
if (!capabilities_elements.is_empty()) {
|
|
||||||
capabilities_string = "<Capabilities>\n" + capabilities_elements + " </Capabilities>";
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result.replace("$capabilities_place$", capabilities_string);
|
|
||||||
|
|
||||||
Vector<uint8_t> r_ret;
|
|
||||||
r_ret.resize(result.length());
|
|
||||||
|
|
||||||
for (int i = 0; i < result.length(); i++) {
|
|
||||||
r_ret.write[i] = result.utf8().get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
|
|
||||||
Vector<uint8_t> data;
|
|
||||||
CompressedTexture2D *texture = nullptr;
|
|
||||||
|
|
||||||
if (p_path.find("StoreLogo") != -1) {
|
|
||||||
texture = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/store_logo")));
|
|
||||||
} else if (p_path.find("Square44x44Logo") != -1) {
|
|
||||||
texture = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
|
|
||||||
} else if (p_path.find("Square71x71Logo") != -1) {
|
|
||||||
texture = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
|
|
||||||
} else if (p_path.find("Square150x150Logo") != -1) {
|
|
||||||
texture = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
|
|
||||||
} else if (p_path.find("Square310x310Logo") != -1) {
|
|
||||||
texture = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
|
|
||||||
} else if (p_path.find("Wide310x150Logo") != -1) {
|
|
||||||
texture = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
|
|
||||||
} else if (p_path.find("SplashScreen") != -1) {
|
|
||||||
texture = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<CompressedTexture2D>(((Object *)p_preset->get("images/splash_screen")));
|
|
||||||
} else {
|
|
||||||
ERR_PRINT("Unable to load logo");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!texture) {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("uwp_tmp_logo.png");
|
|
||||||
|
|
||||||
Error err = texture->get_image()->save_png(tmp_path);
|
|
||||||
|
|
||||||
if (err != OK) {
|
|
||||||
String err_string = "Couldn't save temp logo file.";
|
|
||||||
|
|
||||||
EditorNode::add_io_error(err_string);
|
|
||||||
ERR_FAIL_V_MSG(data, err_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Ref<FileAccess> f = FileAccess::open(tmp_path, FileAccess::READ, &err);
|
|
||||||
|
|
||||||
if (err != OK) {
|
|
||||||
String err_string = "Couldn't open temp logo file.";
|
|
||||||
// Cleanup generated file.
|
|
||||||
DirAccess::remove_file_or_error(tmp_path);
|
|
||||||
EditorNode::add_io_error(err_string);
|
|
||||||
ERR_FAIL_V_MSG(data, err_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.resize(f->get_length());
|
|
||||||
f->get_buffer(data.ptrw(), data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
DirAccess::remove_file_or_error(tmp_path);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data) {
|
|
||||||
/* TODO: This was copied verbatim from Android export. It should be
|
|
||||||
* refactored to the parent class and also be used for .zip export.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* By not compressing files with little or not benefit in doing so,
|
|
||||||
* a performance gain is expected at runtime. Moreover, if the APK is
|
|
||||||
* zip-aligned, assets stored as they are can be efficiently read by
|
|
||||||
* Android by memory-mapping them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// -- Unconditional uncompress to mimic AAPT plus some other
|
|
||||||
|
|
||||||
static const char *unconditional_compress_ext[] = {
|
|
||||||
// From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp
|
|
||||||
// These formats are already compressed, or don't compress well:
|
|
||||||
".jpg", ".jpeg", ".png", ".gif",
|
|
||||||
".wav", ".mp2", ".mp3", ".ogg", ".aac",
|
|
||||||
".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",
|
|
||||||
".rtttl", ".imy", ".xmf", ".mp4", ".m4a",
|
|
||||||
".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",
|
|
||||||
".amr", ".awb", ".wma", ".wmv",
|
|
||||||
// Godot-specific:
|
|
||||||
".webp", // Same reasoning as .png
|
|
||||||
".cfb", // Don't let small config files slow-down startup
|
|
||||||
".scn", // Binary scenes are usually already compressed
|
|
||||||
".ctex", // Streamable textures are usually already compressed
|
|
||||||
// Trailer for easier processing
|
|
||||||
nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const char **ext = unconditional_compress_ext; *ext; ++ext) {
|
|
||||||
if (p_path.to_lower().ends_with(String(*ext))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- Compressed resource?
|
|
||||||
|
|
||||||
if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') {
|
|
||||||
// Already compressed
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- TODO: Decide on texture resources according to their image compression setting
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Error save_appx_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
|
||||||
AppxPackager *packager = static_cast<AppxPackager *>(p_userdata);
|
|
||||||
String dst_path = p_path.replace_first("res://", "game/");
|
|
||||||
|
|
||||||
return packager->add_file(dst_path, p_data.ptr(), p_data.size(), p_file, p_total, _should_compress_asset(p_path, p_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual String get_name() const override;
|
|
||||||
virtual String get_os_name() const override;
|
|
||||||
|
|
||||||
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
|
|
||||||
|
|
||||||
virtual Ref<Texture2D> get_logo() const override;
|
|
||||||
|
|
||||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
|
||||||
|
|
||||||
virtual void get_export_options(List<ExportOption> *r_options) const override;
|
|
||||||
|
|
||||||
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug = false) const override;
|
|
||||||
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
|
|
||||||
|
|
||||||
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
|
|
||||||
|
|
||||||
virtual void get_platform_features(List<String> *r_features) const override;
|
|
||||||
|
|
||||||
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, HashSet<String> &p_features) override;
|
|
||||||
|
|
||||||
EditorExportPlatformUWP();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // UWP_EXPORT_PLUGIN_H
|
|
|
@ -1 +0,0 @@
|
||||||
<svg height="32" width="32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="translate(8.981 1.816)"><circle style="fill:#2f75bb;fill-opacity:1;stroke:none;stroke-width:.815427" cx="7.019" cy="14.184" r="13.825"/><path d="m-1.192 8.234 6.73-.927v6.503h-6.73Zm0 11.899 6.73.927v-6.422h-6.73Zm7.47 1.026 8.952 1.236v-7.757H6.278Zm0-13.951v6.602h8.952V5.973Z" fill="#00abed" style="fill:#fff;fill-opacity:1"/></g></svg>
|
|
Before Width: | Height: | Size: 438 B |
|
@ -1,174 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* joypad_uwp.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "joypad_uwp.h"
|
|
||||||
|
|
||||||
#include "core/os/os.h"
|
|
||||||
|
|
||||||
using namespace Windows::Gaming::Input;
|
|
||||||
using namespace Windows::Foundation;
|
|
||||||
|
|
||||||
void JoypadUWP::register_events() {
|
|
||||||
Gamepad::GamepadAdded +=
|
|
||||||
ref new EventHandler<Gamepad ^>(this, &JoypadUWP::OnGamepadAdded);
|
|
||||||
Gamepad::GamepadRemoved +=
|
|
||||||
ref new EventHandler<Gamepad ^>(this, &JoypadUWP::OnGamepadRemoved);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoypadUWP::process_controllers() {
|
|
||||||
for (int i = 0; i < MAX_CONTROLLERS; i++) {
|
|
||||||
ControllerDevice &joy = controllers[i];
|
|
||||||
|
|
||||||
if (!joy.connected) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (joy.type) {
|
|
||||||
case ControllerType::GAMEPAD_CONTROLLER: {
|
|
||||||
GamepadReading reading = ((Gamepad ^) joy.controller_reference)->GetCurrentReading();
|
|
||||||
|
|
||||||
int button_mask = (int)GamepadButtons::Menu;
|
|
||||||
for (int j = 0; j < 14; j++) {
|
|
||||||
input->joy_button(joy.id, j, (int)reading.Buttons & button_mask);
|
|
||||||
button_mask *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
input->joy_axis(joy.id, JoyAxis::LEFT_X, axis_correct(reading.LeftThumbstickX));
|
|
||||||
input->joy_axis(joy.id, JoyAxis::LEFT_Y, axis_correct(reading.LeftThumbstickY, true));
|
|
||||||
input->joy_axis(joy.id, JoyAxis::RIGHT_X, axis_correct(reading.RightThumbstickX));
|
|
||||||
input->joy_axis(joy.id, JoyAxis::RIGHT_Y, axis_correct(reading.RightThumbstickY, true));
|
|
||||||
input->joy_axis(joy.id, JoyAxis::TRIGGER_LEFT, axis_correct(reading.LeftTrigger, false, true));
|
|
||||||
input->joy_axis(joy.id, JoyAxis::TRIGGER_RIGHT, axis_correct(reading.RightTrigger, false, true));
|
|
||||||
|
|
||||||
uint64_t timestamp = input->get_joy_vibration_timestamp(joy.id);
|
|
||||||
if (timestamp > joy.ff_timestamp) {
|
|
||||||
Vector2 strength = input->get_joy_vibration_strength(joy.id);
|
|
||||||
float duration = input->get_joy_vibration_duration(joy.id);
|
|
||||||
if (strength.x == 0 && strength.y == 0) {
|
|
||||||
joypad_vibration_stop(i, timestamp);
|
|
||||||
} else {
|
|
||||||
joypad_vibration_start(i, strength.x, strength.y, duration, timestamp);
|
|
||||||
}
|
|
||||||
} else if (joy.vibrating && joy.ff_end_timestamp != 0) {
|
|
||||||
uint64_t current_time = OS::get_singleton()->get_ticks_usec();
|
|
||||||
if (current_time >= joy.ff_end_timestamp) {
|
|
||||||
joypad_vibration_stop(i, current_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JoypadUWP::JoypadUWP() {
|
|
||||||
for (int i = 0; i < MAX_CONTROLLERS; i++) {
|
|
||||||
controllers[i].id = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JoypadUWP::JoypadUWP(InputDefault *p_input) {
|
|
||||||
input = p_input;
|
|
||||||
|
|
||||||
JoypadUWP();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoypadUWP::OnGamepadAdded(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value) {
|
|
||||||
short idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < MAX_CONTROLLERS; i++) {
|
|
||||||
if (!controllers[i].connected) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND(idx == -1);
|
|
||||||
|
|
||||||
controllers[idx].connected = true;
|
|
||||||
controllers[idx].controller_reference = value;
|
|
||||||
controllers[idx].id = idx;
|
|
||||||
controllers[idx].type = ControllerType::GAMEPAD_CONTROLLER;
|
|
||||||
|
|
||||||
input->joy_connection_changed(controllers[idx].id, true, "Xbox Controller", "__UWP_GAMEPAD__");
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoypadUWP::OnGamepadRemoved(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value) {
|
|
||||||
short idx = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < MAX_CONTROLLERS; i++) {
|
|
||||||
if (controllers[i].controller_reference == value) {
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND(idx == -1);
|
|
||||||
|
|
||||||
controllers[idx] = ControllerDevice();
|
|
||||||
|
|
||||||
input->joy_connection_changed(idx, false, "Xbox Controller");
|
|
||||||
}
|
|
||||||
|
|
||||||
float JoypadUWP::axis_correct(double p_val, bool p_negate, bool p_trigger) const {
|
|
||||||
if (p_trigger) {
|
|
||||||
// Convert to a value between -1.0f and 1.0f.
|
|
||||||
return 2.0f * p_val - 1.0f;
|
|
||||||
}
|
|
||||||
return (float)(p_negate ? -p_val : p_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoypadUWP::joypad_vibration_start(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) {
|
|
||||||
ControllerDevice &joy = controllers[p_device];
|
|
||||||
if (joy.connected) {
|
|
||||||
GamepadVibration vibration;
|
|
||||||
vibration.LeftMotor = p_strong_magnitude;
|
|
||||||
vibration.RightMotor = p_weak_magnitude;
|
|
||||||
((Gamepad ^) joy.controller_reference)->Vibration = vibration;
|
|
||||||
|
|
||||||
joy.ff_timestamp = p_timestamp;
|
|
||||||
joy.ff_end_timestamp = p_duration == 0 ? 0 : p_timestamp + (uint64_t)(p_duration * 1000000.0);
|
|
||||||
joy.vibrating = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JoypadUWP::joypad_vibration_stop(int p_device, uint64_t p_timestamp) {
|
|
||||||
ControllerDevice &joy = controllers[p_device];
|
|
||||||
if (joy.connected) {
|
|
||||||
GamepadVibration vibration;
|
|
||||||
vibration.LeftMotor = 0.0;
|
|
||||||
vibration.RightMotor = 0.0;
|
|
||||||
((Gamepad ^) joy.controller_reference)->Vibration = vibration;
|
|
||||||
|
|
||||||
joy.ff_timestamp = p_timestamp;
|
|
||||||
joy.vibrating = false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* joypad_uwp.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef JOYPAD_UWP_H
|
|
||||||
#define JOYPAD_UWP_H
|
|
||||||
|
|
||||||
#include "core/input/input.h"
|
|
||||||
|
|
||||||
ref class JoypadUWP sealed {
|
|
||||||
/** clang-format breaks this, it does not understand this token. */
|
|
||||||
/* clang-format off */
|
|
||||||
internal:
|
|
||||||
void register_events();
|
|
||||||
void process_controllers();
|
|
||||||
/* clang-format on */
|
|
||||||
|
|
||||||
JoypadUWP();
|
|
||||||
JoypadUWP(InputDefault *p_input);
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum {
|
|
||||||
MAX_CONTROLLERS = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ControllerType {
|
|
||||||
GAMEPAD_CONTROLLER,
|
|
||||||
ARCADE_STICK_CONTROLLER,
|
|
||||||
RACING_WHEEL_CONTROLLER,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControllerDevice {
|
|
||||||
Windows::Gaming::Input::IGameController ^ controller_reference;
|
|
||||||
|
|
||||||
int id = -1;
|
|
||||||
bool connected = false;
|
|
||||||
ControllerType type = ControllerType::GAMEPAD_CONTROLLER;
|
|
||||||
float ff_timestamp = 0;
|
|
||||||
float ff_end_timestamp = 0;
|
|
||||||
bool vibrating = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
ControllerDevice controllers[MAX_CONTROLLERS];
|
|
||||||
|
|
||||||
InputDefault *input = nullptr;
|
|
||||||
|
|
||||||
void OnGamepadAdded(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value);
|
|
||||||
void OnGamepadRemoved(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value);
|
|
||||||
|
|
||||||
float axis_correct(double p_val, bool p_negate = false, bool p_trigger = false) const;
|
|
||||||
void joypad_vibration_start(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
|
|
||||||
void joypad_vibration_stop(int p_device, uint64_t p_timestamp);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // JOYPAD_UWP_H
|
|
|
@ -1,845 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* os_uwp.cpp */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include "os_uwp.h"
|
|
||||||
|
|
||||||
#include "core/config/project_settings.h"
|
|
||||||
#include "core/io/marshalls.h"
|
|
||||||
#include "drivers/unix/ip_unix.h"
|
|
||||||
#include "drivers/unix/net_socket_posix.h"
|
|
||||||
#include "drivers/windows/dir_access_windows.h"
|
|
||||||
#include "drivers/windows/file_access_windows.h"
|
|
||||||
#include "drivers/windows/mutex_windows.h"
|
|
||||||
#include "drivers/windows/semaphore_windows.h"
|
|
||||||
#include "main/main.h"
|
|
||||||
#include "platform/windows/windows_terminal_logger.h"
|
|
||||||
#include "servers/audio_server.h"
|
|
||||||
#include "servers/rendering/rendering_server_default.h"
|
|
||||||
|
|
||||||
#include <ppltasks.h>
|
|
||||||
#include <wrl.h>
|
|
||||||
|
|
||||||
using namespace Windows::ApplicationModel::Core;
|
|
||||||
using namespace Windows::ApplicationModel::Activation;
|
|
||||||
using namespace Windows::UI::Core;
|
|
||||||
using namespace Windows::UI::Input;
|
|
||||||
using namespace Windows::UI::Popups;
|
|
||||||
using namespace Windows::Foundation;
|
|
||||||
using namespace Windows::Graphics::Display;
|
|
||||||
using namespace Microsoft::WRL;
|
|
||||||
using namespace Windows::UI::ViewManagement;
|
|
||||||
using namespace Windows::Devices::Input;
|
|
||||||
using namespace Windows::Devices::Sensors;
|
|
||||||
using namespace Windows::ApplicationModel::DataTransfer;
|
|
||||||
using namespace concurrency;
|
|
||||||
|
|
||||||
static const float earth_gravity = 9.80665;
|
|
||||||
|
|
||||||
int OS_UWP::get_video_driver_count() const {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
Size2 OS_UWP::get_window_size() const {
|
|
||||||
Size2 size;
|
|
||||||
size.width = video_mode.width;
|
|
||||||
size.height = video_mode.height;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int OS_UWP::get_current_video_driver() const {
|
|
||||||
return video_driver_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_window_size(const Size2 p_size) {
|
|
||||||
Windows::Foundation::Size new_size;
|
|
||||||
new_size.Width = p_size.width;
|
|
||||||
new_size.Height = p_size.height;
|
|
||||||
|
|
||||||
ApplicationView ^ view = ApplicationView::GetForCurrentView();
|
|
||||||
|
|
||||||
if (view->TryResizeView(new_size)) {
|
|
||||||
video_mode.width = p_size.width;
|
|
||||||
video_mode.height = p_size.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_window_fullscreen(bool p_enabled) {
|
|
||||||
ApplicationView ^ view = ApplicationView::GetForCurrentView();
|
|
||||||
|
|
||||||
video_mode.fullscreen = view->IsFullScreenMode;
|
|
||||||
|
|
||||||
if (video_mode.fullscreen == p_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_enabled) {
|
|
||||||
video_mode.fullscreen = view->TryEnterFullScreenMode();
|
|
||||||
} else {
|
|
||||||
view->ExitFullScreenMode();
|
|
||||||
video_mode.fullscreen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::is_window_fullscreen() const {
|
|
||||||
return ApplicationView::GetForCurrentView()->IsFullScreenMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_keep_screen_on(bool p_enabled) {
|
|
||||||
if (is_keep_screen_on() == p_enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_enabled) {
|
|
||||||
display_request->RequestActive();
|
|
||||||
} else {
|
|
||||||
display_request->RequestRelease();
|
|
||||||
}
|
|
||||||
|
|
||||||
OS::set_keep_screen_on(p_enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::initialize_core() {
|
|
||||||
//RedirectIOToConsole();
|
|
||||||
|
|
||||||
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES);
|
|
||||||
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA);
|
|
||||||
FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM);
|
|
||||||
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES);
|
|
||||||
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
|
|
||||||
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
|
|
||||||
|
|
||||||
NetSocketPosix::make_default();
|
|
||||||
|
|
||||||
// We need to know how often the clock is updated
|
|
||||||
QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second);
|
|
||||||
QueryPerformanceCounter((LARGE_INTEGER *)&ticks_start);
|
|
||||||
|
|
||||||
IPUnix::make_default();
|
|
||||||
|
|
||||||
cursor_shape = CURSOR_ARROW;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_window(Windows::UI::Core::CoreWindow ^ p_window) {
|
|
||||||
window = p_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::screen_size_changed() {
|
|
||||||
gl_context->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
|
|
||||||
main_loop = nullptr;
|
|
||||||
outside = true;
|
|
||||||
|
|
||||||
// FIXME: Hardcoded for now, add Vulkan support.
|
|
||||||
p_video_driver = RENDERING_DRIVER_OPENGL3;
|
|
||||||
ContextEGL_UWP::Driver opengl_api_type = ContextEGL_UWP::GLES_2_0;
|
|
||||||
|
|
||||||
bool gl_initialization_error = false;
|
|
||||||
|
|
||||||
gl_context = memnew(ContextEGL_UWP(window, opengl_api_type));
|
|
||||||
|
|
||||||
if (gl_context->initialize() != OK) {
|
|
||||||
memdelete(gl_context);
|
|
||||||
gl_context = nullptr;
|
|
||||||
gl_initialization_error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opengl_api_type == ContextEGL_UWP::GLES_2_0) {
|
|
||||||
if (RasterizerGLES3::is_viable() == OK) {
|
|
||||||
RasterizerGLES3::register_config();
|
|
||||||
RasterizerGLES3::make_current();
|
|
||||||
} else {
|
|
||||||
gl_initialization_error = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gl_initialization_error) {
|
|
||||||
OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n"
|
|
||||||
"Please update your drivers or if you have a very old or integrated GPU upgrade it.",
|
|
||||||
"Unable to initialize video driver");
|
|
||||||
return ERR_UNAVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
video_driver_index = p_video_driver;
|
|
||||||
gl_context->make_current();
|
|
||||||
gl_context->set_use_vsync(video_mode.use_vsync);
|
|
||||||
|
|
||||||
VideoMode vm;
|
|
||||||
vm.width = gl_context->get_window_width();
|
|
||||||
vm.height = gl_context->get_window_height();
|
|
||||||
vm.resizable = false;
|
|
||||||
|
|
||||||
ApplicationView ^ view = ApplicationView::GetForCurrentView();
|
|
||||||
vm.fullscreen = view->IsFullScreenMode;
|
|
||||||
|
|
||||||
view->SetDesiredBoundsMode(ApplicationViewBoundsMode::UseVisible);
|
|
||||||
view->PreferredLaunchWindowingMode = ApplicationViewWindowingMode::PreferredLaunchViewSize;
|
|
||||||
|
|
||||||
if (p_desired.fullscreen != view->IsFullScreenMode) {
|
|
||||||
if (p_desired.fullscreen) {
|
|
||||||
vm.fullscreen = view->TryEnterFullScreenMode();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
view->ExitFullScreenMode();
|
|
||||||
vm.fullscreen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Windows::Foundation::Size desired;
|
|
||||||
desired.Width = p_desired.width;
|
|
||||||
desired.Height = p_desired.height;
|
|
||||||
|
|
||||||
view->PreferredLaunchViewSize = desired;
|
|
||||||
|
|
||||||
if (view->TryResizeView(desired)) {
|
|
||||||
vm.width = view->VisibleBounds.Width;
|
|
||||||
vm.height = view->VisibleBounds.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_video_mode(vm);
|
|
||||||
|
|
||||||
rendering_server = memnew(RenderingServerDefault);
|
|
||||||
// FIXME: Reimplement threaded rendering
|
|
||||||
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
|
|
||||||
rendering_server = memnew(RenderingServerWrapMT(rendering_server, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
rendering_server->init();
|
|
||||||
|
|
||||||
input = memnew(InputDefault);
|
|
||||||
|
|
||||||
joypad = ref new JoypadUWP(input);
|
|
||||||
joypad->register_events();
|
|
||||||
|
|
||||||
AudioDriverManager::initialize(p_audio_driver);
|
|
||||||
|
|
||||||
managed_object->update_clipboard();
|
|
||||||
|
|
||||||
Clipboard::ContentChanged += ref new EventHandler<Platform::Object ^>(managed_object, &ManagedType::on_clipboard_changed);
|
|
||||||
|
|
||||||
accelerometer = Accelerometer::GetDefault();
|
|
||||||
if (accelerometer != nullptr) {
|
|
||||||
// 60 FPS
|
|
||||||
accelerometer->ReportInterval = (1.0f / 60.0f) * 1000;
|
|
||||||
accelerometer->ReadingChanged +=
|
|
||||||
ref new TypedEventHandler<Accelerometer ^, AccelerometerReadingChangedEventArgs ^>(managed_object, &ManagedType::on_accelerometer_reading_changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
magnetometer = Magnetometer::GetDefault();
|
|
||||||
if (magnetometer != nullptr) {
|
|
||||||
// 60 FPS
|
|
||||||
magnetometer->ReportInterval = (1.0f / 60.0f) * 1000;
|
|
||||||
magnetometer->ReadingChanged +=
|
|
||||||
ref new TypedEventHandler<Magnetometer ^, MagnetometerReadingChangedEventArgs ^>(managed_object, &ManagedType::on_magnetometer_reading_changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
gyrometer = Gyrometer::GetDefault();
|
|
||||||
if (gyrometer != nullptr) {
|
|
||||||
// 60 FPS
|
|
||||||
gyrometer->ReportInterval = (1.0f / 60.0f) * 1000;
|
|
||||||
gyrometer->ReadingChanged +=
|
|
||||||
ref new TypedEventHandler<Gyrometer ^, GyrometerReadingChangedEventArgs ^>(managed_object, &ManagedType::on_gyroscope_reading_changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ensure_user_data_dir();
|
|
||||||
|
|
||||||
if (is_keep_screen_on()) {
|
|
||||||
display_request->RequestActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
set_keep_screen_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_clipboard(const String &p_text) {
|
|
||||||
DataPackage ^ clip = ref new DataPackage();
|
|
||||||
clip->RequestedOperation = DataPackageOperation::Copy;
|
|
||||||
clip->SetText(ref new Platform::String((LPCWSTR)(p_text.utf16().get_data())));
|
|
||||||
|
|
||||||
Clipboard::SetContent(clip);
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_clipboard() const {
|
|
||||||
if (managed_object->clipboard != nullptr) {
|
|
||||||
return managed_object->clipboard->Data();
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::input_event(const Ref<InputEvent> &p_event) {
|
|
||||||
input->parse_input_event(p_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::delete_main_loop() {
|
|
||||||
if (main_loop) {
|
|
||||||
memdelete(main_loop);
|
|
||||||
}
|
|
||||||
main_loop = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_main_loop(MainLoop *p_main_loop) {
|
|
||||||
input->set_main_loop(p_main_loop);
|
|
||||||
main_loop = p_main_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::finalize() {
|
|
||||||
if (main_loop) {
|
|
||||||
memdelete(main_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
main_loop = nullptr;
|
|
||||||
|
|
||||||
rendering_server->finish();
|
|
||||||
memdelete(rendering_server);
|
|
||||||
#ifdef GLES3_ENABLED
|
|
||||||
if (gl_context) {
|
|
||||||
memdelete(gl_context);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memdelete(input);
|
|
||||||
|
|
||||||
joypad = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::finalize_core() {
|
|
||||||
NetSocketPosix::cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::alert(const String &p_alert, const String &p_title) {
|
|
||||||
Platform::String ^ alert = ref new Platform::String((LPCWSTR)(p_alert.utf16().get_data()));
|
|
||||||
Platform::String ^ title = ref new Platform::String((LPCWSTR)(p_title.utf16().get_data()));
|
|
||||||
|
|
||||||
MessageDialog ^ msg = ref new MessageDialog(alert, title);
|
|
||||||
|
|
||||||
UICommand ^ close = ref new UICommand("Close", ref new UICommandInvokedHandler(managed_object, &OS_UWP::ManagedType::alert_close));
|
|
||||||
msg->Commands->Append(close);
|
|
||||||
msg->DefaultCommandIndex = 0;
|
|
||||||
|
|
||||||
managed_object->alert_close_handle = true;
|
|
||||||
|
|
||||||
msg->ShowAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::ManagedType::alert_close(IUICommand ^ command) {
|
|
||||||
alert_close_handle = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::ManagedType::on_clipboard_changed(Platform::Object ^ sender, Platform::Object ^ ev) {
|
|
||||||
update_clipboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::ManagedType::update_clipboard() {
|
|
||||||
DataPackageView ^ data = Clipboard::GetContent();
|
|
||||||
|
|
||||||
if (data->Contains(StandardDataFormats::Text)) {
|
|
||||||
create_task(data->GetTextAsync()).then([this](Platform::String ^ clipboard_content) {
|
|
||||||
this->clipboard = clipboard_content;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::ManagedType::on_accelerometer_reading_changed(Accelerometer ^ sender, AccelerometerReadingChangedEventArgs ^ args) {
|
|
||||||
AccelerometerReading ^ reading = args->Reading;
|
|
||||||
|
|
||||||
os->input->set_accelerometer(Vector3(
|
|
||||||
reading->AccelerationX * earth_gravity,
|
|
||||||
reading->AccelerationY * earth_gravity,
|
|
||||||
reading->AccelerationZ * earth_gravity));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::ManagedType::on_magnetometer_reading_changed(Magnetometer ^ sender, MagnetometerReadingChangedEventArgs ^ args) {
|
|
||||||
MagnetometerReading ^ reading = args->Reading;
|
|
||||||
|
|
||||||
os->input->set_magnetometer(Vector3(
|
|
||||||
reading->MagneticFieldX,
|
|
||||||
reading->MagneticFieldY,
|
|
||||||
reading->MagneticFieldZ));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::ManagedType::on_gyroscope_reading_changed(Gyrometer ^ sender, GyrometerReadingChangedEventArgs ^ args) {
|
|
||||||
GyrometerReading ^ reading = args->Reading;
|
|
||||||
|
|
||||||
os->input->set_magnetometer(Vector3(
|
|
||||||
reading->AngularVelocityX,
|
|
||||||
reading->AngularVelocityY,
|
|
||||||
reading->AngularVelocityZ));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_mouse_mode(MouseMode p_mode) {
|
|
||||||
if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) {
|
|
||||||
CoreWindow::GetForCurrentThread()->SetPointerCapture();
|
|
||||||
} else {
|
|
||||||
CoreWindow::GetForCurrentThread()->ReleasePointerCapture();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_mode == MouseMode::MOUSE_MODE_HIDDEN || p_mode == MouseMode::MOUSE_MODE_CAPTURED || p_mode == MouseMode::MOUSE_MODE_CONFINED_HIDDEN) {
|
|
||||||
CoreWindow::GetForCurrentThread()->PointerCursor = nullptr;
|
|
||||||
} else {
|
|
||||||
CoreWindow::GetForCurrentThread()->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
mouse_mode = p_mode;
|
|
||||||
|
|
||||||
SetEvent(mouse_mode_changed);
|
|
||||||
}
|
|
||||||
|
|
||||||
OS_UWP::MouseMode OS_UWP::get_mouse_mode() const {
|
|
||||||
return mouse_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Point2 OS_UWP::get_mouse_position() const {
|
|
||||||
return Point2(old_x, old_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseButton OS_UWP::get_mouse_button_state() const {
|
|
||||||
return last_button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_window_title(const String &p_title) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_video_mode(const VideoMode &p_video_mode, int p_screen) {
|
|
||||||
video_mode = p_video_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
OS::VideoMode OS_UWP::get_video_mode(int p_screen) const {
|
|
||||||
return video_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_name() const {
|
|
||||||
return "UWP";
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_distribution_name() const {
|
|
||||||
return get_name();
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_version() const {
|
|
||||||
winrt::hstring df_version = VersionInfo().DeviceFamilyVersion();
|
|
||||||
return String(winrt::to_string(df_version).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
OS::DateTime OS_UWP::get_datetime(bool p_utc) const {
|
|
||||||
SYSTEMTIME systemtime;
|
|
||||||
if (p_utc) {
|
|
||||||
GetSystemTime(&systemtime);
|
|
||||||
} else {
|
|
||||||
GetLocalTime(&systemtime);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get DST information from Windows, but only if p_utc is false.
|
|
||||||
TIME_ZONE_INFORMATION info;
|
|
||||||
bool daylight = false;
|
|
||||||
if (!p_utc && GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) {
|
|
||||||
daylight = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime dt;
|
|
||||||
dt.year = systemtime.wYear;
|
|
||||||
dt.month = Month(systemtime.wMonth);
|
|
||||||
dt.day = systemtime.wDay;
|
|
||||||
dt.weekday = Weekday(systemtime.wDayOfWeek);
|
|
||||||
dt.hour = systemtime.wHour;
|
|
||||||
dt.minute = systemtime.wMinute;
|
|
||||||
dt.second = systemtime.wSecond;
|
|
||||||
dt.dst = daylight;
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
OS::TimeZoneInfo OS_UWP::get_time_zone_info() const {
|
|
||||||
TIME_ZONE_INFORMATION info;
|
|
||||||
bool daylight = false;
|
|
||||||
if (GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) {
|
|
||||||
daylight = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeZoneInfo ret;
|
|
||||||
if (daylight) {
|
|
||||||
ret.name = info.DaylightName;
|
|
||||||
} else {
|
|
||||||
ret.name = info.StandardName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bias value returned by GetTimeZoneInformation is inverted of what we expect
|
|
||||||
// For example on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
|
|
||||||
ret.bias = -info.Bias;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t OS_UWP::get_unix_time() const {
|
|
||||||
FILETIME ft;
|
|
||||||
SYSTEMTIME st;
|
|
||||||
GetSystemTime(&st);
|
|
||||||
SystemTimeToFileTime(&st, &ft);
|
|
||||||
|
|
||||||
SYSTEMTIME ep;
|
|
||||||
ep.wYear = 1970;
|
|
||||||
ep.wMonth = 1;
|
|
||||||
ep.wDayOfWeek = 4;
|
|
||||||
ep.wDay = 1;
|
|
||||||
ep.wHour = 0;
|
|
||||||
ep.wMinute = 0;
|
|
||||||
ep.wSecond = 0;
|
|
||||||
ep.wMilliseconds = 0;
|
|
||||||
FILETIME fep;
|
|
||||||
SystemTimeToFileTime(&ep, &fep);
|
|
||||||
|
|
||||||
return (*(uint64_t *)&ft - *(uint64_t *)&fep) / 10000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::delay_usec(uint32_t p_usec) const {
|
|
||||||
int msec = p_usec < 1000 ? 1 : p_usec / 1000;
|
|
||||||
|
|
||||||
// no Sleep()
|
|
||||||
WaitForSingleObjectEx(GetCurrentThread(), msec, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t OS_UWP::get_ticks_usec() const {
|
|
||||||
uint64_t ticks;
|
|
||||||
|
|
||||||
// This is the number of clock ticks since start
|
|
||||||
QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
|
|
||||||
// Subtract the ticks at game start to get
|
|
||||||
// the ticks since the game started
|
|
||||||
ticks -= ticks_start;
|
|
||||||
|
|
||||||
// Divide by frequency to get the time in seconds
|
|
||||||
// original calculation shown below is subject to overflow
|
|
||||||
// with high ticks_per_second and a number of days since the last reboot.
|
|
||||||
// time = ticks * 1000000L / ticks_per_second;
|
|
||||||
|
|
||||||
// we can prevent this by either using 128 bit math
|
|
||||||
// or separating into a calculation for seconds, and the fraction
|
|
||||||
uint64_t seconds = ticks / ticks_per_second;
|
|
||||||
|
|
||||||
// compiler will optimize these two into one divide
|
|
||||||
uint64_t leftover = ticks % ticks_per_second;
|
|
||||||
|
|
||||||
// remainder
|
|
||||||
uint64_t time = (leftover * 1000000L) / ticks_per_second;
|
|
||||||
|
|
||||||
// seconds
|
|
||||||
time += seconds * 1000000L;
|
|
||||||
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::process_events() {
|
|
||||||
joypad->process_controllers();
|
|
||||||
process_key_events();
|
|
||||||
input->flush_buffered_events();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::process_key_events() {
|
|
||||||
for (int i = 0; i < key_event_pos; i++) {
|
|
||||||
KeyEvent &kev = key_event_buffer[i];
|
|
||||||
|
|
||||||
Ref<InputEventKey> key_event;
|
|
||||||
key_event.instantiate();
|
|
||||||
key_event->set_alt_pressed(kev.alt);
|
|
||||||
key_event->set_shift_pressed(kev.shift);
|
|
||||||
key_event->set_ctrl_pressed(kev.control);
|
|
||||||
key_event->set_echo(kev.echo);
|
|
||||||
key_event->set_keycode(kev.keycode);
|
|
||||||
key_event->set_physical_keycode((Key)kev.physical_keycode);
|
|
||||||
key_event->set_unicode(kev.unicode);
|
|
||||||
key_event->set_pressed(kev.pressed);
|
|
||||||
|
|
||||||
input_event(key_event);
|
|
||||||
}
|
|
||||||
key_event_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::queue_key_event(KeyEvent &p_event) {
|
|
||||||
// This merges Char events with the previous Key event, so
|
|
||||||
// the unicode can be retrieved without sending duplicate events.
|
|
||||||
if (p_event.type == KeyEvent::MessageType::CHAR_EVENT_MESSAGE && key_event_pos > 0) {
|
|
||||||
KeyEvent &old = key_event_buffer[key_event_pos - 1];
|
|
||||||
ERR_FAIL_COND(old.type != KeyEvent::MessageType::KEY_EVENT_MESSAGE);
|
|
||||||
|
|
||||||
key_event_buffer[key_event_pos - 1].unicode = p_event.unicode;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ERR_FAIL_COND(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
|
|
||||||
|
|
||||||
key_event_buffer[key_event_pos++] = p_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_cursor_shape(CursorShape p_shape) {
|
|
||||||
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
|
|
||||||
|
|
||||||
if (cursor_shape == p_shape) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const CoreCursorType uwp_cursors[CURSOR_MAX] = {
|
|
||||||
CoreCursorType::Arrow,
|
|
||||||
CoreCursorType::IBeam,
|
|
||||||
CoreCursorType::Hand,
|
|
||||||
CoreCursorType::Cross,
|
|
||||||
CoreCursorType::Wait,
|
|
||||||
CoreCursorType::Wait,
|
|
||||||
CoreCursorType::Arrow,
|
|
||||||
CoreCursorType::Arrow,
|
|
||||||
CoreCursorType::UniversalNo,
|
|
||||||
CoreCursorType::SizeNorthSouth,
|
|
||||||
CoreCursorType::SizeWestEast,
|
|
||||||
CoreCursorType::SizeNortheastSouthwest,
|
|
||||||
CoreCursorType::SizeNorthwestSoutheast,
|
|
||||||
CoreCursorType::SizeAll,
|
|
||||||
CoreCursorType::SizeNorthSouth,
|
|
||||||
CoreCursorType::SizeWestEast,
|
|
||||||
CoreCursorType::Help
|
|
||||||
};
|
|
||||||
|
|
||||||
CoreWindow::GetForCurrentThread()->PointerCursor = ref new CoreCursor(uwp_cursors[p_shape], 0);
|
|
||||||
|
|
||||||
cursor_shape = p_shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
OS::CursorShape OS_UWP::get_cursor_shape() const {
|
|
||||||
return cursor_shape;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::kill(const ProcessID &p_pid) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::is_process_running(const ProcessID &p_pid) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::set_cwd(const String &p_cwd) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_executable_path() const {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::set_icon(const Ref<Image> &p_icon) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::has_environment(const String &p_var) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_environment(const String &p_var) const {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::set_environment(const String &p_var, const String &p_value) const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_stdin_string() {
|
|
||||||
return String();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::move_window_to_foreground() {
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::shell_open(String p_uri) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_locale() const {
|
|
||||||
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // this should work on phone 8.1, but it doesn't
|
|
||||||
return "en";
|
|
||||||
#else
|
|
||||||
Platform::String ^ language = Windows::Globalization::Language::CurrentInputMethodLanguageTag;
|
|
||||||
return String(language->Data()).replace("-", "_");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::release_rendering_thread() {
|
|
||||||
gl_context->release_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::make_rendering_thread() {
|
|
||||||
gl_context->make_current();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::swap_buffers() {
|
|
||||||
gl_context->swap_buffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::has_touchscreen_ui_hint() const {
|
|
||||||
TouchCapabilities ^ tc = ref new TouchCapabilities();
|
|
||||||
return tc->TouchPresent != 0 || UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::has_virtual_keyboard() const {
|
|
||||||
return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
|
|
||||||
InputPane ^ pane = InputPane::GetForCurrentView();
|
|
||||||
pane->TryShow();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::hide_virtual_keyboard() {
|
|
||||||
InputPane ^ pane = InputPane::GetForCurrentView();
|
|
||||||
pane->TryHide();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String format_error_message(DWORD id) {
|
|
||||||
LPWSTR messageBuffer = nullptr;
|
|
||||||
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
||||||
nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
|
|
||||||
|
|
||||||
String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
|
|
||||||
|
|
||||||
LocalFree(messageBuffer);
|
|
||||||
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
|
|
||||||
String full_path = "game/" + p_path;
|
|
||||||
p_library_handle = (void *)LoadPackagedLibrary((LPCWSTR)(full_path.utf16().get_data()), 0);
|
|
||||||
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", full_path, format_error_message(GetLastError())));
|
|
||||||
|
|
||||||
if (r_resolved_path != nullptr) {
|
|
||||||
*r_resolved_path = full_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::close_dynamic_library(void *p_library_handle) {
|
|
||||||
if (!FreeLibrary((HMODULE)p_library_handle)) {
|
|
||||||
return FAILED;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error OS_UWP::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) {
|
|
||||||
p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data());
|
|
||||||
if (!p_symbol_handle) {
|
|
||||||
if (!p_optional) {
|
|
||||||
ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Can't resolve symbol " + p_name + ", error: " + String::num(GetLastError()) + ".");
|
|
||||||
} else {
|
|
||||||
return ERR_CANT_RESOLVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OS_UWP::run() {
|
|
||||||
if (!main_loop) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
main_loop->init();
|
|
||||||
|
|
||||||
uint64_t last_ticks = get_ticks_usec();
|
|
||||||
|
|
||||||
int frames = 0;
|
|
||||||
uint64_t frame = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
|
|
||||||
if (managed_object->alert_close_handle) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
process_events(); // get rid of pending events
|
|
||||||
if (Main::iteration()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main_loop->finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
MainLoop *OS_UWP::get_main_loop() const {
|
|
||||||
return main_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
String OS_UWP::get_user_data_dir() const {
|
|
||||||
Windows::Storage::StorageFolder ^ data_folder = Windows::Storage::ApplicationData::Current->LocalFolder;
|
|
||||||
|
|
||||||
return String(data_folder->Path->Data()).replace("\\", "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OS_UWP::_check_internal_feature_support(const String &p_feature) {
|
|
||||||
return p_feature == "pc";
|
|
||||||
}
|
|
||||||
|
|
||||||
OS_UWP::OS_UWP() {
|
|
||||||
key_event_pos = 0;
|
|
||||||
alt_mem = false;
|
|
||||||
gr_mem = false;
|
|
||||||
shift_mem = false;
|
|
||||||
control_mem = false;
|
|
||||||
meta_mem = false;
|
|
||||||
minimized = false;
|
|
||||||
|
|
||||||
pressrc = 0;
|
|
||||||
old_invalid = true;
|
|
||||||
mouse_mode = MOUSE_MODE_VISIBLE;
|
|
||||||
gl_context = nullptr;
|
|
||||||
|
|
||||||
display_request = ref new Windows::System::Display::DisplayRequest();
|
|
||||||
|
|
||||||
managed_object = ref new ManagedType;
|
|
||||||
managed_object->os = this;
|
|
||||||
|
|
||||||
mouse_mode_changed = CreateEvent(nullptr, TRUE, FALSE, L"os_mouse_mode_changed");
|
|
||||||
|
|
||||||
AudioDriverManager::add_driver(&audio_driver);
|
|
||||||
|
|
||||||
Vector<Logger *> loggers;
|
|
||||||
loggers.push_back(memnew(WindowsTerminalLogger));
|
|
||||||
_set_logger(memnew(CompositeLogger(loggers)));
|
|
||||||
}
|
|
||||||
|
|
||||||
OS_UWP::~OS_UWP() {
|
|
||||||
}
|
|
|
@ -1,256 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* os_uwp.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OS_UWP_H
|
|
||||||
#define OS_UWP_H
|
|
||||||
|
|
||||||
#include "context_egl_uwp.h"
|
|
||||||
#include "joypad_uwp.h"
|
|
||||||
|
|
||||||
#include "core/input/input.h"
|
|
||||||
#include "core/math/transform_2d.h"
|
|
||||||
#include "core/os/os.h"
|
|
||||||
#include "core/string/ustring.h"
|
|
||||||
#include "drivers/xaudio2/audio_driver_xaudio2.h"
|
|
||||||
#include "servers/audio_server.h"
|
|
||||||
#include "servers/rendering/renderer_compositor.h"
|
|
||||||
#include "servers/rendering_server.h"
|
|
||||||
|
|
||||||
#include <io.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
class OS_UWP : public OS {
|
|
||||||
public:
|
|
||||||
struct KeyEvent {
|
|
||||||
enum MessageType {
|
|
||||||
KEY_EVENT_MESSAGE,
|
|
||||||
CHAR_EVENT_MESSAGE
|
|
||||||
};
|
|
||||||
|
|
||||||
bool alt = false, shift = false, control = false;
|
|
||||||
MessageType type = KEY_EVENT_MESSAGE;
|
|
||||||
bool pressed = false;
|
|
||||||
Key keycode = Key::NONE;
|
|
||||||
unsigned int physical_keycode = 0;
|
|
||||||
unsigned int unicode = 0;
|
|
||||||
bool echo = false;
|
|
||||||
CorePhysicalKeyStatus status;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum {
|
|
||||||
JOYPADS_MAX = 8,
|
|
||||||
JOY_AXIS_COUNT = 6,
|
|
||||||
MAX_JOY_AXIS = 32768, // I've no idea
|
|
||||||
KEY_EVENT_BUFFER_SIZE = 512
|
|
||||||
};
|
|
||||||
|
|
||||||
FILE *stdo = nullptr;
|
|
||||||
|
|
||||||
KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
|
|
||||||
int key_event_pos;
|
|
||||||
|
|
||||||
uint64_t ticks_start;
|
|
||||||
uint64_t ticks_per_second;
|
|
||||||
|
|
||||||
bool minimized;
|
|
||||||
bool old_invalid;
|
|
||||||
bool outside;
|
|
||||||
int old_x, old_y;
|
|
||||||
Point2i center;
|
|
||||||
RenderingServer *rendering_server = nullptr;
|
|
||||||
int pressrc;
|
|
||||||
|
|
||||||
ContextEGL_UWP *gl_context = nullptr;
|
|
||||||
Windows::UI::Core::CoreWindow ^ window;
|
|
||||||
|
|
||||||
VideoMode video_mode;
|
|
||||||
int video_driver_index;
|
|
||||||
|
|
||||||
MainLoop *main_loop = nullptr;
|
|
||||||
|
|
||||||
AudioDriverXAudio2 audio_driver;
|
|
||||||
|
|
||||||
MouseMode mouse_mode;
|
|
||||||
bool alt_mem;
|
|
||||||
bool gr_mem;
|
|
||||||
bool shift_mem;
|
|
||||||
bool control_mem;
|
|
||||||
bool meta_mem;
|
|
||||||
MouseButton last_button_state = MouseButton::NONE;
|
|
||||||
|
|
||||||
CursorShape cursor_shape;
|
|
||||||
|
|
||||||
InputDefault *input = nullptr;
|
|
||||||
|
|
||||||
JoypadUWP ^ joypad;
|
|
||||||
|
|
||||||
Windows::System::Display::DisplayRequest ^ display_request;
|
|
||||||
|
|
||||||
ref class ManagedType {
|
|
||||||
public:
|
|
||||||
property bool alert_close_handle;
|
|
||||||
property Platform::String ^ clipboard;
|
|
||||||
void alert_close(Windows::UI::Popups::IUICommand ^ command);
|
|
||||||
void on_clipboard_changed(Platform::Object ^ sender, Platform::Object ^ ev);
|
|
||||||
void update_clipboard();
|
|
||||||
void on_accelerometer_reading_changed(Windows::Devices::Sensors::Accelerometer ^ sender, Windows::Devices::Sensors::AccelerometerReadingChangedEventArgs ^ args);
|
|
||||||
void on_magnetometer_reading_changed(Windows::Devices::Sensors::Magnetometer ^ sender, Windows::Devices::Sensors::MagnetometerReadingChangedEventArgs ^ args);
|
|
||||||
void on_gyroscope_reading_changed(Windows::Devices::Sensors::Gyrometer ^ sender, Windows::Devices::Sensors::GyrometerReadingChangedEventArgs ^ args);
|
|
||||||
|
|
||||||
/** clang-format breaks this, it does not understand this token. */
|
|
||||||
/* clang-format off */
|
|
||||||
internal:
|
|
||||||
ManagedType() { alert_close_handle = false; }
|
|
||||||
property OS_UWP* os;
|
|
||||||
/* clang-format on */
|
|
||||||
};
|
|
||||||
ManagedType ^ managed_object;
|
|
||||||
Windows::Devices::Sensors::Accelerometer ^ accelerometer;
|
|
||||||
Windows::Devices::Sensors::Magnetometer ^ magnetometer;
|
|
||||||
Windows::Devices::Sensors::Gyrometer ^ gyrometer;
|
|
||||||
|
|
||||||
// functions used by main to initialize/deinitialize the OS
|
|
||||||
protected:
|
|
||||||
virtual int get_video_driver_count() const;
|
|
||||||
virtual int get_current_video_driver() const;
|
|
||||||
|
|
||||||
virtual void initialize_core();
|
|
||||||
virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
|
|
||||||
|
|
||||||
virtual void set_main_loop(MainLoop *p_main_loop);
|
|
||||||
virtual void delete_main_loop();
|
|
||||||
|
|
||||||
virtual void finalize();
|
|
||||||
virtual void finalize_core();
|
|
||||||
|
|
||||||
void process_events();
|
|
||||||
|
|
||||||
void process_key_events();
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Event to send to the app wrapper
|
|
||||||
HANDLE mouse_mode_changed;
|
|
||||||
|
|
||||||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
|
|
||||||
String get_stdin_string();
|
|
||||||
|
|
||||||
void set_mouse_mode(MouseMode p_mode);
|
|
||||||
MouseMode get_mouse_mode() const;
|
|
||||||
|
|
||||||
virtual Point2 get_mouse_position() const;
|
|
||||||
virtual MouseButton get_mouse_button_state() const;
|
|
||||||
virtual void set_window_title(const String &p_title);
|
|
||||||
|
|
||||||
virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0);
|
|
||||||
virtual VideoMode get_video_mode(int p_screen = 0) const;
|
|
||||||
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
|
|
||||||
virtual Size2 get_window_size() const;
|
|
||||||
virtual void set_window_size(const Size2 p_size);
|
|
||||||
virtual void set_window_fullscreen(bool p_enabled);
|
|
||||||
virtual bool is_window_fullscreen() const;
|
|
||||||
virtual void set_keep_screen_on(bool p_enabled);
|
|
||||||
|
|
||||||
virtual MainLoop *get_main_loop() const;
|
|
||||||
|
|
||||||
virtual String get_name() const;
|
|
||||||
virtual String get_distribution_name() const;
|
|
||||||
virtual String get_version() const;
|
|
||||||
|
|
||||||
virtual DateTime get_datetime(bool p_utc) const;
|
|
||||||
virtual TimeZoneInfo get_time_zone_info() const;
|
|
||||||
virtual uint64_t get_unix_time() const;
|
|
||||||
|
|
||||||
virtual Error set_cwd(const String &p_cwd);
|
|
||||||
|
|
||||||
virtual void delay_usec(uint32_t p_usec) const;
|
|
||||||
virtual uint64_t get_ticks_usec() const;
|
|
||||||
|
|
||||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false);
|
|
||||||
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false);
|
|
||||||
virtual Error kill(const ProcessID &p_pid);
|
|
||||||
virtual bool is_process_running(const ProcessID &p_pid) const;
|
|
||||||
|
|
||||||
virtual bool has_environment(const String &p_var) const;
|
|
||||||
virtual String get_environment(const String &p_var) const;
|
|
||||||
virtual bool set_environment(const String &p_var, const String &p_value) const;
|
|
||||||
|
|
||||||
virtual void set_clipboard(const String &p_text);
|
|
||||||
virtual String get_clipboard() const;
|
|
||||||
|
|
||||||
void set_cursor_shape(CursorShape p_shape);
|
|
||||||
CursorShape get_cursor_shape() const;
|
|
||||||
virtual void set_custom_mouse_cursor(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
|
||||||
void set_icon(const Ref<Image> &p_icon);
|
|
||||||
|
|
||||||
virtual String get_executable_path() const;
|
|
||||||
|
|
||||||
virtual String get_locale() const;
|
|
||||||
|
|
||||||
virtual void move_window_to_foreground();
|
|
||||||
virtual String get_user_data_dir() const;
|
|
||||||
|
|
||||||
virtual bool _check_internal_feature_support(const String &p_feature);
|
|
||||||
|
|
||||||
void set_window(Windows::UI::Core::CoreWindow ^ p_window);
|
|
||||||
void screen_size_changed();
|
|
||||||
|
|
||||||
virtual void release_rendering_thread();
|
|
||||||
virtual void make_rendering_thread();
|
|
||||||
virtual void swap_buffers();
|
|
||||||
|
|
||||||
virtual bool has_touchscreen_ui_hint() const;
|
|
||||||
|
|
||||||
virtual bool has_virtual_keyboard() const;
|
|
||||||
virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
|
|
||||||
virtual void hide_virtual_keyboard();
|
|
||||||
|
|
||||||
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr);
|
|
||||||
virtual Error close_dynamic_library(void *p_library_handle);
|
|
||||||
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false);
|
|
||||||
|
|
||||||
virtual Error shell_open(String p_uri);
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
virtual bool get_swap_cancel_ok() { return true; }
|
|
||||||
|
|
||||||
void input_event(const Ref<InputEvent> &p_event);
|
|
||||||
|
|
||||||
void queue_key_event(KeyEvent &p_event);
|
|
||||||
|
|
||||||
OS_UWP();
|
|
||||||
~OS_UWP();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // OS_UWP_H
|
|
|
@ -1,31 +0,0 @@
|
||||||
/**************************************************************************/
|
|
||||||
/* platform_config.h */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* This file is part of: */
|
|
||||||
/* GODOT ENGINE */
|
|
||||||
/* https://godotengine.org */
|
|
||||||
/**************************************************************************/
|
|
||||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
||||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
||||||
/* */
|
|
||||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
||||||
/* a copy of this software and associated documentation files (the */
|
|
||||||
/* "Software"), to deal in the Software without restriction, including */
|
|
||||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
||||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
||||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
||||||
/* the following conditions: */
|
|
||||||
/* */
|
|
||||||
/* The above copyright notice and this permission notice shall be */
|
|
||||||
/* included in all copies or substantial portions of the Software. */
|
|
||||||
/* */
|
|
||||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
||||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
||||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
||||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
||||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
||||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include <malloc.h>
|
|
|
@ -81,12 +81,9 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef UWP_ENABLED
|
|
||||||
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
if (!hCon || hCon == INVALID_HANDLE_VALUE) {
|
if (!hCon || hCon == INVALID_HANDLE_VALUE) {
|
||||||
#endif
|
|
||||||
StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
|
StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
|
||||||
#ifndef UWP_ENABLED
|
|
||||||
} else {
|
} else {
|
||||||
CONSOLE_SCREEN_BUFFER_INFO sbi; //original
|
CONSOLE_SCREEN_BUFFER_INFO sbi; //original
|
||||||
GetConsoleScreenBufferInfo(hCon, &sbi);
|
GetConsoleScreenBufferInfo(hCon, &sbi);
|
||||||
|
@ -159,7 +156,6 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
|
||||||
|
|
||||||
SetConsoleTextAttribute(hCon, sbi.wAttributes);
|
SetConsoleTextAttribute(hCon, sbi.wAttributes);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowsTerminalLogger::~WindowsTerminalLogger() {}
|
WindowsTerminalLogger::~WindowsTerminalLogger() {}
|
||||||
|
|
|
@ -288,7 +288,6 @@ def generate_scu_files(verbose, max_includes_per_scu):
|
||||||
process_folder(["platform/ios/export"])
|
process_folder(["platform/ios/export"])
|
||||||
process_folder(["platform/linuxbsd/export"])
|
process_folder(["platform/linuxbsd/export"])
|
||||||
process_folder(["platform/macos/export"])
|
process_folder(["platform/macos/export"])
|
||||||
process_folder(["platform/uwp/export"])
|
|
||||||
process_folder(["platform/web/export"])
|
process_folder(["platform/web/export"])
|
||||||
process_folder(["platform/windows/export"])
|
process_folder(["platform/windows/export"])
|
||||||
|
|
||||||
|
|
|
@ -439,9 +439,7 @@ File extracted from upstream release tarball:
|
||||||
- All `*.h` from `include/mbedtls/` to `thirdparty/mbedtls/include/mbedtls/` except `config_psa.h` and `psa_util.h`.
|
- All `*.h` from `include/mbedtls/` to `thirdparty/mbedtls/include/mbedtls/` except `config_psa.h` and `psa_util.h`.
|
||||||
- All `*.c` and `*.h` from `library/` to `thirdparty/mbedtls/library/` except those starting with `psa_*`.
|
- All `*.c` and `*.h` from `library/` to `thirdparty/mbedtls/library/` except those starting with `psa_*`.
|
||||||
- The `LICENSE` file.
|
- The `LICENSE` file.
|
||||||
- Applied the patch in `patches/1453.diff` to fix UWP build (upstream PR:
|
- Applied the patch in `patches/windows-arm64-hardclock.diff`.
|
||||||
https://github.com/ARMmbed/mbedtls/pull/1453).
|
|
||||||
Applied the patch in `patches/windows-arm64-hardclock.diff`.
|
|
||||||
Applied the patch in `aesni-no-arm-intrinsics.patch` to fix MSVC ARM build.
|
Applied the patch in `aesni-no-arm-intrinsics.patch` to fix MSVC ARM build.
|
||||||
- Added 2 files `godot_core_mbedtls_platform.c` and `godot_core_mbedtls_config.h`
|
- Added 2 files `godot_core_mbedtls_platform.c` and `godot_core_mbedtls_config.h`
|
||||||
providing configuration for light bundling with core.
|
providing configuration for light bundling with core.
|
||||||
|
|
|
@ -55,41 +55,26 @@
|
||||||
#define _WIN32_WINNT 0x0400
|
#define _WIN32_WINNT 0x0400
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <bcrypt.h>
|
#include <wincrypt.h>
|
||||||
#if defined(_MSC_VER) && _MSC_VER <= 1600
|
|
||||||
/* Visual Studio 2010 and earlier issue a warning when both <stdint.h> and
|
|
||||||
* <intsafe.h> are included, as they redefine a number of <TYPE>_MAX constants.
|
|
||||||
* These constants are guaranteed to be the same, though, so we suppress the
|
|
||||||
* warning when including intsafe.h.
|
|
||||||
*/
|
|
||||||
#pragma warning( push )
|
|
||||||
#pragma warning( disable : 4005 )
|
|
||||||
#endif
|
|
||||||
#include <intsafe.h>
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER <= 1600
|
|
||||||
#pragma warning( pop )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,
|
int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,
|
||||||
size_t *olen)
|
size_t *olen)
|
||||||
{
|
{
|
||||||
ULONG len_as_ulong = 0;
|
HCRYPTPROV provider;
|
||||||
((void) data);
|
((void) data);
|
||||||
*olen = 0;
|
*olen = 0;
|
||||||
|
|
||||||
/*
|
if (CryptAcquireContext(&provider, NULL, NULL,
|
||||||
* BCryptGenRandom takes ULONG for size, which is smaller than size_t on
|
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) {
|
||||||
* 64-bit Windows platforms. Ensure len's value can be safely converted into
|
|
||||||
* a ULONG.
|
|
||||||
*/
|
|
||||||
if (FAILED(SizeTToULong(len, &len_as_ulong))) {
|
|
||||||
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, len_as_ulong, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
|
if (CryptGenRandom(provider, (DWORD) len, output) == FALSE) {
|
||||||
|
CryptReleaseContext(provider, 0);
|
||||||
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CryptReleaseContext(provider, 0);
|
||||||
*olen = len;
|
*olen = len;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
diff --git a/thirdparty/mbedtls/library/entropy_poll.c b/thirdparty/mbedtls/library/entropy_poll.c
|
|
||||||
index 3420616a06..57fddd4d62 100644
|
|
||||||
--- a/thirdparty/mbedtls/library/entropy_poll.c
|
|
||||||
+++ b/thirdparty/mbedtls/library/entropy_poll.c
|
|
||||||
@@ -55,26 +55,41 @@
|
|
||||||
#define _WIN32_WINNT 0x0400
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
-#include <wincrypt.h>
|
|
||||||
+#include <bcrypt.h>
|
|
||||||
+#if defined(_MSC_VER) && _MSC_VER <= 1600
|
|
||||||
+/* Visual Studio 2010 and earlier issue a warning when both <stdint.h> and
|
|
||||||
+ * <intsafe.h> are included, as they redefine a number of <TYPE>_MAX constants.
|
|
||||||
+ * These constants are guaranteed to be the same, though, so we suppress the
|
|
||||||
+ * warning when including intsafe.h.
|
|
||||||
+ */
|
|
||||||
+#pragma warning( push )
|
|
||||||
+#pragma warning( disable : 4005 )
|
|
||||||
+#endif
|
|
||||||
+#include <intsafe.h>
|
|
||||||
+#if defined(_MSC_VER) && _MSC_VER <= 1600
|
|
||||||
+#pragma warning( pop )
|
|
||||||
+#endif
|
|
||||||
|
|
||||||
int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,
|
|
||||||
size_t *olen)
|
|
||||||
{
|
|
||||||
- HCRYPTPROV provider;
|
|
||||||
+ ULONG len_as_ulong = 0;
|
|
||||||
((void) data);
|
|
||||||
*olen = 0;
|
|
||||||
|
|
||||||
- if (CryptAcquireContext(&provider, NULL, NULL,
|
|
||||||
- PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) {
|
|
||||||
+ /*
|
|
||||||
+ * BCryptGenRandom takes ULONG for size, which is smaller than size_t on
|
|
||||||
+ * 64-bit Windows platforms. Ensure len's value can be safely converted into
|
|
||||||
+ * a ULONG.
|
|
||||||
+ */
|
|
||||||
+ if (FAILED(SizeTToULong(len, &len_as_ulong))) {
|
|
||||||
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (CryptGenRandom(provider, (DWORD) len, output) == FALSE) {
|
|
||||||
- CryptReleaseContext(provider, 0);
|
|
||||||
+ if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, len_as_ulong, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
|
|
||||||
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
- CryptReleaseContext(provider, 0);
|
|
||||||
*olen = len;
|
|
||||||
|
|
||||||
return 0;
|
|