summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub1
-rw-r--r--core/debugger/engine_debugger.cpp44
-rw-r--r--core/debugger/engine_debugger.h7
-rw-r--r--core/debugger/remote_debugger.cpp10
-rw-r--r--core/debugger/remote_debugger.h2
-rw-r--r--core/debugger/remote_debugger_peer.cpp14
-rw-r--r--core/debugger/remote_debugger_peer.h4
-rw-r--r--core/error_macros.h36
-rw-r--r--core/global_constants.cpp133
-rw-r--r--core/image.cpp4
-rw-r--r--core/image.h2
-rw-r--r--core/input/godotcontrollerdb.txt3
-rw-r--r--core/input/input.cpp492
-rw-r--r--core/input/input.h57
-rw-r--r--core/input/input_builders.py13
-rw-r--r--core/input/input_event.h170
-rw-r--r--core/io/resource_format_binary.cpp24
-rw-r--r--core/io/resource_format_binary.h2
-rw-r--r--core/io/resource_importer.cpp2
-rw-r--r--core/local_vector.h246
-rw-r--r--core/math/basis.cpp111
-rw-r--r--core/math/basis.h1
-rw-r--r--core/math/camera_matrix.cpp16
-rw-r--r--core/math/camera_matrix.h1
-rw-r--r--core/math/delaunay_2d.h (renamed from core/math/delaunay.h)10
-rw-r--r--core/math/delaunay_3d.h387
-rw-r--r--core/math/geometry.cpp195
-rw-r--r--core/math/geometry.h246
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h1
-rw-r--r--core/project_settings.cpp14
-rw-r--r--core/register_core_types.cpp4
-rw-r--r--core/ustring.cpp16
-rw-r--r--core/ustring.h2
-rw-r--r--core/vector.h8
35 files changed, 1841 insertions, 441 deletions
diff --git a/core/SCsub b/core/SCsub
index 0ab4f11d87..d53988fae7 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -49,6 +49,7 @@ thirdparty_misc_dir = "#thirdparty/misc/"
thirdparty_misc_sources = [
# C sources
"fastlz.c",
+ "r128.c",
"smaz.c",
# C++ sources
"hq2x.cpp",
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index bfe38d0f4a..04eba84b30 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -32,6 +32,7 @@
#include "core/debugger/local_debugger.h"
#include "core/debugger/remote_debugger.h"
+#include "core/debugger/remote_debugger_peer.h"
#include "core/debugger/script_debugger.h"
#include "core/os/os.h"
@@ -40,6 +41,7 @@ ScriptDebugger *EngineDebugger::script_debugger = nullptr;
Map<StringName, EngineDebugger::Profiler> EngineDebugger::profilers;
Map<StringName, EngineDebugger::Capture> EngineDebugger::captures;
+Map<String, EngineDebugger::CreatePeerFunc> EngineDebugger::protocols;
void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) {
ERR_FAIL_COND_MSG(profilers.has(p_name), "Profiler already registered: " + p_name);
@@ -66,6 +68,11 @@ void EngineDebugger::unregister_message_capture(const StringName &p_name) {
captures.erase(p_name);
}
+void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) {
+ ERR_FAIL_COND_MSG(protocols.has(p_protocol), "Protocol handler already registered: " + p_protocol);
+ protocols.insert(p_protocol, p_func);
+}
+
void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't change profiler state, no profiler: " + p_name);
Profiler &p = profilers[p_name];
@@ -125,6 +132,7 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, ui
}
void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Vector<String> p_breakpoints) {
+ register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
if (p_uri.empty())
return;
if (p_uri == "local://") {
@@ -132,10 +140,14 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve
script_debugger = memnew(ScriptDebugger);
// Tell the OS that we want to handle termination signals.
OS::get_singleton()->initialize_debugging();
- } else {
- singleton = RemoteDebugger::create_for_uri(p_uri);
- if (!singleton)
+ } else if (p_uri.find("://") >= 0) {
+ const String proto = p_uri.substr(0, p_uri.find("://") + 3);
+ if (!protocols.has(proto))
+ return;
+ RemoteDebuggerPeer *peer = protocols[proto](p_uri);
+ if (!peer)
return;
+ singleton = memnew(RemoteDebugger(Ref<RemoteDebuggerPeer>(peer)));
script_debugger = memnew(ScriptDebugger);
// Notify editor of our pid (to allow focus stealing).
Array msg;
@@ -160,22 +172,24 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Ve
}
void EngineDebugger::deinitialize() {
- if (!singleton)
- return;
-
- // Stop all profilers
- for (Map<StringName, Profiler>::Element *E = profilers.front(); E; E = E->next()) {
- if (E->get().active)
- singleton->profiler_enable(E->key(), false);
+ if (singleton) {
+ // Stop all profilers
+ for (Map<StringName, Profiler>::Element *E = profilers.front(); E; E = E->next()) {
+ if (E->get().active)
+ singleton->profiler_enable(E->key(), false);
+ }
+
+ // Flush any remaining message
+ singleton->poll_events(false);
+
+ memdelete(singleton);
+ singleton = nullptr;
}
- // Flush any remaining message
- singleton->poll_events(false);
-
- memdelete(singleton);
- singleton = nullptr;
+ // Clear profilers/captuers/protocol handlers.
profilers.clear();
captures.clear();
+ protocols.clear();
}
EngineDebugger::~EngineDebugger() {
diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h
index 7b6b77ca9b..8d5ebb2394 100644
--- a/core/debugger/engine_debugger.h
+++ b/core/debugger/engine_debugger.h
@@ -38,6 +38,7 @@
#include "core/variant.h"
#include "core/vector.h"
+class RemoteDebuggerPeer;
class ScriptDebugger;
class EngineDebugger {
@@ -45,8 +46,11 @@ public:
typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts);
typedef void (*ProfilingTick)(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time);
typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr);
+
typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured);
+ typedef RemoteDebuggerPeer *(*CreatePeerFunc)(const String &p_uri);
+
class Profiler {
friend class EngineDebugger;
@@ -94,6 +98,7 @@ protected:
static Map<StringName, Profiler> profilers;
static Map<StringName, Capture> captures;
+ static Map<String, CreatePeerFunc> protocols;
public:
_FORCE_INLINE_ static EngineDebugger *get_singleton() { return singleton; }
@@ -113,6 +118,8 @@ public:
static void unregister_message_capture(const StringName &p_name);
static bool has_capture(const StringName &p_name);
+ static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func);
+
void iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, uint64_t p_physics_ticks, float p_physics_frame_time);
void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured);
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 97d5c71b6f..18c9602eb2 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -673,6 +673,9 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
ERR_FAIL_COND_MSG(!is_peer_connected(), "Script Debugger failed to connect, but being used anyway.");
+ if (!peer->can_block())
+ return; // Peer does not support blocking IO. We could at least send the error though.
+
ScriptLanguage *script_lang = script_debugger->get_break_language();
const String error_str = script_lang ? script_lang->debug_get_error() : "";
Array msg;
@@ -886,13 +889,6 @@ Error RemoteDebugger::_profiler_capture(const String &p_cmd, const Array &p_data
return OK;
}
-RemoteDebugger *RemoteDebugger::create_for_uri(const String &p_uri) {
- Ref<RemoteDebuggerPeer> peer = RemoteDebuggerPeer::create_from_uri(p_uri);
- if (peer.is_valid())
- return memnew(RemoteDebugger(peer));
- return nullptr;
-}
-
RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
peer = p_peer;
max_chars_per_second = GLOBAL_GET("network/limits/debugger/max_chars_per_second");
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index cac0bc3730..dc7e4436e1 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -108,8 +108,6 @@ private:
Error _try_capture(const String &p_name, const Array &p_data, bool &r_captured);
public:
- static RemoteDebugger *create_for_uri(const String &p_uri);
-
// Overrides
void poll_events(bool p_is_idle);
void send_message(const String &p_message, const Array &p_args);
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index ed04431177..458c46df93 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -218,9 +218,8 @@ void RemoteDebuggerPeerTCP::_poll() {
}
}
-Ref<RemoteDebuggerPeer> RemoteDebuggerPeer::create_from_uri(const String p_uri) {
- if (!p_uri.begins_with("tcp://"))
- return Ref<RemoteDebuggerPeer>(); // Only TCP supported for now, more to come.
+RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
+ ERR_FAIL_COND_V(!p_uri.begins_with("tcp://"), nullptr);
String debug_host = p_uri.replace("tcp://", "");
uint16_t debug_port = 6007;
@@ -230,10 +229,13 @@ Ref<RemoteDebuggerPeer> RemoteDebuggerPeer::create_from_uri(const String p_uri)
debug_port = debug_host.substr(sep_pos + 1).to_int();
debug_host = debug_host.substr(0, sep_pos);
}
- Ref<RemoteDebuggerPeerTCP> peer = Ref<RemoteDebuggerPeer>(memnew(RemoteDebuggerPeerTCP));
+
+ RemoteDebuggerPeerTCP *peer = memnew(RemoteDebuggerPeerTCP);
Error err = peer->connect_to_host(debug_host, debug_port);
- if (err != OK)
- return Ref<RemoteDebuggerPeer>();
+ if (err != OK) {
+ memdelete(peer);
+ return nullptr;
+ }
return peer;
}
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index e4b838f145..3a75a2a02b 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -42,7 +42,6 @@ protected:
int max_queued_messages = 4096;
public:
- static Ref<RemoteDebuggerPeer> create_from_uri(const String p_uri);
virtual bool is_peer_connected() = 0;
virtual bool has_message() = 0;
virtual Error put_message(const Array &p_arr) = 0;
@@ -50,6 +49,7 @@ public:
virtual void close() = 0;
virtual void poll() = 0;
virtual int get_max_message_size() const = 0;
+ virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug).
RemoteDebuggerPeer();
};
@@ -77,6 +77,8 @@ private:
void _read_in();
public:
+ static RemoteDebuggerPeer *create(const String &p_uri);
+
Error connect_to_host(const String &p_host, uint16_t p_port);
void poll();
diff --git a/core/error_macros.h b/core/error_macros.h
index 18c46c9e7d..83f92129a5 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -530,19 +530,19 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* Prints `m_msg`.
*/
#define ERR_PRINT(m_msg) \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg))
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
/**
* Prints `m_msg` once during the application lifetime.
*/
-#define ERR_PRINT_ONCE(m_msg) \
- if (1) { \
- static bool first_print = true; \
- if (first_print) { \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg)); \
- first_print = false; \
- } \
- } else \
+#define ERR_PRINT_ONCE(m_msg) \
+ if (1) { \
+ static bool first_print = true; \
+ if (first_print) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg); \
+ first_print = false; \
+ } \
+ } else \
((void)0)
// Print warning message macros.
@@ -553,21 +553,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
#define WARN_PRINT(m_msg) \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg), ERR_HANDLER_WARNING)
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ERR_HANDLER_WARNING)
/**
* Prints `m_msg` once during the application lifetime.
*
* If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
*/
-#define WARN_PRINT_ONCE(m_msg) \
- if (1) { \
- static bool first_print = true; \
- if (first_print) { \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \
- first_print = false; \
- } \
- } else \
+#define WARN_PRINT_ONCE(m_msg) \
+ if (1) { \
+ static bool first_print = true; \
+ if (first_print) { \
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ERR_HANDLER_WARNING); \
+ first_print = false; \
+ } \
+ } else \
((void)0)
// Print deprecated warning message macros.
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index afcb283e05..4f415a2056 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -88,7 +88,8 @@ static Vector<_GlobalConstant> _global_constants;
VARIANT_ENUM_CAST(KeyList);
VARIANT_ENUM_CAST(KeyModifierMask);
VARIANT_ENUM_CAST(ButtonList);
-VARIANT_ENUM_CAST(JoystickList);
+VARIANT_ENUM_CAST(JoyButtonList);
+VARIANT_ENUM_CAST(JoyAxisList);
VARIANT_ENUM_CAST(MidiMessageList);
void register_global_constants() {
@@ -388,90 +389,70 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
BIND_GLOBAL_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
- //joypads
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_0);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_1);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_2);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_3);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_4);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_5);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_6);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_7);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_8);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_9);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_10);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_11);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_12);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_13);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_14);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_15);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_MAX);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_CIRCLE);
+ // Joypad buttons
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_INVALID_BUTTON);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_A);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_B);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_BACK);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_GUIDE);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_START);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_LEFT_STICK);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_RIGHT_STICK);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_LEFT_SHOULDER);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_RIGHT_SHOULDER);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_UP);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_DOWN);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_LEFT);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_DPAD_RIGHT);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SDL_BUTTONS);
BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_CROSS);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_CIRCLE);
BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_SQUARE);
BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_TRIANGLE);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_B);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_SELECT);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_START);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_PS);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_L1);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_R1);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_L3);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SONY_R3);
BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_A);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_B);
BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_X);
BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_BACK);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_START);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_HOME);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_LS);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_RS);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_LB);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_XBOX_RB);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_BUTTON_MAX);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DS_A);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DS_B);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DS_X);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DS_Y);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_VR_GRIP);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_VR_PAD);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_VR_TRIGGER);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_OCULUS_AX);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_OCULUS_BY);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_OCULUS_MENU);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_OPENVR_MENU);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_SELECT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_START);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DPAD_UP);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DPAD_DOWN);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DPAD_LEFT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_DPAD_RIGHT);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_L);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_L2);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_L3);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_R);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_R2);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_R3);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_0);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_1);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_2);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_3);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_4);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_5);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_6);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_7);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_8);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_9);
+ // Joypad axes
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_INVALID_AXIS);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_LEFT_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_LEFT_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_RIGHT_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_RIGHT_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_TRIGGER_LEFT);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_TRIGGER_RIGHT);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_SDL_AXES);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_0_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_0_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_1_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_1_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_2_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_2_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_3_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_3_Y);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_4_X);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_4_Y);
BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_MAX);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_LX);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_LY);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_RX);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_RY);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_L2);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_R2);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_VR_ANALOG_TRIGGER);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_VR_ANALOG_GRIP);
-
- BIND_GLOBAL_ENUM_CONSTANT(JOY_OPENVR_TOUCHPADX);
- BIND_GLOBAL_ENUM_CONSTANT(JOY_OPENVR_TOUCHPADY);
-
// midi
BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_OFF);
BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_ON);
diff --git a/core/image.cpp b/core/image.cpp
index 6f18516ae1..ff8acc54af 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -3668,6 +3668,10 @@ Ref<Resource> Image::duplicate(bool p_subresources) const {
return copy;
}
+void Image::set_as_black() {
+ zeromem(data.ptrw(), data.size());
+}
+
Image::Image() {
width = 0;
diff --git a/core/image.h b/core/image.h
index 5bd73fa677..07b4f49751 100644
--- a/core/image.h
+++ b/core/image.h
@@ -376,6 +376,8 @@ public:
void set_pixelv(const Point2 &p_dst, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);
+ void set_as_black();
+
void copy_internals_from(const Ref<Image> &p_image) {
ERR_FAIL_COND_MSG(p_image.is_null(), "It's not a reference to a valid Image object.");
format = p_image->format;
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index adc3649d64..51ddda1e4e 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -4,6 +4,9 @@
# Windows
__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Windows,
+# Android
+Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
+
# Javascript
Default HTML5 Gamepad, Default Mapping,leftx:a0,lefty:a1,dpdown:b13,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:b14,lefttrigger:a6,x:b2,dpup:b12,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:b15,righttrigger:a7,b:b1,platform:Javascript,
c2a94d6963726f736f66742058626f78,Wireless X360 Controller,leftx:a0,lefty:a1,dpdown:b14,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:b11,lefttrigger:a2,x:b2,dpup:b13,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:b12,righttrigger:a5,b:b1,platform:Javascript,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 357e4c06c1..91ff676211 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -39,6 +39,87 @@
#include "editor/editor_settings.h"
#endif
+static const char *_joy_buttons[JOY_SDL_BUTTONS + 1] = {
+ "a",
+ "b",
+ "x",
+ "y",
+ "back",
+ "guide",
+ "start",
+ "leftstick",
+ "rightstick",
+ "leftshoulder",
+ "rightshoulder",
+ "dpup",
+ "dpdown",
+ "dpleft",
+ "dpright",
+ nullptr
+};
+
+static const char *_joy_button_names[JOY_BUTTON_MAX] = {
+ "Face Bottom",
+ "Face Right",
+ "Face Left",
+ "Face Top",
+ "Select",
+ "Guide",
+ "Start",
+ "Left Stick",
+ "Right Stick",
+ "Left Shoulder",
+ "Right Shoulder",
+ "D-Pad Up",
+ "D-Pad Down",
+ "D-Pad Left",
+ "D-Pad Right",
+ "Button 15",
+ "Button 16",
+ "Button 17",
+ "Button 18",
+ "Button 19",
+ "Button 20",
+ "Button 21",
+ "Button 22",
+ "Button 23",
+ "Button 24",
+ "Button 25",
+ "Button 26",
+ "Button 27",
+ "Button 28",
+ "Button 29",
+ "Button 30",
+ "Button 31",
+ "Button 32",
+ "Button 33",
+ "Button 34",
+ "Button 35"
+};
+
+static const char *_joy_axes[JOY_SDL_AXES + 1] = {
+ "leftx",
+ "lefty",
+ "rightx",
+ "righty",
+ "lefttrigger",
+ "righttrigger",
+ nullptr
+};
+
+static const char *_joy_axis_names[JOY_AXIS_MAX] = {
+ "Left Stick X",
+ "Left Stick Y",
+ "Right Stick X",
+ "Right Stick Y",
+ "Left Trigger",
+ "Right Trigger",
+ "Joystick 3 Stick X",
+ "Joystick 3 Stick Y",
+ "Joystick 4 Stick X",
+ "Joystick 4 Stick Y"
+};
+
Input *Input::singleton = nullptr;
void (*Input::set_mouse_mode_func)(Input::MouseMode) = nullptr;
@@ -336,13 +417,12 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S
} else {
js.connected = false;
for (int i = 0; i < JOY_BUTTON_MAX; i++) {
-
- if (i < JOY_AXIS_MAX)
- set_joy_axis(p_idx, i, 0.0f);
-
int c = _combine_device(i, p_idx);
joy_buttons_pressed.erase(c);
- };
+ }
+ for (int i = 0; i < JOY_AXIS_MAX; i++) {
+ set_joy_axis(p_idx, i, 0.0f);
+ }
};
joy_names[p_idx] = js;
@@ -831,21 +911,9 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) {
return;
}
- const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].buttons.find(p_button);
- if (!el) {
- //don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis
- //return _button_event(p_last_id, p_device, p_button, p_pressed);
- return;
- }
+ JoyEvent map = _get_mapped_button_event(map_db[joy.mapping], p_button);
- JoyEvent map = el->get();
if (map.type == TYPE_BUTTON) {
- //fake additional axis event for triggers
- if (map.index == JOY_L2 || map.index == JOY_R2) {
- float value = p_pressed ? 1.0f : 0.0f;
- int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
- _axis_event(p_device, axis, value);
- }
_button_event(p_device, map.index, p_pressed);
return;
}
@@ -901,32 +969,20 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
return;
};
- const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].axis.find(p_axis);
- if (!el) {
- //return _axis_event(p_last_id, p_device, p_axis, p_value);
- return;
- };
-
- JoyEvent map = el->get();
+ JoyEvent map = _get_mapped_axis_event(map_db[joy.mapping], p_axis, p_value);
if (map.type == TYPE_BUTTON) {
- //send axis event for triggers
- if (map.index == JOY_L2 || map.index == JOY_R2) {
- float value = p_value.min == 0 ? p_value.value : 0.5f + p_value.value / 2.0f;
- int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
- _axis_event(p_device, axis, value);
- }
- if (map.index == JOY_DPAD_UP || map.index == JOY_DPAD_DOWN) {
+ if (map.index == JOY_BUTTON_DPAD_UP || map.index == JOY_BUTTON_DPAD_DOWN) {
bool pressed = p_value.value != 0.0f;
- int button = p_value.value < 0 ? JOY_DPAD_UP : JOY_DPAD_DOWN;
+ int button = p_value.value < 0 ? JOY_BUTTON_DPAD_UP : JOY_BUTTON_DPAD_DOWN;
if (!pressed) {
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_UP, p_device))) {
- _button_event(p_device, JOY_DPAD_UP, false);
+ if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_UP, p_device))) {
+ _button_event(p_device, JOY_BUTTON_DPAD_UP, false);
}
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_DOWN, p_device))) {
- _button_event(p_device, JOY_DPAD_DOWN, false);
+ if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_DOWN, p_device))) {
+ _button_event(p_device, JOY_BUTTON_DPAD_DOWN, false);
}
}
if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
@@ -935,16 +991,17 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
_button_event(p_device, button, true);
return;
}
- if (map.index == JOY_DPAD_LEFT || map.index == JOY_DPAD_RIGHT) {
+
+ if (map.index == JOY_BUTTON_DPAD_LEFT || map.index == JOY_BUTTON_DPAD_RIGHT) {
bool pressed = p_value.value != 0.0f;
- int button = p_value.value < 0 ? JOY_DPAD_LEFT : JOY_DPAD_RIGHT;
+ int button = p_value.value < 0 ? JOY_BUTTON_DPAD_LEFT : JOY_BUTTON_DPAD_RIGHT;
if (!pressed) {
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_LEFT, p_device))) {
- _button_event(p_device, JOY_DPAD_LEFT, false);
+ if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_LEFT, p_device))) {
+ _button_event(p_device, JOY_BUTTON_DPAD_LEFT, false);
}
- if (joy_buttons_pressed.has(_combine_device(JOY_DPAD_RIGHT, p_device))) {
- _button_event(p_device, JOY_DPAD_RIGHT, false);
+ if (joy_buttons_pressed.has(_combine_device(JOY_BUTTON_DPAD_RIGHT, p_device))) {
+ _button_event(p_device, JOY_BUTTON_DPAD_RIGHT, false);
}
}
if (pressed == joy_buttons_pressed.has(_combine_device(button, p_device))) {
@@ -953,19 +1010,21 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
_button_event(p_device, button, true);
return;
}
+
float deadzone = p_value.min == 0 ? 0.5f : 0.0f;
bool pressed = p_value.value > deadzone;
if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) {
// button already pressed or released, this is an axis bounce value
return;
}
+
_button_event(p_device, map.index, pressed);
return;
}
if (map.type == TYPE_AXIS) {
- _axis_event(p_device, map.index, val);
+ _axis_event(p_device, map.index, map.value);
return;
}
//printf("invalid mapping\n");
@@ -976,12 +1035,26 @@ void Input::joy_hat(int p_device, int p_val) {
_THREAD_SAFE_METHOD_;
const Joypad &joy = joy_names[p_device];
- const JoyEvent *map;
+ JoyEvent map[HAT_MAX];
- if (joy.mapping == -1) {
- map = hat_map_default;
- } else {
- map = map_db[joy.mapping].hat;
+ map[HAT_UP].type = TYPE_BUTTON;
+ map[HAT_UP].index = JOY_BUTTON_DPAD_UP;
+ map[HAT_UP].value = 0;
+
+ map[HAT_RIGHT].type = TYPE_BUTTON;
+ map[HAT_RIGHT].index = JOY_BUTTON_DPAD_RIGHT;
+ map[HAT_RIGHT].value = 0;
+
+ map[HAT_DOWN].type = TYPE_BUTTON;
+ map[HAT_DOWN].index = JOY_BUTTON_DPAD_DOWN;
+ map[HAT_DOWN].value = 0;
+
+ map[HAT_LEFT].type = TYPE_BUTTON;
+ map[HAT_LEFT].index = JOY_BUTTON_DPAD_LEFT;
+ map[HAT_LEFT].value = 0;
+
+ if (joy.mapping != -1) {
+ _get_mapped_hat_events(map_db[joy.mapping], 0, map);
};
int cur_val = joy_names[p_device].hat_current;
@@ -1025,50 +1098,149 @@ void Input::_axis_event(int p_device, int p_axis, float p_value) {
parse_input_event(ievent);
};
-Input::JoyEvent Input::_find_to_event(String p_to) {
+Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button) {
+
+ JoyEvent event;
+ event.type = TYPE_MAX;
+
+ for (int i = 0; i < mapping.bindings.size(); i++) {
+ const JoyBinding binding = mapping.bindings[i];
+ if (binding.inputType == TYPE_BUTTON && binding.input.button == p_button) {
+ event.type = binding.outputType;
+ switch (binding.outputType) {
+ case TYPE_BUTTON:
+ event.index = binding.output.button;
+ return event;
+ case TYPE_AXIS:
+ event.index = binding.output.axis.axis;
+ return event;
+ default:
+ ERR_PRINT_ONCE("Joypad button mapping error.");
+ }
+ }
+ }
+ return event;
+}
+
+Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, const JoyAxis &p_value) {
+
+ JoyEvent event;
+ event.type = TYPE_MAX;
+
+ for (int i = 0; i < mapping.bindings.size(); i++) {
+ const JoyBinding binding = mapping.bindings[i];
+ if (binding.inputType == TYPE_AXIS && binding.input.axis.axis == p_axis) {
+ float value = p_value.value;
+ if (binding.input.axis.invert)
+ value = -value;
+ if (binding.input.axis.range == FULL_AXIS ||
+ (binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) ||
+ (binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) {
+ event.type = binding.outputType;
+ switch (binding.outputType) {
+ case TYPE_BUTTON:
+ event.index = binding.output.button;
+ return event;
+ case TYPE_AXIS:
+ event.index = binding.output.axis.axis;
+ event.value = value;
+ if (binding.output.axis.range != binding.input.axis.range) {
+ float shifted_positive_value = 0;
+ switch (binding.input.axis.range) {
+ case POSITIVE_HALF_AXIS:
+ shifted_positive_value = value;
+ break;
+ case NEGATIVE_HALF_AXIS:
+ shifted_positive_value = value + 1;
+ break;
+ case FULL_AXIS:
+ shifted_positive_value = (value + 1) / 2;
+ break;
+ }
+ switch (binding.output.axis.range) {
+ case POSITIVE_HALF_AXIS:
+ event.value = shifted_positive_value;
+ break;
+ case NEGATIVE_HALF_AXIS:
+ event.value = shifted_positive_value - 1;
+ break;
+ case FULL_AXIS:
+ event.value = (shifted_positive_value * 2) - 1;
+ break;
+ }
+ }
+ return event;
+ default:
+ ERR_PRINT_ONCE("Joypad axis mapping error.");
+ }
+ }
+ }
+ }
+ return event;
+}
- // string names of the SDL buttons in the same order as input_event.h godot buttons
- static const char *buttons[] = { "a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", nullptr };
+void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[]) {
- static const char *axis[] = { "leftx", "lefty", "rightx", "righty", nullptr };
+ for (int i = 0; i < mapping.bindings.size(); i++) {
+ const JoyBinding binding = mapping.bindings[i];
+ if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) {
- JoyEvent ret;
- ret.type = -1;
- ret.index = 0;
+ int index;
+ switch (binding.input.hat.hat_mask) {
+ case HAT_MASK_UP:
+ index = 0;
+ break;
+ case HAT_MASK_RIGHT:
+ index = 1;
+ break;
+ case HAT_MASK_DOWN:
+ index = 2;
+ break;
+ case HAT_MASK_LEFT:
+ index = 3;
+ break;
+ default:
+ ERR_PRINT_ONCE("Joypad button mapping error.");
+ continue;
+ }
- int i = 0;
- while (buttons[i]) {
+ r_events[index].type = binding.outputType;
+ switch (binding.outputType) {
+ case TYPE_BUTTON:
+ r_events[index].index = binding.output.button;
+ break;
+ case TYPE_AXIS:
+ r_events[index].index = binding.output.axis.axis;
+ break;
+ default:
+ ERR_PRINT_ONCE("Joypad button mapping error.");
+ }
+ }
+ }
+}
- if (p_to == buttons[i]) {
- ret.type = TYPE_BUTTON;
- ret.index = i;
- ret.value = 0;
- return ret;
- };
- ++i;
- };
+JoyButtonList Input::_get_output_button(String output) {
- i = 0;
- while (axis[i]) {
+ for (int i = 0; _joy_buttons[i]; i++) {
+ if (output == _joy_buttons[i])
+ return JoyButtonList(i);
+ }
+ return JoyButtonList::JOY_INVALID_BUTTON;
+}
- if (p_to == axis[i]) {
- ret.type = TYPE_AXIS;
- ret.index = i;
- ret.value = 0;
- return ret;
- };
- ++i;
- };
+JoyAxisList Input::_get_output_axis(String output) {
- return ret;
-};
+ for (int i = 0; _joy_axes[i]; i++) {
+ if (output == _joy_axes[i])
+ return JoyAxisList(i);
+ }
+ return JoyAxisList::JOY_INVALID_AXIS;
+}
void Input::parse_mapping(String p_mapping) {
_THREAD_SAFE_METHOD_;
JoyDeviceMapping mapping;
- for (int i = 0; i < HAT_MAX; ++i)
- mapping.hat[i].index = 1024 + i;
Vector<String> entry = p_mapping.split(",");
if (entry.size() < 2) {
@@ -1087,45 +1259,79 @@ void Input::parse_mapping(String p_mapping) {
if (entry[idx] == "")
continue;
- String from = entry[idx].get_slice(":", 1).replace(" ", "");
- String to = entry[idx].get_slice(":", 0).replace(" ", "");
+ String output = entry[idx].get_slice(":", 0).replace(" ", "");
+ String input = entry[idx].get_slice(":", 1).replace(" ", "");
+ ERR_CONTINUE_MSG(output.length() < 1 || input.length() < 2,
+ String(entry[idx] + "\nInvalid device mapping entry: " + entry[idx]));
- JoyEvent to_event = _find_to_event(to);
- if (to_event.type == -1)
+ if (output == "platform")
continue;
- String etype = from.substr(0, 1);
- if (etype == "a") {
-
- int aid = from.substr(1, from.length() - 1).to_int();
- mapping.axis[aid] = to_event;
-
- } else if (etype == "b") {
+ JoyAxisRange output_range = FULL_AXIS;
+ if (output[0] == '+' || output[0] == '-') {
+ ERR_CONTINUE_MSG(output.length() < 2, String(entry[idx] + "\nInvalid output: " + entry[idx]));
+ output = output.right(1);
+ if (output[0] == '+')
+ output_range = POSITIVE_HALF_AXIS;
+ else if (output[0] == '-')
+ output_range = NEGATIVE_HALF_AXIS;
+ }
- int bid = from.substr(1, from.length() - 1).to_int();
- mapping.buttons[bid] = to_event;
+ JoyAxisRange input_range = FULL_AXIS;
+ if (input[0] == '+') {
+ input_range = POSITIVE_HALF_AXIS;
+ input = input.right(1);
+ } else if (input[0] == '-') {
+ input_range = NEGATIVE_HALF_AXIS;
+ input = input.right(1);
+ }
+ bool invert_axis = false;
+ if (input[input.length() - 1] == '~')
+ invert_axis = true;
+
+ JoyButtonList output_button = _get_output_button(output);
+ JoyAxisList output_axis = _get_output_axis(output);
+ ERR_CONTINUE_MSG(output_button == JOY_INVALID_BUTTON && output_axis == JOY_INVALID_AXIS,
+ String(entry[idx] + "\nUnrecognised output string: " + output));
+ ERR_CONTINUE_MSG(output_button != JOY_INVALID_BUTTON && output_axis != JOY_INVALID_AXIS,
+ String("BUG: Output string matched both button and axis: " + output));
+
+ JoyBinding binding;
+ if (output_button != JOY_INVALID_BUTTON) {
+ binding.outputType = TYPE_BUTTON;
+ binding.output.button = output_button;
+ } else if (output_axis != JOY_INVALID_AXIS) {
+ binding.outputType = TYPE_AXIS;
+ binding.output.axis.axis = output_axis;
+ binding.output.axis.range = output_range;
+ }
- } else if (etype == "h") {
+ switch (input[0]) {
+ case 'b':
+ binding.inputType = TYPE_BUTTON;
+ binding.input.button = input.right(1).to_int();
+ break;
+ case 'a':
+ binding.inputType = TYPE_AXIS;
+ binding.input.axis.axis = input.right(1).to_int();
+ binding.input.axis.range = input_range;
+ binding.input.axis.invert = invert_axis;
+ break;
+ case 'h':
+ ERR_CONTINUE_MSG(input.length() != 4 || input[2] != '.',
+ String(entry[idx] + "\nInvalid hat input: " + input));
+ binding.inputType = TYPE_HAT;
+ binding.input.hat.hat = input.substr(1, 1).to_int();
+ binding.input.hat.hat_mask = static_cast<HatMask>(input.right(3).to_int());
+ break;
+ default:
+ ERR_CONTINUE_MSG(true, String(entry[idx] + "\nUnrecognised input string: " + input));
+ }
- int hat_value = from.get_slice(".", 1).to_int();
- switch (hat_value) {
- case 1:
- mapping.hat[HAT_UP] = to_event;
- break;
- case 2:
- mapping.hat[HAT_RIGHT] = to_event;
- break;
- case 4:
- mapping.hat[HAT_DOWN] = to_event;
- break;
- case 8:
- mapping.hat[HAT_LEFT] = to_event;
- break;
- };
- };
+ mapping.bindings.push_back(binding);
};
+
map_db.push_back(mapping);
- //printf("added mapping with uuid %ls\n", mapping.uid.c_str());
};
void Input::add_joy_mapping(String p_mapping, bool p_update_existing) {
@@ -1187,50 +1393,18 @@ Array Input::get_connected_joypads() {
return ret;
}
-static const char *_buttons[JOY_BUTTON_MAX] = {
- "Face Button Bottom",
- "Face Button Right",
- "Face Button Left",
- "Face Button Top",
- "L",
- "R",
- "L2",
- "R2",
- "L3",
- "R3",
- "Select",
- "Start",
- "DPAD Up",
- "DPAD Down",
- "DPAD Left",
- "DPAD Right"
-};
-
-static const char *_axes[JOY_AXIS_MAX] = {
- "Left Stick X",
- "Left Stick Y",
- "Right Stick X",
- "Right Stick Y",
- "",
- "",
- "L2",
- "R2",
- "",
- ""
-};
-
String Input::get_joy_button_string(int p_button) {
- ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "");
- return _buttons[p_button];
+ ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "Invalid button");
+ return _joy_button_names[p_button];
}
int Input::get_joy_button_index_from_string(String p_button) {
for (int i = 0; i < JOY_BUTTON_MAX; i++) {
- if (p_button == _buttons[i]) {
+ if (p_button == _joy_button_names[i]) {
return i;
}
}
- ERR_FAIL_V(-1);
+ ERR_FAIL_V(JOY_INVALID_BUTTON);
}
int Input::get_unused_joy_id() {
@@ -1243,17 +1417,17 @@ int Input::get_unused_joy_id() {
}
String Input::get_joy_axis_string(int p_axis) {
- ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "");
- return _axes[p_axis];
+ ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "Invalid axis");
+ return _joy_axis_names[p_axis];
}
int Input::get_joy_axis_index_from_string(String p_axis) {
for (int i = 0; i < JOY_AXIS_MAX; i++) {
- if (p_axis == _axes[i]) {
+ if (p_axis == _joy_axis_names[i]) {
return i;
}
}
- ERR_FAIL_V(-1);
+ ERR_FAIL_V(JOY_INVALID_AXIS);
}
Input::Input() {
@@ -1268,22 +1442,6 @@ Input::Input() {
event_dispatch_function = nullptr;
default_shape = CURSOR_ARROW;
- hat_map_default[HAT_UP].type = TYPE_BUTTON;
- hat_map_default[HAT_UP].index = JOY_DPAD_UP;
- hat_map_default[HAT_UP].value = 0;
-
- hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
- hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
- hat_map_default[HAT_RIGHT].value = 0;
-
- hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
- hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
- hat_map_default[HAT_DOWN].value = 0;
-
- hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
- hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
- hat_map_default[HAT_LEFT].value = 0;
-
fallback_mapping = -1;
// Parse default mappings.
diff --git a/core/input/input.h b/core/input/input.h
index 2e136dbf02..9accf14a4f 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -145,7 +145,7 @@ private:
StringName name;
StringName uid;
bool connected;
- bool last_buttons[JOY_BUTTON_MAX + 19]; //apparently SDL specifies 35 possible buttons on android
+ bool last_buttons[JOY_BUTTON_MAX];
float last_axis[JOY_AXIS_MAX];
float filter;
int last_hat;
@@ -154,11 +154,9 @@ private:
Joypad() {
for (int i = 0; i < JOY_AXIS_MAX; i++) {
-
last_axis[i] = 0.0f;
}
- for (int i = 0; i < JOY_BUTTON_MAX + 19; i++) {
-
+ for (int i = 0; i < JOY_BUTTON_MAX; i++) {
last_buttons[i] = false;
}
connected = false;
@@ -183,26 +181,61 @@ private:
TYPE_MAX,
};
+ enum JoyAxisRange {
+ NEGATIVE_HALF_AXIS = -1,
+ FULL_AXIS = 0,
+ POSITIVE_HALF_AXIS = 1
+ };
+
struct JoyEvent {
int type;
int index;
- int value;
+ float value;
};
- struct JoyDeviceMapping {
+ struct JoyBinding {
+ JoyType inputType;
+ union {
+ int button;
+
+ struct {
+ int axis;
+ JoyAxisRange range;
+ bool invert;
+ } axis;
+
+ struct {
+ int hat;
+ HatMask hat_mask;
+ } hat;
+ } input;
+
+ JoyType outputType;
+ union {
+ JoyButtonList button;
+
+ struct {
+ JoyAxisList axis;
+ JoyAxisRange range;
+ } axis;
+
+ } output;
+ };
+
+ struct JoyDeviceMapping {
String uid;
String name;
- Map<int, JoyEvent> buttons;
- Map<int, JoyEvent> axis;
- JoyEvent hat[HAT_MAX];
+ Vector<JoyBinding> bindings;
};
- JoyEvent hat_map_default[HAT_MAX];
-
Vector<JoyDeviceMapping> map_db;
- JoyEvent _find_to_event(String p_to);
+ JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button);
+ JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, const JoyAxis &p_value);
+ void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]);
+ JoyButtonList _get_output_button(String output);
+ JoyAxisList _get_output_axis(String output);
void _button_event(int p_device, int p_index, bool p_pressed);
void _axis_event(int p_device, int p_axis, float p_value);
float _handle_deadzone(int p_device, int p_axis, float p_value);
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index 53b90f2073..748ec06133 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -42,18 +42,7 @@ def make_default_controller_mappings(target, source, env):
src_path, current_platform, platform_mappings[current_platform][guid]
)
)
- valid_mapping = True
- for input_map in line_parts[2:]:
- if "+" in input_map or "-" in input_map or "~" in input_map:
- g.write(
- "// WARNING - DISCARDED UNSUPPORTED MAPPING TYPE FROM DATABASE {}: {} {}\n".format(
- src_path, current_platform, line
- )
- )
- valid_mapping = False
- break
- if valid_mapping:
- platform_mappings[current_platform][guid] = line
+ platform_mappings[current_platform][guid] = line
platform_variables = {
"Linux": "#if X11_ENABLED",
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 8774b3b1db..99ea2efee9 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -59,98 +59,84 @@ enum ButtonList {
BUTTON_MASK_XBUTTON2 = (1 << (BUTTON_XBUTTON2 - 1))
};
-enum JoystickList {
-
- JOY_BUTTON_0 = 0,
- JOY_BUTTON_1 = 1,
- JOY_BUTTON_2 = 2,
- JOY_BUTTON_3 = 3,
- JOY_BUTTON_4 = 4,
- JOY_BUTTON_5 = 5,
- JOY_BUTTON_6 = 6,
- JOY_BUTTON_7 = 7,
- JOY_BUTTON_8 = 8,
- JOY_BUTTON_9 = 9,
- JOY_BUTTON_10 = 10,
- JOY_BUTTON_11 = 11,
- JOY_BUTTON_12 = 12,
- JOY_BUTTON_13 = 13,
- JOY_BUTTON_14 = 14,
- JOY_BUTTON_15 = 15,
- JOY_BUTTON_MAX = 16,
-
- JOY_L = JOY_BUTTON_4,
- JOY_R = JOY_BUTTON_5,
- JOY_L2 = JOY_BUTTON_6,
- JOY_R2 = JOY_BUTTON_7,
- JOY_L3 = JOY_BUTTON_8,
- JOY_R3 = JOY_BUTTON_9,
- JOY_SELECT = JOY_BUTTON_10,
- JOY_START = JOY_BUTTON_11,
- JOY_DPAD_UP = JOY_BUTTON_12,
- JOY_DPAD_DOWN = JOY_BUTTON_13,
- JOY_DPAD_LEFT = JOY_BUTTON_14,
- JOY_DPAD_RIGHT = JOY_BUTTON_15,
-
- JOY_SONY_CIRCLE = JOY_BUTTON_1,
- JOY_SONY_X = JOY_BUTTON_0,
- JOY_SONY_SQUARE = JOY_BUTTON_2,
- JOY_SONY_TRIANGLE = JOY_BUTTON_3,
-
- JOY_XBOX_A = JOY_BUTTON_0,
- JOY_XBOX_B = JOY_BUTTON_1,
- JOY_XBOX_X = JOY_BUTTON_2,
- JOY_XBOX_Y = JOY_BUTTON_3,
-
- JOY_DS_A = JOY_BUTTON_1,
- JOY_DS_B = JOY_BUTTON_0,
- JOY_DS_X = JOY_BUTTON_3,
- JOY_DS_Y = JOY_BUTTON_2,
-
- JOY_WII_C = JOY_BUTTON_5,
- JOY_WII_Z = JOY_BUTTON_6,
-
- JOY_WII_MINUS = JOY_BUTTON_10,
- JOY_WII_PLUS = JOY_BUTTON_11,
-
- JOY_VR_GRIP = JOY_BUTTON_2,
- JOY_VR_PAD = JOY_BUTTON_14,
- JOY_VR_TRIGGER = JOY_BUTTON_15,
-
- JOY_OCULUS_AX = JOY_BUTTON_7,
- JOY_OCULUS_BY = JOY_BUTTON_1,
- JOY_OCULUS_MENU = JOY_BUTTON_3,
-
- JOY_OPENVR_MENU = JOY_BUTTON_1,
-
- // end of history
-
- JOY_AXIS_0 = 0,
- JOY_AXIS_1 = 1,
- JOY_AXIS_2 = 2,
- JOY_AXIS_3 = 3,
- JOY_AXIS_4 = 4,
- JOY_AXIS_5 = 5,
- JOY_AXIS_6 = 6,
- JOY_AXIS_7 = 7,
- JOY_AXIS_8 = 8,
- JOY_AXIS_9 = 9,
- JOY_AXIS_MAX = 10,
-
- JOY_ANALOG_LX = JOY_AXIS_0,
- JOY_ANALOG_LY = JOY_AXIS_1,
-
- JOY_ANALOG_RX = JOY_AXIS_2,
- JOY_ANALOG_RY = JOY_AXIS_3,
-
- JOY_ANALOG_L2 = JOY_AXIS_6,
- JOY_ANALOG_R2 = JOY_AXIS_7,
-
- JOY_VR_ANALOG_TRIGGER = JOY_AXIS_2,
- JOY_VR_ANALOG_GRIP = JOY_AXIS_4,
-
- JOY_OPENVR_TOUCHPADX = JOY_AXIS_0,
- JOY_OPENVR_TOUCHPADY = JOY_AXIS_1,
+enum JoyButtonList {
+
+ JOY_INVALID_BUTTON = -1,
+
+ // SDL Buttons
+ JOY_BUTTON_A = 0,
+ JOY_BUTTON_B = 1,
+ JOY_BUTTON_X = 2,
+ JOY_BUTTON_Y = 3,
+ JOY_BUTTON_BACK = 4,
+ JOY_BUTTON_GUIDE = 5,
+ JOY_BUTTON_START = 6,
+ JOY_BUTTON_LEFT_STICK = 7,
+ JOY_BUTTON_RIGHT_STICK = 8,
+ JOY_BUTTON_LEFT_SHOULDER = 9,
+ JOY_BUTTON_RIGHT_SHOULDER = 10,
+ JOY_BUTTON_DPAD_UP = 11,
+ JOY_BUTTON_DPAD_DOWN = 12,
+ JOY_BUTTON_DPAD_LEFT = 13,
+ JOY_BUTTON_DPAD_RIGHT = 14,
+ JOY_SDL_BUTTONS = 15,
+
+ // Sony Buttons
+ JOY_SONY_X = JOY_BUTTON_A,
+ JOY_SONY_CROSS = JOY_BUTTON_A,
+ JOY_SONY_CIRCLE = JOY_BUTTON_B,
+ JOY_SONY_SQUARE = JOY_BUTTON_X,
+ JOY_SONY_TRIANGLE = JOY_BUTTON_Y,
+ JOY_SONY_SELECT = JOY_BUTTON_BACK,
+ JOY_SONY_START = JOY_BUTTON_START,
+ JOY_SONY_PS = JOY_BUTTON_GUIDE,
+ JOY_SONY_L1 = JOY_BUTTON_LEFT_SHOULDER,
+ JOY_SONY_R1 = JOY_BUTTON_RIGHT_SHOULDER,
+ JOY_SONY_L3 = JOY_BUTTON_LEFT_STICK,
+ JOY_SONY_R3 = JOY_BUTTON_RIGHT_STICK,
+
+ // Xbox Buttons
+ JOY_XBOX_A = JOY_BUTTON_A,
+ JOY_XBOX_B = JOY_BUTTON_B,
+ JOY_XBOX_X = JOY_BUTTON_X,
+ JOY_XBOX_Y = JOY_BUTTON_Y,
+ JOY_XBOX_BACK = JOY_BUTTON_BACK,
+ JOY_XBOX_START = JOY_BUTTON_START,
+ JOY_XBOX_HOME = JOY_BUTTON_GUIDE,
+ JOY_XBOX_LS = JOY_BUTTON_LEFT_STICK,
+ JOY_XBOX_RS = JOY_BUTTON_RIGHT_STICK,
+ JOY_XBOX_LB = JOY_BUTTON_LEFT_SHOULDER,
+ JOY_XBOX_RB = JOY_BUTTON_RIGHT_SHOULDER,
+
+ JOY_BUTTON_MAX = 36 // Apparently Android supports up to 36 buttons.
+};
+
+enum JoyAxisList {
+
+ JOY_INVALID_AXIS = -1,
+
+ // SDL Axes
+ JOY_AXIS_LEFT_X = 0,
+ JOY_AXIS_LEFT_Y = 1,
+ JOY_AXIS_RIGHT_X = 2,
+ JOY_AXIS_RIGHT_Y = 3,
+ JOY_AXIS_TRIGGER_LEFT = 4,
+ JOY_AXIS_TRIGGER_RIGHT = 5,
+ JOY_SDL_AXES = 6,
+
+ // Joystick axes.
+ JOY_AXIS_0_X = 0,
+ JOY_AXIS_0_Y = 1,
+ JOY_AXIS_1_X = 2,
+ JOY_AXIS_1_Y = 3,
+ JOY_AXIS_2_X = 4,
+ JOY_AXIS_2_Y = 5,
+ JOY_AXIS_3_X = 6,
+ JOY_AXIS_3_Y = 7,
+ JOY_AXIS_4_X = 8,
+ JOY_AXIS_4_Y = 9,
+
+ JOY_AXIS_MAX = 10 // OpenVR supports up to 5 Joysticks making a total of 10 axes.
};
enum MidiMessageList {
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 8c7559479b..e0fea143bb 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -337,10 +337,14 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
} break;
case OBJECT_INTERNAL_RESOURCE: {
uint32_t index = f->get_32();
+ String path = res_path + "::" + itos(index);
+
if (use_nocache) {
- r_v = internal_resources[index].cache;
+ if (!internal_index_cache.has(path)) {
+ WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
+ }
+ r_v = internal_index_cache[path];
} else {
- String path = res_path + "::" + itos(index);
RES res = ResourceLoader::load(path);
if (res.is_null()) {
WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data());
@@ -720,13 +724,15 @@ Error ResourceLoaderBinary::load() {
if (!main) {
+ path = internal_resources[i].path;
+
+ if (path.begins_with("local://")) {
+ path = path.replace_first("local://", "");
+ subindex = path.to_int();
+ path = res_path + "::" + path;
+ }
+
if (!use_nocache) {
- path = internal_resources[i].path;
- if (path.begins_with("local://")) {
- path = path.replace_first("local://", "");
- subindex = path.to_int();
- path = res_path + "::" + path;
- }
if (ResourceCache::has(path)) {
//already loaded, don't do anything
@@ -769,7 +775,7 @@ Error ResourceLoaderBinary::load() {
r->set_subindex(subindex);
if (!main) {
- internal_resources.write[i].cache = res;
+ internal_index_cache[path] = res;
}
int pc = f->get_32();
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 0f8fc9445b..3c8d916c0a 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -68,10 +68,10 @@ class ResourceLoaderBinary {
struct IntResource {
String path;
uint64_t offset;
- RES cache;
};
Vector<IntResource> internal_resources;
+ Map<String, RES> internal_index_cache;
String get_unicode_string();
void _advance_padding(uint32_t p_len);
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 643df53f8c..9e22bdced7 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -91,7 +91,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
r_path_and_type.path = value;
path_found = true; //first match must have priority
} else if (assign == "type") {
- r_path_and_type.type = value;
+ r_path_and_type.type = ClassDB::get_compatibility_remapped_class(value);
} else if (assign == "importer") {
r_path_and_type.importer = value;
} else if (assign == "group_file") {
diff --git a/core/local_vector.h b/core/local_vector.h
new file mode 100644
index 0000000000..0b0ef6dfdc
--- /dev/null
+++ b/core/local_vector.h
@@ -0,0 +1,246 @@
+/*************************************************************************/
+/* local_vector.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 LOCAL_VECTOR_H
+#define LOCAL_VECTOR_H
+
+#include "core/error_macros.h"
+#include "core/os/copymem.h"
+#include "core/os/memory.h"
+#include "core/sort_array.h"
+#include "core/vector.h"
+
+template <class T, class U = uint32_t, bool force_trivial = false>
+class LocalVector {
+private:
+ U count = 0;
+ U capacity = 0;
+ T *data = nullptr;
+
+public:
+ _FORCE_INLINE_ void push_back(T p_elem) {
+ if (unlikely(count == capacity)) {
+ if (capacity == 0) {
+ capacity = 1;
+ } else {
+ capacity <<= 1;
+ }
+ data = (T *)memrealloc(data, capacity * sizeof(T));
+ CRASH_COND_MSG(!data, "Out of memory");
+ }
+
+ if (!__has_trivial_constructor(T) && !force_trivial) {
+ memnew_placement(&data[count++], T(p_elem));
+ } else {
+ data[count++] = p_elem;
+ }
+ }
+
+ void remove(U p_index) {
+ ERR_FAIL_UNSIGNED_INDEX(p_index, count);
+ for (U i = p_index; i < count; i++) {
+ data[i] = data[i + 1];
+ }
+ count--;
+ if (!__has_trivial_destructor(T) && !force_trivial) {
+ data[count].~T();
+ }
+ }
+
+ void erase(const T &p_val) {
+ U idx = find(p_val);
+ if (idx >= 0)
+ remove(idx);
+ }
+
+ void invert() {
+
+ for (U i = 0; i < count / 2; i++) {
+ SWAP(data[i], data[count - i - 1]);
+ }
+ }
+
+ _FORCE_INLINE_ void clear() { resize(0); }
+ _FORCE_INLINE_ void reset() {
+ clear();
+ if (data) {
+ memfree(data);
+ data = nullptr;
+ capacity = 0;
+ }
+ }
+ _FORCE_INLINE_ bool empty() const { return count == 0; }
+ _FORCE_INLINE_ void reserve(U p_size) {
+ p_size = nearest_power_of_2_templated(p_size);
+ if (p_size > capacity) {
+ capacity = p_size;
+ data = (T *)memrealloc(data, capacity * sizeof(T));
+ CRASH_COND_MSG(!data, "Out of memory");
+ }
+ }
+
+ _FORCE_INLINE_ U size() const { return count; }
+ void resize(U p_size) {
+
+ if (p_size < count) {
+
+ if (!__has_trivial_destructor(T) && !force_trivial) {
+ for (U i = p_size; i < count; i++) {
+ data[i].~T();
+ }
+ }
+ count = p_size;
+ } else if (p_size > count) {
+
+ if (unlikely(p_size > capacity)) {
+ if (capacity == 0) {
+ capacity = 1;
+ }
+ while (capacity < p_size) {
+ capacity <<= 1;
+ }
+ data = (T *)memrealloc(data, capacity * sizeof(T));
+ CRASH_COND_MSG(!data, "Out of memory");
+ }
+ if (!__has_trivial_constructor(T) && !force_trivial) {
+ for (U i = count; i < p_size; i++) {
+ memnew_placement(&data[i], T);
+ }
+ }
+ count = p_size;
+ }
+ }
+ _FORCE_INLINE_ const T &operator[](U p_index) const {
+ CRASH_BAD_UNSIGNED_INDEX(p_index, count);
+ return data[p_index];
+ }
+ _FORCE_INLINE_ T &operator[](U p_index) {
+ CRASH_BAD_UNSIGNED_INDEX(p_index, count);
+ return data[p_index];
+ }
+
+ void insert(U p_pos, T p_val) {
+ ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
+ if (p_pos == count) {
+ push_back(p_val);
+ } else {
+ resize(count + 1);
+ for (U i = count; i > p_pos; i--) {
+ data[i] = data[i - 1];
+ }
+ data[p_pos] = p_val;
+ }
+ }
+
+ int64_t find(const T &p_val, U p_from = 0) const {
+
+ for (U i = 0; i < count; i++) {
+ if (data[i] == p_val) {
+ return int64_t(i);
+ }
+ }
+ return -1;
+ }
+
+ template <class C>
+ void sort_custom() {
+
+ U len = count;
+ if (len == 0)
+ return;
+
+ SortArray<T, C> sorter;
+ sorter.sort(data, len);
+ }
+
+ void sort() {
+
+ sort_custom<_DefaultComparator<T>>();
+ }
+
+ void ordered_insert(T p_val) {
+
+ U i;
+ for (i = 0; i < count; i++) {
+
+ if (p_val < data[i]) {
+ break;
+ };
+ };
+ insert(i, p_val);
+ }
+
+ operator Vector<T>() const {
+ Vector<T> ret;
+ ret.resize(size());
+ T *w = ret.ptrw();
+ copymem(w, data, sizeof(T) * count);
+ return ret;
+ }
+
+ Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
+ Vector<uint8_t> ret;
+ ret.resize(count * sizeof(T));
+ uint8_t *w = ret.ptrw();
+ copymem(w, data, sizeof(T) * count);
+ return ret;
+ }
+
+ _FORCE_INLINE_ LocalVector() {}
+ _FORCE_INLINE_ LocalVector(const LocalVector &p_from) {
+ resize(p_from.size());
+ for (U i = 0; i < p_from.count; i++) {
+ data[i] = p_from.data[i];
+ }
+ }
+ inline LocalVector &operator=(const LocalVector &p_from) {
+ resize(p_from.size());
+ for (U i = 0; i < p_from.count; i++) {
+ data[i] = p_from.data[i];
+ }
+ return *this;
+ }
+ inline LocalVector &operator=(const Vector<T> &p_from) {
+ resize(p_from.size());
+ for (U i = 0; i < count; i++) {
+ data[i] = p_from[i];
+ }
+ return *this;
+ }
+
+ _FORCE_INLINE_ ~LocalVector() {
+
+ if (data) {
+ reset();
+ }
+ }
+};
+
+#endif // LOCAL_VECTOR_H
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 87abf2dbc1..6218b7e248 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -878,3 +878,114 @@ Basis Basis::slerp(const Basis &target, const real_t &t) const {
return b;
}
+
+void Basis::rotate_sh(real_t *p_values) {
+
+ // code by John Hable
+ // http://filmicworlds.com/blog/simple-and-fast-spherical-harmonic-rotation/
+ // this code is Public Domain
+
+ const static real_t s_c3 = 0.94617469575; // (3*sqrt(5))/(4*sqrt(pi))
+ const static real_t s_c4 = -0.31539156525; // (-sqrt(5))/(4*sqrt(pi))
+ const static real_t s_c5 = 0.54627421529; // (sqrt(15))/(4*sqrt(pi))
+
+ const static real_t s_c_scale = 1.0 / 0.91529123286551084;
+ const static real_t s_c_scale_inv = 0.91529123286551084;
+
+ const static real_t s_rc2 = 1.5853309190550713 * s_c_scale;
+ const static real_t s_c4_div_c3 = s_c4 / s_c3;
+ const static real_t s_c4_div_c3_x2 = (s_c4 / s_c3) * 2.0;
+
+ const static real_t s_scale_dst2 = s_c3 * s_c_scale_inv;
+ const static real_t s_scale_dst4 = s_c5 * s_c_scale_inv;
+
+ real_t src[9] = { p_values[0], p_values[1], p_values[2], p_values[3], p_values[4], p_values[5], p_values[6], p_values[7], p_values[8] };
+
+ real_t m00 = elements[0][0];
+ real_t m01 = elements[0][1];
+ real_t m02 = elements[0][2];
+ real_t m10 = elements[1][0];
+ real_t m11 = elements[1][1];
+ real_t m12 = elements[1][2];
+ real_t m20 = elements[2][0];
+ real_t m21 = elements[2][1];
+ real_t m22 = elements[2][2];
+
+ p_values[0] = src[0];
+ p_values[1] = m11 * src[1] - m12 * src[2] + m10 * src[3];
+ p_values[2] = -m21 * src[1] + m22 * src[2] - m20 * src[3];
+ p_values[3] = m01 * src[1] - m02 * src[2] + m00 * src[3];
+
+ real_t sh0 = src[7] + src[8] + src[8] - src[5];
+ real_t sh1 = src[4] + s_rc2 * src[6] + src[7] + src[8];
+ real_t sh2 = src[4];
+ real_t sh3 = -src[7];
+ real_t sh4 = -src[5];
+
+ // Rotations. R0 and R1 just use the raw matrix columns
+ real_t r2x = m00 + m01;
+ real_t r2y = m10 + m11;
+ real_t r2z = m20 + m21;
+
+ real_t r3x = m00 + m02;
+ real_t r3y = m10 + m12;
+ real_t r3z = m20 + m22;
+
+ real_t r4x = m01 + m02;
+ real_t r4y = m11 + m12;
+ real_t r4z = m21 + m22;
+
+ // dense matrix multiplication one column at a time
+
+ // column 0
+ real_t sh0_x = sh0 * m00;
+ real_t sh0_y = sh0 * m10;
+ real_t d0 = sh0_x * m10;
+ real_t d1 = sh0_y * m20;
+ real_t d2 = sh0 * (m20 * m20 + s_c4_div_c3);
+ real_t d3 = sh0_x * m20;
+ real_t d4 = sh0_x * m00 - sh0_y * m10;
+
+ // column 1
+ real_t sh1_x = sh1 * m02;
+ real_t sh1_y = sh1 * m12;
+ d0 += sh1_x * m12;
+ d1 += sh1_y * m22;
+ d2 += sh1 * (m22 * m22 + s_c4_div_c3);
+ d3 += sh1_x * m22;
+ d4 += sh1_x * m02 - sh1_y * m12;
+
+ // column 2
+ real_t sh2_x = sh2 * r2x;
+ real_t sh2_y = sh2 * r2y;
+ d0 += sh2_x * r2y;
+ d1 += sh2_y * r2z;
+ d2 += sh2 * (r2z * r2z + s_c4_div_c3_x2);
+ d3 += sh2_x * r2z;
+ d4 += sh2_x * r2x - sh2_y * r2y;
+
+ // column 3
+ real_t sh3_x = sh3 * r3x;
+ real_t sh3_y = sh3 * r3y;
+ d0 += sh3_x * r3y;
+ d1 += sh3_y * r3z;
+ d2 += sh3 * (r3z * r3z + s_c4_div_c3_x2);
+ d3 += sh3_x * r3z;
+ d4 += sh3_x * r3x - sh3_y * r3y;
+
+ // column 4
+ real_t sh4_x = sh4 * r4x;
+ real_t sh4_y = sh4 * r4y;
+ d0 += sh4_x * r4y;
+ d1 += sh4_y * r4z;
+ d2 += sh4 * (r4z * r4z + s_c4_div_c3_x2);
+ d3 += sh4_x * r4z;
+ d4 += sh4_x * r4x - sh4_y * r4y;
+
+ // extra multipliers
+ p_values[4] = d0;
+ p_values[5] = -d1;
+ p_values[6] = d2 * s_scale_dst2;
+ p_values[7] = -d3;
+ p_values[8] = d4 * s_scale_dst4;
+}
diff --git a/core/math/basis.h b/core/math/basis.h
index 0261cf67c6..2924a0ddbd 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -159,6 +159,7 @@ public:
bool is_rotation() const;
Basis slerp(const Basis &target, const real_t &t) const;
+ void rotate_sh(real_t *p_values);
operator String() const;
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 76321b0679..5d3ebc9f6d 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -33,6 +33,22 @@
#include "core/math/math_funcs.h"
#include "core/print_string.h"
+float CameraMatrix::determinant() const {
+
+ return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] -
+ matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] +
+ matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] -
+ matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] +
+ matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] -
+ matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] +
+ matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] -
+ matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] +
+ matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] -
+ matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] +
+ matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] -
+ matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3];
+}
+
void CameraMatrix::set_identity() {
for (int i = 0; i < 4; i++) {
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index c10193bc84..5420fa2984 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -47,6 +47,7 @@ struct CameraMatrix {
real_t matrix[4][4];
+ float determinant() const;
void set_identity();
void set_zero();
void set_light_bias();
diff --git a/core/math/delaunay.h b/core/math/delaunay_2d.h
index 29f84210d2..b8252e9d16 100644
--- a/core/math/delaunay.h
+++ b/core/math/delaunay_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* delaunay.h */
+/* delaunay_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef DELAUNAY_H
-#define DELAUNAY_H
+#ifndef DELAUNAY_2D_H
+#define DELAUNAY_2D_H
#include "core/math/rect2.h"
@@ -115,8 +115,6 @@ public:
triangles.push_back(Triangle(p_points.size() + 0, p_points.size() + 1, p_points.size() + 2));
for (int i = 0; i < p_points.size(); i++) {
- //std::cout << "Traitement du point " << *p << std::endl;
- //std::cout << "_triangles contains " << _triangles.size() << " elements" << std::endl;
Vector<Edge> polygon;
@@ -172,4 +170,4 @@ public:
}
};
-#endif // DELAUNAY_H
+#endif // DELAUNAY_2D_H
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
new file mode 100644
index 0000000000..57f3a78d35
--- /dev/null
+++ b/core/math/delaunay_3d.h
@@ -0,0 +1,387 @@
+#ifndef DELAUNAY_3D_H
+#define DELAUNAY_3D_H
+
+#include "core/local_vector.h"
+#include "core/math/aabb.h"
+#include "core/math/camera_matrix.h"
+#include "core/math/vector3.h"
+#include "core/oa_hash_map.h"
+#include "core/os/file_access.h"
+#include "core/print_string.h"
+#include "core/variant.h"
+#include "core/vector.h"
+
+#include "thirdparty/misc/r128.h"
+
+class Delaunay3D {
+ struct Simplex;
+
+ enum {
+ ACCEL_GRID_SIZE = 16
+ };
+ struct GridPos {
+ Vector3i pos;
+ List<Simplex *>::Element *E = nullptr;
+ };
+
+ struct Simplex {
+
+ uint32_t points[4];
+ R128 circum_center_x;
+ R128 circum_center_y;
+ R128 circum_center_z;
+ R128 circum_r2;
+ LocalVector<GridPos> grid_positions;
+ List<Simplex *>::Element *SE = nullptr;
+
+ _FORCE_INLINE_ Simplex() {}
+ _FORCE_INLINE_ Simplex(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d) {
+ points[0] = p_a;
+ points[1] = p_b;
+ points[2] = p_c;
+ points[3] = p_d;
+ }
+ };
+
+ struct Triangle {
+ uint32_t triangle[3];
+ bool bad;
+ _FORCE_INLINE_ bool operator==(const Triangle &p_triangle) const {
+ return triangle[0] == p_triangle.triangle[0] && triangle[1] == p_triangle.triangle[1] && triangle[2] == p_triangle.triangle[2];
+ }
+
+ _FORCE_INLINE_ Triangle() { bad = false; }
+ _FORCE_INLINE_ Triangle(uint32_t p_a, uint32_t p_b, uint32_t p_c) {
+ if (p_a > p_b)
+ SWAP(p_a, p_b);
+ if (p_b > p_c)
+ SWAP(p_b, p_c);
+ if (p_a > p_b)
+ SWAP(p_a, p_b);
+
+ bad = false;
+ triangle[0] = p_a;
+ triangle[1] = p_b;
+ triangle[2] = p_c;
+ }
+ };
+
+ struct TriangleHasher {
+ _FORCE_INLINE_ static uint32_t hash(const Triangle &p_triangle) {
+ uint32_t h = hash_djb2_one_32(p_triangle.triangle[0]);
+ h = hash_djb2_one_32(p_triangle.triangle[1], h);
+ return hash_djb2_one_32(p_triangle.triangle[2], h);
+ }
+ };
+
+ struct FPVal {
+ };
+
+ _FORCE_INLINE_ static void circum_sphere_compute(const Vector3 *p_points, Simplex *p_simplex) {
+
+ // the only part in the algorithm where there may be precision errors is this one, so ensure that
+ // we do it as maximum precision as possible
+
+ R128 v0_x = p_points[p_simplex->points[0]].x;
+ R128 v0_y = p_points[p_simplex->points[0]].y;
+ R128 v0_z = p_points[p_simplex->points[0]].z;
+ R128 v1_x = p_points[p_simplex->points[1]].x;
+ R128 v1_y = p_points[p_simplex->points[1]].y;
+ R128 v1_z = p_points[p_simplex->points[1]].z;
+ R128 v2_x = p_points[p_simplex->points[2]].x;
+ R128 v2_y = p_points[p_simplex->points[2]].y;
+ R128 v2_z = p_points[p_simplex->points[2]].z;
+ R128 v3_x = p_points[p_simplex->points[3]].x;
+ R128 v3_y = p_points[p_simplex->points[3]].y;
+ R128 v3_z = p_points[p_simplex->points[3]].z;
+
+ //Create the rows of our "unrolled" 3x3 matrix
+ R128 row1_x = v1_x - v0_x;
+ R128 row1_y = v1_y - v0_y;
+ R128 row1_z = v1_z - v0_z;
+
+ R128 row2_x = v2_x - v0_x;
+ R128 row2_y = v2_y - v0_y;
+ R128 row2_z = v2_z - v0_z;
+
+ R128 row3_x = v3_x - v0_x;
+ R128 row3_y = v3_y - v0_y;
+ R128 row3_z = v3_z - v0_z;
+
+ R128 sq_lenght1 = row1_x * row1_x + row1_y * row1_y + row1_z * row1_z;
+ R128 sq_lenght2 = row2_x * row2_x + row2_y * row2_y + row2_z * row2_z;
+ R128 sq_lenght3 = row3_x * row3_x + row3_y * row3_y + row3_z * row3_z;
+
+ //Compute the determinant of said matrix
+ R128 determinant = row1_x * (row2_y * row3_z - row3_y * row2_z) - row2_x * (row1_y * row3_z - row3_y * row1_z) + row3_x * (row1_y * row2_z - row2_y * row1_z);
+
+ // Compute the volume of the tetrahedron, and precompute a scalar quantity for re-use in the formula
+ R128 volume = determinant / R128(6.f);
+ R128 i12volume = R128(1.f) / (volume * R128(12.f));
+
+ R128 center_x = v0_x + i12volume * ((row2_y * row3_z - row3_y * row2_z) * sq_lenght1 - (row1_y * row3_z - row3_y * row1_z) * sq_lenght2 + (row1_y * row2_z - row2_y * row1_z) * sq_lenght3);
+ R128 center_y = v0_y + i12volume * (-(row2_x * row3_z - row3_x * row2_z) * sq_lenght1 + (row1_x * row3_z - row3_x * row1_z) * sq_lenght2 - (row1_x * row2_z - row2_x * row1_z) * sq_lenght3);
+ R128 center_z = v0_z + i12volume * ((row2_x * row3_y - row3_x * row2_y) * sq_lenght1 - (row1_x * row3_y - row3_x * row1_y) * sq_lenght2 + (row1_x * row2_y - row2_x * row1_y) * sq_lenght3);
+
+ //Once we know the center, the radius is clearly the distance to any vertex
+
+ R128 rel1_x = center_x - v0_x;
+ R128 rel1_y = center_y - v0_y;
+ R128 rel1_z = center_z - v0_z;
+
+ R128 radius1 = rel1_x * rel1_x + rel1_y * rel1_y + rel1_z * rel1_z;
+
+ p_simplex->circum_center_x = center_x;
+ p_simplex->circum_center_y = center_y;
+ p_simplex->circum_center_z = center_z;
+ p_simplex->circum_r2 = radius1;
+ }
+
+ _FORCE_INLINE_ static bool simplex_contains(const Vector3 *p_points, const Simplex &p_simplex, uint32_t p_vertex) {
+
+ R128 v_x = p_points[p_vertex].x;
+ R128 v_y = p_points[p_vertex].y;
+ R128 v_z = p_points[p_vertex].z;
+
+ R128 rel2_x = p_simplex.circum_center_x - v_x;
+ R128 rel2_y = p_simplex.circum_center_y - v_y;
+ R128 rel2_z = p_simplex.circum_center_z - v_z;
+
+ R128 radius2 = rel2_x * rel2_x + rel2_y * rel2_y + rel2_z * rel2_z;
+
+ return radius2 < (p_simplex.circum_r2 - R128(0.00001));
+ }
+
+ static bool simplex_is_coplanar(const Vector3 *p_points, const Simplex &p_simplex) {
+
+ Plane p(p_points[p_simplex.points[0]], p_points[p_simplex.points[1]], p_points[p_simplex.points[2]]);
+ if (ABS(p.distance_to(p_points[p_simplex.points[3]])) < CMP_EPSILON) {
+ return true;
+ }
+
+ CameraMatrix cm;
+
+ cm.matrix[0][0] = p_points[p_simplex.points[0]].x;
+ cm.matrix[0][1] = p_points[p_simplex.points[1]].x;
+ cm.matrix[0][2] = p_points[p_simplex.points[2]].x;
+ cm.matrix[0][3] = p_points[p_simplex.points[3]].x;
+
+ cm.matrix[1][0] = p_points[p_simplex.points[0]].y;
+ cm.matrix[1][1] = p_points[p_simplex.points[1]].y;
+ cm.matrix[1][2] = p_points[p_simplex.points[2]].y;
+ cm.matrix[1][3] = p_points[p_simplex.points[3]].y;
+
+ cm.matrix[2][0] = p_points[p_simplex.points[0]].z;
+ cm.matrix[2][1] = p_points[p_simplex.points[1]].z;
+ cm.matrix[2][2] = p_points[p_simplex.points[2]].z;
+ cm.matrix[2][3] = p_points[p_simplex.points[3]].z;
+
+ cm.matrix[3][0] = 1.0;
+ cm.matrix[3][1] = 1.0;
+ cm.matrix[3][2] = 1.0;
+ cm.matrix[3][3] = 1.0;
+
+ return ABS(cm.determinant()) <= CMP_EPSILON;
+ }
+
+public:
+ struct OutputSimplex {
+ uint32_t points[4];
+ };
+
+ static Vector<OutputSimplex> tetrahedralize(const Vector<Vector3> &p_points) {
+
+ uint32_t point_count = p_points.size();
+ Vector3 *points = (Vector3 *)memalloc(sizeof(Vector3) * (point_count + 4));
+
+ {
+ const Vector3 *src_points = p_points.ptr();
+ AABB rect;
+ for (uint32_t i = 0; i < point_count; i++) {
+ Vector3 point = src_points[i];
+ if (i == 0) {
+ rect.position = point;
+ } else {
+ rect.expand_to(point);
+ }
+ points[i] = point;
+ }
+
+ for (uint32_t i = 0; i < point_count; i++) {
+ points[i] = (points[i] - rect.position) / rect.size;
+ }
+
+ float delta_max = Math::sqrt(2.0) * 20.0;
+ Vector3 center = Vector3(0.5, 0.5, 0.5);
+
+ // any simplex that contains everything is good
+ points[point_count + 0] = center + Vector3(0, 1, 0) * delta_max;
+ points[point_count + 1] = center + Vector3(0, -1, 1) * delta_max;
+ points[point_count + 2] = center + Vector3(1, -1, -1) * delta_max;
+ points[point_count + 3] = center + Vector3(-1, -1, -1) * delta_max;
+ }
+
+ List<Simplex *> acceleration_grid[ACCEL_GRID_SIZE][ACCEL_GRID_SIZE][ACCEL_GRID_SIZE];
+
+ List<Simplex *> simplex_list;
+ {
+ //create root simplex
+ Simplex *root = memnew(Simplex(point_count + 0, point_count + 1, point_count + 2, point_count + 3));
+ root->SE = simplex_list.push_back(root);
+
+ for (uint32_t i = 0; i < ACCEL_GRID_SIZE; i++) {
+ for (uint32_t j = 0; j < ACCEL_GRID_SIZE; j++) {
+ for (uint32_t k = 0; k < ACCEL_GRID_SIZE; k++) {
+ GridPos gp;
+ gp.E = acceleration_grid[i][j][k].push_back(root);
+ gp.pos = Vector3i(i, j, k);
+ root->grid_positions.push_back(gp);
+ }
+ }
+ }
+
+ circum_sphere_compute(points, root);
+ }
+
+ OAHashMap<Triangle, uint32_t, TriangleHasher> triangles_inserted;
+ LocalVector<Triangle> triangles;
+
+ for (uint32_t i = 0; i < point_count; i++) {
+
+ bool unique = true;
+ for (uint32_t j = i + 1; j < point_count; j++) {
+ if (points[i].is_equal_approx(points[j])) {
+ unique = false;
+ break;
+ }
+ }
+ if (!unique) {
+ continue;
+ }
+
+ Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE);
+ grid_pos.x = CLAMP(grid_pos.x, 0, ACCEL_GRID_SIZE - 1);
+ grid_pos.y = CLAMP(grid_pos.y, 0, ACCEL_GRID_SIZE - 1);
+ grid_pos.z = CLAMP(grid_pos.z, 0, ACCEL_GRID_SIZE - 1);
+
+ for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) {
+ List<Simplex *>::Element *N = E->next(); //may be deleted
+
+ Simplex *simplex = E->get();
+
+ if (simplex_contains(points, *simplex, i)) {
+
+ static const uint32_t triangle_order[4][3] = {
+ { 0, 1, 2 },
+ { 0, 1, 3 },
+ { 0, 2, 3 },
+ { 1, 2, 3 },
+ };
+
+ for (uint32_t k = 0; k < 4; k++) {
+ Triangle t = Triangle(simplex->points[triangle_order[k][0]], simplex->points[triangle_order[k][1]], simplex->points[triangle_order[k][2]]);
+ uint32_t *p = triangles_inserted.lookup_ptr(t);
+ if (p) {
+ triangles[*p].bad = true;
+ } else {
+ triangles_inserted.insert(t, triangles.size());
+ triangles.push_back(t);
+ }
+ }
+
+ //remove simplex and continue
+ simplex_list.erase(simplex->SE);
+
+ for (uint32_t k = 0; k < simplex->grid_positions.size(); k++) {
+ Vector3i p = simplex->grid_positions[k].pos;
+ acceleration_grid[p.x][p.y][p.z].erase(simplex->grid_positions[k].E);
+ }
+ memdelete(simplex);
+ }
+ E = N;
+ }
+
+ uint32_t good_triangles = 0;
+ for (uint32_t j = 0; j < triangles.size(); j++) {
+
+ if (triangles[j].bad) {
+ continue;
+ }
+ Simplex *new_simplex = memnew(Simplex(triangles[j].triangle[0], triangles[j].triangle[1], triangles[j].triangle[2], i));
+ circum_sphere_compute(points, new_simplex);
+ new_simplex->SE = simplex_list.push_back(new_simplex);
+ {
+ Vector3 center;
+ center.x = double(new_simplex->circum_center_x);
+ center.y = double(new_simplex->circum_center_y);
+ center.z = double(new_simplex->circum_center_z);
+
+ float radius2 = Math::sqrt(double(new_simplex->circum_r2));
+ radius2 += 0.0001; //
+ Vector3 extents = Vector3(radius2, radius2, radius2);
+ Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE);
+ Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE);
+ from.x = CLAMP(from.x, 0, ACCEL_GRID_SIZE - 1);
+ from.y = CLAMP(from.y, 0, ACCEL_GRID_SIZE - 1);
+ from.z = CLAMP(from.z, 0, ACCEL_GRID_SIZE - 1);
+ to.x = CLAMP(to.x, 0, ACCEL_GRID_SIZE - 1);
+ to.y = CLAMP(to.y, 0, ACCEL_GRID_SIZE - 1);
+ to.z = CLAMP(to.z, 0, ACCEL_GRID_SIZE - 1);
+
+ for (int32_t x = from.x; x <= to.x; x++) {
+ for (int32_t y = from.y; y <= to.y; y++) {
+ for (int32_t z = from.z; z <= to.z; z++) {
+ GridPos gp;
+ gp.pos = Vector3(x, y, z);
+ gp.E = acceleration_grid[x][y][z].push_back(new_simplex);
+ new_simplex->grid_positions.push_back(gp);
+ }
+ }
+ }
+ }
+
+ good_triangles++;
+ }
+
+ //print_line("at point " + itos(i) + "/" + itos(point_count) + " simplices added " + itos(good_triangles) + "/" + itos(simplex_list.size()) + " - triangles: " + itos(triangles.size()));
+ triangles.clear();
+ triangles_inserted.clear();
+ }
+
+ //print_line("end with simplices: " + itos(simplex_list.size()));
+ Vector<OutputSimplex> ret_simplices;
+ ret_simplices.resize(simplex_list.size());
+ OutputSimplex *ret_simplicesw = ret_simplices.ptrw();
+ uint32_t simplices_written = 0;
+
+ for (List<Simplex *>::Element *E = simplex_list.front(); E; E = E->next()) {
+ Simplex *simplex = E->get();
+ bool invalid = false;
+ for (int j = 0; j < 4; j++) {
+ if (simplex->points[j] >= point_count) {
+ invalid = true;
+ break;
+ }
+ }
+ if (invalid || simplex_is_coplanar(points, *simplex)) {
+ memdelete(simplex);
+ continue;
+ }
+
+ ret_simplicesw[simplices_written].points[0] = simplex->points[0];
+ ret_simplicesw[simplices_written].points[1] = simplex->points[1];
+ ret_simplicesw[simplices_written].points[2] = simplex->points[2];
+ ret_simplicesw[simplices_written].points[3] = simplex->points[3];
+ simplices_written++;
+ memdelete(simplex);
+ }
+
+ ret_simplices.resize(simplices_written);
+
+ memfree(points);
+
+ return ret_simplices;
+ }
+};
+
+#endif // DELAUNAY_3D_H
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index e556eb3b9c..b0a46036f9 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -31,8 +31,11 @@
#include "geometry.h"
#include "core/print_string.h"
+
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/triangulator.h"
+#define STB_RECT_PACK_IMPLEMENTATION
+#include "thirdparty/misc/stb_rect_pack.h"
#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON.
@@ -1242,3 +1245,195 @@ Vector<Vector3> Geometry::compute_convex_mesh_points(const Plane *p_planes, int
return points;
}
+
+Vector<Point2i> Geometry::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) {
+
+ Vector<stbrp_node> nodes;
+ nodes.resize(p_atlas_size.width);
+
+ stbrp_context context;
+ stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
+
+ Vector<stbrp_rect> rects;
+ rects.resize(p_sizes.size());
+
+ for (int i = 0; i < p_sizes.size(); i++) {
+ rects.write[i].id = 0;
+ rects.write[i].w = p_sizes[i].width;
+ rects.write[i].h = p_sizes[i].height;
+ rects.write[i].x = 0;
+ rects.write[i].y = 0;
+ rects.write[i].was_packed = 0;
+ }
+
+ int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size());
+ if (res == 0) { //pack failed
+ return Vector<Point2i>();
+ }
+
+ Vector<Point2i> ret;
+ ret.resize(p_sizes.size());
+
+ for (int i = 0; i < p_sizes.size(); i++) {
+ Point2i r(rects[i].x, rects[i].y);
+ ret.write[i] = r;
+ }
+
+ return ret;
+}
+
+Vector<Vector3i> Geometry::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) {
+
+ Vector<stbrp_node> nodes;
+ nodes.resize(p_atlas_size.width);
+ zeromem(nodes.ptrw(), sizeof(stbrp_node) * nodes.size());
+
+ stbrp_context context;
+ stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
+
+ Vector<stbrp_rect> rects;
+ rects.resize(p_sizes.size());
+
+ for (int i = 0; i < p_sizes.size(); i++) {
+ rects.write[i].id = i;
+ rects.write[i].w = p_sizes[i].width;
+ rects.write[i].h = p_sizes[i].height;
+ rects.write[i].x = 0;
+ rects.write[i].y = 0;
+ rects.write[i].was_packed = 0;
+ }
+
+ stbrp_pack_rects(&context, rects.ptrw(), rects.size());
+
+ Vector<Vector3i> ret;
+ ret.resize(p_sizes.size());
+
+ for (int i = 0; i < p_sizes.size(); i++) {
+ ret.write[rects[i].id] = Vector3i(rects[i].x, rects[i].y, rects[i].was_packed != 0 ? 1 : 0);
+ }
+
+ return ret;
+}
+
+#define square(m_s) ((m_s) * (m_s))
+#define INF 1e20
+
+/* dt of 1d function using squared distance */
+static void edt(float *f, int stride, int n) {
+
+ float *d = (float *)alloca(sizeof(float) * n + sizeof(int) * n + sizeof(float) * (n + 1));
+ int *v = (int *)&(d[n]);
+ float *z = (float *)&v[n];
+
+ int k = 0;
+ v[0] = 0;
+ z[0] = -INF;
+ z[1] = +INF;
+ for (int q = 1; q <= n - 1; q++) {
+ float s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]);
+ while (s <= z[k]) {
+ k--;
+ s = ((f[q * stride] + square(q)) - (f[v[k] * stride] + square(v[k]))) / (2 * q - 2 * v[k]);
+ }
+ k++;
+ v[k] = q;
+
+ z[k] = s;
+ z[k + 1] = +INF;
+ }
+
+ k = 0;
+ for (int q = 0; q <= n - 1; q++) {
+ while (z[k + 1] < q)
+ k++;
+ d[q] = square(q - v[k]) + f[v[k] * stride];
+ }
+
+ for (int i = 0; i < n; i++) {
+ f[i * stride] = d[i];
+ }
+}
+
+#undef square
+
+Vector<uint32_t> Geometry::generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative) {
+
+ uint32_t float_count = p_size.x * p_size.y * p_size.z;
+
+ ERR_FAIL_COND_V((uint32_t)p_voxels.size() != float_count, Vector<uint32_t>());
+
+ float *work_memory = memnew_arr(float, float_count);
+ for (uint32_t i = 0; i < float_count; i++) {
+ work_memory[i] = INF;
+ }
+
+ uint32_t y_mult = p_size.x;
+ uint32_t z_mult = y_mult * p_size.y;
+
+ //plot solid cells
+ {
+ const bool *voxr = p_voxels.ptr();
+ for (uint32_t i = 0; i < float_count; i++) {
+
+ bool plot = voxr[i];
+ if (p_negative) {
+ plot = !plot;
+ }
+ if (plot) {
+ work_memory[i] = 0;
+ }
+ }
+ }
+
+ //process in each direction
+
+ //xy->z
+
+ for (int i = 0; i < p_size.x; i++) {
+ for (int j = 0; j < p_size.y; j++) {
+ edt(&work_memory[i + j * y_mult], z_mult, p_size.z);
+ }
+ }
+
+ //xz->y
+
+ for (int i = 0; i < p_size.x; i++) {
+ for (int j = 0; j < p_size.z; j++) {
+ edt(&work_memory[i + j * z_mult], y_mult, p_size.y);
+ }
+ }
+
+ //yz->x
+ for (int i = 0; i < p_size.y; i++) {
+ for (int j = 0; j < p_size.z; j++) {
+ edt(&work_memory[i * y_mult + j * z_mult], 1, p_size.x);
+ }
+ }
+
+ Vector<uint32_t> ret;
+ ret.resize(float_count);
+ {
+ uint32_t *w = ret.ptrw();
+ for (uint32_t i = 0; i < float_count; i++) {
+ w[i] = uint32_t(Math::sqrt(work_memory[i]));
+ }
+ }
+
+ return ret;
+}
+
+Vector<int8_t> Geometry::generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative) {
+ ERR_FAIL_COND_V(p_positive.size() != p_negative.size(), Vector<int8_t>());
+ Vector<int8_t> sdf8;
+ int s = p_positive.size();
+ sdf8.resize(s);
+
+ const uint32_t *rpos = p_positive.ptr();
+ const uint32_t *rneg = p_negative.ptr();
+ int8_t *wsdf = sdf8.ptrw();
+ for (int i = 0; i < s; i++) {
+ int32_t diff = int32_t(rpos[i]) - int32_t(rneg[i]);
+ wsdf[i] = CLAMP(diff, -128, 127);
+ }
+ return sdf8;
+}
diff --git a/core/math/geometry.h b/core/math/geometry.h
index 3bbd1911ee..45c8558fac 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -31,13 +31,12 @@
#ifndef GEOMETRY_H
#define GEOMETRY_H
-#include "core/math/delaunay.h"
+#include "core/math/delaunay_2d.h"
#include "core/math/face3.h"
#include "core/math/rect2.h"
#include "core/math/triangulate.h"
#include "core/math/vector3.h"
#include "core/object.h"
-
#include "core/print_string.h"
#include "core/vector.h"
@@ -1024,6 +1023,249 @@ public:
static Vector<Vector3> compute_convex_mesh_points(const Plane *p_planes, int p_plane_count);
+#define FINDMINMAX(x0, x1, x2, min, max) \
+ min = max = x0; \
+ if (x1 < min) \
+ min = x1; \
+ if (x1 > max) \
+ max = x1; \
+ if (x2 < min) \
+ min = x2; \
+ if (x2 > max) \
+ max = x2;
+
+ _FORCE_INLINE_ static bool planeBoxOverlap(Vector3 normal, float d, Vector3 maxbox) {
+ int q;
+ Vector3 vmin, vmax;
+ for (q = 0; q <= 2; q++) {
+ if (normal[q] > 0.0f) {
+ vmin[q] = -maxbox[q];
+ vmax[q] = maxbox[q];
+ } else {
+ vmin[q] = maxbox[q];
+ vmax[q] = -maxbox[q];
+ }
+ }
+ if (normal.dot(vmin) + d > 0.0f)
+ return false;
+ if (normal.dot(vmax) + d >= 0.0f)
+ return true;
+
+ return false;
+ }
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb) \
+ p0 = a * v0.y - b * v0.z; \
+ p2 = a * v2.y - b * v2.z; \
+ if (p0 < p2) { \
+ min = p0; \
+ max = p2; \
+ } else { \
+ min = p2; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if (min > rad || max < -rad) \
+ return false;
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ p0 = a * v0.y - b * v0.z; \
+ p1 = a * v1.y - b * v1.z; \
+ if (p0 < p1) { \
+ min = p0; \
+ max = p1; \
+ } else { \
+ min = p1; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if (min > rad || max < -rad) \
+ return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb) \
+ p0 = -a * v0.x + b * v0.z; \
+ p2 = -a * v2.x + b * v2.z; \
+ if (p0 < p2) { \
+ min = p0; \
+ max = p2; \
+ } else { \
+ min = p2; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if (min > rad || max < -rad) \
+ return false;
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ p0 = -a * v0.x + b * v0.z; \
+ p1 = -a * v1.x + b * v1.z; \
+ if (p0 < p1) { \
+ min = p0; \
+ max = p1; \
+ } else { \
+ min = p1; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if (min > rad || max < -rad) \
+ return false;
+
+ /*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb) \
+ p1 = a * v1.x - b * v1.y; \
+ p2 = a * v2.x - b * v2.y; \
+ if (p2 < p1) { \
+ min = p2; \
+ max = p1; \
+ } else { \
+ min = p1; \
+ max = p2; \
+ } \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if (min > rad || max < -rad) \
+ return false;
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ p0 = a * v0.x - b * v0.y; \
+ p1 = a * v1.x - b * v1.y; \
+ if (p0 < p1) { \
+ min = p0; \
+ max = p1; \
+ } else { \
+ min = p1; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if (min > rad || max < -rad) \
+ return false;
+
+ _FORCE_INLINE_ static bool triangle_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalfsize, const Vector3 *triverts) {
+
+ /* use separating axis theorem to test overlap between triangle and box */
+ /* need to test for overlap in these directions: */
+ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+ /* we do not even need to test these) */
+ /* 2) normal of the triangle */
+ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
+ /* this gives 3x3=9 more tests */
+ Vector3 v0, v1, v2;
+ float min, max, d, p0, p1, p2, rad, fex, fey, fez;
+ Vector3 normal, e0, e1, e2;
+
+ /* This is the fastest branch on Sun */
+ /* move everything so that the boxcenter is in (0,0,0) */
+
+ v0 = triverts[0] - boxcenter;
+ v1 = triverts[1] - boxcenter;
+ v2 = triverts[2] - boxcenter;
+
+ /* compute triangle edges */
+ e0 = v1 - v0; /* tri edge 0 */
+ e1 = v2 - v1; /* tri edge 1 */
+ e2 = v0 - v2; /* tri edge 2 */
+
+ /* Bullet 3: */
+ /* test the 9 tests first (this was faster) */
+ fex = Math::abs(e0.x);
+ fey = Math::abs(e0.y);
+ fez = Math::abs(e0.z);
+ AXISTEST_X01(e0.z, e0.y, fez, fey);
+ AXISTEST_Y02(e0.z, e0.x, fez, fex);
+ AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+ fex = Math::abs(e1.x);
+ fey = Math::abs(e1.y);
+ fez = Math::abs(e1.z);
+ AXISTEST_X01(e1.z, e1.y, fez, fey);
+ AXISTEST_Y02(e1.z, e1.x, fez, fex);
+ AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+ fex = Math::abs(e2.x);
+ fey = Math::abs(e2.y);
+ fez = Math::abs(e2.z);
+ AXISTEST_X2(e2.z, e2.y, fez, fey);
+ AXISTEST_Y1(e2.z, e2.x, fez, fex);
+ AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+ /* Bullet 1: */
+ /* first test overlap in the {x,y,z}-directions */
+ /* find min, max of the triangle each direction, and test for overlap in */
+ /* that direction -- this is equivalent to testing a minimal AABB around */
+ /* the triangle against the AABB */
+
+ /* test in X-direction */
+ FINDMINMAX(v0.x, v1.x, v2.x, min, max);
+ if (min > boxhalfsize.x || max < -boxhalfsize.x)
+ return false;
+
+ /* test in Y-direction */
+ FINDMINMAX(v0.y, v1.y, v2.y, min, max);
+ if (min > boxhalfsize.y || max < -boxhalfsize.y)
+ return false;
+
+ /* test in Z-direction */
+ FINDMINMAX(v0.z, v1.z, v2.z, min, max);
+ if (min > boxhalfsize.z || max < -boxhalfsize.z)
+ return false;
+
+ /* Bullet 2: */
+ /* test if the box intersects the plane of the triangle */
+ /* compute plane equation of triangle: normal*x+d=0 */
+ normal = e0.cross(e1);
+ d = -normal.dot(v0); /* plane eq: normal.x+d=0 */
+ return planeBoxOverlap(normal, d, boxhalfsize); /* if true, box and triangle overlaps */
+ }
+
+ static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size);
+ static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size);
+
+ static Vector<uint32_t> generate_edf(const Vector<bool> &p_voxels, const Vector3i &p_size, bool p_negative);
+ static Vector<int8_t> generate_sdf8(const Vector<uint32_t> &p_positive, const Vector<uint32_t> &p_negative);
+
+ static Vector3 triangle_get_barycentric_coords(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector3 &p_pos) {
+ Vector3 v0 = p_b - p_a;
+ Vector3 v1 = p_c - p_a;
+ Vector3 v2 = p_pos - p_a;
+
+ float d00 = v0.dot(v0);
+ float d01 = v0.dot(v1);
+ float d11 = v1.dot(v1);
+ float d20 = v2.dot(v0);
+ float d21 = v2.dot(v1);
+ float denom = (d00 * d11 - d01 * d01);
+ if (denom == 0) {
+ return Vector3(); //invalid triangle, return empty
+ }
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+ return Vector3(u, v, w);
+ }
+
+ static Color tetrahedron_get_barycentric_coords(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, const Vector3 &p_d, const Vector3 &p_pos) {
+ Vector3 vap = p_pos - p_a;
+ Vector3 vbp = p_pos - p_b;
+
+ Vector3 vab = p_b - p_a;
+ Vector3 vac = p_c - p_a;
+ Vector3 vad = p_d - p_a;
+
+ Vector3 vbc = p_c - p_b;
+ Vector3 vbd = p_d - p_b;
+ // ScTP computes the scalar triple product
+#define STP(m_a, m_b, m_c) ((m_a).dot((m_b).cross((m_c))))
+ float va6 = STP(vbp, vbd, vbc);
+ float vb6 = STP(vap, vac, vad);
+ float vc6 = STP(vap, vad, vab);
+ float vd6 = STP(vap, vab, vac);
+ float v6 = 1 / STP(vab, vac, vad);
+ return Color(va6 * v6, vb6 * v6, vc6 * v6, vd6 * v6);
+#undef STP
+ }
+
private:
static Vector<Vector<Point2>> _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
static Vector<Vector<Point2>> _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index a3818698bc..26ac0aac47 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -153,6 +153,10 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
/* misc */
+bool Plane::is_equal_approx_any_side(const Plane &p_plane) const {
+ return (normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d)) || (normal.is_equal_approx(-p_plane.normal) && Math::is_equal_approx(d, -p_plane.d));
+}
+
bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
diff --git a/core/math/plane.h b/core/math/plane.h
index 771c8fc705..d4f23ff2b6 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -69,6 +69,7 @@ public:
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
+ bool is_equal_approx_any_side(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 8829181489..12522281d0 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -1037,7 +1037,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_SPACE);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_BUTTON_0);
+ joyb->set_button_index(JOY_BUTTON_A);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_accept", action);
@@ -1050,7 +1050,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_SPACE);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_BUTTON_3);
+ joyb->set_button_index(JOY_BUTTON_Y);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_select", action);
@@ -1063,7 +1063,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_ESCAPE);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_BUTTON_1);
+ joyb->set_button_index(JOY_BUTTON_B);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_cancel", action);
@@ -1097,7 +1097,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_LEFT);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_DPAD_LEFT);
+ joyb->set_button_index(JOY_BUTTON_DPAD_LEFT);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_left", action);
@@ -1110,7 +1110,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_RIGHT);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_DPAD_RIGHT);
+ joyb->set_button_index(JOY_BUTTON_DPAD_RIGHT);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_right", action);
@@ -1123,7 +1123,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_UP);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_DPAD_UP);
+ joyb->set_button_index(JOY_BUTTON_DPAD_UP);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_up", action);
@@ -1136,7 +1136,7 @@ ProjectSettings::ProjectSettings() {
key->set_keycode(KEY_DOWN);
events.push_back(key);
joyb.instance();
- joyb->set_button_index(JOY_DPAD_DOWN);
+ joyb->set_button_index(JOY_BUTTON_DPAD_DOWN);
events.push_back(joyb);
action["events"] = events;
GLOBAL_DEF("input/ui_down", action);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 23f549be1a..4cf7e45205 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -233,8 +233,8 @@ void register_core_settings() {
GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16));
ProjectSettings::get_singleton()->set_custom_property_info("network/limits/packet_peer_stream/max_buffer_po2", PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "0,64,1,or_greater"));
- GLOBAL_DEF("network/ssl/certificates", "");
- ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificates", PropertyInfo(Variant::STRING, "network/ssl/certificates", PROPERTY_HINT_FILE, "*.crt"));
+ GLOBAL_DEF("network/ssl/certificate_bundle_override", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("network/ssl/certificate_bundle_override", PropertyInfo(Variant::STRING, "network/ssl/certificate_bundle_override", PROPERTY_HINT_FILE, "*.crt"));
}
void register_core_singletons() {
diff --git a/core/ustring.cpp b/core/ustring.cpp
index beafb3018d..3e8a1ddbe3 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -548,8 +548,8 @@ signed char String::naturalnocasecmp_to(const String &p_str) const {
return -1;
/* Compare the numbers */
- this_int = to_int(this_str);
- that_int = to_int(that_str);
+ this_int = to_int(this_str, -1, true);
+ that_int = to_int(that_str, -1, true);
if (this_int < that_int)
return -1;
@@ -2138,7 +2138,7 @@ double String::to_double(const CharType *p_str, const CharType **r_end) {
return built_in_strtod<CharType>(p_str, (CharType **)r_end);
}
-int64_t String::to_int(const CharType *p_str, int p_len) {
+int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) {
if (p_len == 0 || !p_str[0])
return 0;
@@ -2182,7 +2182,15 @@ int64_t String::to_int(const CharType *p_str, int p_len) {
while (*str && str != limit) {
number += *(str++);
}
- ERR_FAIL_V_MSG(sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + number + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ if (p_clamp) {
+ if (sign == 1) {
+ return INT64_MAX;
+ } else {
+ return INT64_MIN;
+ }
+ } else {
+ ERR_FAIL_V_MSG(sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + number + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ }
}
integer *= 10;
integer += c - '0';
diff --git a/core/ustring.h b/core/ustring.h
index ee7e3b1e16..15bc2b323c 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -254,7 +254,7 @@ public:
static int to_int(const char *p_str, int p_len = -1);
static double to_double(const char *p_str);
static double to_double(const CharType *p_str, const CharType **r_end = nullptr);
- static int64_t to_int(const CharType *p_str, int p_len = -1);
+ static int64_t to_int(const CharType *p_str, int p_len = -1, bool p_clamp = false);
String capitalize() const;
String camelcase_to_underscore(bool lowercase = true) const;
diff --git a/core/vector.h b/core/vector.h
index b2133f800b..74e0ab91c0 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -39,6 +39,7 @@
#include "core/cowdata.h"
#include "core/error_macros.h"
+#include "core/os/copymem.h"
#include "core/os/memory.h"
#include "core/sort_array.h"
@@ -125,6 +126,13 @@ public:
return *this;
}
+ Vector<uint8_t> to_byte_array() const {
+ Vector<uint8_t> ret;
+ ret.resize(size() * sizeof(T));
+ copymem(ret.ptrw(), ptr(), sizeof(T) * size());
+ return ret;
+ }
+
Vector<T> subarray(int p_from, int p_to) const {
if (p_from < 0) {