diff options
42 files changed, 553 insertions, 161 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index f17d7372e2..f6828ea76a 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -225,8 +225,12 @@ int _OS::get_video_driver_count() const { return OS::get_singleton()->get_video_driver_count(); } -String _OS::get_video_driver_name(int p_driver) const { - return OS::get_singleton()->get_video_driver_name(p_driver); +String _OS::get_video_driver_name(VideoDriver p_driver) const { + return OS::get_singleton()->get_video_driver_name((int)p_driver); +} + +_OS::VideoDriver _OS::get_current_video_driver() const { + return (VideoDriver)OS::get_singleton()->get_current_video_driver(); } int _OS::get_audio_driver_count() const { @@ -1108,6 +1112,8 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_video_driver_count"), &_OS::get_video_driver_count); ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name); + ClassDB::bind_method(D_METHOD("get_current_video_driver"), &_OS::get_current_video_driver); + ClassDB::bind_method(D_METHOD("get_audio_driver_count"), &_OS::get_audio_driver_count); ClassDB::bind_method(D_METHOD("get_audio_driver_name", "driver"), &_OS::get_audio_driver_name); ClassDB::bind_method(D_METHOD("get_connected_midi_inputs"), &_OS::get_connected_midi_inputs); @@ -1276,6 +1282,9 @@ void _OS::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "window_position"), "set_window_position", "get_window_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "window_size"), "set_window_size", "get_window_size"); + BIND_ENUM_CONSTANT(VIDEO_DRIVER_GLES2); + BIND_ENUM_CONSTANT(VIDEO_DRIVER_GLES3); + BIND_ENUM_CONSTANT(DAY_SUNDAY); BIND_ENUM_CONSTANT(DAY_MONDAY); BIND_ENUM_CONSTANT(DAY_TUESDAY); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 1c8b985d73..f3bc4644d8 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -103,6 +103,11 @@ protected: static _OS *singleton; public: + enum VideoDriver { + VIDEO_DRIVER_GLES3, + VIDEO_DRIVER_GLES2, + }; + enum PowerState { POWERSTATE_UNKNOWN, /**< cannot determine power status */ POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */ @@ -152,7 +157,8 @@ public: Array get_fullscreen_mode_list(int p_screen = 0) const; virtual int get_video_driver_count() const; - virtual String get_video_driver_name(int p_driver) const; + virtual String get_video_driver_name(VideoDriver p_driver) const; + virtual VideoDriver get_current_video_driver() const; virtual int get_audio_driver_count() const; virtual String get_audio_driver_name(int p_driver) const; @@ -355,6 +361,7 @@ public: _OS(); }; +VARIANT_ENUM_CAST(_OS::VideoDriver); VARIANT_ENUM_CAST(_OS::PowerState); VARIANT_ENUM_CAST(_OS::Weekday); VARIANT_ENUM_CAST(_OS::Month); diff --git a/core/command_queue_mt.cpp b/core/command_queue_mt.cpp index 36d4b0a32f..2bdf02295c 100644 --- a/core/command_queue_mt.cpp +++ b/core/command_queue_mt.cpp @@ -97,7 +97,7 @@ tryagain: return false; } - dealloc_ptr += (size >> 1) + sizeof(uint32_t); + dealloc_ptr += (size >> 1) + 8; return true; } @@ -107,6 +107,7 @@ CommandQueueMT::CommandQueueMT(bool p_sync) { write_ptr = 0; dealloc_ptr = 0; mutex = Mutex::create(); + command_mem = (uint8_t *)memalloc(COMMAND_MEM_SIZE); for (int i = 0; i < SYNC_SEMAPHORES; i++) { @@ -128,4 +129,5 @@ CommandQueueMT::~CommandQueueMT() { memdelete(sync_sems[i].sem); } + memfree(command_mem); } diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h index 3fd660a3db..59eabd8786 100644 --- a/core/command_queue_mt.h +++ b/core/command_queue_mt.h @@ -36,6 +36,7 @@ #include "core/os/semaphore.h" #include "core/simple_type.h" #include "core/typedefs.h" + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -254,6 +255,7 @@ unlock(); \ if (sync) sync->post(); \ ss->sem->wait(); \ + ss->in_use = false; \ } #define CMD_SYNC_TYPE(N) CommandSync##N<T, M COMMA(N) COMMA_SEP_LIST(TYPE_ARG, N)> @@ -270,6 +272,7 @@ unlock(); \ if (sync) sync->post(); \ ss->sem->wait(); \ + ss->in_use = false; \ } #define MAX_CMD_PARAMS 13 @@ -295,7 +298,6 @@ class CommandQueueMT { virtual void post() { sync_sem->sem->post(); - sync_sem->in_use = false; } }; @@ -318,7 +320,7 @@ class CommandQueueMT { SYNC_SEMAPHORES = 8 }; - uint8_t command_mem[COMMAND_MEM_SIZE]; + uint8_t *command_mem; uint32_t read_ptr; uint32_t write_ptr; uint32_t dealloc_ptr; @@ -330,7 +332,7 @@ class CommandQueueMT { T *allocate() { // alloc size is size+T+safeguard - uint32_t alloc_size = sizeof(T) + sizeof(uint32_t); + uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)) + 8; tryagain: @@ -360,7 +362,7 @@ class CommandQueueMT { } // if this happens, it's a bug - ERR_FAIL_COND_V((COMMAND_MEM_SIZE - write_ptr) < sizeof(uint32_t), NULL); + ERR_FAIL_COND_V((COMMAND_MEM_SIZE - write_ptr) < 8, NULL); // zero means, wrap to beginning uint32_t *p = (uint32_t *)&command_mem[write_ptr]; @@ -372,12 +374,13 @@ class CommandQueueMT { // Allocate the size and the 'in use' bit. // First bit used to mark if command is still in use (1) // or if it has been destroyed and can be deallocated (0). + uint32_t size = (sizeof(T) + 8 - 1) & ~(8 - 1); uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = (sizeof(T) << 1) | 1; - write_ptr += sizeof(uint32_t); + *p = (size << 1) | 1; + write_ptr += 8; // allocate the command T *cmd = memnew_placement(&command_mem[write_ptr], T); - write_ptr += sizeof(T); + write_ptr += size; return cmd; } @@ -415,7 +418,7 @@ class CommandQueueMT { goto tryagain; } - read_ptr += sizeof(uint32_t); + read_ptr += 8; CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index b3fd814870..b25b1934ff 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -426,11 +426,10 @@ Error HTTPClient::poll() { response_headers.clear(); response_num = RESPONSE_OK; - // Per the HTTP 1.1 spec, keep-alive is the default, but in practice - // it's safe to assume it only if the explicit header is found, allowing - // to handle body-up-to-EOF responses on naive servers; that's what Curl - // and browsers do - bool keep_alive = false; + // Per the HTTP 1.1 spec, keep-alive is the default. + // Not following that specification breaks standard implemetations. + // Broken web servers should be fixed. + bool keep_alive = true; for (int i = 0; i < responses.size(); i++) { @@ -447,8 +446,8 @@ Error HTTPClient::poll() { if (encoding == "chunked") { chunked = true; } - } else if (s.begins_with("connection: keep-alive")) { - keep_alive = true; + } else if (s.begins_with("connection: close")) { + keep_alive = false; } if (i == 0 && responses[i].begins_with("HTTP")) { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 4aa002e9a2..10a32bae41 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -55,7 +55,7 @@ Error ResourceInteractiveLoader::wait() { ResourceInteractiveLoader::~ResourceInteractiveLoader() { if (path_loading != String()) { - ResourceLoader::_remove_from_loading_map(path_loading); + ResourceLoader::_remove_from_loading_map_and_thread(path_loading, path_loading_thread); } } @@ -293,10 +293,14 @@ bool ResourceLoader::_add_to_loading_map(const String &p_path) { loading_map_mutex->lock(); } - if (loading_map.has(p_path)) { + LoadingMapKey key; + key.path = p_path; + key.thread = Thread::get_caller_id(); + + if (loading_map.has(key)) { success = false; } else { - loading_map[p_path] = true; + loading_map[key] = true; success = true; } @@ -312,7 +316,27 @@ void ResourceLoader::_remove_from_loading_map(const String &p_path) { loading_map_mutex->lock(); } - loading_map.erase(p_path); + LoadingMapKey key; + key.path = p_path; + key.thread = Thread::get_caller_id(); + + loading_map.erase(key); + + if (loading_map_mutex) { + loading_map_mutex->unlock(); + } +} + +void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread) { + if (loading_map_mutex) { + loading_map_mutex->lock(); + } + + LoadingMapKey key; + key.path = p_path; + key.thread = p_thread; + + loading_map.erase(key); if (loading_map_mutex) { loading_map_mutex->unlock(); @@ -471,6 +495,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ ril->resource = res_cached; ril->path_loading = local_path; + ril->path_loading_thread = Thread::get_caller_id(); return ril; } } @@ -499,6 +524,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ if (!p_no_cache) { ril->set_local_path(local_path); ril->path_loading = local_path; + ril->path_loading_thread = Thread::get_caller_id(); } if (xl_remapped) @@ -919,7 +945,7 @@ void ResourceLoader::remove_custom_loaders() { } Mutex *ResourceLoader::loading_map_mutex = NULL; -HashMap<String, int> ResourceLoader::loading_map; +HashMap<ResourceLoader::LoadingMapKey, int, ResourceLoader::LoadingMapKeyHasher> ResourceLoader::loading_map; void ResourceLoader::initialize() { #ifndef NO_THREADS @@ -929,9 +955,9 @@ void ResourceLoader::initialize() { void ResourceLoader::finalize() { #ifndef NO_THREADS - const String *K = NULL; + const LoadingMapKey *K = NULL; while ((K = loading_map.next(K))) { - ERR_PRINTS("Exited while resource is being loaded: " + *K); + ERR_PRINTS("Exited while resource is being loaded: " + K->path); } loading_map.clear(); memdelete(loading_map_mutex); diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 622b74a998..70eb1a3de0 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -31,8 +31,8 @@ #ifndef RESOURCE_LOADER_H #define RESOURCE_LOADER_H +#include "core/os/thread.h" #include "core/resource.h" - /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -42,6 +42,7 @@ class ResourceInteractiveLoader : public Reference { GDCLASS(ResourceInteractiveLoader, Reference); friend class ResourceLoader; String path_loading; + Thread::ID path_loading_thread; protected: static void _bind_methods(); @@ -121,10 +122,25 @@ class ResourceLoader { static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path); static Mutex *loading_map_mutex; - static HashMap<String, int> loading_map; + + //used to track paths being loaded in a thread, avoids cyclic recursion + struct LoadingMapKey { + String path; + Thread::ID thread; + bool operator==(const LoadingMapKey &p_key) const { + return (thread == p_key.thread && path == p_key.path); + } + }; + struct LoadingMapKeyHasher { + + static _FORCE_INLINE_ uint32_t hash(const LoadingMapKey &p_key) { return p_key.path.hash() + HashMapHasherDefault::hash(p_key.thread); } + }; + + static HashMap<LoadingMapKey, int, LoadingMapKeyHasher> loading_map; static bool _add_to_loading_map(const String &p_path); static void _remove_from_loading_map(const String &p_path); + static void _remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread); public: static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index ea0bfd88cc..629002ced6 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -242,8 +242,8 @@ public: static void randomize(); static uint32_t rand_from_seed(uint64_t *seed); static uint32_t rand(); - static _ALWAYS_INLINE_ double randf() { return (double)rand() / (double)Math::RANDOM_MAX; } - static _ALWAYS_INLINE_ float randd() { return (float)rand() / (float)Math::RANDOM_MAX; } + static _ALWAYS_INLINE_ double randd() { return (double)rand() / (double)Math::RANDOM_MAX; } + static _ALWAYS_INLINE_ float randf() { return (float)rand() / (float)Math::RANDOM_MAX; } static double random(double from, double to); static float random(float from, float to); diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 1e0e83c8d2..24ec8a1963 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -749,6 +749,15 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool * return match; } +bool InputEventJoypadButton::shortcut_match(const Ref<InputEvent> &p_event) const { + + Ref<InputEventJoypadButton> button = p_event; + if (button.is_null()) + return false; + + return button_index == button->button_index; +} + String InputEventJoypadButton::as_text() const { return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure)); @@ -950,11 +959,10 @@ bool InputEventAction::is_pressed() const { } bool InputEventAction::shortcut_match(const Ref<InputEvent> &p_event) const { - Ref<InputEventKey> event = p_event; - if (event.is_null()) + if (p_event.is_null()) return false; - return event->is_action(action); + return p_event->is_action(action); } bool InputEventAction::is_action(const StringName &p_action) const { diff --git a/core/os/input_event.h b/core/os/input_event.h index db31055b5f..a6a7012298 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -400,6 +400,7 @@ public: float get_pressure() const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; + virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml index 072eec800f..b56e5bf8e7 100644 --- a/doc/classes/@GDScript.xml +++ b/doc/classes/@GDScript.xml @@ -809,7 +809,7 @@ <argument index="1" name="to" type="float"> </argument> <description> - Random range, any floating point value between [code]from[/code] and [code]to[/code]. + Random range, any floating point value in the interval [[code]from[/code], [code]to[/code]]. [codeblock] prints(rand_range(0, 1), rand_range(0, 1)) # prints 0.135591 0.405263 [/codeblock] @@ -828,7 +828,7 @@ <return type="float"> </return> <description> - Returns a random floating point value between 0 and 1. + Returns a random floating point value on the interval [0, 1]. [codeblock] randf() # returns 0.375671 [/codeblock] @@ -838,7 +838,7 @@ <return type="int"> </return> <description> - Returns a random 32 bit integer. Use remainder to obtain a random value between 0 and N (where N is smaller than 2^32 -1). + Returns a random 32 bit integer. Use remainder to obtain a random value in the interval [0, N] (where N is smaller than 2^32 -1). [codeblock] randi() % 20 # returns random number between 0 and 19 randi() % 100 # returns random number between 0 and 99 diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index a7cae709a4..eaaa64d53d 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -648,6 +648,12 @@ The animation step value. </member> </members> + <signals> + <signal name="tracks_changed"> + <description> + </description> + </signal> + </signals> <constants> <constant name="TYPE_VALUE" value="0" enum="TrackType"> Value tracks set values in node properties, but only those which can be Interpolated. diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 7986461840..565e19c229 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -48,6 +48,14 @@ Return the transform of a specific instance. </description> </method> + <method name="get_instance_transform_2d" qualifiers="const"> + <return type="Transform2D"> + </return> + <argument index="0" name="instance" type="int"> + </argument> + <description> + </description> + </method> <method name="set_instance_color"> <return type="void"> </return> @@ -81,6 +89,16 @@ Set the transform for a specific instance. </description> </method> + <method name="set_instance_transform_2d"> + <return type="void"> + </return> + <argument index="0" name="instance" type="int"> + </argument> + <argument index="1" name="transform" type="Transform2D"> + </argument> + <description> + </description> + </method> </methods> <members> <member name="color_format" type="int" setter="set_color_format" getter="get_color_format" enum="MultiMesh.ColorFormat"> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index f6ad71b6e2..5e71ed094e 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -159,6 +159,13 @@ <description> </description> </method> + <method name="get_current_video_driver" qualifiers="const"> + <return type="int" enum="OS.VideoDriver"> + </return> + <description> + Returns the currently used video driver, using one of the values from [enum OS.VideoDriver]. + </description> + </method> <method name="get_date" qualifiers="const"> <return type="Dictionary"> </return> @@ -459,14 +466,16 @@ <return type="int"> </return> <description> + Returns the number of video drivers supported on the current platform. </description> </method> <method name="get_video_driver_name" qualifiers="const"> <return type="String"> </return> - <argument index="0" name="driver" type="int"> + <argument index="0" name="driver" type="int" enum="OS.VideoDriver"> </argument> <description> + Returns the name of the video driver matching the given [code]driver[/code] index. This index is a value from [enum OS.VideoDriver], and you can use [method get_current_video_driver] to get the current backend's index. </description> </method> <method name="get_virtual_keyboard_height"> @@ -806,6 +815,12 @@ </member> </members> <constants> + <constant name="VIDEO_DRIVER_GLES2" value="1" enum="VideoDriver"> + The GLES2 rendering backend. It uses OpenGL ES 2.0 on mobile devices, OpenGL 2.1 on desktop platforms and WebGL 1.0 on the web. + </constant> + <constant name="VIDEO_DRIVER_GLES3" value="0" enum="VideoDriver"> + The GLES3 rendering backend. It uses OpenGL ES 3.0 on mobile devices, OpenGL 3.3 on desktop platforms and WebGL 2.0 on the web. + </constant> <constant name="DAY_SUNDAY" value="0" enum="Weekday"> Sunday. </constant> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 09b9167149..0f795b4bf8 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -74,15 +74,15 @@ Return the ID of the item at index [code]idx[/code]. </description> </method> - <method name="get_item_index" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <description> - Return the index of the item with the given [code]id[/code]. - </description> - </method> + <method name="get_item_index" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + Return the index of the item with the given [code]id[/code]. + </description> + </method> <method name="get_item_metadata" qualifiers="const"> <return type="Variant"> </return> diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index 04285b62df..3c5bc25def 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -216,6 +216,8 @@ </theme_item> <theme_item name="tab_bg" type="StyleBox"> </theme_item> + <theme_item name="tab_disabled" type="StyleBox"> + </theme_item> <theme_item name="tab_fg" type="StyleBox"> </theme_item> <theme_item name="top_margin" type="int"> diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml index de57250d8b..b22d9d73da 100644 --- a/doc/classes/Tabs.xml +++ b/doc/classes/Tabs.xml @@ -279,6 +279,8 @@ </theme_item> <theme_item name="tab_bg" type="StyleBox"> </theme_item> + <theme_item name="tab_disabled" type="StyleBox"> + </theme_item> <theme_item name="tab_fg" type="StyleBox"> </theme_item> <theme_item name="top_margin" type="int"> diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index bbce2353ee..e9580ae0d1 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1042,35 +1042,43 @@ void CodeTextEditor::delete_lines() { } void CodeTextEditor::clone_lines_down() { + const int cursor_column = text_editor->cursor_get_column(); int from_line = text_editor->cursor_get_line(); int to_line = text_editor->cursor_get_line(); - int column = text_editor->cursor_get_column(); - + int from_column = 0; + int to_column = 0; + int cursor_new_line = to_line + 1; + int cursor_new_column = text_editor->cursor_get_column(); + String new_text = "\n" + text_editor->get_line(from_line); + bool selection_active = false; + + text_editor->cursor_set_column(text_editor->get_line(from_line).length()); if (text_editor->is_selection_active()) { + from_column = text_editor->get_selection_from_column(); + to_column = text_editor->get_selection_to_column(); + from_line = text_editor->get_selection_from_line(); to_line = text_editor->get_selection_to_line(); - column = text_editor->cursor_get_column(); + cursor_new_line = to_line + text_editor->cursor_get_line() - from_line; + cursor_new_column = to_column == cursor_column ? 2 * to_column - from_column : to_column; + new_text = text_editor->get_selection_text(); + selection_active = true; + + text_editor->cursor_set_line(to_line); + text_editor->cursor_set_column(to_column); } - int next_line = to_line + 1; - bool caret_at_start = text_editor->cursor_get_line() == from_line; text_editor->begin_complex_operation(); + for (int i = from_line; i <= to_line; i++) { text_editor->unfold_line(i); - text_editor->set_line(next_line - 1, text_editor->get_line(next_line - 1) + "\n"); - text_editor->set_line(next_line, text_editor->get_line(i)); - next_line++; - } - - if (caret_at_start) { - text_editor->cursor_set_line(to_line + 1); - } else { - text_editor->cursor_set_line(next_line - 1); } - - text_editor->cursor_set_column(column); - if (text_editor->is_selection_active()) { - text_editor->select(to_line + 1, text_editor->get_selection_from_column(), next_line - 1, text_editor->get_selection_to_column()); + text_editor->deselect(); + text_editor->insert_text_at_cursor(new_text); + text_editor->cursor_set_line(cursor_new_line); + text_editor->cursor_set_column(cursor_new_column); + if (selection_active) { + text_editor->select(to_line, to_column, 2 * to_line - from_line, 2 * to_column - from_column); } text_editor->end_complex_operation(); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 56bab440c9..614edda58c 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -115,8 +115,8 @@ void EditorPropertyMultilineText::_open_big_text() { add_child(big_text_dialog); } - big_text->set_text(text->get_text()); big_text_dialog->popup_centered_ratio(); + big_text->set_text(text->get_text()); } void EditorPropertyMultilineText::update_property() { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index ffbb4339df..3fe19c0b31 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -286,7 +286,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { } else if (preset == "Solarized (Dark)") { preset_accent_color = Color::html("#268bd2"); preset_base_color = Color::html("#073642"); - preset_contrast = 0.15; + preset_contrast = 0.23; } else if (preset == "Solarized (Light)") { preset_accent_color = Color::html("#268bd2"); preset_base_color = Color::html("#fdf6e3"); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 8f6f244e8f..82cd9e84dd 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -275,9 +275,30 @@ void AbstractPolygon2DEditor::_wip_close() { selected_point = Vertex(); } +void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_reason) { + + _polygon_editing_enabled = !p_disable; + + button_create->set_disabled(p_disable); + button_edit->set_disabled(p_disable); + button_delete->set_disabled(p_disable); + + if (p_disable) { + + button_create->set_tooltip(p_reason); + button_edit->set_tooltip(p_reason); + button_delete->set_tooltip(p_reason); + } else { + + button_create->set_tooltip(TTR("Create points.")); + button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point")); + button_delete->set_tooltip(TTR("Erase points.")); + } +} + bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { - if (!_get_node()) + if (!_get_node() || !_polygon_editing_enabled) return false; Ref<InputEventMouseButton> mb = p_event; @@ -297,12 +318,6 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) if (mb.is_valid()) { - String cant_edit = _why_cant_edit_polygon(); - if (cant_edit != String()) { - EditorNode::get_singleton()->show_warning(cant_edit); - return true; - } - Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); Vector2 gpoint = mb->get_position(); @@ -633,9 +648,8 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl void AbstractPolygon2DEditor::edit(Node *p_polygon) { - if (!canvas_item_editor) { + if (!canvas_item_editor) canvas_item_editor = CanvasItemEditor::get_singleton(); - } if (p_polygon) { @@ -654,7 +668,6 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) { selected_point = Vertex(); canvas_item_editor->update_viewport(); - } else { _set_node(NULL); @@ -784,24 +797,23 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi selected_point = Vertex(); edge_point = PosVertex(); + disable_polygon_editing(false, String()); + add_child(memnew(VSeparator)); button_create = memnew(ToolButton); add_child(button_create); button_create->connect("pressed", this, "_menu_option", varray(MODE_CREATE)); button_create->set_toggle_mode(true); - button_create->set_tooltip(TTR("Create points.")); button_edit = memnew(ToolButton); add_child(button_edit); button_edit->connect("pressed", this, "_menu_option", varray(MODE_EDIT)); button_edit->set_toggle_mode(true); - button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point")); button_delete = memnew(ToolButton); add_child(button_delete); button_delete->connect("pressed", this, "_menu_option", varray(MODE_DELETE)); button_delete->set_toggle_mode(true); - button_delete->set_tooltip(TTR("Erase points.")); create_resource = memnew(ConfirmationDialog); add_child(create_resource); diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index f10af4ee6e..97244fa4e9 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -81,6 +81,8 @@ class AbstractPolygon2DEditor : public HBoxContainer { bool wip_active; bool wip_destructive; + bool _polygon_editing_enabled; + CanvasItemEditor *canvas_item_editor; EditorNode *editor; Panel *panel; @@ -134,9 +136,9 @@ protected: virtual bool _has_resource() const; virtual void _create_resource(); - virtual String _why_cant_edit_polygon() const { return String(); } - public: + void disable_polygon_editing(bool p_disable, String p_reason); + bool forward_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index c68023ee9b..ab3936407b 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -1338,6 +1338,7 @@ void EditorAssetLibrary::_bind_methods() { EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { + requesting = REQUESTING_NONE; templates_only = p_templates_only; VBoxContainer *library_main = memnew(VBoxContainer); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 873bdd9e7f..b5d59dae99 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4559,6 +4559,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { snap_grid = true; snap_guides = true; snap_rotation = false; + snap_relative = false; snap_pixel = false; skeleton_show_bones = true; diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 28a17d0bef..33157bc88f 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -45,6 +45,7 @@ Node2D *Polygon2DEditor::_get_node() const { void Polygon2DEditor::_set_node(Node *p_polygon) { node = Object::cast_to<Polygon2D>(p_polygon); + _update_polygon_editing_state(); } Vector2 Polygon2DEditor::_get_offset(int p_idx) const { @@ -52,17 +53,8 @@ Vector2 Polygon2DEditor::_get_offset(int p_idx) const { return node->get_offset(); } -String Polygon2DEditor::_why_cant_edit_polygon() const { - - if (node->get_internal_vertex_count() > 0) { - - return TTR("Polygon 2D has internal vertices, so it can no longer be edited in the viewport."); - } - - return String(); -} - int Polygon2DEditor::_get_polygon_count() const { + if (node->get_internal_vertex_count() > 0) { return 0; //do not edit if internal vertices exist } else { @@ -375,6 +367,8 @@ void Polygon2DEditor::_cancel_editing() { node->set_vertex_colors(uv_create_colors_prev); node->call("_set_bones", uv_create_bones_prev); node->set_polygons(polygons_prev); + + _update_polygon_editing_state(); } else if (uv_drag) { uv_drag = false; if (uv_edit_mode[0]->is_pressed()) { // Edit UV. @@ -387,9 +381,20 @@ void Polygon2DEditor::_cancel_editing() { polygon_create.clear(); } +void Polygon2DEditor::_update_polygon_editing_state() { + + if (!_get_node()) + return; + + if (node->get_internal_vertex_count() > 0) + disable_polygon_editing(true, TTR("Polygon 2D has internal vertices, so it can no longer be edited in the viewport.")); + else + disable_polygon_editing(false, String()); +} + void Polygon2DEditor::_commit_action() { - // Makes that undo/redoing actions made outside of the UV editor still affects its polygon. + // Makes that undo/redoing actions made outside of the UV editor still affect its polygon. undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport"); @@ -490,6 +495,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { uv_create_colors_prev = node->get_vertex_colors(); uv_create_bones_prev = node->call("_get_bones"); polygons_prev = node->get_polygons(); + disable_polygon_editing(false, String()); node->set_polygon(points_prev); node->set_uv(points_prev); node->set_internal_vertex_count(0); @@ -511,6 +517,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { undo_redo->add_undo_method(node, "set_vertex_colors", uv_create_colors_prev); undo_redo->add_do_method(node, "clear_bones"); undo_redo->add_undo_method(node, "_set_bones", uv_create_bones_prev); + undo_redo->add_do_method(this, "_update_polygon_editing_state"); + undo_redo->add_undo_method(this, "_update_polygon_editing_state"); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -562,7 +570,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } undo_redo->add_do_method(node, "set_internal_vertex_count", internal_vertices + 1); undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices); - + undo_redo->add_do_method(this, "_update_polygon_editing_state"); + undo_redo->add_undo_method(this, "_update_polygon_editing_state"); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -616,7 +625,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { } undo_redo->add_do_method(node, "set_internal_vertex_count", internal_vertices - 1); undo_redo->add_undo_method(node, "set_internal_vertex_count", internal_vertices); - + undo_redo->add_do_method(this, "_update_polygon_editing_state"); + undo_redo->add_undo_method(this, "_update_polygon_editing_state"); undo_redo->add_do_method(uv_edit_draw, "update"); undo_redo->add_undo_method(uv_edit_draw, "update"); undo_redo->commit_action(); @@ -1233,6 +1243,7 @@ void Polygon2DEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_uv_edit_popup_hide"), &Polygon2DEditor::_uv_edit_popup_hide); ClassDB::bind_method(D_METHOD("_sync_bones"), &Polygon2DEditor::_sync_bones); ClassDB::bind_method(D_METHOD("_update_bone_list"), &Polygon2DEditor::_update_bone_list); + ClassDB::bind_method(D_METHOD("_update_polygon_editing_state"), &Polygon2DEditor::_update_polygon_editing_state); ClassDB::bind_method(D_METHOD("_bone_paint_selected"), &Polygon2DEditor::_bone_paint_selected); } diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index d3277e90f7..24ca2ea3f4 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -128,6 +128,7 @@ class Polygon2DEditor : public AbstractPolygon2DEditor { virtual void _menu_option(int p_option); void _cancel_editing(); + void _update_polygon_editing_state(); void _uv_scroll_changed(float); void _uv_input(const Ref<InputEvent> &p_input); @@ -152,7 +153,6 @@ protected: virtual void _set_node(Node *p_polygon); virtual Vector2 _get_offset(int p_idx) const; - virtual String _why_cant_edit_polygon() const; virtual bool _has_uv() const { return true; }; virtual void _commit_action(); diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index a9a40c0508..569033d93c 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 1FE9269F1FBBF86B00F53A6F /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FE926901FBBF78E00F53A6F /* CoreMedia.framework */; }; 1FE926A01FBBF86D00F53A6F /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FE9268E1FBBF77300F53A6F /* AudioToolbox.framework */; }; 1FE926A11FBBF86D00F53A6F /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FE9268F1FBBF77F00F53A6F /* CoreAudio.framework */; }; + E360193721F32F38009258C1 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E360193621F32F37009258C1 /* CoreVideo.framework */; }; DEADBEEF2F582BE20003B888 /* $binary.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DEADBEEF1F582BE20003B888 /* $binary.a */; }; 1FF8DBB11FBA9DE1009DE660 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */; }; 1FF4C1851F584E3F00A41E41 /* GameKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FF4C1841F584E3F00A41E41 /* GameKit.framework */; }; @@ -53,6 +54,7 @@ D0BCFE3418AEBDA2004A7AAE /* $binary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = $binary.app; sourceTree = BUILT_PRODUCTS_DIR; }; D0BCFE3718AEBDA2004A7AAE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; D0BCFE3918AEBDA2004A7AAE /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + E360193621F32F37009258C1 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; D0BCFE3B18AEBDA2004A7AAE /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; D0BCFE3D18AEBDA2004A7AAE /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; D0BCFE3F18AEBDA2004A7AAE /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; @@ -69,6 +71,7 @@ buildActionMask = 2147483647; files = ( D0BCFE3A18AEBDA2004A7AAE /* CoreGraphics.framework in Frameworks */, + E360193721F32F38009258C1 /* CoreVideo.framework in Frameworks */, 1FE926991FBBF85400F53A6F /* SystemConfiguration.framework in Frameworks */, 1FE9269A1FBBF85F00F53A6F /* Security.framework in Frameworks */, 1FE9269B1FBBF86200F53A6F /* QuartzCore.framework in Frameworks */, @@ -124,6 +127,7 @@ 1FE926911FBBF79500F53A6F /* CoreMotion.framework */, 1FE926901FBBF78E00F53A6F /* CoreMedia.framework */, 1FE9268F1FBBF77F00F53A6F /* CoreAudio.framework */, + E360193621F32F37009258C1 /* CoreVideo.framework */, 1FE9268E1FBBF77300F53A6F /* AudioToolbox.framework */, 1FF4C1861F584E5600A41E41 /* StoreKit.framework */, 1FF4C1841F584E3F00A41E41 /* GameKit.framework */, @@ -190,15 +194,82 @@ TargetAttributes = { D0BCFE3318AEBDA2004A7AAE = { DevelopmentTeam = $team_id; + ProvisioningStyle = Automatic; SystemCapabilities = { - com.apple.GameCenter = { - enabled = 1; + com.apple.AccessWiFi = { + enabled = $access_wifi; + }; + com.apple.ApplePay = { + enabled = 0; + }; + com.apple.ApplicationGroups.iOS = { + enabled = 0; + }; + com.apple.AutoFillCredentialProvider = { + enabled = 0; + }; + com.apple.BackgroundModes = { + enabled = 0; + }; + com.apple.ClassKit = { + enabled = 0; + }; + com.apple.DataProtection = { + enabled = 0; + }; + com.apple.GameCenter.iOS = { + enabled = $game_center; + }; + com.apple.HealthKit = { + enabled = 0; + }; + com.apple.HomeKit = { + enabled = 0; + }; + com.apple.HotspotConfiguration = { + enabled = 0; }; com.apple.InAppPurchase = { - enabled = 1; + enabled = $in_app_purchases; + }; + com.apple.InterAppAudio = { + enabled = 0; + }; + com.apple.Keychain = { + enabled = 0; + }; + com.apple.Maps.iOS = { + enabled = 0; + }; + com.apple.Multipath = { + enabled = 0; + }; + com.apple.NearFieldCommunicationTagReading = { + enabled = 0; + }; + com.apple.NetworkExtensions.iOS = { + enabled = 0; }; com.apple.Push = { - enabled = 1; + enabled = $push_notifications; + }; + com.apple.SafariKeychain = { + enabled = 0; + }; + com.apple.Siri = { + enabled = 0; + }; + com.apple.VPNLite = { + enabled = 0; + }; + com.apple.WAC = { + enabled = 0; + }; + com.apple.Wallet = { + enabled = 0; + }; + com.apple.iCloud = { + enabled = 0; }; }; }; @@ -277,6 +348,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "$code_sign_identity_debug"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug"; COPY_PHASE_STRIP = NO; ENABLE_BITCODE = NO; @@ -400,7 +472,7 @@ D0BCFE7018AEBDA3004A7AAE /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; D0BCFE7118AEBDA3004A7AAE /* Build configuration list for PBXNativeTarget "$binary" */ = { isa = XCConfigurationList; @@ -409,7 +481,7 @@ D0BCFE7318AEBDA3004A7AAE /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist index 6907ae4a9d..1c68c72385 100644 --- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist +++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist @@ -13,7 +13,7 @@ <key>CFBundleIcons~ipad</key> <dict/> <key>CFBundleIdentifier</key> - <string>$identifier</string> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> @@ -30,26 +30,25 @@ <true/> <key>UIRequiredDeviceCapabilities</key> <array> - <string>armv7</string> - <string>gamekit</string> + $required_device_capabilities </array> + <key>NSCameraUsageDescription</key> + <string>$camera_usage_description</string> + <key>NSMicrophoneUsageDescription</key> + <string>$microphone_usage_description</string> + <key>NSPhotoLibraryUsageDescription</key> + <string>$photolibrary_usage_description</string> <key>UIRequiresFullScreen</key> <true/> <key>UIStatusBarHidden</key> <true/> <key>UISupportedInterfaceOrientations</key> <array> - <string>UIInterfaceOrientationLandscapeLeft</string> - <string>UIInterfaceOrientationLandscapeRight</string> - <string>UIInterfaceOrientationPortrait</string> - <string>UIInterfaceOrientationPortraitUpsideDown</string> + $interface_orientations </array> <key>UISupportedInterfaceOrientations~ipad</key> <array> - <string>UIInterfaceOrientationLandscapeLeft</string> - <string>UIInterfaceOrientationLandscapeRight</string> - <string>UIInterfaceOrientationPortrait</string> - <string>UIInterfaceOrientationPortraitUpsideDown</string> + $interface_orientations </array> $additional_plist_content </dict> diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 3daa006353..af770ac533 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -479,12 +479,15 @@ struct GDScriptCompletionContext { Object *base; String base_path; int line; + uint32_t depth; GDScriptCompletionContext() : _class(NULL), function(NULL), block(NULL), - base(NULL) {} + base(NULL), + line(0), + depth(0) {} }; struct GDScriptCompletionIdentifier { @@ -634,12 +637,18 @@ static GDScriptCompletionIdentifier _type_from_gdtype(const GDScriptDataType &p_ return ci; } -static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); -static bool _guess_identifier_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); -static bool _guess_method_return_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); +static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); -static bool _guess_expression_type(const GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_expression, GDScriptCompletionIdentifier &r_type) { +static bool _guess_expression_type(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_expression, GDScriptCompletionIdentifier &r_type) { bool found = false; + + if (++p_context.depth > 100) { + print_error("Maximum _guess_expression_type depth limit reached. Please file a bugreport."); + return false; + } + switch (p_expression->type) { case GDScriptParser::Node::TYPE_CONSTANT: { const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(p_expression); @@ -1128,7 +1137,7 @@ static bool _guess_expression_type(const GDScriptCompletionContext &p_context, c return found; } -static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { +static bool _guess_identifier_type(GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { // Look in blocks first const GDScriptParser::BlockNode *blk = p_context.block; @@ -1358,7 +1367,7 @@ static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, c return false; } -static bool _guess_identifier_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { +static bool _guess_identifier_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; while (base_type.has_type) { @@ -1547,7 +1556,7 @@ static bool _find_last_return_in_block(const GDScriptCompletionContext &p_contex return false; } -static bool _guess_method_return_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { +static bool _guess_method_return_type_from_base(GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { GDScriptParser::DataType base_type = p_base.type; bool _static = base_type.is_meta_type; @@ -2312,7 +2321,7 @@ static void _find_call_arguments(const GDScriptCompletionContext &p_context, con } } -static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Set<String> &r_result, bool &r_forced, String &r_arghint) { +static void _find_call_arguments(GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Set<String> &r_result, bool &r_forced, String &r_arghint) { if (!p_node || p_node->type != GDScriptParser::Node::TYPE_OPERATOR) { return; diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 849e6d4a14..d234ddac27 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -246,7 +246,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "iPhone Developer")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_debug", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release"), "")); @@ -255,12 +255,27 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "come.example.game"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/arkit"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/game_center"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/in_app_purchases"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false)); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description"), "Godot would like to use your camera")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description"), "Godot would like to use your microphone")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description"), "Godot would like to use your photos")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_left"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_right"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_upside_down"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with retina display r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store @@ -337,6 +352,62 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n"; } else if (lines[i].find("$cpp_code") != -1) { strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n"; + } else if (lines[i].find("$access_wifi") != -1) { + bool is_on = p_preset->get("capabilities/access_wifi"); + strnew += lines[i].replace("$access_wifi", is_on ? "1" : "0") + "\n"; + } else if (lines[i].find("$game_center") != -1) { + bool is_on = p_preset->get("capabilities/game_center"); + strnew += lines[i].replace("$game_center", is_on ? "1" : "0") + "\n"; + } else if (lines[i].find("$in_app_purchases") != -1) { + bool is_on = p_preset->get("capabilities/in_app_purchases"); + strnew += lines[i].replace("$in_app_purchases", is_on ? "1" : "0") + "\n"; + } else if (lines[i].find("$push_notifications") != -1) { + bool is_on = p_preset->get("capabilities/push_notifications"); + strnew += lines[i].replace("$push_notifications", is_on ? "1" : "0") + "\n"; + } else if (lines[i].find("$required_device_capabilities") != -1) { + String capabilities; + + // I've removed armv7 as we can run on 64bit only devices + // Note that capabilities listed here are requirements for the app to be installed. + // They don't enable anything. + + if ((bool)p_preset->get("capabilities/arkit")) { + capabilities += "<string>arkit</string>\n"; + } + if ((bool)p_preset->get("capabilities/game_center")) { + capabilities += "<string>gamekit</string>\n"; + } + if ((bool)p_preset->get("capabilities/access_wifi")) { + capabilities += "<string>wifi</string>\n"; + } + + strnew += lines[i].replace("$required_device_capabilities", capabilities); + } else if (lines[i].find("$interface_orientations") != -1) { + String orientations; + + if ((bool)p_preset->get("orientation/portrait")) { + orientations += "<string>UIInterfaceOrientationPortrait</string>\n"; + } + if ((bool)p_preset->get("orientation/landscape_left")) { + orientations += "<string>UIInterfaceOrientationLandscapeLeft</string>\n"; + } + if ((bool)p_preset->get("orientation/landscape_right")) { + orientations += "<string>UIInterfaceOrientationLandscapeRight</string>\n"; + } + if ((bool)p_preset->get("orientation/portrait_upside_down")) { + orientations += "<string>UIInterfaceOrientationPortraitUpsideDown</string>\n"; + } + + strnew += lines[i].replace("$interface_orientations", orientations); + } else if (lines[i].find("$camera_usage_description") != -1) { + String description = p_preset->get("privacy/camera_usage_description"); + strnew += lines[i].replace("$camera_usage_description", description) + "\n"; + } else if (lines[i].find("$microphone_usage_description") != -1) { + String description = p_preset->get("privacy/microphone_usage_description"); + strnew += lines[i].replace("$microphone_usage_description", description) + "\n"; + } else if (lines[i].find("$photolibrary_usage_description") != -1) { + String description = p_preset->get("privacy/photolibrary_usage_description"); + strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n"; } else { strnew += lines[i] + "\n"; } @@ -648,6 +719,10 @@ void EditorExportPlatformIOS::_add_assets_to_project(Vector<uint8_t> &p_project_ pbx_files += file_info_format.format(format_dict, "$_"); } + // Note, frameworks like gamekit are always included in our project.pbxprof file + // even if turned off in capabilities. + // Frameworks that are used by modules (like arkit) we may need to optionally add here. + String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size()); str = str.replace("$additional_pbx_files", pbx_files); str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index f4bc8ad6b9..44b81dc0cc 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1290,7 +1290,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const floor_velocity = collision.collider_vel; if (p_stop_on_slope) { - if (Vector2() == lv_n + p_floor_direction && collision.travel.length() < 1) { + if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { Transform2D gt = get_global_transform(); gt.elements[2] -= collision.travel.project(p_floor_direction.tangent()); set_global_transform(gt); @@ -1338,13 +1338,21 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci Transform2D gt = get_global_transform(); if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { - gt.elements[2] += col.travel; - if (p_floor_direction != Vector2() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { - on_floor = true; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; + bool apply = true; + if (p_floor_direction != Vector2()) { + if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + on_floor = true; + on_floor_body = col.collider_rid; + floor_velocity = col.collider_vel; + } else { + apply = false; + } + } + + if (apply) { + gt.elements[2] += col.travel; + set_global_transform(gt); } - set_global_transform(gt); } return ret; diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 50abbd483a..f85b51af08 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1222,7 +1222,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve floor_velocity = collision.collider_vel; if (p_stop_on_slope) { - if (Vector3() == lv_n + p_floor_direction) { + if ((lv_n + p_floor_direction).length() < 0.01) { Transform gt = get_global_transform(); gt.origin -= collision.travel; set_global_transform(gt); @@ -1243,6 +1243,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve motion = motion.slide(p_floor_direction); lv = lv.slide(p_floor_direction); } else { + Vector3 n = collision.normal; motion = motion.slide(n); lv = lv.slide(n); @@ -1280,13 +1281,21 @@ Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity Transform gt = get_global_transform(); if (move_and_collide(p_snap, p_infinite_inertia, col, true)) { - gt.origin += col.travel; - if (p_floor_direction != Vector3() && Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { - on_floor = true; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; + + bool apply = true; + if (p_floor_direction != Vector3()) { + if (Math::acos(p_floor_direction.normalized().dot(col.normal)) < p_floor_max_angle) { + on_floor = true; + on_floor_body = col.collider_rid; + floor_velocity = col.collider_vel; + } else { + apply = false; //snapped with floor direction, but did not snap to a floor, do not snap. + } + } + if (apply) { + gt.origin += col.travel; + set_global_transform(gt); } - set_global_transform(gt); } return ret; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 4abde6cc0f..d2c56dba06 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2202,10 +2202,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { bool had_selection = selection.active; // stuff to do when selection is active.. - if (selection.active) { - - if (readonly) - return; + if (!readonly && selection.active) { bool clear = false; bool unselect = false; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 805d30245a..a9878ef5c1 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -787,7 +787,6 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & Surface s; VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)p_primitive, p_arrays, p_blend_shapes, p_flags); - surfaces.push_back(s); /* make aABB? */ { @@ -808,8 +807,9 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & aabb.expand_to(vtx[i]); } - surfaces.write[surfaces.size() - 1].aabb = aabb; - surfaces.write[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; + s.aabb = aabb; + s.is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; + surfaces.push_back(s); _recompute_aabb(); } diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp index 1087cd2483..80c17b437c 100644 --- a/servers/physics/space_sw.cpp +++ b/servers/physics/space_sw.cpp @@ -387,6 +387,7 @@ struct _RestCallbackData { Vector3 best_contact; Vector3 best_normal; real_t best_len; + real_t min_allowed_depth; }; static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) { @@ -395,6 +396,8 @@ static void _rest_cbk_result(const Vector3 &p_point_A, const Vector3 &p_point_B, Vector3 contact_rel = p_point_B - p_point_A; real_t len = contact_rel.length(); + if (len < rd->min_allowed_depth) + return; if (len <= rd->best_len) return; @@ -418,6 +421,7 @@ bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform &p_shape_ rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = space->test_motion_min_contact_depth; for (int i = 0; i < amount; i++) { @@ -593,7 +597,6 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo bool collided = false; int amount = _cull_aabb_for_body(p_body, body_aabb); - int ray_index = 0; for (int j = 0; j < p_body->get_shape_count(); j++) { if (p_body->is_shape_set_as_disabled(j)) @@ -627,7 +630,19 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo collided = true; } - if (ray_index < p_result_max) { + int ray_index = -1; //reuse shape + for (int k = 0; k < rays_found; k++) { + if (r_results[ray_index].collision_local_shape == j) { + ray_index = k; + } + } + + if (ray_index == -1 && rays_found < p_result_max) { + ray_index = rays_found; + rays_found++; + } + + if (ray_index != -1) { PhysicsServer::SeparationResult &result = r_results[ray_index]; for (int k = 0; k < cbk.amount; k++) { @@ -642,9 +657,10 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo result.collision_depth = depth; result.collision_point = b; result.collision_normal = (b - a).normalized(); - result.collision_local_shape = shape_idx; + result.collision_local_shape = j; result.collider = col_obj->get_self(); result.collider_id = col_obj->get_instance_id(); + result.collider_shape = shape_idx; //result.collider_metadata = col_obj->get_shape_metadata(shape_idx); if (col_obj->get_type() == CollisionObjectSW::TYPE_BODY) { BodySW *body = (BodySW *)col_obj; @@ -658,12 +674,8 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo } } } - - ray_index++; } - rays_found = MAX(ray_index, rays_found); - if (!collided || recover_motion == Vector3()) { break; } @@ -717,6 +729,11 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve } if (!shapes_found) { + if (r_result) { + *r_result = PhysicsServer::MotionResult(); + r_result->motion = p_motion; + } + return false; } @@ -924,6 +941,7 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = test_motion_min_contact_depth; Transform body_shape_xform = ugt * p_body->get_shape_transform(best_shape); ShapeSW *body_shape = p_body->get_shape(best_shape); @@ -1148,6 +1166,7 @@ void SpaceSW::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) { case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break; case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio = p_value; break; case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; + case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break; } } @@ -1163,6 +1182,7 @@ real_t SpaceSW::get_param(PhysicsServer::SpaceParameter p_param) const { case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep; case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio; case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; + case PhysicsServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth; } return 0; } @@ -1198,6 +1218,7 @@ SpaceSW::SpaceSW() { contact_recycle_radius = 0.01; contact_max_separation = 0.05; contact_max_allowed_penetration = 0.01; + test_motion_min_contact_depth = 0.00001; constraint_bias = 0.01; body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1); diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index ae6f349e51..3aaa552845 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -96,6 +96,7 @@ private: real_t contact_max_separation; real_t contact_max_allowed_penetration; real_t constraint_bias; + real_t test_motion_min_contact_depth; enum { diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 5ed70803ed..2e338b03cc 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -375,6 +375,7 @@ struct _RestCallbackData2D { real_t best_len; Vector2 valid_dir; real_t valid_depth; + real_t min_allowed_depth; }; static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { @@ -390,6 +391,10 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, Vector2 contact_rel = p_point_B - p_point_A; real_t len = contact_rel.length(); + + if (len < rd->min_allowed_depth) + return; + if (len <= rd->best_len) return; @@ -416,6 +421,7 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = space->test_motion_min_contact_depth; for (int i = 0; i < amount; i++) { @@ -555,7 +561,6 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t bool collided = false; int amount = _cull_aabb_for_body(p_body, body_aabb); - int ray_index = 0; for (int j = 0; j < p_body->get_shape_count(); j++) { if (p_body->is_shape_set_as_disabled(j)) @@ -587,6 +592,10 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + /* + * There is no point in supporting one way collisions with ray shapes, as they will always collide in the desired + * direction. Use a short ray shape if you want to achieve a similar effect. + * if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); @@ -594,10 +603,15 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t cbk.invalid_by_dir = 0; } else { - cbk.valid_dir = Vector2(); - cbk.valid_depth = 0; - cbk.invalid_by_dir = 0; +*/ + + cbk.valid_dir = Vector2(); + cbk.valid_depth = 0; + cbk.invalid_by_dir = 0; + + /* } + */ Shape2DSW *against_shape = col_obj->get_shape(shape_idx); if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, NULL, p_margin)) { @@ -605,7 +619,19 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t collided = true; } - if (ray_index < p_result_max) { + int ray_index = -1; //reuse shape + for (int k = 0; k < rays_found; k++) { + if (r_results[ray_index].collision_local_shape == j) { + ray_index = k; + } + } + + if (ray_index == -1 && rays_found < p_result_max) { + ray_index = rays_found; + rays_found++; + } + + if (ray_index != -1) { Physics2DServer::SeparationResult &result = r_results[ray_index]; for (int k = 0; k < cbk.amount; k++) { @@ -620,7 +646,8 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t result.collision_depth = depth; result.collision_point = b; result.collision_normal = (b - a).normalized(); - result.collision_local_shape = shape_idx; + result.collision_local_shape = j; + result.collider_shape = shape_idx; result.collider = col_obj->get_self(); result.collider_id = col_obj->get_instance_id(); result.collider_metadata = col_obj->get_shape_metadata(shape_idx); @@ -635,12 +662,8 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t } } } - - ray_index++; } - rays_found = MAX(ray_index, rays_found); - if (!collided || recover_motion == Vector2()) { break; } @@ -695,6 +718,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } if (!shapes_found) { + if (r_result) { + *r_result = Physics2DServer::MotionResult(); + r_result->motion = p_motion; + } return false; } @@ -990,12 +1017,17 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co rcd.best_len = 0; rcd.best_object = NULL; rcd.best_shape = 0; + rcd.min_allowed_depth = test_motion_min_contact_depth; //optimization int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); for (int j = from_shape; j < to_shape; j++) { + + if (p_body->is_shape_set_as_disabled(j)) + continue; + Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j); Shape2DSW *body_shape = p_body->get_shape(j); @@ -1249,6 +1281,7 @@ void Space2DSW::set_param(Physics2DServer::SpaceParameter p_param, real_t p_valu case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: body_angular_velocity_sleep_threshold = p_value; break; case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep = p_value; break; case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; + case Physics2DServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: test_motion_min_contact_depth = p_value; break; } } @@ -1263,6 +1296,7 @@ real_t Space2DSW::get_param(Physics2DServer::SpaceParameter p_param) const { case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD: return body_angular_velocity_sleep_threshold; case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep; case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; + case Physics2DServer::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: return test_motion_min_contact_depth; } return 0; } @@ -1299,6 +1333,7 @@ Space2DSW::Space2DSW() { contact_recycle_radius = 1.0; contact_max_separation = 1.5; contact_max_allowed_penetration = 0.3; + test_motion_min_contact_depth = 0.005; constraint_bias = 0.2; body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0); diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 64f8c9e156..14c24959b7 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -104,6 +104,7 @@ private: real_t contact_max_separation; real_t contact_max_allowed_penetration; real_t constraint_bias; + real_t test_motion_min_contact_depth; enum { diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index ca914b67e0..3a05791f17 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -693,6 +693,7 @@ void Physics2DServer::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); + BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); BIND_ENUM_CONSTANT(SHAPE_LINE); BIND_ENUM_CONSTANT(SHAPE_RAY); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index df7fe46f76..1de9c7df93 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -289,6 +289,7 @@ public: SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD, SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, + SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH, }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -504,6 +505,12 @@ public: RID collider; int collider_shape; Variant collider_metadata; + + MotionResult() { + collision_local_shape = 0; + collider_shape = 0; + collider_id = 0; + } }; virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, float p_margin = 0.001, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true) = 0; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index 967e74d322..e07133b5bb 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -709,6 +709,8 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); + BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); + BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Z); diff --git a/servers/physics_server.h b/servers/physics_server.h index 4ba096a994..c71bb01943 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -274,6 +274,7 @@ public: SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, + SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -492,6 +493,11 @@ public: RID collider; int collider_shape; Variant collider_metadata; + MotionResult() { + collision_local_shape = 0; + collider_id = 0; + collider_shape = 0; + } }; virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL, bool p_exclude_raycast_shapes = true) = 0; |