diff options
146 files changed, 3430 insertions, 899 deletions
diff --git a/SConstruct b/SConstruct index 9783b3eaca..4085f713b7 100644 --- a/SConstruct +++ b/SConstruct @@ -288,7 +288,7 @@ if selected_platform in platform_list: if (env["warnings"] == 'yes'): print("WARNING: warnings=yes is deprecated; assuming warnings=all") - if (os.name == "nt" and os.getenv("VSINSTALLDIR") and (platform_arg == "windows" or platform_arg == "uwp")): # MSVC, needs to stand out of course + if (os.name == "nt" and os.getenv("VCINSTALLDIR") and (platform_arg == "windows" or platform_arg == "uwp")): # MSVC, needs to stand out of course disable_nonessential_warnings = ['/wd4267', '/wd4244', '/wd4305', '/wd4800'] # Truncations, narrowing conversions... if (env["warnings"] == 'extra'): env.Append(CCFLAGS=['/Wall']) # Implies /W4 diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 4f535fb05e..18071d7748 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -106,7 +106,6 @@ static _GlobalConstant _global_constants[] = { BIND_GLOBAL_CONSTANT(KEY_F14), BIND_GLOBAL_CONSTANT(KEY_F15), BIND_GLOBAL_CONSTANT(KEY_F16), - BIND_GLOBAL_CONSTANT(KEY_KP_ENTER), BIND_GLOBAL_CONSTANT(KEY_KP_MULTIPLY), BIND_GLOBAL_CONSTANT(KEY_KP_DIVIDE), BIND_GLOBAL_CONSTANT(KEY_KP_SUBTRACT), diff --git a/core/input_map.cpp b/core/input_map.cpp index 1abe019167..24d0624e98 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "input_map.h" -#include "project_settings.h" #include "os/keyboard.h" +#include "project_settings.h" InputMap *InputMap::singleton = NULL; diff --git a/core/io/compression.cpp b/core/io/compression.cpp index ca35ece8f5..139383710c 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "compression.h" -#include "project_settings.h" #include "os/copymem.h" +#include "project_settings.h" #include "zip_io.h" #include "thirdparty/misc/fastlz.h" diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 2197b187eb..8e719568e5 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -29,10 +29,10 @@ /*************************************************************************/ #include "file_access_memory.h" -#include "project_settings.h" #include "map.h" #include "os/copymem.h" #include "os/dir_access.h" +#include "project_settings.h" static Map<String, Vector<uint8_t> > *files = NULL; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 46457d1425..aa67479d7e 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "file_access_network.h" -#include "project_settings.h" #include "io/ip.h" #include "marshalls.h" #include "os/os.h" +#include "project_settings.h" //#define DEBUG_PRINT(m_p) print_line(m_p) //#define DEBUG_TIME(m_what) printf("MS: %s - %lli\n",m_what,OS::get_singleton()->get_ticks_usec()); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 81446a3886..a3d33593dd 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "packet_peer.h" -#include "project_settings.h" #include "io/marshalls.h" +#include "project_settings.h" /* helpers / binders */ PacketPeer::PacketPeer() { diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 602cbe6f30..9aa16ed7e7 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_format_binary.h" -#include "project_settings.h" #include "image.h" #include "io/file_access_compressed.h" #include "io/marshalls.h" #include "os/dir_access.h" +#include "project_settings.h" #include "version.h" //#define print_bl(m_what) print_line(m_what) #define print_bl(m_what) diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 285cc6e3c2..9b89fa3399 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -430,6 +430,9 @@ void ResourceLoader::reload_translation_remaps() { void ResourceLoader::load_translation_remaps() { + if (!ProjectSettings::get_singleton()->has("locale/translation_remaps")) + return; + Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps"); List<Variant> keys; remaps.get_key_list(&keys); diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 58913b80cc..314259b2e9 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "resource_saver.h" -#include "project_settings.h" #include "os/file_access.h" +#include "project_settings.h" #include "resource_loader.h" #include "script_language.h" diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 33ad522315..a1666ccd8b 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -91,6 +91,72 @@ void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_ matrix[3][3] = 0; } +void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { + if (p_flip_fov) { + p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect); + } + + real_t left, right, modeltranslation, ymax, xmax, frustumshift; + + ymax = p_z_near * tan(p_fovy_degrees * Math_PI / 360.0f); + xmax = ymax * p_aspect; + frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist; + + switch (p_eye) { + case 1: { // left eye + left = -xmax + frustumshift; + right = xmax + frustumshift; + modeltranslation = p_intraocular_dist / 2.0; + }; break; + case 2: { // right eye + left = -xmax - frustumshift; + right = xmax - frustumshift; + modeltranslation = -p_intraocular_dist / 2.0; + }; break; + default: { // mono, should give the same result as set_perspective(p_fovy_degrees,p_aspect,p_z_near,p_z_far,p_flip_fov) + left = -xmax; + right = xmax; + modeltranslation = 0.0; + }; break; + }; + + set_frustum(left, right, -ymax, ymax, p_z_near, p_z_far); + + // translate matrix by (modeltranslation, 0.0, 0.0) + CameraMatrix cm; + cm.set_identity(); + cm.matrix[3][0] = modeltranslation; + *this = *this * cm; +} + +void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) { + // we first calculate our base frustum on our values without taking our lens magnification into account. + real_t display_to_eye = 2.0 * p_display_to_lens; + real_t f1 = (p_intraocular_dist * 0.5) / p_display_to_lens; + real_t f2 = ((p_display_width - p_intraocular_dist) * 0.5) / p_display_to_lens; + real_t f3 = (p_display_width / 4.0) / p_display_to_lens; + + // now we apply our oversample factor to increase our FOV. how much we oversample is always a balance we strike between performance and how much + // we're willing to sacrifice in FOV. + real_t add = ((f1 + f2) * (p_oversample - 1.0)) / 2.0; + f1 += add; + f2 += add; + + // always apply KEEP_WIDTH aspect ratio + f3 *= p_aspect; + + switch (p_eye) { + case 1: { // left eye + set_frustum(-f2 * p_z_near, f1 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far); + }; break; + case 2: { // right eye + set_frustum(-f1 * p_z_near, f2 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far); + }; break; + default: { // mono, does not apply here! + }; break; + }; +}; + void CameraMatrix::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { set_identity(); @@ -243,23 +309,44 @@ bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8point -matrix[15] + matrix[13]); top_plane.normalize(); - Vector3 near_endpoint; - Vector3 far_endpoint; + Vector3 near_endpoint_left, near_endpoint_right; + Vector3 far_endpoint_left, far_endpoint_right; - bool res = near_plane.intersect_3(right_plane, top_plane, &near_endpoint); + bool res = near_plane.intersect_3(right_plane, top_plane, &near_endpoint_right); ERR_FAIL_COND_V(!res, false); - res = far_plane.intersect_3(right_plane, top_plane, &far_endpoint); + res = far_plane.intersect_3(right_plane, top_plane, &far_endpoint_right); ERR_FAIL_COND_V(!res, false); - p_8points[0] = p_transform.xform(Vector3(near_endpoint.x, near_endpoint.y, near_endpoint.z)); - p_8points[1] = p_transform.xform(Vector3(near_endpoint.x, -near_endpoint.y, near_endpoint.z)); - p_8points[2] = p_transform.xform(Vector3(-near_endpoint.x, near_endpoint.y, near_endpoint.z)); - p_8points[3] = p_transform.xform(Vector3(-near_endpoint.x, -near_endpoint.y, near_endpoint.z)); - p_8points[4] = p_transform.xform(Vector3(far_endpoint.x, far_endpoint.y, far_endpoint.z)); - p_8points[5] = p_transform.xform(Vector3(far_endpoint.x, -far_endpoint.y, far_endpoint.z)); - p_8points[6] = p_transform.xform(Vector3(-far_endpoint.x, far_endpoint.y, far_endpoint.z)); - p_8points[7] = p_transform.xform(Vector3(-far_endpoint.x, -far_endpoint.y, far_endpoint.z)); + if ((matrix[8] == 0) && (matrix[9] == 0)) { + near_endpoint_left = near_endpoint_right; + near_endpoint_left.x = -near_endpoint_left.x; + + far_endpoint_left = far_endpoint_right; + far_endpoint_left.x = -far_endpoint_left.x; + } else { + ///////--- Left Plane ---/////// + Plane left_plane = Plane(matrix[0] + matrix[3], + matrix[4] + matrix[7], + matrix[8] + matrix[11], + -matrix[15] - matrix[12]); + left_plane.normalize(); + + res = near_plane.intersect_3(left_plane, top_plane, &near_endpoint_left); + ERR_FAIL_COND_V(!res, false); + + res = far_plane.intersect_3(left_plane, top_plane, &far_endpoint_left); + ERR_FAIL_COND_V(!res, false); + } + + p_8points[0] = p_transform.xform(Vector3(near_endpoint_right.x, near_endpoint_right.y, near_endpoint_right.z)); + p_8points[1] = p_transform.xform(Vector3(near_endpoint_right.x, -near_endpoint_right.y, near_endpoint_right.z)); + p_8points[2] = p_transform.xform(Vector3(near_endpoint_left.x, near_endpoint_left.y, near_endpoint_left.z)); + p_8points[3] = p_transform.xform(Vector3(near_endpoint_left.x, -near_endpoint_left.y, near_endpoint_left.z)); + p_8points[4] = p_transform.xform(Vector3(far_endpoint_right.x, far_endpoint_right.y, far_endpoint_right.z)); + p_8points[5] = p_transform.xform(Vector3(far_endpoint_right.x, -far_endpoint_right.y, far_endpoint_right.z)); + p_8points[6] = p_transform.xform(Vector3(far_endpoint_left.x, far_endpoint_left.y, far_endpoint_left.z)); + p_8points[7] = p_transform.xform(Vector3(far_endpoint_left.x, -far_endpoint_left.y, far_endpoint_left.z)); return true; } @@ -546,7 +633,18 @@ real_t CameraMatrix::get_fov() const { -matrix[15] + matrix[12]); right_plane.normalize(); - return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; + if ((matrix[8] == 0) && (matrix[9] == 0)) { + return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; + } else { + // our frustum is asymetrical need to calculate the left planes angle seperately.. + Plane left_plane = Plane(matrix[3] + matrix[0], + matrix[7] + matrix[4], + matrix[11] + matrix[8], + matrix[15] + matrix[12]); + left_plane.normalize(); + + return Math::rad2deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))); + } } void CameraMatrix::make_scale(const Vector3 &p_scale) { diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index af61e35993..4be8ffab8c 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -54,6 +54,8 @@ struct CameraMatrix { void set_light_bias(); void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); + void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); + void set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far); void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far); diff --git a/core/math/face3.h b/core/math/face3.h index 1cc94321c3..3d02ae4014 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -115,20 +115,20 @@ bool Face3::intersects_aabb2(const Rect3 &p_aabb) const { if (dist_a * dist_b > 0) return false; //does not intersect the plane -#define TEST_AXIS(m_ax) \ - { \ +#define TEST_AXIS(m_ax) \ + { \ real_t aabb_min = p_aabb.position.m_ax; \ real_t aabb_max = p_aabb.position.m_ax + p_aabb.size.m_ax; \ - real_t tri_min, tri_max; \ - for (int i = 0; i < 3; i++) { \ - if (i == 0 || vertex[i].m_ax > tri_max) \ - tri_max = vertex[i].m_ax; \ - if (i == 0 || vertex[i].m_ax < tri_min) \ - tri_min = vertex[i].m_ax; \ - } \ - \ - if (tri_max < aabb_min || aabb_max < tri_min) \ - return false; \ + real_t tri_min, tri_max; \ + for (int i = 0; i < 3; i++) { \ + if (i == 0 || vertex[i].m_ax > tri_max) \ + tri_max = vertex[i].m_ax; \ + if (i == 0 || vertex[i].m_ax < tri_min) \ + tri_min = vertex[i].m_ax; \ + } \ + \ + if (tri_max < aabb_min || aabb_max < tri_min) \ + return false; \ } TEST_AXIS(x); diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index 484942bad5..391ae78c85 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "dir_access.h" -#include "project_settings.h" #include "os/file_access.h" #include "os/memory.h" #include "os/os.h" +#include "project_settings.h" String DirAccess::_get_root_path() const { diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 2bb676381f..3bd5ac3f41 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -31,8 +31,8 @@ #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" -#include "project_settings.h" #include "os/os.h" +#include "project_settings.h" #include "thirdparty/misc/md5.h" #include "thirdparty/misc/sha256.h" @@ -300,6 +300,8 @@ Vector<String> FileAccess::get_csv_line(String delim) const { String l; int qc = 0; do { + ERR_FAIL_COND_V(eof_reached(), Vector<String>()); + l += get_line() + "\n"; qc = 0; for (int i = 0; i < l.length(); i++) { diff --git a/core/os/input.cpp b/core/os/input.cpp index 18d644668c..a90a552d1d 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "input.h" -#include "project_settings.h" #include "input_map.h" #include "os/os.h" +#include "project_settings.h" Input *Input::singleton = NULL; Input *Input::get_singleton() { diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 2f5dc03614..e154b1934d 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -81,7 +81,6 @@ static const _KeyCodeText _keycodes[] = { {KEY_F14 ,"F14"}, {KEY_F15 ,"F15"}, {KEY_F16 ,"F16"}, - {KEY_KP_ENTER ,"Kp Enter"}, {KEY_KP_MULTIPLY ,"Kp Multiply"}, {KEY_KP_DIVIDE ,"Kp Divide"}, {KEY_KP_SUBTRACT ,"Kp Subtract"}, @@ -334,7 +333,6 @@ bool keycode_has_unicode(uint32_t p_keycode) { case KEY_F14: case KEY_F15: case KEY_F16: - case KEY_KP_ENTER: case KEY_SUPER_L: case KEY_SUPER_R: case KEY_MENU: diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 0a72663867..c6985c887d 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -96,7 +96,6 @@ enum KeyList { KEY_F14 = SPKEY | 0x29, KEY_F15 = SPKEY | 0x2A, KEY_F16 = SPKEY | 0x2B, - KEY_KP_ENTER = SPKEY | 0x80, KEY_KP_MULTIPLY = SPKEY | 0x81, KEY_KP_DIVIDE = SPKEY | 0x82, KEY_KP_SUBTRACT = SPKEY | 0x83, diff --git a/core/os/os.cpp b/core/os/os.cpp index 5a9766891d..8e4c357195 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -512,7 +512,13 @@ bool OS::check_feature_support(const String &p_feature) { return false; } +void *OS::get_stack_bottom() const { + return _stack_bottom; +} + OS::OS() { + void *volatile stack_bottom; + last_error = NULL; singleton = this; _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. @@ -525,6 +531,7 @@ OS::OS() { _render_thread_mode = RENDER_THREAD_SAFE; _allow_hidpi = true; + _stack_bottom = (void *)(&stack_bottom); } OS::~OS() { diff --git a/core/os/os.h b/core/os/os.h index 362fec8a9e..703c6a6bcd 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -60,6 +60,8 @@ class OS { char *last_error; + void *_stack_bottom; + public: enum RenderThreadMode { @@ -182,9 +184,9 @@ public: virtual void set_ime_position(const Point2 &p_pos) {} - virtual Error open_dynamic_library(const String p_path, void *&p_library_handle) { return ERR_UNAVAILABLE; }; - virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; }; - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle) { return ERR_UNAVAILABLE; }; + virtual Error open_dynamic_library(const String p_path, void *&p_library_handle) { return ERR_UNAVAILABLE; } + virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; } + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; } virtual void set_keep_screen_on(bool p_enabled); virtual bool is_keep_screen_on() const; @@ -411,6 +413,13 @@ public: bool check_feature_support(const String &p_feature); + /** + * Returns the stack bottom of the main thread of the application. + * This may be of use when integrating languages with garbage collectors that + * need to check whether a pointer is on the stack. + */ + virtual void *get_stack_bottom() const; + bool is_hidpi_allowed() const { return _allow_hidpi; } OS(); virtual ~OS(); diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 1a0a50a10f..b31f78ec20 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -455,8 +455,10 @@ Error ProjectSettings::_load_settings(const String p_path) { memdelete(f); ERR_FAIL_COND_V(config_version > FORMAT_VERSION, ERR_FILE_CANT_OPEN); } + } else { + // config_version is checked and dropped + set(section + "/" + assign, value); } - set(section + "/" + assign, value); } else if (next_tag.name != String()) { section = next_tag.name; } @@ -600,9 +602,19 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin ERR_FAIL_COND_V(err, err) } + file->store_line("; Engine configuration file."); + file->store_line("; It's best edited using the editor UI and not directly,"); + file->store_line("; since the parameters that go here are not all obvious."); + file->store_line("; "); + file->store_line("; Format: "); + file->store_line("; [section] ; section goes between []"); + file->store_line("; param=value ; assign values to parameters"); + file->store_line(""); + file->store_string("config_version=" + itos(FORMAT_VERSION) + "\n"); if (p_custom_features != String()) - file->store_string("_custom_featores=\"" + p_custom_features + "\"\n"); + file->store_string("custom_features=\"" + p_custom_features + "\"\n"); + file->store_string("\n"); for (Map<String, List<String> >::Element *E = props.front(); E; E = E->next()) { @@ -639,38 +651,43 @@ Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other par return save_custom(p_file); }; -Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features) { +Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) { ERR_FAIL_COND_V(p_path == "", ERR_INVALID_PARAMETER); Set<_VCSort> vclist; - for (Map<StringName, VariantContainer>::Element *G = props.front(); G; G = G->next()) { + if (p_merge_with_current) { + for (Map<StringName, VariantContainer>::Element *G = props.front(); G; G = G->next()) { - const VariantContainer *v = &G->get(); + const VariantContainer *v = &G->get(); - if (v->hide_from_editor) - continue; + if (v->hide_from_editor) + continue; - if (p_custom.has(G->key())) - continue; + if (p_custom.has(G->key())) + continue; - _VCSort vc; - vc.name = G->key(); //*k; - vc.order = v->order; - vc.type = v->variant.get_type(); - vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE; - if (v->variant == v->initial) - continue; + _VCSort vc; + vc.name = G->key(); //*k; + vc.order = v->order; + vc.type = v->variant.get_type(); + vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE; + if (v->variant == v->initial) + continue; - vclist.insert(vc); + vclist.insert(vc); + } } for (const Map<String, Variant>::Element *E = p_custom.front(); E; E = E->next()) { + // Lookup global prop to store in the same order + Map<StringName, VariantContainer>::Element *global_prop = props.find(E->key()); + _VCSort vc; vc.name = E->key(); - vc.order = 0xFFFFFFF; + vc.order = global_prop ? global_prop->get().order : 0xFFFFFFF; vc.type = E->get().get_type(); vc.flags = PROPERTY_USAGE_STORAGE; vclist.insert(vc); diff --git a/core/project_settings.h b/core/project_settings.h index 278d4b8132..c58ac3ca49 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -138,7 +138,7 @@ public: Error setup(const String &p_path, const String &p_main_pack); - Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>()); + Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true); Error save(); void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info); diff --git a/core/reference.cpp b/core/reference.cpp index c55f8a7fe3..060608eacb 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -74,7 +74,8 @@ bool Reference::unreference() { bool die = refcount.unref(); if (get_script_instance()) { - die = die && get_script_instance()->refcount_decremented(); + bool script_ret = get_script_instance()->refcount_decremented(); + die = die && script_ret; } return die; diff --git a/core/reference.h b/core/reference.h index 4e2d6c36c0..90f2791f4b 100644 --- a/core/reference.h +++ b/core/reference.h @@ -330,7 +330,7 @@ struct PtrToArg<Ref<T> > { _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { - return Ref<T>(reinterpret_cast<const T *>(p_ptr)); + return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr))); } _FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) { @@ -355,7 +355,7 @@ struct PtrToArg<RefPtr> { _FORCE_INLINE_ static RefPtr convert(const void *p_ptr) { - return Ref<Reference>(reinterpret_cast<const Reference *>(p_ptr)).get_ref_ptr(); + return Ref<Reference>(const_cast<Reference *>(reinterpret_cast<const Reference *>(p_ptr))).get_ref_ptr(); } _FORCE_INLINE_ static void encode(RefPtr p_val, const void *p_ptr) { @@ -370,7 +370,7 @@ struct PtrToArg<const RefPtr &> { _FORCE_INLINE_ static RefPtr convert(const void *p_ptr) { - return Ref<Reference>(reinterpret_cast<const Reference *>(p_ptr)).get_ref_ptr(); + return Ref<Reference>(const_cast<Reference *>(reinterpret_cast<const Reference *>(p_ptr))).get_ref_ptr(); } }; diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 07715f9718..43f781af55 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -36,7 +36,6 @@ #include "core_string_names.h" #include "func_ref.h" #include "geometry.h" -#include "project_settings.h" #include "input_map.h" #include "io/config_file.h" #include "io/http_client.h" @@ -54,6 +53,7 @@ #include "os/main_loop.h" #include "packed_data_container.h" #include "path_remap.h" +#include "project_settings.h" #include "translation.h" #include "undo_redo.h" diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index a7b6f25590..d19fe213f6 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -29,10 +29,10 @@ /*************************************************************************/ #include "script_debugger_remote.h" -#include "project_settings.h" #include "io/ip.h" #include "os/input.h" #include "os/os.h" +#include "project_settings.h" void ScriptDebuggerRemote::_send_video_memory() { @@ -74,7 +74,7 @@ Error ScriptDebuggerRemote::connect_to_host(const String &p_host, uint16_t p_por } else { OS::get_singleton()->delay_usec(1000000); - print_line("Remote Debugger: Connection failed with status: " + String::num(tcp_client->get_status()) + "'', retrying in 1 sec."); + print_line("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in 1 sec."); }; }; diff --git a/core/translation.cpp b/core/translation.cpp index d782006ddc..50694e4a2d 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "translation.h" -#include "project_settings.h" #include "io/resource_loader.h" #include "os/os.h" +#include "project_settings.h" static const char *locale_list[] = { "aa", // Afar diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp index 26a6a05a30..398f20caf3 100644 --- a/core/variant_parser.cpp +++ b/core/variant_parser.cpp @@ -1099,7 +1099,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return OK; - } else if (id == "PoolFloatArray" || id == "FloatArray") { + } else if (id == "PoolRealArray" || id == "FloatArray") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -1855,7 +1855,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::POOL_REAL_ARRAY: { - p_store_string_func(p_store_string_ud, "PoolFloatArray( "); + p_store_string_func(p_store_string_ud, "PoolRealArray( "); PoolVector<real_t> data = p_variant; int len = data.size(); PoolVector<real_t>::Read r = data.read(); diff --git a/doc/base/classes.xml b/doc/base/classes.xml index ba5f0bba94..70a7dcb651 100644 --- a/doc/base/classes.xml +++ b/doc/base/classes.xml @@ -39,7 +39,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Remove sign (works for integer and float). + Returns the absolute value of parameter s (i.e. unsigned value, works for integer and float). </description> </method> <method name="acos"> @@ -48,7 +48,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Arc-cosine. + Returns the principal value of the arc cosine of s, expressed in radians. In trigonometrics, arc cosine is the inverse operation of cosine. </description> </method> <method name="asin"> @@ -57,7 +57,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Arc-sine. + Returns the principal value of the arc sine of s, expressed in radians. In trigonometrics, arc sine is the inverse operation of sine. </description> </method> <method name="assert"> @@ -75,7 +75,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Arc-tangent. + Returns the principal value of the arc tangent of s, expressed in radians. In trigonometrics, arc tangent is the inverse operation of tangent. Notice that because of the sign ambiguity, the function cannot determine with certainty in which quadrant the angle falls only by its tangent value. See [method atan2] for an alternative that takes a fractional argument instead. </description> </method> <method name="atan2"> @@ -86,7 +86,7 @@ <argument index="1" name="y" type="float"> </argument> <description> - Arc-tangent that takes a 2D vector as argument, returns the full -pi to +pi range. + Returns the principal value of the arc tangent of y/x, expressed in radians. To compute the value, the function takes into account the sign of both arguments in order to determine the quadrant. </description> </method> <method name="bytes2var"> @@ -104,7 +104,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Ceiling (rounds up to nearest integer). + Rounds s upward, returning the smallest integral value that is not less than s. </description> </method> <method name="char"> @@ -125,7 +125,7 @@ <argument index="2" name="max" type="float"> </argument> <description> - Clamp both values to a range. + Clamps a value between a minimum and maximum value. </description> </method> <method name="convert"> @@ -145,7 +145,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Standard cosine function. + Returns the cosine of an angle of s radians. </description> </method> <method name="cosh"> @@ -154,7 +154,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Hyperbolic cosine. + Returns the hyperbolic cosine of s. </description> </method> <method name="db2linear"> @@ -223,7 +223,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Exponential logarithm. + Returns the base-e exponential function of s, which is e raised to the power s: e^s. </description> </method> <method name="floor"> @@ -232,7 +232,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Floor (rounds down to nearest integer). + Rounds s downward, returning the largest integral value that is not greater than s. </description> </method> <method name="fmod"> @@ -243,7 +243,11 @@ <argument index="1" name="y" type="float"> </argument> <description> - Module (remainder of x/y). + Returns the floating-point remainder of x/y (rounded towards zero): + [codeblock] + fmod = x - tquot * y + [/codeblock] + Where tquot is the truncated (i.e., rounded towards zero) result of: x/y. </description> </method> <method name="fposmod"> @@ -301,6 +305,7 @@ <argument index="0" name="s" type="float"> </argument> <description> + Returns whether s is an infinity value (either positive infinity or negative infinity). </description> </method> <method name="is_nan"> @@ -309,6 +314,7 @@ <argument index="0" name="s" type="float"> </argument> <description> + Returns whether s is a NaN (Not-A-Number) value. </description> </method> <method name="lerp"> @@ -539,7 +545,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Round to nearest integer. + Returns the integral value that is nearest to s, with halfway cases rounded away from zero. </description> </method> <method name="seed"> @@ -566,7 +572,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Standard sine function. + Returns the sine of an angle of s radians. </description> </method> <method name="sinh"> @@ -575,7 +581,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Hyperbolic sine. + Returns the hyperbolic sine of s. </description> </method> <method name="sqrt"> @@ -584,7 +590,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Square root. + Returns the square root of s. </description> </method> <method name="stepify"> @@ -606,7 +612,7 @@ <argument index="1" name="..." type="Variant"> </argument> <description> - Convert one or more arguments to strings in the best way possible. + Convert one or more arguments to string in the best way possible. </description> </method> <method name="str2var"> @@ -624,7 +630,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Standard tangent function. + Returns the tangent of an angle of s radians. </description> </method> <method name="tanh"> @@ -633,7 +639,7 @@ <argument index="0" name="s" type="float"> </argument> <description> - Hyperbolic tangent. + Returns the hyperbolic tangent of s. </description> </method> <method name="to_json"> @@ -668,6 +674,7 @@ <argument index="0" name="json" type="String"> </argument> <description> + This method is used to validate the structure and data types of a piece of JSON, similar to XML Schema for XML. </description> </method> <method name="var2bytes"> @@ -695,6 +702,7 @@ </argument> <description> Return a weak reference to an object. + A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it. </description> </method> <method name="yield"> @@ -715,8 +723,11 @@ Constant that represents how many times the diameter of a circumference fits around its perimeter. </constant> <constant name="INF" value="inf"> + A positive infinity. (For negative infinity, use -INF). </constant> <constant name="NAN" value="nan"> + Macro constant that expands to an expression of type float that represents a NaN. + The NaN values are used to identify undefined or non-representable values for floating-point elements, such as the square root of negative numbers or the result of 0/0. </constant> </constants> </class> @@ -946,9 +957,6 @@ <constant name="KEY_F16" value="16777259"> F16 Key </constant> - <constant name="KEY_KP_ENTER" value="16777344"> - Enter Key on Numpad - </constant> <constant name="KEY_KP_MULTIPLY" value="16777345"> Multiply Key on Numpad </constant> @@ -1960,8 +1968,11 @@ </class> <class name="AStar" inherits="Reference" category="Core"> <brief_description> + AStar class representation that uses vectors as edges. </brief_description> <description> + A* (A star) is a computer algorithm that is widely used in pathfinding and graph traversal, the process of plotting an efficiently directed path between multiple points. It enjoys widespread use due to its performance and accuracy. Godot's A* implementation make use of vectors as points. + You must add points manually with [method AStar.add_point] and create segments manually with [method AStar.connect_points]. So you can test if there is a path between two points with the [method AStar.are_points_connected] function, get the list of existing ids in the found path with [method AStar.get_id_path], or the points list with [method AStar.get_point_path]. </description> <methods> <method name="_compute_cost" qualifiers="virtual"> @@ -1988,7 +1999,7 @@ <argument index="2" name="weight_scale" type="float" default="1"> </argument> <description> - Add a new point at the given position. The [code]weight_scale[/code] has to be 1 or larger. + Add a new point at the given position [code]pos[/code] with the given identifier [code]id[/code]. The [code]weight_scale[/code] has to be 1 or larger. </description> </method> <method name="are_points_connected" qualifiers="const"> @@ -1999,10 +2010,12 @@ <argument index="1" name="to_id" type="int"> </argument> <description> + Returns if there is a connection/segment between points [code]id[/code] and [code]from_id[/code] </description> </method> <method name="clear"> <description> + Clear all the points and segments from AStar instance. </description> </method> <method name="connect_points"> @@ -2013,6 +2026,7 @@ <argument index="2" name="bidirectional" type="bool" default="true"> </argument> <description> + Create a segment between points [code]id[/code] and [code]to_id[/code]. </description> </method> <method name="disconnect_points"> @@ -2021,6 +2035,7 @@ <argument index="1" name="to_id" type="int"> </argument> <description> + Deletes a segment between points [code]id[/code] and [code]to_id[/code]. </description> </method> <method name="get_available_point_id" qualifiers="const"> @@ -2035,6 +2050,7 @@ <argument index="0" name="to_pos" type="Vector3"> </argument> <description> + Returns the id of closest point of given point. -1 is returned if there are no points on AStar. </description> </method> <method name="get_closest_pos_in_segment" qualifiers="const"> @@ -2043,6 +2059,7 @@ <argument index="0" name="to_pos" type="Vector3"> </argument> <description> + Returns the position of closest point that has segments. </description> </method> <method name="get_id_path"> @@ -2053,6 +2070,7 @@ <argument index="1" name="to_id" type="int"> </argument> <description> + Returns an array with the point ids of path found by AStar between two given points. </description> </method> <method name="get_point_path"> @@ -2063,6 +2081,7 @@ <argument index="1" name="to_id" type="int"> </argument> <description> + Returns an array with the points of path found by AStar between two given points. </description> </method> <method name="get_point_pos" qualifiers="const"> @@ -2071,6 +2090,7 @@ <argument index="0" name="id" type="int"> </argument> <description> + Returns the position of point with given id. </description> </method> <method name="get_point_weight_scale" qualifiers="const"> @@ -2079,6 +2099,7 @@ <argument index="0" name="id" type="int"> </argument> <description> + Returns the weight scale of point with given id. </description> </method> <method name="has_point" qualifiers="const"> @@ -2087,12 +2108,14 @@ <argument index="0" name="id" type="int"> </argument> <description> + Returns if the point with given id exists on AStar; </description> </method> <method name="remove_point"> <argument index="0" name="id" type="int"> </argument> <description> + Removes the point with given id. </description> </method> </methods> @@ -10146,12 +10169,73 @@ <description> </description> </method> + <method name="create_shape_owner"> + <return type="int"> + </return> + <argument index="0" name="owner" type="Object"> + </argument> + <description> + Creates new holder for the shapes. Argument is a [CollisionShape] node. It will return owner_id which usually you will want to save for later use. + </description> + </method> <method name="get_rid" qualifiers="const"> <return type="RID"> </return> <description> </description> </method> + <method name="get_shape_owners"> + <return type="Array"> + </return> + <description> + Shape owner is a node which is holding concrete shape resources. This method will return an array which is holding an integer numbers that are representing unique ID of each owner. You can use those ids when you are using others shape_owner methods. + </description> + </method> + <method name="shape_owner_clear_shapes"> + <argument index="0" name="owner_id" type="int"> + </argument> + <description> + Will remove all the shapes associated with given owner. + </description> + </method> + <method name="shape_owner_get_shape"> + <return type="Shape"> + </return> + <argument index="0" name="owner_id" type="int"> + </argument> + <argument index="1" name="shape_id" type="int"> + </argument> + <description> + Will return a [Shape]. First argument owner_id is an integer that can be obtained from [method get_shape_owners]. Shape_id is a position of the shape inside owner; it's a value in range from 0 to [method shape_owner_get_shape_count]. + </description> + </method> + <method name="shape_owner_get_shape_count"> + <return type="int"> + </return> + <argument index="0" name="owner_id" type="int"> + </argument> + <description> + Returns number of shapes to which given owner is associated to. + </description> + </method> + <method name="shape_owner_get_transform"> + <return type="Transform"> + </return> + <argument index="0" name="owner_id" type="int"> + </argument> + <description> + Will return [Transform] of an owner node. + </description> + </method> + <method name="shape_owner_remove_shape"> + <argument index="0" name="owner_id" type="int"> + </argument> + <argument index="1" name="shape_id" type="int"> + </argument> + <description> + Removes related shape from the owner. + </description> + </method> <method name="is_ray_pickable" qualifiers="const"> <return type="bool"> </return> @@ -10222,6 +10306,15 @@ <description> </description> </method> + <method name="create_shape_owner"> + <return type="int"> + </return> + <argument index="0" name="owner" type="Object"> + </argument> + <description> + Creates new holder for the shapes. Argument is a [CollisionShape2D] node. It will return owner_id which usually you will want to save for later use. + </description> + </method> <method name="get_rid" qualifiers="const"> <return type="RID"> </return> @@ -10229,6 +10322,58 @@ Return the RID of this object. </description> </method> + <method name="get_shape_owners"> + <return type="Array"> + </return> + <description> + Shape owner is a node which is holding concrete shape resources. This method will return an array which is holding an integer numbers that are representing unique ID of each owner. You can use those ids when you are using others shape_owner methods. + </description> + </method> + <method name="shape_owner_clear_shapes"> + <argument index="0" name="owner_id" type="int"> + </argument> + <description> + Will remove all the shapes associated with given owner. + </description> + </method> + <method name="shape_owner_get_shape"> + <return type="Shape2D"> + </return> + <argument index="0" name="owner_id" type="int"> + </argument> + <argument index="1" name="shape_id" type="int"> + </argument> + <description> + Will return a [Shape2D]. First argument owner_id is an integer that can be obtained from [method get_shape_owners]. Shape_id is a position of the shape inside owner; it's a value in range from 0 to [method shape_owner_get_shape_count]. + </description> + </method> + <method name="shape_owner_get_shape_count"> + <return type="int"> + </return> + <argument index="0" name="owner_id" type="int"> + </argument> + <description> + Returns number of shapes to which given owner is associated to. + </description> + </method> + <method name="shape_owner_get_transform"> + <return type="Transform2D"> + </return> + <argument index="0" name="owner_id" type="int"> + </argument> + <description> + Will return [Transform2D] of an owner node. + </description> + </method> + <method name="shape_owner_remove_shape"> + <argument index="0" name="owner_id" type="int"> + </argument> + <argument index="1" name="shape_id" type="int"> + </argument> + <description> + Removes related shape from the owner. + </description> + </method> <method name="is_pickable" qualifiers="const"> <return type="bool"> </return> @@ -10743,17 +10888,17 @@ </theme_item> <theme_item name="color_sample" type="Texture"> </theme_item> - <theme_item name="color_width" type="int"> - </theme_item> - <theme_item name="hseparator" type="int"> + <theme_item name="h_width" type="int"> </theme_item> <theme_item name="label_width" type="int"> </theme_item> + <theme_item name="margin" type="int"> + </theme_item> <theme_item name="screen_picker" type="Texture"> </theme_item> - <theme_item name="value_height" type="int"> + <theme_item name="sv_height" type="int"> </theme_item> - <theme_item name="value_width" type="int"> + <theme_item name="sv_width" type="int"> </theme_item> </theme_items> </class> @@ -14036,7 +14181,7 @@ <description> Add a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed. When given node or resource is selected, the base type will be instanced (ie, "Spatial", "Control", "Resource"), then the script will be loaded and set to this object. - You can use the [method EditorPlugin.handles] to check if your custom object is being edited by checking the script or using 'extends' keyword. + You can use the [method EditorPlugin.handles] to check if your custom object is being edited by checking the script or using 'is' keyword. During run-time, this will be a simple object with a script so this function does not need to be called then. </description> </method> @@ -14114,6 +14259,8 @@ <argument index="1" name="event" type="InputEvent"> </argument> <description> + Implement this function if you are interested in 3D view screen input events. It will be called only if currently selected node is handled by your plugin. + If you would like to always gets those input events then additionally use [method set_input_forwarding_always_enabled]. </description> </method> <method name="get_base_control"> @@ -14137,6 +14284,13 @@ Get the general settings for the editor (the same window that appears in the Settings menu). </description> </method> + <method name="get_edited_scene_root"> + <return type="Node"> + </return> + <description> + Returns root node of currently edited scene. + </description> + </method> <method name="get_editor_viewport"> <return type="Control"> </return> @@ -14151,6 +14305,13 @@ Get the name of the editor plugin. For main scren plugins this is what will appear in the selector (which by default is 2D, 3D, Script). </description> </method> + <method name="get_open_scenes"> + <return type="Array"> + </return> + <description> + Will return an Array of Strings which represent file paths to currently open scenes. + </description> + </method> <method name="get_resource_filesystem"> <return type="EditorFileSystem"> </return> @@ -14165,6 +14326,13 @@ Get tool for generating resource previews. </description> </method> + <method name="get_script_editor"> + <return type="ScriptEditor"> + </return> + <description> + Will return ScriptEditor object which contains informations about state of the scripts which are currently open by the editor. + </description> + </method> <method name="get_selection"> <return type="EditorSelection"> </return> @@ -14289,6 +14457,7 @@ </method> <method name="set_input_event_forwarding_always_enabled"> <description> + Use this method if you always want to receive inputs from 3D view screen inside [method forward_spatial_gui_input]. It might be especially usable if your plugin will want to use raycast in the scene. </description> </method> <method name="set_state" qualifiers="virtual"> @@ -14345,6 +14514,29 @@ <constant name="DOCK_SLOT_MAX" value="8"> </constant> </constants> + <signals> + <signal name="main_screen_changed"> + <argument index="0" name="screen_name" type="String"> + </argument> + <description> + Emitted when user change main screen view (2D, 3D, Script, AssetLib). Works also with screens which are defined by plugins. + </description> + </signal> + <signal name="scene_changed"> + <argument index="0" name="scene_root" type="Node"> + </argument> + <description> + Emitted when user change scene. The argument is a root node of freshly opened scene. + </description> + </signal> + <signal name="scene_closed"> + <argument index="0" name="filepath" type="String"> + </argument> + <description> + Emitted when user close scene. The argument is file path to a closed scene. + </description> + </signal> + </signals> </class> <class name="EditorResourcePreview" inherits="Node" category="Core"> <brief_description> @@ -16260,6 +16452,8 @@ <constant name="COMPRESSION_ZSTD" value="2"> Use the Zstd compression method. </constant> + <constant name="COMPRESSION_GZIP" value="3"> + </constant> </constants> </class> <class name="FileDialog" inherits="ConfirmationDialog" category="Core"> @@ -16768,6 +16962,12 @@ <description> </description> </method> + <method name="get_normal_bias" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_probe_data" qualifiers="const"> <return type="Object"> </return> @@ -16834,6 +17034,12 @@ <description> </description> </method> + <method name="set_normal_bias"> + <argument index="0" name="max" type="float"> + </argument> + <description> + </description> + </method> <method name="set_probe_data"> <argument index="0" name="data" type="Object"> </argument> @@ -16868,6 +17074,8 @@ </member> <member name="interior" type="bool" setter="set_interior" getter="is_interior" brief=""> </member> + <member name="normal_bias" type="float" setter="set_normal_bias" getter="get_normal_bias" brief=""> + </member> <member name="propagation" type="float" setter="set_propagation" getter="get_propagation" brief=""> </member> <member name="subdiv" type="int" setter="set_subdiv" getter="get_subdiv" brief=""> @@ -16926,6 +17134,12 @@ <description> </description> </method> + <method name="get_normal_bias" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> <method name="get_propagation" qualifiers="const"> <return type="float"> </return> @@ -16998,6 +17212,12 @@ <description> </description> </method> + <method name="set_normal_bias"> + <argument index="0" name="bias" type="float"> + </argument> + <description> + </description> + </method> <method name="set_propagation"> <argument index="0" name="propagation" type="float"> </argument> @@ -17028,6 +17248,8 @@ </member> <member name="interior" type="bool" setter="set_interior" getter="is_interior" brief=""> </member> + <member name="normal_bias" type="float" setter="set_normal_bias" getter="get_normal_bias" brief=""> + </member> <member name="propagation" type="float" setter="set_propagation" getter="get_propagation" brief=""> </member> <member name="to_cell_xform" type="Transform" setter="set_to_cell_xform" getter="get_to_cell_xform" brief=""> @@ -22287,7 +22509,16 @@ <argument index="0" name="rel_vec" type="Vector3"> </argument> <description> - Move the body in the given direction, stopping if there is an obstacle. The returned vector is how much movement was remaining before being stopped. + Move the body in the given direction, stopping if there is an obstacle. If as a result of a movement there will be any collision then informations about this collision will be in returned dictionary. Dictionary will contains those keys: + - "position" - collision position + - "normal" - collision normal + - "local_shape" - id of this kinematic body shape that took part in a collision + - "travel" - traveled movement before being stopped + - "remainder" - remaining movement before being stopped + - "collider_id" - id of the collider, it can be used when dealing with [PhysicsServer] + - "collider" - colliding body + - "collider_shape_index" - index of the colliding shape, inside collider body "collider_metadata" + If the body did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead. Please note that this method is less user friendly than [method move_and_slide]. If you don't want to program each edge case manually, then it's recommended to use [method move_and_slide] instead. </description> </method> <method name="move_and_slide"> @@ -22469,7 +22700,16 @@ <argument index="0" name="rel_vec" type="Vector2"> </argument> <description> - Move the body in the given direction, stopping if there is an obstacle. The returned vector is how much movement was remaining before being stopped. + Move the body in the given direction, stopping if there is an obstacle. If as a result of a movement there will be any collision then informations about this collision will be in returned dictionary. Dictionary will contains those keys: + - "position" - collision position + - "normal" - collision normal + - "local_shape" - id of this kinematic body shape that took part in a collision + - "travel" - traveled movement before being stopped + - "remainder" - remaining movement before being stopped + - "collider_id" - id of the collider, it can be used when dealing with [Physics2DServer] + - "collider" - colliding body + - "collider_shape_index" - index of the colliding shape, inside collider body "collider_metadata" + If the body did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead. Please note that this method is less user friendly than [method move_and_slide]. If you don't want to program each edge case manually, then it's recommended to use [method move_and_slide] instead. </description> </method> <method name="move_and_slide"> @@ -24667,7 +24907,7 @@ <description> </description> </method> - <method name="create_debug_tagents"> + <method name="create_debug_tangents"> <description> </description> </method> @@ -27915,6 +28155,8 @@ </description> </method> <method name="get_meta" qualifiers="const"> + <return type="Variant"> + </return> <argument index="0" name="name" type="String"> </argument> <description> @@ -39989,6 +40231,44 @@ <constants> </constants> </class> +<class name="ScriptEditor" inherits="PanelContainer" category="Core"> + <brief_description> + </brief_description> + <description> + </description> + <methods> + <method name="get_current_script"> + <return type="Script"> + </return> + <description> + Returns a [Script] that is currently active in editor. + </description> + </method> + <method name="get_open_scripts"> + <return type="Array"> + </return> + <description> + Returns an array with all [Script] objects which are currently open in editor. + </description> + </method> + </methods> + <signals> + <signal name="editor_script_changed"> + <argument index="0" name="script" type="Script"> + </argument> + <description> + Emitted when user changed active script. Argument is a freshly activated [Script]. + </description> + </signal> + <signal name="script_close"> + <argument index="0" name="script" type="Script"> + </argument> + <description> + Emitted when editor is about to close the active script. Argument is a [Script] that is going to be closed. + </description> + </signal> + </signals> +</class> <class name="SegmentShape2D" inherits="Shape2D" category="Core"> <brief_description> Segment Shape for 2D Collision Detection. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 21bdb217fc..cd74c450f5 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -3516,7 +3516,6 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p _copy_screen(); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, false); - state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false); @@ -3611,6 +3610,16 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p composite_from = storage->frame.current_rt->effects.mip_maps[0].color; } + if (env->dof_blur_near_enabled || env->dof_blur_far_enabled) { + //these needed to disable filtering, reenamble + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + if (env->auto_exposure) { //compute auto exposure diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 76df57d410..89bea1e8cc 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5999,6 +5999,13 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { static const int msaa_value[] = { 0, 2, 4, 8, 16 }; int msaa = msaa_value[rt->msaa]; + int max_samples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &max_samples); + if (msaa > max_samples) { + WARN_PRINTS("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); + msaa = max_samples; + } + //regular fbo glGenFramebuffers(1, &rt->buffers.fbo); glBindFramebuffer(GL_FRAMEBUFFER, rt->buffers.fbo); @@ -6189,6 +6196,8 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glBindTexture(GL_TEXTURE_2D, rt->effects.mip_maps[i].color); int level = 0; + int fb_w = w; + int fb_h = h; while (true) { @@ -6206,13 +6215,15 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { level++; } - glTexStorage2DCustom(GL_TEXTURE_2D, level + 1, color_internal_format, rt->width, rt->height, color_format, color_type); + glTexStorage2DCustom(GL_TEXTURE_2D, level + 1, color_internal_format, fb_w, fb_h, color_format, color_type); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); glDisable(GL_SCISSOR_TEST); glColorMask(1, 1, 1, 1); - glDepthMask(GL_TRUE); + if (rt->buffers.active == false) { + glDepthMask(GL_TRUE); + } for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { @@ -6235,7 +6246,6 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { float zero[4] = { 1, 0, 1, 0 }; glViewport(0, 0, rt->effects.mip_maps[i].sizes[j].width, rt->effects.mip_maps[i].sizes[j].height); - glClearBufferfv(GL_COLOR, 0, zero); if (used_depth) { glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); @@ -6912,7 +6922,7 @@ void RasterizerStorageGLES3::initialize() { config.use_anisotropic_filter = config.extensions.has("GL_EXT_texture_filter_anisotropic"); if (config.use_anisotropic_filter) { glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &config.anisotropic_level); - config.anisotropic_level = MIN(int(ProjectSettings::get_singleton()->get("rendering/quality/anisotropic_filter_level")), config.anisotropic_level); + config.anisotropic_level = MIN(int(ProjectSettings::get_singleton()->get("rendering/quality/filters/anisotropic_filter_level")), config.anisotropic_level); } frame.clear_request = false; diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 7d0f3e5745..b536c9841c 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1285,12 +1285,11 @@ public: buffers.fbo = 0; used_in_frame = false; - flags[RENDER_TARGET_VFLIP] = false; - flags[RENDER_TARGET_TRANSPARENT] = false; - flags[RENDER_TARGET_NO_3D_EFFECTS] = false; - flags[RENDER_TARGET_NO_3D] = false; - flags[RENDER_TARGET_NO_SAMPLING] = false; + for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { + flags[i] = false; + } flags[RENDER_TARGET_HDR] = true; + buffers.active = false; buffers.effects_active = false; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index acece2e639..340a1f24d2 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -810,6 +810,9 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { vec2 screen_rel = to_screen - from_screen; + if (length(screen_rel)<0.00001) + return 1.0; //too small, don't do anything + /*float pixel_size; //approximate pixel size if (screen_rel.x > screen_rel.y) { @@ -825,15 +828,16 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { vec2 pixel_incr = normalize(screen_rel)*screen_pixel_size; - float steps = length(screen_rel) / length(pixel_incr); + float steps = length(screen_rel) / length(pixel_incr); + steps = min(2000.0,steps); //put a limit to avoid freezing in some strange situation //steps=10.0; vec4 incr = (dest - source)/steps; float ratio=0.0; float ratio_incr = 1.0/steps; - do { + while(steps>0.0) { source += incr*2.0; bias+=incr*2.0; @@ -851,7 +855,7 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { ratio+=ratio_incr; steps-=1.0; - } while (steps>0.0); + } return 1.0; } diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index c6dfc6917d..988e31d1ea 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -144,6 +144,38 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod) #endif +vec3 tonemap_filmic(vec3 color,float white) { + + float A = 0.15; + float B = 0.50; + float C = 0.10; + float D = 0.20; + float E = 0.02; + float F = 0.30; + float W = 11.2; + + vec3 coltn = ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F; + float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F; + + return coltn/whitetn; + +} + +vec3 tonemap_aces(vec3 color) { + float a = 2.51f; + float b = 0.03f; + float c = 2.43f; + float d = 0.59f; + float e = 0.14f; + return color = clamp((color*(a*color+b))/(color*(c*color+d)+e),vec3(0.0),vec3(1.0)); +} + +vec3 tonemap_reindhart(vec3 color,vec3 white) { + + return ( color * ( 1.0 + ( color / ( white) ) ) ) / ( 1.0 + color ); +} + + void main() { ivec2 coord = ivec2(gl_FragCoord.xy); @@ -157,8 +189,11 @@ void main() { color*=exposure; - #if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) +#define USING_GLOW +#endif + +#if defined(USING_GLOW) vec3 glow = vec3(0.0); #ifdef USE_GLOW_LEVEL1 @@ -193,85 +228,83 @@ void main() { glow *= glow_intensity; +#endif -#ifdef USE_GLOW_REPLACE +#ifdef USE_REINDHART_TONEMAPPER - color.rgb = glow; + color.rgb = tonemap_reindhart(color.rgb,white); + +# if defined(USING_GLOW) + glow = tonemap_reindhart(glow,white); +# endif #endif -#ifdef USE_GLOW_SCREEN +#ifdef USE_FILMIC_TONEMAPPER - color.rgb = clamp((color.rgb + glow) - (color.rgb * glow), 0.0, 1.0); + color.rgb = tonemap_filmic(color.rgb,white); + +# if defined(USING_GLOW) + glow = tonemap_filmic(glow,white); +# endif #endif -#ifdef USE_GLOW_SOFTLIGHT +#ifdef USE_ACES_TONEMAPPER - { + color.rgb = tonemap_aces(color.rgb); - glow = (glow * 0.5) + 0.5; - color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); - } +# if defined(USING_GLOW) + glow = tonemap_aces(glow); +# endif #endif -#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) - color.rgb+=glow; -#endif - + //regular Linear -> SRGB conversion + vec3 a = vec3(0.055); + color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308))); +#if defined(USING_GLOW) + glow = mix( (vec3(1.0)+a)*pow(glow,vec3(1.0/2.4))-a , 12.92*glow , lessThan(glow,vec3(0.0031308))); #endif +//glow needs to be added in SRGB space (together with image space effects) -#ifdef USE_REINDHART_TONEMAPPER + color.rgb = clamp(color.rgb,0.0,1.0); - { - color.rgb = ( color.rgb * ( 1.0 + ( color.rgb / ( white) ) ) ) / ( 1.0 + color.rgb ); - - } +#if defined(USING_GLOW) + glow = clamp(glow,0.0,1.0); #endif -#ifdef USE_FILMIC_TONEMAPPER +#ifdef USE_GLOW_REPLACE - { + color.rgb = glow; - float A = 0.15; - float B = 0.50; - float C = 0.10; - float D = 0.20; - float E = 0.02; - float F = 0.30; - float W = 11.2; +#endif - vec3 coltn = ((color.rgb*(A*color.rgb+C*B)+D*E)/(color.rgb*(A*color.rgb+B)+D*F))-E/F; - float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F; +#ifdef USE_GLOW_SCREEN - color.rgb=coltn/whitetn; + color.rgb = max((color.rgb + glow) - (color.rgb * glow), vec3(0.0)); - } #endif -#ifdef USE_ACES_TONEMAPPER +#ifdef USE_GLOW_SOFTLIGHT { - float a = 2.51f; - float b = 0.03f; - float c = 2.43f; - float d = 0.59f; - float e = 0.14f; - color.rgb = clamp((color.rgb*(a*color.rgb+b))/(color.rgb*(c*color.rgb+d)+e),vec3(0.0),vec3(1.0)); + + glow = (glow * 0.5) + 0.5; + color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); + color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); + color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); } #endif - //regular Linear -> SRGB conversion - vec3 a = vec3(0.055); - color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308))); - +#if defined(USING_GLOW) && !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) + //additive + color.rgb+=glow; +#endif #ifdef USE_BCS diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index d05529ef9a..e424590881 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -453,7 +453,7 @@ Error OS_Unix::close_dynamic_library(void *p_library_handle) { return OK; } -Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle) { +Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { const char *error; dlerror(); // Clear existing errors @@ -461,8 +461,12 @@ Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const S error = dlerror(); if (error != NULL) { - ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + error); - ERR_FAIL_V(ERR_CANT_RESOLVE); + if (!p_optional) { + ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + error); + ERR_FAIL_V(ERR_CANT_RESOLVE); + } else { + return ERR_CANT_RESOLVE; + } } return OK; } diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 953b0f0431..fdc6d6e28f 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -85,7 +85,7 @@ public: virtual Error open_dynamic_library(const String p_path, void *&p_library_handle); virtual Error close_dynamic_library(void *p_library_handle); - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle); + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); virtual Error set_cwd(const String &p_cwd); diff --git a/editor/asset_library_editor_plugin.cpp b/editor/asset_library_editor_plugin.cpp index 74e21b31ea..f92b70d0c0 100644 --- a/editor/asset_library_editor_plugin.cpp +++ b/editor/asset_library_editor_plugin.cpp @@ -1334,10 +1334,13 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { search_hb2->add_child(memnew(Label(TTR("Site:") + " "))); repository = memnew(OptionButton); + // FIXME: Reenable me once GH-7147 is fixed. + /* repository->add_item("godotengine.org"); repository->set_item_metadata(0, "https://godotengine.org/asset-library/api"); - repository->add_item("localhost"); // TODO: Maybe remove? - repository->set_item_metadata(1, "http://127.0.0.1/asset-library/api"); + */ + repository->add_item("localhost"); + repository->set_item_metadata(/*1*/ 0, "http://127.0.0.1/asset-library/api"); repository->connect("item_selected", this, "_repository_changed"); search_hb2->add_child(repository); diff --git a/editor/collada/collada.h b/editor/collada/collada.h index 38e66a7e45..8945e14cce 100644 --- a/editor/collada/collada.h +++ b/editor/collada/collada.h @@ -32,9 +32,9 @@ #ifndef COLLADA_H #define COLLADA_H -#include "project_settings.h" #include "io/xml_parser.h" #include "map.h" +#include "project_settings.h" #include "scene/resources/material.h" class Collada { diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index fa90cd36b3..69d7475f4c 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -29,10 +29,10 @@ /*************************************************************************/ #include "doc_data.h" -#include "project_settings.h" #include "global_constants.h" #include "io/compression.h" #include "io/marshalls.h" +#include "project_settings.h" #include "scene/resources/theme.h" #include "script_language.h" #include "version.h" diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 2328a42a07..fd90c766fd 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -137,7 +137,6 @@ EditorAbout::EditorAbout() { tc->add_child(license_thirdparty); Label *tpl_label = memnew(Label); - tpl_label->set_custom_minimum_size(Size2(0, 64 * EDSCALE)); tpl_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); tpl_label->set_autowrap(true); tpl_label->set_text(TTR("Godot Engine relies on a number of thirdparty free and open source libraries, all compatible with the terms of its MIT license. The following is an exhaustive list of all such thirdparty components with their respective copyright statements and license terms.")); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 399c22bf2c..dde94cb334 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -30,8 +30,8 @@ #include "editor_autoload_settings.h" #include "editor_node.h" -#include "project_settings.h" #include "global_constants.h" +#include "project_settings.h" #define PREVIEW_LIST_MAX_SIZE 10 diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index f8dbd9abe5..c82e8f1226 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -31,10 +31,10 @@ #include "editor_node.h" #include "editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" #include "os/dir_access.h" #include "os/file_access.h" +#include "project_settings.h" #include "scene/resources/packed_scene.h" void EditorHistory::_cleanup_history() { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 0c47daf5e6..0cdb981306 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1949,7 +1949,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case FILE_CLOSE: { if (!p_confirmed && (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER)) { - tab_closing = p_option == FILE_CLOSE ? editor_data.get_edited_scene() : _next_unsaved_scene(); + tab_closing = p_option == FILE_CLOSE ? editor_data.get_edited_scene() : _next_unsaved_scene(false); String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename(); save_confirmation->get_ok()->set_text(TTR("Save & Close")); save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene")); @@ -2481,7 +2481,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case RUN_PROJECT_MANAGER: { if (!p_confirmed) { - if (_next_unsaved_scene() == -1) { + bool save_each = EDITOR_DEF("interface/save_each_scene_on_quit", true); + if (_next_unsaved_scene(!save_each) == -1) { bool confirm = EDITOR_DEF("interface/quit_confirmation", true); if (confirm) { @@ -2495,21 +2496,16 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } else { - bool save_each = EDITOR_DEF("interface/save_each_scene_on_quit", true); if (save_each) { _menu_option_confirm(p_option == FILE_QUIT ? FILE_CLOSE_ALL_AND_QUIT : FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER, false); } else { String unsaved_scenes; - for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; - if (unsaved) { - - String scene_filename = editor_data.get_edited_scene_root(i)->get_filename(); - unsaved_scenes += "\n " + scene_filename; - } + int i = _next_unsaved_scene(true, 0); + while (i != -1) { + unsaved_scenes += "\n " + editor_data.get_edited_scene_root(i)->get_filename(); + i = _next_unsaved_scene(true, ++i); } save_confirmation->get_ok()->set_text(TTR("Save & Quit")); @@ -2522,7 +2518,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { break; } - if (_next_unsaved_scene() != -1) { + if (_next_unsaved_scene(true) != -1) { _save_all_scenes(); } _discard_changes(); @@ -2751,15 +2747,18 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } -int EditorNode::_next_unsaved_scene() { +int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { - for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { + for (int i = p_start; i < editor_data.get_edited_scene_count(); i++) { if (!editor_data.get_edited_scene_root(i)) continue; int current = editor_data.get_edited_scene(); bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; if (unsaved) { + String scene_filename = editor_data.get_edited_scene_root(i)->get_filename(); + if (p_valid_filename && scene_filename.length() == 0) + continue; return i; } } @@ -2779,7 +2778,7 @@ void EditorNode::_discard_changes(const String &p_str) { _update_scene_tabs(); if (current_option == FILE_CLOSE_ALL_AND_QUIT || current_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) { - if (_next_unsaved_scene() == -1) { + if (_next_unsaved_scene(false) == -1) { current_option = current_option == FILE_CLOSE_ALL_AND_QUIT ? FILE_QUIT : RUN_PROJECT_MANAGER; _discard_changes(); } else { diff --git a/editor/editor_node.h b/editor/editor_node.h index 6553d3eee2..a440aaa1e6 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -464,7 +464,7 @@ private: void _save_scene(String p_file, int idx = -1); void _save_all_scenes(); - int _next_unsaved_scene(); + int _next_unsaved_scene(bool p_valid_filename, int p_start = 0); void _discard_changes(const String &p_str = String()); void _instance_request(const Vector<String> &p_files); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 6ab1468b1d..63bee33092 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -30,10 +30,10 @@ #include "editor_plugin_settings.h" #include "editor_node.h" -#include "project_settings.h" #include "io/config_file.h" #include "os/file_access.h" #include "os/main_loop.h" +#include "project_settings.h" #include "scene/gui/margin_container.h" void EditorPluginSettings::_notification(int p_what) { diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 3a6b34b7b4..89fa004eb1 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -31,11 +31,11 @@ #include "editor_scale.h" #include "editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "message_queue.h" #include "os/file_access.h" +#include "project_settings.h" bool EditorResourcePreviewGenerator::handles(const String &p_type) const { diff --git a/editor/file_type_cache.cpp b/editor/file_type_cache.cpp index 100ebe21cd..728e80bba7 100644 --- a/editor/file_type_cache.cpp +++ b/editor/file_type_cache.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "file_type_cache.h" -#include "project_settings.h" #include "os/file_access.h" +#include "project_settings.h" FileTypeCache *FileTypeCache::singleton = NULL; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index eacb1d2cd9..77ca1a5145 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -31,11 +31,11 @@ #include "editor_node.h" #include "editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" #include "os/dir_access.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" #include "scene/main/viewport.h" bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir) { diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 5bf2da9912..3626c6be59 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -554,10 +554,10 @@ static void _generate_tangents_and_binormals(const PoolVector<int> &p_indices, c tangent = Vector3(); } else { tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, - (t2 * z1 - t1 * z2) * r) + (t2 * z1 - t1 * z2) * r) .normalized(); binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, - (s1 * z2 - s2 * z1) * r) + (s1 * z2 - s2 * z1) * r) .normalized(); } diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 25548f7899..8f86e64cf2 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -323,8 +323,8 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in surf_tool->add_smooth_group(false); else surf_tool->add_smooth_group(true); - } else if (l.begins_with("g ") || l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh - + } else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh + //groups are too annoying if (surf_tool->get_vertex_array().size()) { //another group going on, commit it if (normals.size() == 0) { diff --git a/editor/io_plugins/editor_export_scene.cpp b/editor/io_plugins/editor_export_scene.cpp index 390217053a..6392b4a715 100644 --- a/editor/io_plugins/editor_export_scene.cpp +++ b/editor/io_plugins/editor_export_scene.cpp @@ -30,11 +30,11 @@ #include "editor_export_scene.h" #if 0 #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/dir_access.h" #include "os/file_access.h" +#include "project_settings.h" #include "scene/resources/packed_scene.h" Vector<uint8_t> EditorSceneExportPlugin::custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) { diff --git a/editor/io_plugins/editor_scene_import_plugin.cpp b/editor/io_plugins/editor_scene_import_plugin.cpp index 5f0e928844..aa96f731ce 100644 --- a/editor/io_plugins/editor_scene_import_plugin.cpp +++ b/editor/io_plugins/editor_scene_import_plugin.cpp @@ -31,10 +31,10 @@ #if 0 #include "editor/create_dialog.h" #include "editor/editor_node.h" -#include "project_settings.h" #include "io/resource_saver.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" #include "scene/3d/body_shape.h" #include "scene/3d/mesh_instance.h" #include "scene/3d/navigation.h" diff --git a/editor/io_plugins/editor_texture_import_plugin.cpp b/editor/io_plugins/editor_texture_import_plugin.cpp index 842c43f4de..095bc02fa0 100644 --- a/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/editor/io_plugins/editor_texture_import_plugin.cpp @@ -33,10 +33,10 @@ #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor_atlas.h" -#include "project_settings.h" #include "io/image_loader.h" #include "io/marshalls.h" #include "io/resource_saver.h" +#include "project_settings.h" #include "scene/gui/button_group.h" #include "scene/gui/check_button.h" #include "scene/gui/margin_container.h" diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 82b03d3a19..c4e79bf263 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -31,10 +31,10 @@ #include "editor/animation_editor.h" #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" #include "io/resource_saver.h" #include "os/keyboard.h" +#include "project_settings.h" void AnimationPlayerEditor::_node_removed(Node *p_node) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 4f07fdba2b..a809a68c23 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -35,10 +35,10 @@ #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/script_editor_debugger.h" -#include "project_settings.h" #include "os/input.h" #include "os/keyboard.h" #include "print_string.h" +#include "project_settings.h" #include "scene/2d/light_2d.h" #include "scene/2d/particles_2d.h" #include "scene/2d/polygon_2d.h" @@ -176,7 +176,6 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) { for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Node2D *n2d = E->get()->cast_to<Node2D>(); - if (n2d && n2d->edit_has_pivot()) { Vector2 offset = n2d->edit_get_pivot(); @@ -241,7 +240,6 @@ void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) { } else if (!Input::get_singleton()->is_mouse_button_pressed(0)) { List<Node *> &selection = editor_selection->get_selected_node_list(); - Vector2 mouse_pos = viewport->get_local_mouse_pos(); if (selection.size() && viewport->get_rect().has_point(mouse_pos)) { //just in case, make it work if over viewport @@ -258,7 +256,6 @@ void CanvasItemEditor::_tool_select(int p_index) { ToolButton *tb[TOOL_MAX] = { select_button, list_select_button, move_button, rotate_button, pivot_button, pan_button }; for (int i = 0; i < TOOL_MAX; i++) { - tb[i]->set_pressed(i == p_index); } @@ -449,44 +446,7 @@ bool CanvasItemEditor::_is_part_of_subscene(CanvasItem *p_item) { return item_owner && item_owner != scene_node && p_item != scene_node && item_owner->get_filename() != ""; } -// slow but modern computers should have no problem -CanvasItem *CanvasItemEditor::_select_canvas_item_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { - - if (!p_node) - return NULL; - if (p_node->cast_to<Viewport>()) - return NULL; - - CanvasItem *c = p_node->cast_to<CanvasItem>(); - - for (int i = p_node->get_child_count() - 1; i >= 0; i--) { - - CanvasItem *r = NULL; - - if (c && !c->is_set_as_toplevel()) - r = _select_canvas_item_at_pos(p_pos, p_node->get_child(i), p_parent_xform * c->get_transform(), p_canvas_xform); - else { - CanvasLayer *cl = p_node->cast_to<CanvasLayer>(); - r = _select_canvas_item_at_pos(p_pos, p_node->get_child(i), transform, cl ? cl->get_transform() : p_canvas_xform); //use base transform - } - - if (r) - return r; - } - - if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !_is_part_of_subscene(c) && !c->cast_to<CanvasLayer>()) { - - Rect2 rect = c->get_item_rect(); - Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos); - - if (rect.has_point(local_pos)) - return c; - } - - return NULL; -} - -void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items) { +void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items, unsigned int limit) { if (!p_node) return; if (p_node->cast_to<Viewport>()) @@ -502,6 +462,9 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no CanvasLayer *cl = p_node->cast_to<CanvasLayer>(); _find_canvas_items_at_pos(p_pos, p_node->get_child(i), transform, cl ? cl->get_transform() : p_canvas_xform, r_items); //use base transform } + + if (limit != 0 && r_items.size() >= limit) + return; } if (c && c->is_visible_in_tree() && !c->has_meta("_edit_lock_") && !c->cast_to<CanvasLayer>()) { @@ -565,72 +528,50 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_n } } -bool CanvasItemEditor::_select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) { - - if (p_append) { - //additive selection - - if (!item) { - - if (p_drag) { - drag_from = transform.affine_inverse().xform(p_click_pos); - - box_selecting = true; - box_selecting_to = drag_from; - } +void CanvasItemEditor::_select_click_on_empty_area(Point2 p_click_pos, bool p_append, bool p_box_selection) { + if (!p_append) { + editor_selection->clear(); + viewport->update(); + }; - return false; //nothing to add - } + if (p_box_selection) { + // Start a box selection + drag_from = transform.affine_inverse().xform(p_click_pos); + box_selecting = true; + box_selecting_to = drag_from; + } +} +bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) { + bool still_selected = true; + if (p_append) { if (editor_selection->is_selected(item)) { - //already in here, erase it + // Already in the selection, remove it from the selected nodes editor_selection->remove_node(item); - //_remove_canvas_item(c); - - viewport->update(); - return false; + still_selected = false; + } else { + // Add the item to the selection + _append_canvas_item(item); } - _append_canvas_item(item); - viewport->update(); - - return true; - } else { - //regular selection - - if (!item) { - //clear because nothing clicked - editor_selection->clear(); - - if (p_drag) { - drag_from = transform.affine_inverse().xform(p_click_pos); - - box_selecting = true; - box_selecting_to = drag_from; - } - - viewport->update(); - return false; - } - if (!editor_selection->is_selected(item)) { - //select a new one and clear previous selection + // Select a new one and clear previous selection editor_selection->clear(); editor_selection->add_node(item); - //reselect + // Reselect if (get_tree()->is_editor_hint()) { editor->call("edit_node", item); } } + } - if (p_drag) { - _prepare_drag(p_click_pos); - } - - viewport->update(); - - return true; + if (still_selected && p_drag) { + // Drag the node(s) if requested + _prepare_drag(p_click_pos); } + + viewport->update(); + return still_selected; } void CanvasItemEditor::_key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE p_move_mode) { @@ -766,7 +707,7 @@ CanvasItem *CanvasItemEditor::get_single_item() { return single_item; } -CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D &p_xform, const Rect2 &p_local_rect, const Point2 &p_click, Vector2 &r_point) { +CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Point2 &p_click, Vector2 &r_point) { CanvasItem *canvas_item = get_single_item(); @@ -805,8 +746,6 @@ CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D & float radius = (select_handle->get_size().width / 2) * 1.5; - //try draggers - for (int i = 0; i < 4; i++) { int prev = (i + 3) % 4; @@ -831,14 +770,6 @@ CanvasItemEditor::DragType CanvasItemEditor::_find_drag_type(const Transform2D & return dragger[i * 2 + 1]; } - /* - if (rect.has_point(xform.affine_inverse().xform(p_click))) { - r_point=_find_topleftmost_point(); - return DRAG_ALL; - }*/ - - //try draggers - return DRAG_NONE; } @@ -966,7 +897,7 @@ void CanvasItemEditor::_selection_result_pressed(int p_result) { CanvasItem *item = selection_results[p_result].item; if (item) - _select(item, Point2(), additive_selection, false); + _select_click_on_item(item, Point2(), additive_selection, false); } void CanvasItemEditor::_selection_menu_hide() { @@ -1006,7 +937,8 @@ void CanvasItemEditor::_list_select(const Ref<InputEventMouseButton> &b) { selection_results.clear(); additive_selection = b->get_shift(); - if (!_select(item, click, additive_selection, false)) + + if (!_select_click_on_item(item, click, additive_selection, false)) return; } else if (!selection_results.empty()) { @@ -1048,7 +980,6 @@ void CanvasItemEditor::_list_select(const Ref<InputEventMouseButton> &b) { void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { { - EditorNode *en = editor; EditorPluginList *over_plugin_list = en->get_editor_plugins_over(); @@ -1062,11 +993,11 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseButton> b = p_event; - if (b.is_valid()) { + // Button event if (b->get_button_index() == BUTTON_WHEEL_DOWN) { - + // Scroll or pan down if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { v_scroll->set_value(v_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1092,7 +1023,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (b->get_button_index() == BUTTON_WHEEL_UP) { - + // Scroll or pan up if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { v_scroll->set_value(v_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1116,7 +1047,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (b->get_button_index() == BUTTON_WHEEL_LEFT) { - + // Pan left if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { h_scroll->set_value(h_scroll->get_value() - int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1124,7 +1055,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (b->get_button_index() == BUTTON_WHEEL_RIGHT) { - + // Pan right if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) { h_scroll->set_value(h_scroll->get_value() + int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor()); @@ -1134,29 +1065,24 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { if (b->get_button_index() == BUTTON_RIGHT) { if (b->is_pressed() && (tool == TOOL_SELECT && b->get_alt())) { - + // Open the selection list _list_select(b); return; } if (get_item_count() > 0 && drag != DRAG_NONE) { - //cancel drag - + // Cancel a drag if (bone_ik_list.size()) { - for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) { - E->get().node->edit_set_state(E->get().orig_state); } bone_ik_list.clear(); } else { - List<Node *> &selection = editor_selection->get_selected_node_list(); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>(); if (!canvas_item || !canvas_item->is_visible_in_tree()) continue; @@ -1180,33 +1106,23 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { can_move_pivot = false; } else if (box_selecting) { + // Cancel box selection box_selecting = false; viewport->update(); - } else if (b->is_pressed()) { -#if 0 - ref_item = NULL; - Node* scene = get_scene()->get_root_node()->cast_to<EditorNode>()->get_edited_scene(); - if ( scene ) ref_item =_select_canvas_item_at_pos( Point2( b.x, b.y ), scene, transform ); -#endif - //popup->set_position(Point2(b.x,b.y)); - //popup->popup(); } return; } - /* - if (!canvas_items.size()) - return; - */ if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT) { if (b->is_pressed()) + // Open the selection list _list_select(b); return; } if (b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) { if (b->is_pressed()) { - + // Set the pivot point Point2 mouse_pos = b->get_position(); mouse_pos = transform.affine_inverse().xform(mouse_pos); mouse_pos = snap_point(mouse_pos); @@ -1216,16 +1132,18 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (tool == TOOL_PAN || b->get_button_index() != BUTTON_LEFT || Input::get_singleton()->is_key_pressed(KEY_SPACE)) + // Pan the view return; + // -- From now we consider that the button is BUTTON_LEFT -- + if (!b->is_pressed()) { if (drag != DRAG_NONE) { - + // Stop dragging if (undo_redo) { if (bone_ik_list.size()) { - undo_redo->create_action(TTR("Edit IK Chain")); for (List<BoneIK>::Element *E = bone_ik_list.back(); E; E = E->prev()) { @@ -1241,7 +1159,6 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { undo_redo->commit_action(); } else { - undo_redo->create_action(TTR("Edit CanvasItem")); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -1285,11 +1202,7 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } if (box_selecting) { -#if 0 - if ( ! b->get_shift() ) _clear_canvas_items(); - if ( box_selection_end() ) return; -#endif - + // Stop box selection Node *scene = editor->get_edited_scene(); if (scene) { @@ -1316,6 +1229,8 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { return; } + // -- From now we consider that the button is BUTTON_LEFT and that it is pressed -- + Map<ObjectID, BoneList>::Element *Cbone = NULL; //closest { @@ -1390,19 +1305,16 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } } - CanvasItem *single_item = get_single_item(); - - if (single_item) { - //try single canvas_item edit - - CanvasItem *canvas_item = single_item; + // Single selected item + CanvasItem *canvas_item = get_single_item(); + if (canvas_item) { CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); ERR_FAIL_COND(!se); Point2 click = b->get_position(); + // Rotation if ((b->get_control() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) { - drag = DRAG_ROTATE; drag_from = transform.affine_inverse().xform(click); se->undo_state = canvas_item->edit_get_state(); @@ -1413,72 +1325,59 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { return; } - Transform2D xform = transform * canvas_item->get_global_transform_with_canvas(); - Rect2 rect = canvas_item->get_item_rect(); - //float handle_radius = handle_len * 1.4144; //magic number, guess what it means! - if (tool == TOOL_SELECT) { - drag = _find_drag_type(xform, rect, click, drag_point_from); - + // Open a sub-scene on double-click if (b->is_doubleclick()) { - if (canvas_item->get_filename() != "" && canvas_item != editor->get_edited_scene()) { - editor->open_request(canvas_item->get_filename()); return; } } - if (drag != DRAG_NONE && (!Cbone || drag != DRAG_ALL)) { + // Drag + drag = _find_drag_type(click, drag_point_from); + if (drag != DRAG_NONE) { drag_from = transform.affine_inverse().xform(click); se->undo_state = canvas_item->edit_get_state(); if (canvas_item->cast_to<Node2D>()) se->undo_pivot = canvas_item->cast_to<Node2D>()->edit_get_pivot(); if (canvas_item->cast_to<Control>()) se->undo_pivot = canvas_item->cast_to<Control>()->get_pivot_offset(); - return; } - } else { - - drag = DRAG_NONE; } } - //multi canvas_item edit - + // Multiple selected items Point2 click = b->get_position(); if ((b->get_alt() || tool == TOOL_MOVE) && get_item_count()) { + // Drag the nodes _prepare_drag(click); viewport->update(); return; } - Node *scene = editor->get_edited_scene(); - if (!scene) - return; - - /* - if (current_window) { - //no window.... ? - click-=current_window->get_scroll(); - }*/ CanvasItem *c = NULL; - if (Cbone) { - Object *obj = ObjectDB::get_instance(Cbone->get().bone); if (obj) c = obj->cast_to<CanvasItem>(); if (c) c = c->get_parent_item(); } + + Node *scene = editor->get_edited_scene(); + if (!scene) + return; + // Find the item to select if (!c) { - c = _select_canvas_item_at_pos(click, scene, transform, Transform2D()); + Vector<_SelectResult> selection; + _find_canvas_items_at_pos(click, scene, transform, Transform2D(), selection, 1); + if (!selection.empty()) + c = selection[0].item; CanvasItem *cn = c; - while (cn) { if (cn->has_meta("_edit_group_")) { c = cn; @@ -1488,28 +1387,29 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } Node *n = c; - while ((n && n != scene && n->get_owner() != scene) || (n && !n->is_class("CanvasItem"))) { n = n->get_parent(); }; c = n->cast_to<CanvasItem>(); -#if 0 - if ( b->is_pressed() ) box_selection_start( click ); -#endif + // Select the item additive_selection = b->get_shift(); - if (!_select(c, click, additive_selection)) + if (!c) { + _select_click_on_empty_area(click, additive_selection, true); + } else if (!_select_click_on_item(c, click, additive_selection, true)) { return; + } } Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { + // Mouse motion event if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) viewport->call_deferred("grab_focus"); if (box_selecting) { - + // Update box selection box_selecting_to = transform.affine_inverse().xform(m->get_position()); viewport->update(); return; @@ -1618,8 +1518,21 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { Vector2 minsize = canvas_item->edit_get_minimum_size(); if (uniform) { + // Keep the height/width ratio of the item float aspect = local_rect.size.aspect(); switch (drag) { + case DRAG_LEFT: { + drag_vector.y = -drag_vector.x / aspect; + } break; + case DRAG_RIGHT: { + drag_vector.y = drag_vector.x / aspect; + } break; + case DRAG_TOP: { + drag_vector.x = -drag_vector.y * aspect; + } break; + case DRAG_BOTTOM: { + drag_vector.x = drag_vector.y * aspect; + } break; case DRAG_BOTTOM_LEFT: case DRAG_TOP_RIGHT: { if (aspect > 1.0) { // width > height, take x as reference @@ -1636,7 +1549,17 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { drag_vector.x = drag_vector.y * aspect; } } break; - default: {} + } + } else { + switch (drag) { + case DRAG_RIGHT: + case DRAG_LEFT: { + drag_vector.y = 0; + } break; + case DRAG_TOP: + case DRAG_BOTTOM: { + drag_vector.x = 0; + } break; } } @@ -1645,44 +1568,25 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { begin += drag_vector; end += drag_vector; } break; - case DRAG_RIGHT: { - - incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric); - - } break; - case DRAG_BOTTOM: { - - incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric); - - } break; + case DRAG_RIGHT: + case DRAG_BOTTOM: case DRAG_BOTTOM_RIGHT: { - incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric); incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric); } break; - case DRAG_TOP_LEFT: { + case DRAG_TOP_LEFT: { incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric); incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric); } break; - case DRAG_TOP: { - incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric); - - } break; - case DRAG_LEFT: { - - incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric); - - } break; + case DRAG_TOP: case DRAG_TOP_RIGHT: { - incbeg(begin.y, end.y, drag_vector.y, minsize.y, symmetric); incend(begin.x, end.x, drag_vector.x, minsize.x, symmetric); - } break; + case DRAG_LEFT: case DRAG_BOTTOM_LEFT: { - incbeg(begin.x, end.x, drag_vector.x, minsize.x, symmetric); incend(begin.y, end.y, drag_vector.y, minsize.y, symmetric); } break; @@ -1831,11 +1735,9 @@ void CanvasItemEditor::_viewport_gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventKey> k = p_event; - if (k.is_valid()) { - if (k->is_pressed() && drag == DRAG_NONE) { - + // Move the object with the arrow keys KeyMoveMODE move_mode = MOVE_VIEW_BASE; if (k->get_alt()) move_mode = MOVE_LOCAL_BASE; if (k->get_control() || k->get_metakey()) move_mode = MOVE_LOCAL_WITH_ROT; @@ -1868,13 +1770,23 @@ void CanvasItemEditor::_viewport_draw() { RID ci = viewport->get_canvas_item(); if (snap_show_grid) { + //Draw the grid Size2 s = viewport->get_size(); int last_cell; Transform2D xform = transform.affine_inverse(); + Vector2 grid_offset; + if (snap_relative && snap_grid && get_item_count() > 0) { + Vector2 topleft = _find_topleftmost_point(); + grid_offset.x = fmod(topleft.x, snap_step.x); + grid_offset.y = fmod(topleft.y, snap_step.y); + } else { + grid_offset = snap_offset; + } + if (snap_step.x != 0) { for (int i = 0; i < s.width; i++) { - int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - snap_offset.x) / snap_step.x)); + int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(i, 0)).x - grid_offset.x) / snap_step.x)); if (i == 0) last_cell = cell; if (last_cell != cell) @@ -1885,7 +1797,7 @@ void CanvasItemEditor::_viewport_draw() { if (snap_step.y != 0) { for (int i = 0; i < s.height; i++) { - int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(0, i)).y - snap_offset.y) / snap_step.y)); + int cell = Math::fast_ftoi(Math::floor((xform.xform(Vector2(0, i)).y - grid_offset.y) / snap_step.y)); if (i == 0) last_cell = cell; if (last_cell != cell) @@ -2478,6 +2390,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { snap_grid = !snap_grid; int idx = edit_menu->get_popup()->get_item_index(SNAP_USE); edit_menu->get_popup()->set_item_checked(idx, snap_grid); + viewport->update(); } break; case SNAP_SHOW_GRID: { snap_show_grid = !snap_show_grid; @@ -2494,6 +2407,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { snap_relative = !snap_relative; int idx = edit_menu->get_popup()->get_item_index(SNAP_RELATIVE); edit_menu->get_popup()->set_item_checked(idx, snap_relative); + viewport->update(); } break; case SNAP_USE_PIXEL: { snap_pixel = !snap_pixel; diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index f40a7cbc4a..4383be251c 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -303,11 +303,11 @@ class CanvasItemEditor : public VBoxContainer { int handle_len; bool _is_part_of_subscene(CanvasItem *p_item); - CanvasItem *_select_canvas_item_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform); - void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items); + void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, Vector<_SelectResult> &r_items, unsigned int limit = 0); void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, List<CanvasItem *> *r_items); - bool _select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag = true); + void _select_click_on_empty_area(Point2 p_click_pos, bool p_append, bool p_box_selection); + bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag); ConfirmationDialog *snap_dialog; @@ -325,7 +325,7 @@ class CanvasItemEditor : public VBoxContainer { void _key_move(const Vector2 &p_dir, bool p_snap, KeyMoveMODE p_move_mode); void _list_select(const Ref<InputEventMouseButton> &b); - DragType _find_drag_type(const Transform2D &p_xform, const Rect2 &p_local_rect, const Point2 &p_click, Vector2 &r_point); + DragType _find_drag_type(const Point2 &p_click, Vector2 &r_point); void _prepare_drag(const Point2 &p_click_pos); void _popup_callback(int p_op); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 463b6360ad..2703da12fe 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -30,8 +30,8 @@ #include "resource_preloader_editor_plugin.h" #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" +#include "project_settings.h" void ResourcePreloaderEditor::_gui_input(Ref<InputEvent> p_event) { } diff --git a/editor/plugins/sample_editor_plugin.cpp b/editor/plugins/sample_editor_plugin.cpp index 0b99ab5460..739a8abb53 100644 --- a/editor/plugins/sample_editor_plugin.cpp +++ b/editor/plugins/sample_editor_plugin.cpp @@ -31,8 +31,8 @@ #if 0 #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" +#include "project_settings.h" diff --git a/editor/plugins/sample_library_editor_plugin.cpp b/editor/plugins/sample_library_editor_plugin.cpp index 04c805165f..5ccfde15ff 100644 --- a/editor/plugins/sample_library_editor_plugin.cpp +++ b/editor/plugins/sample_library_editor_plugin.cpp @@ -32,8 +32,8 @@ #include "sample_library_editor_plugin.h" #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" +#include "project_settings.h" #include "sample_editor_plugin.h" #include "scene/main/viewport.h" diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index fef7f07abb..77c540b746 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2229,7 +2229,7 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts); ADD_SIGNAL(MethodInfo("editor_script_changed", PropertyInfo(Variant::OBJECT, "script:Script"))); - ADD_SIGNAL(MethodInfo("script_close", PropertyInfo(Variant::STRING, "script:String"))); + ADD_SIGNAL(MethodInfo("script_close", PropertyInfo(Variant::OBJECT, "script:Script"))); } ScriptEditor::ScriptEditor(EditorNode *p_editor) { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index ef7ed5f7f6..2d77bfb2c1 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -1563,13 +1563,13 @@ void SpatialEditorViewport::_update_freelook(real_t delta) { Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0)); Vector3 up = camera->get_transform().basis.xform(Vector3(0, 1, 0)); - int key_left = ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); - int key_right = ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); - int key_forward = ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); - int key_backwards = ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); - int key_up = ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_Q)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); - int key_down = ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_E)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); - int key_speed_modifier = ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT)->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_left = ED_GET_SHORTCUT("spatial_editor/freelook_left")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_right = ED_GET_SHORTCUT("spatial_editor/freelook_right")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_forward = ED_GET_SHORTCUT("spatial_editor/freelook_forward")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_backwards = ED_GET_SHORTCUT("spatial_editor/freelook_backwards")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_up = ED_GET_SHORTCUT("spatial_editor/freelook_up")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_down = ED_GET_SHORTCUT("spatial_editor/freelook_down")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); + int key_speed_modifier = ED_GET_SHORTCUT("spatial_editor/freelook_speed_modifier")->get_shortcut()->cast_to<InputEventKey>()->get_scancode(); Vector3 velocity; bool pressed = false; @@ -2424,6 +2424,14 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_selection_with_view"), VIEW_ALIGN_SELECTION_WITH_VIEW); view_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A); + ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D); + ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W); + ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S); + ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_Q); + ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_E); + ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT); + preview_camera = memnew(Button); preview_camera->set_toggle_mode(true); preview_camera->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, 90); @@ -3134,7 +3142,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { xform_scale[i]->set_text("1"); } - xform_dialog->popup_centered(Size2(200, 200)); + xform_dialog->popup_centered(Size2(320, 240) * EDSCALE); } break; case MENU_VIEW_USE_1_VIEWPORT: { @@ -3956,55 +3964,59 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { xform_dialog = memnew(ConfirmationDialog); xform_dialog->set_title(TTR("Transform Change")); add_child(xform_dialog); + + VBoxContainer *xform_vbc = memnew(VBoxContainer); + xform_dialog->add_child(xform_vbc); + Label *l = memnew(Label); l->set_text(TTR("Translate:")); - l->set_position(Point2(5, 5)); - xform_dialog->add_child(l); + xform_vbc->add_child(l); + + HBoxContainer *xform_hbc = memnew(HBoxContainer); + xform_vbc->add_child(xform_hbc); for (int i = 0; i < 3; i++) { xform_translate[i] = memnew(LineEdit); - xform_translate[i]->set_position(Point2(15 + i * 60, 22)); - xform_translate[i]->set_size(Size2(50, 12)); - xform_dialog->add_child(xform_translate[i]); + xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL); + xform_hbc->add_child(xform_translate[i]); } l = memnew(Label); l->set_text(TTR("Rotate (deg.):")); - l->set_position(Point2(5, 45)); - xform_dialog->add_child(l); + xform_vbc->add_child(l); + + xform_hbc = memnew(HBoxContainer); + xform_vbc->add_child(xform_hbc); for (int i = 0; i < 3; i++) { xform_rotate[i] = memnew(LineEdit); - xform_rotate[i]->set_position(Point2(15 + i * 60, 62)); - xform_rotate[i]->set_size(Size2(50, 22)); - xform_dialog->add_child(xform_rotate[i]); + xform_rotate[i]->set_h_size_flags(SIZE_EXPAND_FILL); + xform_hbc->add_child(xform_rotate[i]); } l = memnew(Label); l->set_text(TTR("Scale (ratio):")); - l->set_position(Point2(5, 85)); - xform_dialog->add_child(l); + xform_vbc->add_child(l); + + xform_hbc = memnew(HBoxContainer); + xform_vbc->add_child(xform_hbc); for (int i = 0; i < 3; i++) { xform_scale[i] = memnew(LineEdit); - xform_scale[i]->set_position(Point2(15 + i * 60, 102)); - xform_scale[i]->set_size(Size2(50, 22)); - xform_dialog->add_child(xform_scale[i]); + xform_scale[i]->set_h_size_flags(SIZE_EXPAND_FILL); + xform_hbc->add_child(xform_scale[i]); } l = memnew(Label); l->set_text(TTR("Transform Type")); - l->set_position(Point2(5, 125)); - xform_dialog->add_child(l); + xform_vbc->add_child(l); xform_type = memnew(OptionButton); - xform_type->set_anchor(MARGIN_RIGHT, ANCHOR_END); - xform_type->set_begin(Point2(15, 142)); - xform_type->set_end(Point2(15, 75)); + xform_type->set_h_size_flags(SIZE_EXPAND_FILL); xform_type->add_item(TTR("Pre")); xform_type->add_item(TTR("Post")); - xform_dialog->add_child(xform_type); + xform_vbc->add_child(xform_type); xform_dialog->connect("confirmed", this, "_xform_dialog_action"); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index fa80894f7b..6a010062f2 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -30,8 +30,8 @@ #include "sprite_frames_editor_plugin.h" #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" +#include "project_settings.h" #include "scene/3d/sprite_3d.h" void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) { diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 70a1227c52..125d906460 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -30,8 +30,8 @@ #include "texture_editor_plugin.h" #include "editor/editor_settings.h" -#include "project_settings.h" #include "io/resource_loader.h" +#include "project_settings.h" void TextureEditor::_gui_input(Ref<InputEvent> p_event) { } diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index a83ea70508..f5bb9d4a35 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -493,11 +493,10 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { Ref<Theme> base_theme; - type_select->show(); - type_select_label->show(); name_select_label->show(); - name_edit->show(); - name_menu->show(); + name_hbc->show(); + type_select_label->show(); + type_select->show(); if (p_option == POPUP_ADD) { //add @@ -515,11 +514,10 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { base_theme = Theme::get_default(); - type_select->hide(); name_select_label->hide(); + name_hbc->hide(); type_select_label->hide(); - name_edit->hide(); - name_menu->hide(); + type_select->hide(); } else if (p_option == POPUP_REMOVE) { @@ -537,11 +535,10 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { base_theme = Theme::get_default(); - type_select->hide(); name_select_label->hide(); + name_hbc->hide(); type_select_label->hide(); - name_edit->hide(); - name_menu->hide(); + type_select->hide(); } popup_mode = p_option; @@ -832,48 +829,46 @@ ThemeEditor::ThemeEditor() { add_del_dialog->hide(); add_child(add_del_dialog); + VBoxContainer *dialog_vbc = memnew(VBoxContainer); + add_del_dialog->add_child(dialog_vbc); + Label *l = memnew(Label); - l->set_position(Point2(5, 5) * EDSCALE); l->set_text(TTR("Type:")); - add_del_dialog->add_child(l); - dtype_select_label = l; + dialog_vbc->add_child(l); + + type_hbc = memnew(HBoxContainer); + dialog_vbc->add_child(type_hbc); type_edit = memnew(LineEdit); - type_edit->set_position(Point2(5, 25) * EDSCALE); - type_edit->set_size(Point2(150, 5) * EDSCALE); - add_del_dialog->add_child(type_edit); + type_edit->set_h_size_flags(SIZE_EXPAND_FILL); + type_hbc->add_child(type_edit); type_menu = memnew(MenuButton); - type_menu->set_position(Point2(160, 25) * EDSCALE); - type_menu->set_size(Point2(30, 5) * EDSCALE); type_menu->set_text(".."); - add_del_dialog->add_child(type_menu); + type_hbc->add_child(type_menu); type_menu->get_popup()->connect("id_pressed", this, "_type_menu_cbk"); l = memnew(Label); - l->set_position(Point2(200, 5) * EDSCALE); l->set_text(TTR("Name:")); - add_del_dialog->add_child(l); + dialog_vbc->add_child(l); name_select_label = l; + name_hbc = memnew(HBoxContainer); + dialog_vbc->add_child(name_hbc); + name_edit = memnew(LineEdit); - name_edit->set_position(Point2(200, 25) * EDSCALE); - name_edit->set_size(Point2(150, 5) * EDSCALE); - add_del_dialog->add_child(name_edit); + name_edit->set_h_size_flags(SIZE_EXPAND_FILL); + name_hbc->add_child(name_edit); name_menu = memnew(MenuButton); - name_menu->set_position(Point2(360, 25) * EDSCALE); - name_menu->set_size(Point2(30, 5) * EDSCALE); name_menu->set_text(".."); - - add_del_dialog->add_child(name_menu); + name_hbc->add_child(name_menu); name_menu->get_popup()->connect("about_to_show", this, "_name_menu_about_to_show"); name_menu->get_popup()->connect("id_pressed", this, "_name_menu_cbk"); type_select_label = memnew(Label); - type_select_label->set_position(Point2(400, 5) * EDSCALE); type_select_label->set_text(TTR("Data Type:")); - add_del_dialog->add_child(type_select_label); + dialog_vbc->add_child(type_select_label); type_select = memnew(OptionButton); type_select->add_item(TTR("Icon")); @@ -881,10 +876,8 @@ ThemeEditor::ThemeEditor() { type_select->add_item(TTR("Font")); type_select->add_item(TTR("Color")); type_select->add_item(TTR("Constant")); - type_select->set_position(Point2(400, 25) * EDSCALE); - type_select->set_size(Point2(80, 5) * EDSCALE); - add_del_dialog->add_child(type_select); + dialog_vbc->add_child(type_select); add_del_dialog->get_ok()->connect("pressed", this, "_dialog_cbk"); diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index 6db01c6246..a75b83e76a 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -54,14 +54,15 @@ class ThemeEditor : public Control { MenuButton *theme_menu; ConfirmationDialog *add_del_dialog; + HBoxContainer *type_hbc; MenuButton *type_menu; LineEdit *type_edit; + HBoxContainer *name_hbc; MenuButton *name_menu; LineEdit *name_edit; OptionButton *type_select; Label *type_select_label; Label *name_select_label; - Label *dtype_select_label; enum PopupMode { POPUP_ADD, diff --git a/editor/project_export.cpp b/editor/project_export.cpp index b498044a65..b9694dffcb 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -32,7 +32,6 @@ #include "editor_data.h" #include "editor_node.h" #include "editor_settings.h" -#include "project_settings.h" #include "io/image_loader.h" #include "io/resource_loader.h" #include "io/resource_saver.h" @@ -40,6 +39,7 @@ #include "os/dir_access.h" #include "os/file_access.h" #include "os/os.h" +#include "project_settings.h" #include "scene/gui/box_container.h" #include "scene/gui/margin_container.h" #include "scene/gui/scroll_container.h" diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index acf5fe02cc..82f17b80d5 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -187,30 +187,17 @@ private: } else { if (mode == MODE_NEW) { - FileAccess *f = FileAccess::open(dir.plus_file("/project.godot"), FileAccess::WRITE); - if (!f) { + ProjectSettings::CustomMap initial_settings; + initial_settings["application/config/name"] = project_name->get_text(); + initial_settings["application/config/icon"] = "res://icon.png"; + initial_settings["rendering/environment/default_environment"] = "res://default_env.tres"; + + if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("/project.godot"), initial_settings, Vector<String>(), false)) { error->set_text(TTR("Couldn't create project.godot in project path.")); } else { - - f->store_line("; Engine configuration file."); - f->store_line("; It's best edited using the editor UI and not directly,"); - f->store_line("; since the parameters that go here are not all obvious."); - f->store_line("; "); - f->store_line("; Format: "); - f->store_line("; [section] ; section goes between []"); - f->store_line("; param=value ; assign values to parameters"); - f->store_line("\n"); - f->store_line("[application]"); - f->store_line("\n"); - f->store_line("config/name=\"" + project_name->get_text() + "\""); - f->store_line("config/icon=\"res://icon.png\""); - f->store_line("[rendering]"); - f->store_line("environment/default_environment=\"res://default_env.tres\""); - memdelete(f); - ResourceSaver::save(dir.plus_file("/icon.png"), get_icon("DefaultProjectIcon", "EditorIcons")); - f = FileAccess::open(dir.plus_file("/default_env.tres"), FileAccess::WRITE); + FileAccess *f = FileAccess::open(dir.plus_file("/default_env.tres"), FileAccess::WRITE); if (!f) { error->set_text(TTR("Couldn't create project.godot in project path.")); } else { diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index c2af2445cc..42485317c1 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -1957,11 +1957,6 @@ CustomPropertyEditor::CustomPropertyEditor() { add_child(error); //error->get_cancel()->hide(); - type_button = memnew(MenuButton); - add_child(type_button); - type_button->hide(); - type_button->get_popup()->connect("id_pressed", this, "_type_create_selected"); - scene_tree = memnew(SceneTreeDialog); add_child(scene_tree); scene_tree->connect("selected", this, "_node_path_selected"); @@ -1979,6 +1974,11 @@ CustomPropertyEditor::CustomPropertyEditor() { //easing_draw->emit_signal(SceneStringNames::get_singleton()->input_event,InputEvent()); easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE); + type_button = memnew(MenuButton); + add_child(type_button); + type_button->hide(); + type_button->get_popup()->connect("id_pressed", this, "_type_create_selected"); + menu = memnew(PopupMenu); add_child(menu); menu->connect("id_pressed", this, "_menu_option"); @@ -3858,7 +3858,7 @@ void PropertyEditor::_item_edited() { break; if (type == Variant::INT) - _edit_set(name, int(item->get_range(1)), refresh_all); + _edit_set(name, round(item->get_range(1)), refresh_all); else _edit_set(name, item->get_range(1), refresh_all); } break; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 57ab931827..47a9185389 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -37,9 +37,9 @@ #include "editor/plugins/spatial_editor_plugin.h" #include "editor_node.h" #include "editor_settings.h" -#include "project_settings.h" #include "multi_node_edit.h" #include "os/keyboard.h" +#include "project_settings.h" #include "scene/main/viewport.h" #include "scene/resources/packed_scene.h" #include "script_editor_debugger.h" @@ -1885,7 +1885,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (is_external) { bool is_inherited = selection[0]->get_scene_inherited_state() != NULL; bool is_top_level = selection[0]->get_owner() == NULL; - if (is_inherited) { + if (is_inherited && is_top_level) { menu->add_separator(); menu->add_item(TTR("Clear Inheritance"), TOOL_SCENE_CLEAR_INHERITANCE); menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN_INHERITED); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index c3a3410717..d81161ae94 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -31,9 +31,9 @@ #include "editor/editor_scale.h" #include "editor_file_system.h" -#include "project_settings.h" #include "io/resource_saver.h" #include "os/file_access.h" +#include "project_settings.h" #include "script_language.h" void ScriptCreateDialog::_notification(int p_what) { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 2af3bd5f31..f4ed430d3d 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -32,8 +32,8 @@ #include "editor_node.h" #include "editor_profiler.h" #include "editor_settings.h" -#include "project_settings.h" #include "main/performance.h" +#include "project_settings.h" #include "property_editor.h" #include "scene/gui/dialogs.h" #include "scene/gui/label.h" diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index eec047cd9a..d455e0cea9 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -32,8 +32,8 @@ #include "editor_file_system.h" #include "editor_node.h" #include "editor_settings.h" -#include "project_settings.h" #include "os/keyboard.h" +#include "project_settings.h" #include "scene/gui/margin_container.h" void EditorSettingsDialog::ok_pressed() { diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index e810c33f1c..158f7fd94d 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -185,6 +185,8 @@ void GDNative::_bind_methods() { } void GDNative::set_library(Ref<GDNativeLibrary> p_library) { + ERR_EXPLAIN("Tried to change library of GDNative when it is already set"); + ERR_FAIL_COND(library.is_valid()); library = p_library; } @@ -229,6 +231,7 @@ bool GDNative::initialize() { options.core_api_hash = ClassDB::get_api_hash(ClassDB::API_CORE); options.editor_api_hash = ClassDB::get_api_hash(ClassDB::API_EDITOR); options.no_api_hash = ClassDB::get_api_hash(ClassDB::API_NONE); + options.gd_native_library = (godot_object *)(get_library().ptr()); library_init_fpointer(&options); diff --git a/modules/gdnative/godot/gdnative.cpp b/modules/gdnative/godot/gdnative.cpp index 7b94b75a52..29b499ebab 100644 --- a/modules/gdnative/godot/gdnative.cpp +++ b/modules/gdnative/godot/gdnative.cpp @@ -33,6 +33,7 @@ #include "error_macros.h" #include "gdnative.h" #include "global_constants.h" +#include "os/os.h" #include "project_settings.h" #include "variant.h" @@ -89,6 +90,10 @@ godot_object GDAPI *godot_global_get_singleton(char *p_name) { return (godot_object *)ProjectSettings::get_singleton()->get_singleton_object(String(p_name)); } // result shouldn't be freed +void GDAPI *godot_get_stack_bottom() { + return OS::get_singleton()->get_stack_bottom(); +} + // MethodBind API godot_method_bind GDAPI *godot_method_bind_get_method(const char *p_classname, const char *p_methodname) { diff --git a/modules/gdnative/godot/gdnative.h b/modules/gdnative/godot/gdnative.h index 4b79706b52..b0343272ef 100644 --- a/modules/gdnative/godot/gdnative.h +++ b/modules/gdnative/godot/gdnative.h @@ -245,6 +245,10 @@ void GDAPI godot_object_destroy(godot_object *p_o); godot_object GDAPI *godot_global_get_singleton(char *p_name); // result shouldn't be freed +////// OS API + +void GDAPI *godot_get_stack_bottom(); // returns stack bottom of the main thread + ////// MethodBind API typedef struct { @@ -261,6 +265,7 @@ typedef struct { uint64_t core_api_hash; uint64_t editor_api_hash; uint64_t no_api_hash; + godot_object *gd_native_library; // pointer to GDNativeLibrary that is being initialized } godot_gdnative_init_options; typedef struct { diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index 20ac1ecc0c..d180d5aada 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -47,7 +47,8 @@ godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( handle, *(String *)p_procedure, - library_proc); + library_proc, + true); // we roll our own message if (err != OK) { ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data()); godot_variant ret; diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 1e1327d72f..c88889767c 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -1334,8 +1334,8 @@ static void _find_identifiers(GDCompletionContext &context, int p_line, bool p_o static const char *_type_names[Variant::VARIANT_MAX] = { "null", "bool", "int", "float", "String", "Vector2", "Rect2", "Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", - "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "RawArray", "IntArray", "FloatArray", "StringArray", - "Vector2Array", "Vector3Array", "ColorArray" + "Color", "NodePath", "RID", "Object", "Dictionary", "Array", "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray", + "PoolVector2Array", "PoolVector3Array", "PoolColorArray" }; for (int i = 0; i < Variant::VARIANT_MAX; i++) { diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 75029a020b..36aa249398 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -185,8 +185,8 @@ void GDParser::_make_completable_call(int p_arg) { bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &identifier) { identifier = StringName(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - identifier = tokenizer->get_token_identifier(); + if (tokenizer->is_token_literal()) { + identifier = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() == GDTokenizer::TK_CURSOR) { @@ -201,8 +201,8 @@ bool GDParser::_get_completable_identifier(CompletionType p_type, StringName &id completion_ident_is_call = false; tokenizer->advance(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - identifier = identifier.operator String() + tokenizer->get_token_identifier().operator String(); + if (tokenizer->is_token_literal()) { + identifier = identifier.operator String() + tokenizer->get_token_literal().operator String(); tokenizer->advance(); } @@ -296,17 +296,6 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool need_identifier = false; } break; - case GDTokenizer::TK_IDENTIFIER: { - if (!need_identifier) { - done = true; - break; - } - - path += String(tokenizer->get_token_identifier()); - tokenizer->advance(); - need_identifier = false; - - } break; case GDTokenizer::TK_OP_DIV: { if (need_identifier) { @@ -320,7 +309,15 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool } break; default: { - done = true; + // Instead of checking for TK_IDENTIFIER, we check with is_token_literal, as this allows us to use match/sync/etc. as a name + if (need_identifier && tokenizer->is_token_literal()) { + path += String(tokenizer->get_token_literal()); + tokenizer->advance(); + need_identifier = false; + } else { + done = true; + } + break; } } @@ -585,7 +582,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool cn->value = Variant::get_numeric_constant_value(bi_type, identifier); expr = cn; - } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token() == GDTokenizer::TK_BUILT_IN_FUNC)) { + } else if (tokenizer->get_token(1) == GDTokenizer::TK_PARENTHESIS_OPEN && tokenizer->is_token_literal()) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //function or constructor OperatorNode *op = alloc_node<OperatorNode>(); @@ -627,7 +625,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool expr = op; - } else if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { + } else if (tokenizer->is_token_literal(0, true)) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //identifier (reference) const ClassNode *cln = current_class; @@ -827,10 +826,11 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool if (expecting == DICT_EXPECT_KEY) { - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) { + if (tokenizer->is_token_literal() && tokenizer->get_token(1) == GDTokenizer::TK_OP_ASSIGN) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name //lua style identifier, easier to write ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value = tokenizer->get_token_identifier(); + cn->value = tokenizer->get_token_literal(); key = cn; tokenizer->advance(2); expecting = DICT_EXPECT_VALUE; @@ -870,7 +870,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool expr = dict; - } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->get_token(1) == GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { + } else if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && (tokenizer->is_token_literal(1) || tokenizer->get_token(1) == GDTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name // parent call tokenizer->advance(); //goto identifier @@ -922,7 +923,8 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool //indexing using "." - if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && tokenizer->get_token(1) != GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1) != GDTokenizer::TK_BUILT_IN_FUNC) { + if (tokenizer->get_token(1) != GDTokenizer::TK_CURSOR && !tokenizer->is_token_literal(1)) { + // We check with is_token_literal, as this allows us to use match/sync/etc. as a name _set_error("Expected identifier as member"); return NULL; } else if (tokenizer->get_token(2) == GDTokenizer::TK_PARENTHESIS_OPEN) { @@ -2341,12 +2343,12 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { //variale declaration and (eventual) initialization tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for local variable name."); return; } - StringName n = tokenizer->get_token_identifier(); + StringName n = tokenizer->get_token_literal(); tokenizer->advance(); if (current_function) { for (int i = 0; i < current_function->arguments.size(); i++) { @@ -2571,7 +2573,7 @@ void GDParser::_parse_block(BlockNode *p_block, bool p_static) { tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("identifier expected after 'for'"); } @@ -3108,7 +3110,7 @@ void GDParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); //var before the identifier is allowed } - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for argument."); return; @@ -3260,7 +3262,7 @@ void GDParser::_parse_class(ClassNode *p_class) { case GDTokenizer::TK_PR_SIGNAL: { tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal()) { _set_error("Expected identifier after 'signal'."); return; } @@ -3282,7 +3284,7 @@ void GDParser::_parse_class(ClassNode *p_class) { break; } - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier in signal argument."); return; } @@ -3847,13 +3849,13 @@ void GDParser::_parse_class(ClassNode *p_class) { bool onready = tokenizer->get_token(-1) == GDTokenizer::TK_PR_ONREADY; tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for member variable name."); return; } - member.identifier = tokenizer->get_token_identifier(); + member.identifier = tokenizer->get_token_literal(); member.expression = NULL; member._export.name = member.identifier; member.line = tokenizer->get_token_line(); @@ -3979,11 +3981,11 @@ void GDParser::_parse_class(ClassNode *p_class) { if (tokenizer->get_token() != GDTokenizer::TK_COMMA) { //just comma means using only getter - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { - _set_error("Expected identifier for setter function after 'notify'."); + if (!tokenizer->is_token_literal()) { + _set_error("Expected identifier for setter function after 'setget'."); } - member.setter = tokenizer->get_token_identifier(); + member.setter = tokenizer->get_token_literal(); tokenizer->advance(); } @@ -3992,11 +3994,11 @@ void GDParser::_parse_class(ClassNode *p_class) { //there is a getter tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal()) { _set_error("Expected identifier for getter function after ','."); } - member.getter = tokenizer->get_token_identifier(); + member.getter = tokenizer->get_token_literal(); tokenizer->advance(); } } @@ -4014,13 +4016,13 @@ void GDParser::_parse_class(ClassNode *p_class) { ClassNode::Constant constant; tokenizer->advance(); - if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected name (identifier) for constant."); return; } - constant.identifier = tokenizer->get_token_identifier(); + constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); if (tokenizer->get_token() != GDTokenizer::TK_OP_ASSIGN) { @@ -4061,8 +4063,8 @@ void GDParser::_parse_class(ClassNode *p_class) { Dictionary enum_dict; tokenizer->advance(); - if (tokenizer->get_token() == GDTokenizer::TK_IDENTIFIER) { - enum_name = tokenizer->get_token_identifier(); + if (tokenizer->is_token_literal(0, true)) { + enum_name = tokenizer->get_token_literal(); tokenizer->advance(); } if (tokenizer->get_token() != GDTokenizer::TK_CURLY_BRACKET_OPEN) { @@ -4079,7 +4081,7 @@ void GDParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); break; // End of enum - } else if (tokenizer->get_token() != GDTokenizer::TK_IDENTIFIER) { + } else if (!tokenizer->is_token_literal(0, true)) { if (tokenizer->get_token() == GDTokenizer::TK_EOF) { _set_error("Unexpected end of file."); @@ -4088,10 +4090,10 @@ void GDParser::_parse_class(ClassNode *p_class) { } return; - } else { // tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER + } else { // tokenizer->is_token_literal(0, true) ClassNode::Constant constant; - constant.identifier = tokenizer->get_token_identifier(); + constant.identifier = tokenizer->get_token_literal(); tokenizer->advance(); diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index f4e0cc8e29..5803046185 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -130,12 +130,222 @@ const char *GDTokenizer::token_names[TK_MAX] = { "Cursor" }; +struct _bit { + Variant::Type type; + const char *text; +}; +//built in types + +static const _bit _type_list[] = { + //types + { Variant::BOOL, "bool" }, + { Variant::INT, "int" }, + { Variant::REAL, "float" }, + { Variant::STRING, "String" }, + { Variant::VECTOR2, "Vector2" }, + { Variant::RECT2, "Rect2" }, + { Variant::TRANSFORM2D, "Transform2D" }, + { Variant::VECTOR3, "Vector3" }, + { Variant::RECT3, "Rect3" }, + { Variant::PLANE, "Plane" }, + { Variant::QUAT, "Quat" }, + { Variant::BASIS, "Basis" }, + { Variant::TRANSFORM, "Transform" }, + { Variant::COLOR, "Color" }, + { Variant::_RID, "RID" }, + { Variant::OBJECT, "Object" }, + { Variant::NODE_PATH, "NodePath" }, + { Variant::DICTIONARY, "Dictionary" }, + { Variant::ARRAY, "Array" }, + { Variant::POOL_BYTE_ARRAY, "PoolByteArray" }, + { Variant::POOL_INT_ARRAY, "PoolIntArray" }, + { Variant::POOL_REAL_ARRAY, "PoolRealArray" }, + { Variant::POOL_STRING_ARRAY, "PoolStringArray" }, + { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" }, + { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" }, + { Variant::POOL_COLOR_ARRAY, "PoolColorArray" }, + { Variant::VARIANT_MAX, NULL }, +}; + +struct _kws { + GDTokenizer::Token token; + const char *text; +}; + +static const _kws _keyword_list[] = { + //ops + { GDTokenizer::TK_OP_IN, "in" }, + { GDTokenizer::TK_OP_NOT, "not" }, + { GDTokenizer::TK_OP_OR, "or" }, + { GDTokenizer::TK_OP_AND, "and" }, + //func + { GDTokenizer::TK_PR_FUNCTION, "func" }, + { GDTokenizer::TK_PR_CLASS, "class" }, + { GDTokenizer::TK_PR_EXTENDS, "extends" }, + { GDTokenizer::TK_PR_IS, "is" }, + { GDTokenizer::TK_PR_ONREADY, "onready" }, + { GDTokenizer::TK_PR_TOOL, "tool" }, + { GDTokenizer::TK_PR_STATIC, "static" }, + { GDTokenizer::TK_PR_EXPORT, "export" }, + { GDTokenizer::TK_PR_SETGET, "setget" }, + { GDTokenizer::TK_PR_VAR, "var" }, + { GDTokenizer::TK_PR_PRELOAD, "preload" }, + { GDTokenizer::TK_PR_ASSERT, "assert" }, + { GDTokenizer::TK_PR_YIELD, "yield" }, + { GDTokenizer::TK_PR_SIGNAL, "signal" }, + { GDTokenizer::TK_PR_BREAKPOINT, "breakpoint" }, + { GDTokenizer::TK_PR_REMOTE, "remote" }, + { GDTokenizer::TK_PR_MASTER, "master" }, + { GDTokenizer::TK_PR_SLAVE, "slave" }, + { GDTokenizer::TK_PR_SYNC, "sync" }, + { GDTokenizer::TK_PR_CONST, "const" }, + { GDTokenizer::TK_PR_ENUM, "enum" }, + //controlflow + { GDTokenizer::TK_CF_IF, "if" }, + { GDTokenizer::TK_CF_ELIF, "elif" }, + { GDTokenizer::TK_CF_ELSE, "else" }, + { GDTokenizer::TK_CF_FOR, "for" }, + { GDTokenizer::TK_CF_WHILE, "while" }, + { GDTokenizer::TK_CF_DO, "do" }, + { GDTokenizer::TK_CF_SWITCH, "switch" }, + { GDTokenizer::TK_CF_CASE, "case" }, + { GDTokenizer::TK_CF_BREAK, "break" }, + { GDTokenizer::TK_CF_CONTINUE, "continue" }, + { GDTokenizer::TK_CF_RETURN, "return" }, + { GDTokenizer::TK_CF_MATCH, "match" }, + { GDTokenizer::TK_CF_PASS, "pass" }, + { GDTokenizer::TK_SELF, "self" }, + { GDTokenizer::TK_CONST_PI, "PI" }, + { GDTokenizer::TK_WILDCARD, "_" }, + { GDTokenizer::TK_CONST_INF, "INF" }, + { GDTokenizer::TK_CONST_NAN, "NAN" }, + { GDTokenizer::TK_ERROR, NULL } +}; + const char *GDTokenizer::get_token_name(Token p_token) { ERR_FAIL_INDEX_V(p_token, TK_MAX, "<error>"); return token_names[p_token]; } +bool GDTokenizer::is_token_literal(int p_offset, bool variable_safe) const { + switch (get_token(p_offset)) { + // Can always be literal: + case TK_IDENTIFIER: + + case TK_PR_ONREADY: + case TK_PR_TOOL: + case TK_PR_STATIC: + case TK_PR_EXPORT: + case TK_PR_SETGET: + case TK_PR_SIGNAL: + case TK_PR_REMOTE: + case TK_PR_MASTER: + case TK_PR_SLAVE: + case TK_PR_SYNC: + return true; + + // Literal for non-variables only: + case TK_BUILT_IN_TYPE: + case TK_BUILT_IN_FUNC: + + case TK_OP_IN: + //case TK_OP_NOT: + //case TK_OP_OR: + //case TK_OP_AND: + + case TK_PR_CLASS: + case TK_PR_CONST: + case TK_PR_ENUM: + case TK_PR_PRELOAD: + case TK_PR_FUNCTION: + case TK_PR_EXTENDS: + case TK_PR_ASSERT: + case TK_PR_YIELD: + case TK_PR_VAR: + + case TK_CF_IF: + case TK_CF_ELIF: + case TK_CF_ELSE: + case TK_CF_FOR: + case TK_CF_WHILE: + case TK_CF_DO: + case TK_CF_SWITCH: + case TK_CF_CASE: + case TK_CF_BREAK: + case TK_CF_CONTINUE: + case TK_CF_RETURN: + case TK_CF_MATCH: + case TK_CF_PASS: + case TK_SELF: + case TK_CONST_PI: + case TK_WILDCARD: + case TK_CONST_INF: + case TK_CONST_NAN: + case TK_ERROR: + return !variable_safe; + + case TK_CONSTANT: { + switch (get_token_constant(p_offset).get_type()) { + case Variant::NIL: + case Variant::BOOL: + return true; + default: + return false; + } + } + default: + return false; + } +} + +StringName GDTokenizer::get_token_literal(int p_offset) const { + Token token = get_token(p_offset); + switch (token) { + case TK_IDENTIFIER: + return get_token_identifier(p_offset); + case TK_BUILT_IN_TYPE: { + Variant::Type type = get_token_type(p_offset); + int idx = 0; + + while (_type_list[idx].text) { + if (type == _type_list[idx].type) { + return _type_list[idx].text; + } + idx++; + } + } break; // Shouldn't get here, stuff happens + case TK_BUILT_IN_FUNC: + return GDFunctions::get_func_name(get_token_built_in_func(p_offset)); + case TK_CONSTANT: { + const Variant value = get_token_constant(p_offset); + + switch (value.get_type()) { + case Variant::NIL: + return "null"; + case Variant::BOOL: + return value ? "true" : "false"; + default: {} + } + } + case TK_OP_AND: + case TK_OP_OR: + break; // Don't get into default, since they can be non-literal + default: { + int idx = 0; + + while (_keyword_list[idx].text) { + if (token == _keyword_list[idx].token) { + return _keyword_list[idx].text; + } + idx++; + } + } + } + ERR_EXPLAIN("Failed to get token literal"); + ERR_FAIL_V(""); +} + static bool _is_text_char(CharType c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; @@ -779,51 +989,14 @@ void GDTokenizerText::_advance() { bool found = false; - struct _bit { - Variant::Type type; - const char *text; - }; - //built in types - - static const _bit type_list[] = { - //types - { Variant::BOOL, "bool" }, - { Variant::INT, "int" }, - { Variant::REAL, "float" }, - { Variant::STRING, "String" }, - { Variant::VECTOR2, "Vector2" }, - { Variant::RECT2, "Rect2" }, - { Variant::TRANSFORM2D, "Transform2D" }, - { Variant::VECTOR3, "Vector3" }, - { Variant::RECT3, "Rect3" }, - { Variant::PLANE, "Plane" }, - { Variant::QUAT, "Quat" }, - { Variant::BASIS, "Basis" }, - { Variant::TRANSFORM, "Transform" }, - { Variant::COLOR, "Color" }, - { Variant::_RID, "RID" }, - { Variant::OBJECT, "Object" }, - { Variant::NODE_PATH, "NodePath" }, - { Variant::DICTIONARY, "Dictionary" }, - { Variant::ARRAY, "Array" }, - { Variant::POOL_BYTE_ARRAY, "PoolByteArray" }, - { Variant::POOL_INT_ARRAY, "PoolIntArray" }, - { Variant::POOL_REAL_ARRAY, "PoolFloatArray" }, - { Variant::POOL_STRING_ARRAY, "PoolStringArray" }, - { Variant::POOL_VECTOR2_ARRAY, "PoolVector2Array" }, - { Variant::POOL_VECTOR3_ARRAY, "PoolVector3Array" }, - { Variant::POOL_COLOR_ARRAY, "PoolColorArray" }, - { Variant::VARIANT_MAX, NULL }, - }; - { int idx = 0; - while (type_list[idx].text) { + while (_type_list[idx].text) { - if (str == type_list[idx].text) { - _make_type(type_list[idx].type); + if (str == _type_list[idx].text) { + _make_type(_type_list[idx].type); found = true; break; } @@ -844,74 +1017,18 @@ void GDTokenizerText::_advance() { break; } } - - //keywor } if (!found) { - - struct _kws { - Token token; - const char *text; - }; - - static const _kws keyword_list[] = { - //ops - { TK_OP_IN, "in" }, - { TK_OP_NOT, "not" }, - { TK_OP_OR, "or" }, - { TK_OP_AND, "and" }, - //func - { TK_PR_FUNCTION, "func" }, - { TK_PR_CLASS, "class" }, - { TK_PR_EXTENDS, "extends" }, - { TK_PR_IS, "is" }, - { TK_PR_ONREADY, "onready" }, - { TK_PR_TOOL, "tool" }, - { TK_PR_STATIC, "static" }, - { TK_PR_EXPORT, "export" }, - { TK_PR_SETGET, "setget" }, - { TK_PR_VAR, "var" }, - { TK_PR_PRELOAD, "preload" }, - { TK_PR_ASSERT, "assert" }, - { TK_PR_YIELD, "yield" }, - { TK_PR_SIGNAL, "signal" }, - { TK_PR_BREAKPOINT, "breakpoint" }, - { TK_PR_REMOTE, "remote" }, - { TK_PR_MASTER, "master" }, - { TK_PR_SLAVE, "slave" }, - { TK_PR_SYNC, "sync" }, - { TK_PR_CONST, "const" }, - { TK_PR_ENUM, "enum" }, - //controlflow - { TK_CF_IF, "if" }, - { TK_CF_ELIF, "elif" }, - { TK_CF_ELSE, "else" }, - { TK_CF_FOR, "for" }, - { TK_CF_WHILE, "while" }, - { TK_CF_DO, "do" }, - { TK_CF_SWITCH, "switch" }, - { TK_CF_CASE, "case" }, - { TK_CF_BREAK, "break" }, - { TK_CF_CONTINUE, "continue" }, - { TK_CF_RETURN, "return" }, - { TK_CF_MATCH, "match" }, - { TK_CF_PASS, "pass" }, - { TK_SELF, "self" }, - { TK_CONST_PI, "PI" }, - { TK_WILDCARD, "_" }, - { TK_CONST_INF, "INF" }, - { TK_CONST_NAN, "NAN" }, - { TK_ERROR, NULL } - }; + //keyword int idx = 0; found = false; - while (keyword_list[idx].text) { + while (_keyword_list[idx].text) { - if (str == keyword_list[idx].text) { - _make_token(keyword_list[idx].token); + if (str == _keyword_list[idx].text) { + _make_token(_keyword_list[idx].token); found = true; break; } @@ -992,6 +1109,7 @@ const Variant &GDTokenizerText::get_token_constant(int p_offset) const { ERR_FAIL_COND_V(tk_rb[ofs].type != TK_CONSTANT, tk_rb[0].constant); return tk_rb[ofs].constant; } + StringName GDTokenizerText::get_token_identifier(int p_offset) const { ERR_FAIL_COND_V(p_offset <= -MAX_LOOKAHEAD, StringName()); diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index c051176097..4e868301a3 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -149,6 +149,9 @@ protected: public: static const char *get_token_name(Token p_token); + bool is_token_literal(int p_offset = 0, bool variable_safe = false) const; + StringName get_token_literal(int p_offset = 0) const; + virtual const Variant &get_token_constant(int p_offset = 0) const = 0; virtual Token get_token(int p_offset = 0) const = 0; virtual StringName get_token_identifier(int p_offset = 0) const = 0; diff --git a/modules/nativescript/nativescript.cpp b/modules/nativescript/nativescript.cpp index 952e8e349c..e7445e6da9 100644 --- a/modules/nativescript/nativescript.cpp +++ b/modules/nativescript/nativescript.cpp @@ -40,6 +40,10 @@ #include "scene/main/scene_tree.h" #include "scene/resources/scene_format_text.h" +#ifndef NO_THREADS +#include "os/thread.h" +#endif + #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) #include "api_generator.h" #endif @@ -59,6 +63,8 @@ void NativeScript::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "class_name"), "set_class_name", "get_class_name"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "GDNativeLibrary"), "set_library", "get_library"); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &NativeScript::_new, MethodInfo(Variant::OBJECT, "new")); } #define NSL NativeScriptLanguage::get_singleton() @@ -104,42 +110,16 @@ void NativeScript::set_library(Ref<GDNativeLibrary> p_library) { return; } library = p_library; - - // See if this library was "registered" already. - lib_path = library->get_active_library_path(); - Map<String, Ref<GDNative> >::Element *E = NSL->library_gdnatives.find(lib_path); - - if (!E) { - Ref<GDNative> gdn; - gdn.instance(); - gdn->set_library(library); - - // TODO(karroffel): check the return value? - gdn->initialize(); - - NSL->library_gdnatives.insert(lib_path, gdn); - - NSL->library_classes.insert(lib_path, Map<StringName, NativeScriptDesc>()); - - if (!NSL->library_script_users.has(lib_path)) - NSL->library_script_users.insert(lib_path, Set<NativeScript *>()); - - NSL->library_script_users[lib_path].insert(this); - void *args[1] = { - (void *)&lib_path - }; - - // here the library registers all the classes and stuff. - gdn->call_native_raw(NSL->_init_call_type, - NSL->_init_call_name, - NULL, - 1, - args, - NULL); - } else { - // already initialized. Nice. +#ifndef NO_THREADS + if (Thread::get_caller_ID() != Thread::get_main_ID()) { + NSL->defer_init_library(p_library, this); + } else +#endif + { + NSL->init_library(p_library); + NSL->register_script(this); } } @@ -223,7 +203,21 @@ ScriptInstance *NativeScript::instance_create(Object *p_this) { nsi->userdata = script_data->create_func.create_func((godot_object *)p_this, script_data->create_func.method_data); #endif +#ifndef NO_THREADS + owners_lock->lock(); +#endif + instance_owners.insert(p_this); + +#ifndef NO_THREADS + owners_lock->unlock(); +#endif + + // try to call _init + // we don't care if it doesn't exist, so we ignore errors. + Variant::CallError err; + call("_init", NULL, 0, err); + return nsi; } @@ -294,9 +288,13 @@ ScriptLanguage *NativeScript::get_language() const { bool NativeScript::has_script_signal(const StringName &p_signal) const { NativeScriptDesc *script_data = get_script_desc(); - if (!script_data) - return false; - return script_data->signals_.has(p_signal); + + while (script_data) { + if (script_data->signals_.has(p_signal)) + return true; + script_data = script_data->base_data; + } + return false; } void NativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const { @@ -413,9 +411,6 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Variant::Call ref = REF(r); } - // GDScript does it like this: _create_instance(p_args, p_argcount, owner, r != NULL, r_error); - // TODO(karroffel): support varargs for constructors. - NativeScriptInstance *instance = (NativeScriptInstance *)instance_create(owner); owner->set_script_instance(instance); @@ -439,11 +434,18 @@ NativeScript::NativeScript() { library = Ref<GDNative>(); lib_path = ""; class_name = ""; +#ifndef NO_THREADS + owners_lock = Mutex::create(); +#endif } // TODO(karroffel): implement this NativeScript::~NativeScript() { - NSL->library_script_users[lib_path].erase(this); + NSL->unregister_script(this); + +#ifndef NO_THREADS + memdelete(owners_lock); +#endif } ////// ScriptInstance stuff @@ -500,7 +502,7 @@ bool NativeScriptInstance::get(const StringName &p_name, Variant &r_ret) const { if (P) { godot_variant value; value = P->get().getter.get_func((godot_object *)owner, - P->get().setter.method_data, + P->get().getter.method_data, userdata); r_ret = *(Variant *)&value; godot_variant_destroy(&value); @@ -648,6 +650,28 @@ void NativeScriptInstance::notification(int p_notification) { call_multilevel("_notification", args, 1); } +void NativeScriptInstance::refcount_incremented() { + Variant::CallError err; + call("_refcount_incremented", NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK && err.error != Variant::CallError::CALL_ERROR_INVALID_METHOD) { + ERR_PRINT("Failed to invoke _refcount_incremented - should not happen"); + } +} + +bool NativeScriptInstance::refcount_decremented() { + Variant::CallError err; + Variant ret = call("_refcount_decremented", NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK && err.error != Variant::CallError::CALL_ERROR_INVALID_METHOD) { + ERR_PRINT("Failed to invoke _refcount_decremented - should not happen"); + return true; // assume we can destroy the object + } + if (err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) { + // the method does not exist, default is true + return true; + } + return ret; +} + Ref<Script> NativeScriptInstance::get_script() const { return script; } @@ -752,7 +776,16 @@ NativeScriptInstance::~NativeScriptInstance() { script_data->destroy_func.destroy_func((godot_object *)owner, script_data->destroy_func.method_data, userdata); if (owner) { + +#ifndef NO_THREADS + script->owners_lock->lock(); +#endif + script->instance_owners.erase(owner); + +#ifndef NO_THREADS + script->owners_lock->unlock(); +#endif } } @@ -796,6 +829,9 @@ void NativeScriptLanguage::_unload_stuff() { NativeScriptLanguage::NativeScriptLanguage() { NativeScriptLanguage::singleton = this; +#ifndef NO_THREADS + mutex = Mutex::create(); +#endif } // TODO(karroffel): implement this @@ -809,6 +845,10 @@ NativeScriptLanguage::~NativeScriptLanguage() { NSL->library_gdnatives.clear(); NSL->library_script_users.clear(); } + +#ifndef NO_THREADS + memdelete(mutex); +#endif } String NativeScriptLanguage::get_name() const { @@ -946,6 +986,134 @@ int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in return -1; } +#ifndef NO_THREADS +void NativeScriptLanguage::defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script) { + MutexLock lock(mutex); + libs_to_init.insert(lib); + scripts_to_register.insert(script); + has_objects_to_register = true; +} +#endif + +void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { +#ifndef NO_THREADS + MutexLock lock(mutex); +#endif + // See if this library was "registered" already. + const String &lib_path = lib->get_active_library_path(); + Map<String, Ref<GDNative> >::Element *E = library_gdnatives.find(lib_path); + + if (!E) { + Ref<GDNative> gdn; + gdn.instance(); + gdn->set_library(lib); + + // TODO(karroffel): check the return value? + gdn->initialize(); + + library_gdnatives.insert(lib_path, gdn); + + library_classes.insert(lib_path, Map<StringName, NativeScriptDesc>()); + + if (!library_script_users.has(lib_path)) + library_script_users.insert(lib_path, Set<NativeScript *>()); + + void *args[1] = { + (void *)&lib_path + }; + + // here the library registers all the classes and stuff. + gdn->call_native_raw(_init_call_type, + _init_call_name, + NULL, + 1, + args, + NULL); + } else { + // already initialized. Nice. + } +} + +void NativeScriptLanguage::register_script(NativeScript *script) { +#ifndef NO_THREADS + MutexLock lock(mutex); +#endif + library_script_users[script->lib_path].insert(script); +} + +void NativeScriptLanguage::unregister_script(NativeScript *script) { +#ifndef NO_THREADS + MutexLock lock(mutex); +#endif + Map<String, Set<NativeScript *> >::Element *S = library_script_users.find(script->lib_path); + if (S) { + S->get().erase(script); + if (S->get().size() == 0) { + library_script_users.erase(S); + } + } +#ifndef NO_THREADS + scripts_to_register.erase(script); +#endif +} + +#ifndef NO_THREADS + +void NativeScriptLanguage::frame() { + if (has_objects_to_register) { + MutexLock lock(mutex); + for (Set<Ref<GDNativeLibrary> >::Element *L = libs_to_init.front(); L; L = L->next()) { + init_library(L->get()); + } + libs_to_init.clear(); + for (Set<NativeScript *>::Element *S = scripts_to_register.front(); S; S = S->next()) { + register_script(S->get()); + } + scripts_to_register.clear(); + has_objects_to_register = false; + } +} + +void NativeScriptLanguage::thread_enter() { + Vector<Ref<GDNative> > libs; + { + MutexLock lock(mutex); + for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) { + libs.push_back(L->get()); + } + } + for (int i = 0; i < libs.size(); ++i) { + libs[i]->call_native_raw( + _thread_cb_call_type, + _thread_enter_call_name, + NULL, + 0, + NULL, + NULL); + } +} + +void NativeScriptLanguage::thread_exit() { + Vector<Ref<GDNative> > libs; + { + MutexLock lock(mutex); + for (Map<String, Ref<GDNative> >::Element *L = library_gdnatives.front(); L; L = L->next()) { + libs.push_back(L->get()); + } + } + for (int i = 0; i < libs.size(); ++i) { + libs[i]->call_native_raw( + _thread_cb_call_type, + _thread_exit_call_name, + NULL, + 0, + NULL, + NULL); + } +} + +#endif // NO_THREADS + void NativeReloadNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_notification"), &NativeReloadNode::_notification); } @@ -956,8 +1124,11 @@ void NativeReloadNode::_notification(int p_what) { switch (p_what) { case MainLoop::NOTIFICATION_WM_FOCUS_OUT: { - print_line("unload"); - + if (unloaded) + break; +#ifndef NO_THREADS + MutexLock lock(NSL->mutex); +#endif NSL->_unload_stuff(); for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { @@ -965,14 +1136,18 @@ void NativeReloadNode::_notification(int p_what) { NSL->library_classes.erase(L->key()); } + unloaded = true; + } break; case MainLoop::NOTIFICATION_WM_FOCUS_IN: { - print_line("load"); - + if (!unloaded) + break; +#ifndef NO_THREADS + MutexLock lock(NSL->mutex); +#endif Set<StringName> libs_to_remove; - for (Map<String, Ref<GDNative> >::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) { if (!L->get()->initialize()) { @@ -1008,6 +1183,8 @@ void NativeReloadNode::_notification(int p_what) { } } + unloaded = false; + for (Set<StringName>::Element *R = libs_to_remove.front(); R; R = R->next()) { NSL->library_gdnatives.erase(R->get()); } diff --git a/modules/nativescript/nativescript.h b/modules/nativescript/nativescript.h index 5702ba2e8d..95b4954171 100644 --- a/modules/nativescript/nativescript.h +++ b/modules/nativescript/nativescript.h @@ -41,6 +41,10 @@ #include "godot_nativescript.h" #include "modules/gdnative/gdnative.h" +#ifndef NO_THREADS +#include "os/mutex.h" +#endif + struct NativeScriptDesc { struct Method { @@ -102,6 +106,9 @@ class NativeScript : public Script { String class_name; +#ifndef NO_THREADS + Mutex *owners_lock; +#endif Set<Object *> instance_owners; protected: @@ -181,6 +188,9 @@ public: virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); + virtual void refcount_incremented(); + virtual bool refcount_decremented(); + ~NativeScriptInstance(); }; @@ -197,6 +207,19 @@ private: void _unload_stuff(); +#ifndef NO_THREADS + Mutex *mutex; + + Set<Ref<GDNativeLibrary> > libs_to_init; + Set<NativeScript *> scripts_to_register; + volatile bool has_objects_to_register; // so that we don't lock mutex every frame - it's rarely needed + void defer_init_library(Ref<GDNativeLibrary> lib, NativeScript *script); +#endif + + void init_library(const Ref<GDNativeLibrary> &lib); + void register_script(NativeScript *script); + void unregister_script(NativeScript *script); + public: Map<String, Map<StringName, NativeScriptDesc> > library_classes; Map<String, Ref<GDNative> > library_gdnatives; @@ -206,6 +229,10 @@ public: const StringName _init_call_type = "nativescript_init"; const StringName _init_call_name = "godot_nativescript_init"; + const StringName _thread_cb_call_type = "godot_nativescript_thread_cb"; + const StringName _thread_enter_call_name = "godot_nativescript_thread_enter"; + const StringName _thread_exit_call_name = "godot_nativescript_thread_exit"; + NativeScriptLanguage(); ~NativeScriptLanguage(); @@ -215,6 +242,13 @@ public: void _hacky_api_anchor(); +#ifndef NO_THREADS + virtual void thread_enter(); + virtual void thread_exit(); + + virtual void frame(); +#endif + virtual String get_name() const; virtual void init(); virtual String get_type() const; @@ -259,6 +293,8 @@ inline NativeScriptDesc *NativeScript::get_script_desc() const { class NativeReloadNode : public Node { GDCLASS(NativeReloadNode, Node) + bool unloaded = false; + public: static void _bind_methods(); void _notification(int p_what); diff --git a/modules/nativescript/register_types.cpp b/modules/nativescript/register_types.cpp index 6c88b04a56..dfa16d8a2a 100644 --- a/modules/nativescript/register_types.cpp +++ b/modules/nativescript/register_types.cpp @@ -50,7 +50,8 @@ void init_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( p_handle, *(String *)p_proc_name, - library_proc); + library_proc, + true); // we print our own message if (err != OK) { ERR_PRINT((String("GDNative procedure \"" + *(String *)p_proc_name) + "\" does not exists and can't be called").utf8().get_data()); return; @@ -61,6 +62,33 @@ void init_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p fn(args[0]); } +#ifndef NO_THREADS + +typedef void (*native_script_empty_callback)(); + +void thread_call_cb(void *p_handle, godot_string *p_proc_name, void *p_data, int p_num_args, void **args, void *r_ret) { + if (p_handle == NULL) { + ERR_PRINT("No valid library handle, can't call nativescript thread enter/exit callback"); + return; + } + + void *library_proc; + Error err = OS::get_singleton()->get_dynamic_library_symbol_handle( + p_handle, + *(String *)p_proc_name, + library_proc, + true); + if (err != OK) { + // it's fine if thread callbacks are not present in the library. + return; + } + + native_script_empty_callback fn = (native_script_empty_callback)library_proc; + fn(); +} + +#endif // NO_THREADS + ResourceFormatLoaderNativeScript *resource_loader_gdns = NULL; ResourceFormatSaverNativeScript *resource_saver_gdns = NULL; @@ -72,6 +100,9 @@ void register_nativescript_types() { ScriptServer::register_language(native_script_language); GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_init_call_type, init_call_cb); +#ifndef NO_THREADS + GDNativeCallRegistry::singleton->register_native_raw_call_type(native_script_language->_thread_cb_call_type, thread_call_cb); +#endif resource_saver_gdns = memnew(ResourceFormatSaverNativeScript); ResourceSaver::add_resource_format_saver(resource_saver_gdns); diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index c645a55703..7b8b2abebb 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -39,7 +39,7 @@ void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_fra int todo = p_frames; - while (todo) { + while (todo && active) { int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, (float *)p_buffer, todo * 2); todo -= mixed; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index ba3463445d..35358d5a1f 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2328,6 +2328,16 @@ void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, p_from.to_int(), from_port, p_to.to_int()); undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, p_from.to_int(), from_port, p_to.to_int()); } else { + + // disconect current, and connect the new one + if (script->is_input_value_port_connected(edited_func, p_to.to_int(), to_port)) { + int conn_from; + int conn_port; + script->get_input_value_port_connection_source(edited_func, p_to.to_int(), to_port, &conn_from, &conn_port); + undo_redo->add_do_method(script.ptr(), "data_disconnect", edited_func, conn_from, conn_port, p_to.to_int(), to_port); + undo_redo->add_undo_method(script.ptr(), "data_connect", edited_func, conn_from, conn_port, p_to.to_int(), to_port); + } + undo_redo->add_do_method(script.ptr(), "data_connect", edited_func, p_from.to_int(), from_port, p_to.to_int(), to_port); undo_redo->add_undo_method(script.ptr(), "data_disconnect", edited_func, p_from.to_int(), from_port, p_to.to_int(), to_port); //update nodes in sgraph diff --git a/platform/android/detect.py b/platform/android/detect.py index 55b7052393..fae1df3f27 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -178,7 +178,7 @@ def configure(env): env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"]) env.Append(CPPFLAGS=string.split('-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing')) - env.Append(CPPFLAGS=string.split('-DANDROID -DNO_STATVFS -DGLES2_ENABLED')) + env.Append(CPPFLAGS=string.split('-DNO_STATVFS -DGLES2_ENABLED')) env['neon_enabled'] = False if env['android_arch'] == 'x86': diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 97f239c4da..a722cd1b8c 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -2050,6 +2050,7 @@ class EditorExportAndroid : public EditorExportPlatform { String id; String name; String description; + int release; }; struct APKExportData { @@ -2123,6 +2124,7 @@ class EditorExportAndroid : public EditorExportPlatform { if (ea->devices[j].id == ldevices[i]) { d.description = ea->devices[j].description; d.name = ea->devices[j].name; + d.release = ea->devices[j].release; } } @@ -2143,6 +2145,7 @@ class EditorExportAndroid : public EditorExportPlatform { String vendor; String device; d.description + "Device ID: " + d.id + "\n"; + d.release = 0; for (int j = 0; j < props.size(); j++) { String p = props[j]; @@ -2153,7 +2156,9 @@ class EditorExportAndroid : public EditorExportPlatform { } else if (p.begins_with("ro.build.display.id=")) { d.description += "Build: " + p.get_slice("=", 1).strip_edges() + "\n"; } else if (p.begins_with("ro.build.version.release=")) { - d.description += "Release: " + p.get_slice("=", 1).strip_edges() + "\n"; + const String release_str = p.get_slice("=", 1).strip_edges(); + d.description += "Release: " + release_str + "\n"; + d.release = release_str.to_int(); } else if (p.begins_with("ro.product.cpu.abi=")) { d.description += "CPU: " + p.get_slice("=", 1).strip_edges() + "\n"; } else if (p.begins_with("ro.product.manufacturer=")) { @@ -3005,15 +3010,19 @@ public: if (use_adb_over_usb) { args.clear(); + args.push_back("-s"); + args.push_back(devices[p_device].id); args.push_back("reverse"); args.push_back("--remove-all"); err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); - int port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); + int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); args.clear(); + args.push_back("-s"); + args.push_back(devices[p_device].id); args.push_back("reverse"); - args.push_back("tcp:" + itos(port)); - args.push_back("tcp:" + itos(port)); + args.push_back("tcp:" + itos(dbg_port)); + args.push_back("tcp:" + itos(dbg_port)); err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); print_line("Reverse result: " + itos(rv)); @@ -3021,6 +3030,8 @@ public: int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port"); args.clear(); + args.push_back("-s"); + args.push_back(devices[p_device].id); args.push_back("reverse"); args.push_back("tcp:" + itos(fs_port)); args.push_back("tcp:" + itos(fs_port)); @@ -3036,7 +3047,10 @@ public: args.push_back("shell"); args.push_back("am"); args.push_back("start"); - args.push_back("--user 0"); + if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].release >= 17) { // Multi-user introduced in Android 17 + args.push_back("--user"); + args.push_back("0"); + } args.push_back("-a"); args.push_back("android.intent.action.MAIN"); args.push_back("-n"); @@ -3044,7 +3058,7 @@ public: err = OS::get_singleton()->execute(adb, args, true, NULL, NULL, &rv); if (err || rv != 0) { - EditorNode::add_io_error("Could not execute ondevice."); + EditorNode::add_io_error("Could not execute on device."); device_lock->unlock(); return ERR_CANT_CREATE; } @@ -3586,6 +3600,7 @@ void register_android_exporter() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/debug_keystore", PROPERTY_HINT_GLOBAL_FILE, "keystore")); EDITOR_DEF("export/android/debug_keystore_user", "androiddebugkey"); EDITOR_DEF("export/android/debug_keystore_pass", "android"); + EDITOR_DEF("export/android/force_system_user", false); EDITOR_DEF("export/android/timestamping_authority_url", ""); EDITOR_DEF("export/android/use_remote_debug_over_adb", false); diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index a5efae8678..6ae2a0692d 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -80,7 +80,15 @@ public: void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { - // what does this need to do? + if (p_preset->get("texture_format/s3tc")) { + r_features->push_back("s3tc"); + } + if (p_preset->get("texture_format/etc")) { + r_features->push_back("etc"); + } + if (p_preset->get("texture_format/etc2")) { + r_features->push_back("etc2"); + } } void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) { @@ -98,6 +106,10 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 1)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true)); + /* probably need some more info */ } diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm index 4b137b7ffa..f2778e8165 100644 --- a/platform/iphone/gl_view.mm +++ b/platform/iphone/gl_view.mm @@ -29,8 +29,8 @@ /*************************************************************************/ #import "gl_view.h" -#include "core/project_settings.h" #include "core/os/keyboard.h" +#include "core/project_settings.h" #include "os_iphone.h" #include "servers/audio_server.h" diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm index e9c164393b..6c95903241 100644 --- a/platform/iphone/ios.mm +++ b/platform/iphone/ios.mm @@ -36,7 +36,7 @@ void iOS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rate_url", "app_id"), &iOS::get_rate_url); }; -void iOS::alert(const char* p_alert, const char* p_title) { +void iOS::alert(const char *p_alert, const char *p_title) { UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:[NSString stringWithUTF8String:p_title] message:[NSString stringWithUTF8String:p_alert] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] autorelease]; [alert show]; } diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 1329c94198..cb5c022764 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -109,7 +109,6 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_ RasterizerGLES3::register_config(); RasterizerGLES3::make_current(); - RasterizerStorageGLES3::system_fbo = gl_view_base_fb; visual_server = memnew(VisualServerRaster()); /* @@ -122,6 +121,9 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_ visual_server->init(); visual_server->cursor_set_visible(false, 0); + // reset this to what it should be, it will have been set to 0 after visual_server->init() is called + RasterizerStorageGLES3::system_fbo = gl_view_base_fb; + audio_driver = memnew(AudioDriverIphone); audio_driver->set_singleton(); audio_driver->init(); @@ -434,7 +436,8 @@ bool OSIPhone::can_draw() const { int OSIPhone::set_base_framebuffer(int p_fb) { - RasterizerStorageGLES3::system_fbo = gl_view_base_fb; + // gl_view_base_fb has not been updated yet + RasterizerStorageGLES3::system_fbo = p_fb; return 0; }; diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp index dabc7989c0..d7a91b1653 100644 --- a/platform/osx/audio_driver_osx.cpp +++ b/platform/osx/audio_driver_osx.cpp @@ -103,6 +103,7 @@ Error AudioDriverOSX::finishDevice() { Error AudioDriverOSX::init() { OSStatus result; + mutex = Mutex::create(); active = false; channels = 2; @@ -159,43 +160,30 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { - AudioBuffer *abuf; AudioDriverOSX *ad = (AudioDriverOSX *)inRefCon; - bool mix = true; - - if (!ad->active) - mix = false; - else if (ad->mutex) { - mix = ad->mutex->try_lock() == OK; - }; - - if (!mix) { + if (!ad->active || !ad->try_lock()) { for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) { - abuf = &ioData->mBuffers[i]; + AudioBuffer *abuf = &ioData->mBuffers[i]; zeromem(abuf->mData, abuf->mDataByteSize); }; return 0; }; - int frames_left; - for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) { - abuf = &ioData->mBuffers[i]; - frames_left = inNumberFrames; + AudioBuffer *abuf = &ioData->mBuffers[i]; + int frames_left = inNumberFrames; int16_t *out = (int16_t *)abuf->mData; while (frames_left) { int frames = MIN(frames_left, ad->buffer_frames); - //ad->lock(); ad->audio_server_process(frames, ad->samples_in); - //ad->unlock(); - for (int i = 0; i < frames * ad->channels; i++) { + for (int j = 0; j < frames * ad->channels; j++) { - out[i] = ad->samples_in[i] >> 16; + out[j] = ad->samples_in[j] >> 16; } frames_left -= frames; @@ -203,8 +191,7 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon, }; }; - if (ad->mutex) - ad->mutex->unlock(); + ad->unlock(); return 0; }; @@ -232,11 +219,18 @@ void AudioDriverOSX::lock() { if (mutex) mutex->lock(); }; + void AudioDriverOSX::unlock() { if (mutex) mutex->unlock(); }; +bool AudioDriverOSX::try_lock() { + if (mutex) + return mutex->try_lock() == OK; + return true; +} + void AudioDriverOSX::finish() { OSStatus result; @@ -247,16 +241,22 @@ void AudioDriverOSX::finish() { ERR_PRINT("AudioObjectRemovePropertyListener failed"); } - memdelete_arr(samples_in); + if (mutex) { + memdelete(mutex); + mutex = NULL; + } + + if (samples_in) { + memdelete_arr(samples_in); + samples_in = NULL; + } }; AudioDriverOSX::AudioDriverOSX() { - - mutex = Mutex::create(); //NULL; + mutex = NULL; + samples_in = NULL; }; -AudioDriverOSX::~AudioDriverOSX(){ - -}; +AudioDriverOSX::~AudioDriverOSX(){}; #endif diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h index d6d00b7970..287c9d6cbf 100644 --- a/platform/osx/audio_driver_osx.h +++ b/platform/osx/audio_driver_osx.h @@ -70,6 +70,7 @@ public: virtual void unlock(); virtual void finish(); + bool try_lock(); Error reopen(); AudioDriverOSX(); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 44f4334786..cb9dd1dd8e 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -101,11 +101,7 @@ public: bool maximized; bool zoomed; - Vector<Rect2> screens; - Vector<int> screen_dpi; - Size2 window_size; - int current_screen; Rect2 restore_rect; power_osx *power_manager; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 82c1313326..4a01532d89 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -152,6 +152,46 @@ static bool mouse_down_control = false; return NO; } +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 +- (void)windowDidEnterFullScreen:(NSNotification *)notification { + OS_OSX::singleton->zoomed = true; +} + +- (void)windowDidExitFullScreen:(NSNotification *)notification { + OS_OSX::singleton->zoomed = false; +} +#endif // MAC_OS_X_VERSION_MAX_ALLOWED + +- (void)windowDidChangeBackingProperties:(NSNotification *)notification { + if (!OS_OSX::singleton) + return; + + NSWindow *window = (NSWindow *)[notification object]; + CGFloat newBackingScaleFactor = [window backingScaleFactor]; + CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; + + if (newBackingScaleFactor != oldBackingScaleFactor) { + //Set new display scale and window size + OS_OSX::singleton->display_scale = newBackingScaleFactor; + + const NSRect contentRect = [OS_OSX::singleton->window_view frame]; + const NSRect fbRect = contentRect; //convertRectToBacking(contentRect); + + OS_OSX::singleton->window_size.width = fbRect.size.width * OS_OSX::singleton->display_scale; + OS_OSX::singleton->window_size.height = fbRect.size.height * OS_OSX::singleton->display_scale; + + //Update context + if (OS_OSX::singleton->main_loop) { + [OS_OSX::singleton->context update]; + + //Force window resize ??? + NSRect frame = [OS_OSX::singleton->window_object frame]; + [OS_OSX::singleton->window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, 1, 1) display:YES]; + [OS_OSX::singleton->window_object setFrame:frame display:YES]; + } + } +} + - (void)windowDidResize:(NSNotification *)notification { [OS_OSX::singleton->context update]; @@ -161,6 +201,12 @@ static bool mouse_down_control = false; OS_OSX::singleton->window_size.width = fbRect.size.width * OS_OSX::singleton->display_scale; OS_OSX::singleton->window_size.height = fbRect.size.height * OS_OSX::singleton->display_scale; + if (OS_OSX::singleton->main_loop) { + Main::force_redraw(); + //Event retrieval blocks until resize is over. Call Main::iteration() directly. + Main::iteration(); + } + /* _GodotInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); _GodotInputWindowSize(window, contentRect.size.width, contentRect.size.height); @@ -512,7 +558,7 @@ static int translateKey(unsigned int key) { /* 49 */ KEY_UNKNOWN, /* VolumeDown */ /* 4a */ KEY_UNKNOWN, /* Mute */ /* 4b */ KEY_KP_DIVIDE, - /* 4c */ KEY_KP_ENTER, + /* 4c */ KEY_ENTER, /* 4d */ KEY_UNKNOWN, /* 4e */ KEY_KP_SUBTRACT, /* 4f */ KEY_UNKNOWN, @@ -930,33 +976,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au _ensure_data_dir(); - NSArray *screenArray = [NSScreen screens]; - printf("nscreen count %i\n", (int)[screenArray count]); - for (int i = 0; i < [screenArray count]; i++) { - - float displayScale = 1.0; - - if (display_scale > 1.0 && [[screenArray objectAtIndex:i] respondsToSelector:@selector(backingScaleFactor)]) { - displayScale = [[screenArray objectAtIndex:i] backingScaleFactor]; - } - - // Note: Use frame to get the whole screen size - NSRect nsrect = [[screenArray objectAtIndex:i] frame]; - Rect2 rect = Rect2(nsrect.origin.x, nsrect.origin.y, nsrect.size.width, nsrect.size.height); - rect.position *= displayScale; - rect.size *= displayScale; - screens.push_back(rect); - - NSDictionary *description = [[screenArray objectAtIndex:i] deviceDescription]; - NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; - CGSize displayPhysicalSize = CGDisplayScreenSize( - [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); - - //printf("width: %i pwidth %i rect width %i\n",int(displayPixelSize.width*displayScale),int(displayPhysicalSize.width*displayScale),int(nsrect.size.width)); - int dpi = (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale; - - screen_dpi.push_back(dpi); - }; restore_rect = Rect2(get_window_position(), get_window_size()); } @@ -977,8 +996,6 @@ void OS_OSX::finalize() { physics_2d_server->finish(); memdelete(physics_2d_server); - - screens.clear(); } void OS_OSX::set_main_loop(MainLoop *p_main_loop) { @@ -1228,37 +1245,80 @@ void OS_OSX::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con } int OS_OSX::get_screen_count() const { - - return screens.size(); + NSArray *screenArray = [NSScreen screens]; + return [screenArray count]; }; int OS_OSX::get_current_screen() const { - - return current_screen; + Vector2 wpos = get_window_position(); + + int count = get_screen_count(); + for (int i = 0; i < count; i++) { + Point2 pos = get_screen_position(i); + Size2 size = get_screen_size(i); + if ((wpos.x >= pos.x && wpos.x < pos.x + size.width) && (wpos.y >= pos.y && wpos.y < pos.y + size.height)) + return i; + } + return 0; }; void OS_OSX::set_current_screen(int p_screen) { - - current_screen = p_screen; + Vector2 wpos = get_window_position() - get_screen_position(get_current_screen()); + set_window_position(wpos + get_screen_position(p_screen)); }; Point2 OS_OSX::get_screen_position(int p_screen) const { + NSArray *screenArray = [NSScreen screens]; + if (p_screen < [screenArray count]) { + float displayScale = 1.0; - ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2()); - return screens[p_screen].position; -}; + if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { + displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; + } + + NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; + return Point2(nsrect.origin.x, nsrect.origin.y) * displayScale; + } + + return Point2(); +} int OS_OSX::get_screen_dpi(int p_screen) const { + NSArray *screenArray = [NSScreen screens]; + if (p_screen < [screenArray count]) { + float displayScale = 1.0; + + if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { + displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; + } + + NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription]; + NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; + CGSize displayPhysicalSize = CGDisplayScreenSize( + [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); - ERR_FAIL_INDEX_V(p_screen, screens.size(), 72); - return screen_dpi[p_screen]; + return (displayPixelSize.width * 25.4f / displayPhysicalSize.width) * displayScale; + } + + return 72; } Size2 OS_OSX::get_screen_size(int p_screen) const { + NSArray *screenArray = [NSScreen screens]; + if (p_screen < [screenArray count]) { + float displayScale = 1.0; - ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2()); - return screens[p_screen].size; -}; + if (display_scale > 1.0 && [[screenArray objectAtIndex:p_screen] respondsToSelector:@selector(backingScaleFactor)]) { + displayScale = [[screenArray objectAtIndex:p_screen] backingScaleFactor]; + } + + // Note: Use frame to get the whole screen size + NSRect nsrect = [[screenArray objectAtIndex:p_screen] frame]; + return Size2(nsrect.size.width, nsrect.size.height) * displayScale; + } + + return Size2(); +} void OS_OSX::_update_window() { bool borderless_full = false; @@ -1383,7 +1443,7 @@ void OS_OSX::set_window_maximized(bool p_enabled) { if (p_enabled) { restore_rect = Rect2(get_window_position(), get_window_size()); - [window_object setFrame:[[[NSScreen screens] objectAtIndex:current_screen] visibleFrame] display:YES]; + [window_object setFrame:[[[NSScreen screens] objectAtIndex:get_current_screen()] visibleFrame] display:YES]; } else { set_window_size(restore_rect.size); set_window_position(restore_rect.position); @@ -1661,12 +1721,52 @@ OS_OSX::OS_OSX() { // In case we are unbundled, make us a proper UI application [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; -#if 0 // Menu bar setup must go between sharedApplication above and // finishLaunching below, in order to properly emulate the behavior // of NSApplicationMain - createMenuBar(); -#endif + NSMenuItem *menu_item; + NSString *title; + + NSString *nsappname = [[[NSBundle mainBundle] performSelector:@selector(localizedInfoDictionary)] objectForKey:@"CFBundleName"]; + if (nsappname == nil) + nsappname = [[NSProcessInfo processInfo] processName]; + + // Setup Apple menu + NSMenu *apple_menu = [[NSMenu alloc] initWithTitle:@""]; + title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname]; + [apple_menu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [apple_menu addItem:[NSMenuItem separatorItem]]; + + NSMenu *services = [[NSMenu alloc] initWithTitle:@""]; + menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""]; + [apple_menu setSubmenu:services forItem:menu_item]; + [NSApp setServicesMenu:services]; + [services release]; + + [apple_menu addItem:[NSMenuItem separatorItem]]; + + title = [NSString stringWithFormat:NSLocalizedString(@"Hide %@", nil), nsappname]; + [apple_menu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menu_item setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)]; + + [apple_menu addItemWithTitle:NSLocalizedString(@"Show all", nil) action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [apple_menu addItem:[NSMenuItem separatorItem]]; + + title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname]; + [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + // Setup menu bar + NSMenu *main_menu = [[NSMenu alloc] initWithTitle:@""]; + menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; + [main_menu setSubmenu:apple_menu forItem:menu_item]; + [NSApp setMainMenu:main_menu]; + + [main_menu release]; + [apple_menu release]; [NSApp finishLaunching]; @@ -1676,8 +1776,6 @@ OS_OSX::OS_OSX() { cursor_shape = CURSOR_ARROW; - current_screen = 0; - maximized = false; minimized = false; window_size = Vector2(1024, 600); diff --git a/platform/windows/detect.py b/platform/windows/detect.py index a2bc5a11ab..4d93b3f244 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -48,7 +48,7 @@ def can_build(): if (os.getenv("MINGW64_PREFIX")): mingw64 = os.getenv("MINGW64_PREFIX") - test = "gcc --version &>/dev/null" + test = "gcc --version > /dev/null 2>&1" if (os.system(mingw + test) == 0 or os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0): return True @@ -65,7 +65,7 @@ def get_opts(): mingw32 = "i686-w64-mingw32-" mingw64 = "x86_64-w64-mingw32-" - if os.system(mingw32 + "gcc --version &>/dev/null") != 0: + if os.system(mingw32 + "gcc --version > /dev/null 2>&1") != 0: mingw32 = mingw if (os.getenv("MINGW32_PREFIX")): @@ -252,13 +252,6 @@ def configure(env): env.Append(LINKFLAGS=['-static']) mingw_prefix = env["mingw_prefix_64"] - nulstr = "" - - if (os.name == "posix"): - nulstr = ">/dev/null" - else: - nulstr = ">nul" - env["CC"] = mingw_prefix + "gcc" env['AS'] = mingw_prefix + "as" env['CXX'] = mingw_prefix + "g++" diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 3413050f4a..da14d5c284 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -805,7 +805,12 @@ void OS_Windows::process_key_events() { k->set_pressed(ke.uMsg == WM_KEYDOWN); - k->set_scancode(KeyMappingWindows::get_keysym(ke.wParam)); + if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) { + // Special case for Numpad Enter key + k->set_scancode(KEY_ENTER); + } else { + k->set_scancode(KeyMappingWindows::get_keysym(ke.wParam)); + } if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) { k->set_unicode(key_event_buffer[i + 1].wParam); @@ -1569,12 +1574,16 @@ Error OS_Windows::close_dynamic_library(void *p_library_handle) { return OK; } -Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle) { +Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) { char *error; p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data()); if (!p_symbol_handle) { - ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + String::num(GetLastError())); - ERR_FAIL_V(ERR_CANT_RESOLVE); + if (!p_optional) { + ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + String::num(GetLastError())); + ERR_FAIL_V(ERR_CANT_RESOLVE); + } else { + return ERR_CANT_RESOLVE; + } } return OK; } diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index e6589ddfad..6856e7e9b8 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -227,7 +227,7 @@ public: virtual Error open_dynamic_library(const String p_path, void *&p_library_handle); virtual Error close_dynamic_library(void *p_library_handle); - virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle); + virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false); virtual MainLoop *get_main_loop() const; diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp index 362fc3618a..1d7eb1692c 100644 --- a/platform/x11/key_mapping_x11.cpp +++ b/platform/x11/key_mapping_x11.cpp @@ -94,7 +94,6 @@ static _XTranslatePair _xkeysym_to_keycode[] = { //{ XK_KP_Separator, KEY_COMMA }, { XK_KP_Decimal, KEY_KP_PERIOD }, { XK_KP_Delete, KEY_KP_PERIOD }, - { XK_KP_Enter, KEY_KP_ENTER }, { XK_KP_Multiply, KEY_KP_MULTIPLY }, { XK_KP_Divide, KEY_KP_DIVIDE }, { XK_KP_Subtract, KEY_KP_SUBTRACT }, diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 3143f30f77..1dde328eda 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -497,6 +497,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au joypad = memnew(JoypadLinux(input)); #endif _ensure_data_dir(); + + power_manager = memnew(PowerX11); } void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data, @@ -1858,7 +1860,7 @@ void OS_X11::set_clipboard(const String &p_text) { XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), x11_window, CurrentTime); }; -static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) { +static String _get_clipboard_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) { String ret; @@ -1875,7 +1877,7 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di }; if (Sown != None) { - XConvertSelection(x11_display, p_source, XA_STRING, selection, + XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime); XFlush(x11_display); while (true) { @@ -1915,6 +1917,18 @@ static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_di return ret; } +static String _get_clipboard(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) { + String ret; + Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True); + if (utf8_atom != None) { + ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom); + } + if (ret == "") { + ret = _get_clipboard_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING); + } + return ret; +} + String OS_X11::get_clipboard() const { String ret; diff --git a/platform/x11/power_x11.cpp b/platform/x11/power_x11.cpp index 093d24f406..8e69a2223f 100644 --- a/platform/x11/power_x11.cpp +++ b/platform/x11/power_x11.cpp @@ -171,25 +171,18 @@ void PowerX11::check_proc_acpi_battery(const char *node, bool *have_battery, boo charge = true; } } else if (String(key) == "remaining capacity") { - char *endptr = NULL; - //const int cvt = (int) strtol(val, &endptr, 10); String sval = val; const int cvt = sval.to_int(); - if (*endptr == ' ') { - remaining = cvt; - } + remaining = cvt; } } ptr = &info[0]; while (make_proc_acpi_key_val(&ptr, &key, &val)) { if (String(key) == "design capacity") { - char *endptr = NULL; String sval = val; const int cvt = sval.to_int(); - if (*endptr == ' ') { - maximum = cvt; - } + maximum = cvt; } } diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp new file mode 100644 index 0000000000..5f2a720748 --- /dev/null +++ b/scene/3d/arvr_nodes.cpp @@ -0,0 +1,313 @@ +/*************************************************************************/ +/* arvr_nodes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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. */ +/*************************************************************************/ + +#include "arvr_nodes.h" +#include "core/os/input.h" +#include "servers/arvr/arvr_interface.h" +#include "servers/arvr/arvr_positional_tracker.h" +#include "servers/arvr_server.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ARVRCamera::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + // need to find our ARVROrigin parent and let it know we're it's camera! + ARVROrigin *origin = get_parent()->cast_to<ARVROrigin>(); + if (origin != NULL) { + origin->set_tracked_camera(this); + } + }; break; + case NOTIFICATION_EXIT_TREE: { + // need to find our ARVROrigin parent and let it know we're no longer it's camera! + ARVROrigin *origin = get_parent()->cast_to<ARVROrigin>(); + if (origin != NULL) { + origin->clear_tracked_camera_if(this); + } + }; break; + }; +}; + +String ARVRCamera::get_configuration_warning() const { + if (!is_visible() || !is_inside_tree()) + return String(); + + // must be child node of ARVROrigin! + ARVROrigin *origin = get_parent()->cast_to<ARVROrigin>(); + if (origin == NULL) { + return TTR("ARVRCamera must have an ARVROrigin node as its parent"); + }; + + return String(); +}; + +ARVRCamera::ARVRCamera(){ + // nothing to do here yet for now.. +}; + +ARVRCamera::~ARVRCamera(){ + // nothing to do here yet for now.. +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void ARVRController::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + set_process_internal(true); + }; break; + case NOTIFICATION_EXIT_TREE: { + set_process_internal(false); + }; break; + case NOTIFICATION_INTERNAL_PROCESS: { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + // find the tracker for our controller + ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id); + if (tracker == NULL) { + // this controller is currently turned off + is_active = false; + button_states = 0; + } else { + set_transform(tracker->get_transform(true)); + + int joy_id = tracker->get_joy_id(); + if (joy_id >= 0) { + int mask = 1; + // check button states + for (int i = 0; i < 16; i++) { + bool was_pressed = (button_states && mask) == mask; + bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, i); + + if (!was_pressed && is_pressed) { + emit_signal("button_pressed", i); + button_states += mask; + } else if (was_pressed && !is_pressed) { + emit_signal("button_release", i); + button_states -= mask; + }; + + mask = mask << 1; + }; + + } else { + button_states = 0; + }; + }; + }; break; + default: + break; + }; +}; + +void ARVRController::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &ARVRController::set_controller_id); + ClassDB::bind_method(D_METHOD("get_controller_id"), &ARVRController::get_controller_id); + ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id"), "set_controller_id", "get_controller_id"); + ClassDB::bind_method(D_METHOD("get_controller_name"), &ARVRController::get_controller_name); + + // passthroughs to information about our related joystick + ClassDB::bind_method(D_METHOD("get_joystick_id"), &ARVRController::get_joystick_id); + ClassDB::bind_method(D_METHOD("is_button_pressed", "button"), &ARVRController::is_button_pressed); + ClassDB::bind_method(D_METHOD("get_joystick_axis", "axis"), &ARVRController::get_joystick_axis); + + ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRController::get_is_active); + + ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button"))); + ADD_SIGNAL(MethodInfo("button_release", PropertyInfo(Variant::INT, "button"))); +}; + +void ARVRController::set_controller_id(int p_controller_id) { + // we don't check any bounds here, this controller may not yet be active and just be a place holder until it is. + controller_id = p_controller_id; +}; + +int ARVRController::get_controller_id(void) const { + return controller_id; +}; + +String ARVRController::get_controller_name(void) const { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, String()); + + ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id); + if (tracker == NULL) { + return String("Not connected"); + }; + + return tracker->get_name(); +}; + +int ARVRController::get_joystick_id() const { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, 0); + + ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, controller_id); + if (tracker == NULL) { + return 0; + }; + + return tracker->get_joy_id(); +}; + +int ARVRController::is_button_pressed(int p_button) const { + int joy_id = get_joystick_id(); + if (joy_id == 0) { + return false; + }; + + return Input::get_singleton()->is_joy_button_pressed(joy_id, p_button); +}; + +float ARVRController::get_joystick_axis(int p_axis) const { + int joy_id = get_joystick_id(); + if (joy_id == 0) { + return 0.0; + }; + + return Input::get_singleton()->get_joy_axis(joy_id, p_axis); +}; + +bool ARVRController::get_is_active() const { + return is_active; +}; + +String ARVRController::get_configuration_warning() const { + if (!is_visible() || !is_inside_tree()) + return String(); + + // must be child node of ARVROrigin! + ARVROrigin *origin = get_parent()->cast_to<ARVROrigin>(); + if (origin == NULL) { + return TTR("ARVRController must have an ARVROrigin node as its parent"); + }; + + if (controller_id == 0) { + return TTR("The controller id must not be 0 or this controller will not be bound to an actual controller"); + }; + + return String(); +}; + +ARVRController::ARVRController() { + controller_id = 0; + is_active = true; +}; + +ARVRController::~ARVRController(){ + // nothing to do here yet for now.. +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +String ARVROrigin::get_configuration_warning() const { + if (!is_visible() || !is_inside_tree()) + return String(); + + if (tracked_camera == NULL) + return TTR("ARVROrigin requires an ARVRCamera child node"); + + return String(); +}; + +void ARVROrigin::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &ARVROrigin::set_world_scale); + ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVROrigin::get_world_scale); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "world_scale"), "set_world_scale", "get_world_scale"); +}; + +void ARVROrigin::set_tracked_camera(ARVRCamera *p_tracked_camera) { + tracked_camera = p_tracked_camera; +}; + +void ARVROrigin::clear_tracked_camera_if(ARVRCamera *p_tracked_camera) { + if (tracked_camera == p_tracked_camera) { + tracked_camera = NULL; + }; +}; + +float ARVROrigin::get_world_scale() const { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, 1.0); + + return arvr_server->get_world_scale(); +}; + +void ARVROrigin::set_world_scale(float p_world_scale) { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + arvr_server->set_world_scale(p_world_scale); +}; + +void ARVROrigin::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + set_process_internal(true); + }; break; + case NOTIFICATION_EXIT_TREE: { + set_process_internal(false); + }; break; + case NOTIFICATION_INTERNAL_PROCESS: { + // get our ARVRServer + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + // set our world origin to our node transform + arvr_server->set_world_origin(get_global_transform()); + + // check if we have a primary interface + Ref<ARVRInterface> arvr_interface = arvr_server->get_primary_interface(); + if (arvr_interface.is_valid() && tracked_camera != NULL) { + // get our positioning transform for our headset + Transform t = arvr_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, Transform()); + + // now apply this to our camera + tracked_camera->set_transform(t); + }; + }; break; + default: + break; + }; +}; + +ARVROrigin::ARVROrigin() { + tracked_camera = NULL; +}; + +ARVROrigin::~ARVROrigin(){ + // nothing to do here yet for now.. +}; diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h new file mode 100644 index 0000000000..3dab263317 --- /dev/null +++ b/scene/3d/arvr_nodes.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* arvr_nodes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 ARVR_NODES_H +#define ARVR_NODES_H + +#include "scene/3d/camera.h" +#include "scene/3d/spatial.h" + +/** + @author Bastiaan Olij <mux213@gmail.com> +**/ + +/* + ARVRCamera is a subclass of camera which will register itself with its parent ARVROrigin and as a result is automatically positioned +*/ +class ARVRCamera : public Camera { + + GDCLASS(ARVRCamera, Camera); + +protected: + void _notification(int p_what); + +public: + String get_configuration_warning() const; + + ARVRCamera(); + ~ARVRCamera(); +}; + +/* + ARVRController is a helper node that automatically updates it's position based on tracker data. + + It must be a child node of our ARVROrigin node +*/ + +class ARVRController : public Spatial { + + GDCLASS(ARVRController, Spatial); + +private: + int controller_id; + bool is_active; + int button_states; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_controller_id(int p_controller_id); + int get_controller_id(void) const; + String get_controller_name(void) const; + + int get_joystick_id() const; + int is_button_pressed(int p_button) const; + float get_joystick_axis(int p_axis) const; + + bool get_is_active() const; + + String get_configuration_warning() const; + + ARVRController(); + ~ARVRController(); +}; + +/* + ARVROrigin is special spatial node that acts as our origin point mapping our real world center of our tracking volume into our virtual world. + + It is this point that you will move around the world as the player 'moves while standing still', i.e. the player moves through teleporting or controller inputs as opposed to physically moving. + + Our camera and controllers will always be child nodes and thus place relative to this origin point. + This node will automatically locate any camera child nodes and update its position while our ARVRController node will handle tracked controllers. +*/ +class ARVROrigin : public Spatial { + + GDCLASS(ARVROrigin, Spatial); + +private: + ARVRCamera *tracked_camera; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + String get_configuration_warning() const; + + void set_tracked_camera(ARVRCamera *p_tracked_camera); + void clear_tracked_camera_if(ARVRCamera *p_tracked_camera); + + float get_world_scale() const; + void set_world_scale(float p_world_scale); + + ARVROrigin(); + ~ARVROrigin(); +}; + +#endif /* ARVR_NODES_H */ diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 0c31282a6c..7aaf4a6e3d 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -999,7 +999,7 @@ GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_mater return mc; } -void GIProbe::_plot_mesh(const Transform &p_xform, Ref<ArrayMesh> &p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { +void GIProbe::_plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material) { for (int i = 0; i < p_mesh->get_surface_count(); i++) { @@ -1093,7 +1093,7 @@ void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { MeshInstance *mi = p_at_node->cast_to<MeshInstance>(); if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT)) { - Ref<ArrayMesh> mesh = mi->get_mesh(); + Ref<Mesh> mesh = mi->get_mesh(); if (mesh.is_valid()) { Rect3 aabb = mesh->get_aabb(); @@ -1120,7 +1120,7 @@ void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { for (int i = 0; i < meshes.size(); i += 2) { Transform mxf = meshes[i]; - Ref<ArrayMesh> mesh = meshes[i + 1]; + Ref<Mesh> mesh = meshes[i + 1]; if (!mesh.is_valid()) continue; diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 3f5a50a560..8346437ebd 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -148,7 +148,7 @@ private: struct PlotMesh { Ref<Material> override_material; Vector<Ref<Material> > instance_materials; - Ref<ArrayMesh> mesh; + Ref<Mesh> mesh; Transform local_xform; }; @@ -177,7 +177,7 @@ private: Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color); Baker::MaterialCache _get_material_cache(Ref<Material> p_material, Baker *p_baker); void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const Baker::MaterialCache &p_material, const Rect3 &p_aabb, Baker *p_baker); - void _plot_mesh(const Transform &p_xform, Ref<ArrayMesh> &p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); + void _plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, Baker *p_baker, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); void _find_meshes(Node *p_at_node, Baker *p_baker); void _fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, Baker *p_baker); diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 558932ceb9..51237c0bc3 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -275,7 +275,7 @@ void MeshInstance::_mesh_changed() { materials.resize(mesh->get_surface_count()); } -void MeshInstance::create_debug_tagents() { +void MeshInstance::create_debug_tangents() { Vector<Vector3> lines; Vector<Color> colors; @@ -366,8 +366,8 @@ void MeshInstance::_bind_methods() { ClassDB::set_method_flags("MeshInstance", "create_convex_collision", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("_mesh_changed"), &MeshInstance::_mesh_changed); - ClassDB::bind_method(D_METHOD("create_debug_tagents"), &MeshInstance::create_debug_tagents); - ClassDB::set_method_flags("MeshInstance", "create_debug_tagents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance::create_debug_tangents); + ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton_path", "get_skeleton_path"); diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index be328084af..1bb2c97d10 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -83,7 +83,7 @@ public: Node *create_convex_collision_node(); void create_convex_collision(); - void create_debug_tagents(); + void create_debug_tangents(); virtual Rect3 get_aabb() const; virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index ee908428d9..ca81b72e89 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2536,7 +2536,7 @@ void Control::_bind_methods() { ADD_GROUP("Size Flags", "size_flags_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_h_size_flags", "get_h_size_flags"); ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_vertical", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_v_size_flags", "get_v_size_flags"); - ADD_PROPERTYNO(PropertyInfo(Variant::INT, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), "set_stretch_ratio", "get_stretch_ratio"); + ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "size_flags_stretch_ratio", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_stretch_ratio", "get_stretch_ratio"); ADD_GROUP("Theme", ""); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme"); ADD_GROUP("", ""); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 1d37529a87..11f750ea70 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -601,7 +601,7 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const int cp_neg_len = get_constant("bezier_len_neg"); if (diff > 0) { - cp_offset = MAX(cp_len, diff * 0.5); + cp_offset = MIN(cp_len, diff * 0.5); } else { cp_offset = MAX(MIN(cp_len - diff, cp_neg_len), -diff * 0.5); } diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 589ba9e538..874156821e 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -36,7 +36,6 @@ void Label::set_autowrap(bool p_autowrap) { autowrap = p_autowrap; word_cache_dirty = true; - minimum_size_changed(); update(); } bool Label::has_autowrap() const { @@ -48,7 +47,6 @@ void Label::set_uppercase(bool p_uppercase) { uppercase = p_uppercase; word_cache_dirty = true; - minimum_size_changed(); update(); } bool Label::is_uppercase() const { @@ -71,7 +69,6 @@ void Label::_notification(int p_what) { xl_text = new_text; regenerate_word_cache(); - minimum_size_changed(); update(); } @@ -496,6 +493,7 @@ void Label::regenerate_word_cache() { minsize.height = (font->get_height() * line_count) + (line_spacing * (line_count - 1)); } + minimum_size_changed(); word_cache_dirty = false; } @@ -533,9 +531,6 @@ void Label::set_text(const String &p_string) { if (percent_visible < 1) visible_chars = get_total_character_count() * percent_visible; update(); - if (!autowrap) { - minimum_size_changed(); - } } void Label::set_clip_text(bool p_clip) { diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index c477a3156f..24eb19fbc2 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -793,7 +793,7 @@ void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &Tabs::set_tab_disabled); ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &Tabs::get_tab_disabled); ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &Tabs::remove_tab); - ClassDB::bind_method(D_METHOD("add_tab", "title", "icon:Texture"), &Tabs::add_tab); + ClassDB::bind_method(D_METHOD("add_tab", "title", "icon:Texture"), &Tabs::add_tab, DEFVAL(""), DEFVAL(Ref<Texture>())); ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &Tabs::set_tab_align); ClassDB::bind_method(D_METHOD("get_tab_align"), &Tabs::get_tab_align); ClassDB::bind_method(D_METHOD("ensure_tab_visible", "idx"), &Tabs::ensure_tab_visible); diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 33d9b76b70..2912aa82fc 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -206,7 +206,7 @@ void TextureButton::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_focused_texture", "get_focused_texture"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_expand", "get_expand"); - ADD_PROPERTYNO(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode"); + ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode"); BIND_CONSTANT(STRETCH_SCALE); BIND_CONSTANT(STRETCH_TILE); diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index 8b3f939f1a..04b6177c3c 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -30,9 +30,9 @@ #include "resource_format_image.h" #if 0 -#include "project_settings.h" #include "io/image_loader.h" #include "os/os.h" +#include "project_settings.h" #include "scene/resources/texture.h" RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_original_path, Error *r_error) { diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 26d1deadf9..c3849f79df 100755 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -311,6 +311,11 @@ void Node::move_child(Node *p_child, int p_pos) { ERR_FAIL_COND(data.blocked > 0); } + // Specifying one place beyond the end + // means the same as moving to the last position + if (p_pos == data.children.size()) + p_pos--; + if (p_child->data.pos == p_pos) return; //do nothing diff --git a/scene/main/node.h b/scene/main/node.h index cfd5c07921..1794cce9f6 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -31,10 +31,10 @@ #define NODE_H #include "class_db.h" -#include "project_settings.h" #include "map.h" #include "object.h" #include "path_db.h" +#include "project_settings.h" #include "scene/main/scene_tree.h" #include "script_language.h" diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 5ce347d79b..76b281ebac 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -701,6 +701,16 @@ RID Viewport::get_viewport_rid() const { return viewport; } +void Viewport::set_use_arvr(bool p_use_arvr) { + arvr = p_use_arvr; + + VS::get_singleton()->viewport_set_use_arvr(viewport, arvr); +} + +bool Viewport::use_arvr() { + return arvr; +} + void Viewport::set_size(const Size2 &p_size) { if (size == p_size.floor()) @@ -2543,6 +2553,9 @@ int Viewport::get_render_info(RenderInfo p_info) { void Viewport::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr); + ClassDB::bind_method(D_METHOD("use_arvr"), &Viewport::use_arvr); + ClassDB::bind_method(D_METHOD("set_size", "size"), &Viewport::set_size); ClassDB::bind_method(D_METHOD("get_size"), &Viewport::get_size); ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d:World2D"), &Viewport::set_world_2d); @@ -2644,6 +2657,8 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv); ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world"); @@ -2729,6 +2744,7 @@ Viewport::Viewport() { parent = NULL; listener = NULL; camera = NULL; + arvr = false; size_override = false; size_override_stretch = false; size_override_size = Size2(1, 1); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index bd9747d878..83c989db54 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -148,6 +148,8 @@ private: Listener *listener; Set<Listener *> listeners; + bool arvr; + Camera *camera; Set<Camera *> cameras; @@ -349,6 +351,9 @@ public: Listener *get_listener() const; Camera *get_camera() const; + void set_use_arvr(bool p_use_arvr); + bool use_arvr(); + void set_as_audio_listener(bool p_enable); bool is_audio_listener() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 74c556931c..f286bfb81a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "register_scene_types.h" -#include "project_settings.h" #include "os/os.h" +#include "project_settings.h" #include "scene/io/resource_format_image.h" #include "scene/io/resource_format_wav.h" @@ -199,6 +199,8 @@ #include "scene/3d/camera.h" #include "scene/3d/listener.h" +#include "scene/3d/arvr_nodes.h" + #include "scene/3d/gi_probe.h" #include "scene/3d/interpolated_camera.h" #include "scene/3d/light.h" @@ -405,6 +407,9 @@ void register_scene_types() { ClassDB::register_virtual_class<VisualInstance>(); ClassDB::register_class<Camera>(); ClassDB::register_class<Listener>(); + ClassDB::register_class<ARVRCamera>(); + ClassDB::register_class<ARVRController>(); + ClassDB::register_class<ARVROrigin>(); ClassDB::register_class<InterpolatedCamera>(); ClassDB::register_class<MeshInstance>(); ClassDB::register_class<ImmediateGeometry>(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index ae89d8ed94..accced404b 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -167,6 +167,7 @@ void Environment::set_tonemap_auto_exposure(bool p_enabled) { tonemap_auto_exposure = p_enabled; VS::get_singleton()->environment_set_tonemap(environment, VS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, tonemap_white, tonemap_auto_exposure, tonemap_auto_exposure_min, tonemap_auto_exposure_max, tonemap_auto_exposure_speed, tonemap_auto_exposure_grey); + _change_notify(); } bool Environment::get_tonemap_auto_exposure() const { diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 3668dda604..a6a70d775f 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -506,7 +506,7 @@ float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_c cpos.y += c->v_align; ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0); if (c->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate); + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), false); return get_char_size(p_char, p_next).width; } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 01a8342fed..6bf3590c12 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "packed_scene.h" #include "core/core_string_names.h" -#include "project_settings.h" #include "io/resource_loader.h" +#include "project_settings.h" #include "scene/2d/node_2d.h" #include "scene/3d/spatial.h" #include "scene/gui/control.h" diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index 585579aad5..03a862b744 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "scene_format_text.h" -#include "project_settings.h" #include "os/dir_access.h" +#include "project_settings.h" #include "version.h" //version 2: changed names for basis, rect3, poolvectors, etc. diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 8b747e1b43..8478432a04 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -818,6 +818,7 @@ void SurfaceTool::clear() { void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("begin", "primitive"), &SurfaceTool::begin); + ClassDB::bind_method(D_METHOD("add_vertex", "vertex"), &SurfaceTool::add_vertex); ClassDB::bind_method(D_METHOD("add_color", "color"), &SurfaceTool::add_color); ClassDB::bind_method(D_METHOD("add_normal", "normal"), &SurfaceTool::add_normal); @@ -827,15 +828,25 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bones", "bones"), &SurfaceTool::add_bones); ClassDB::bind_method(D_METHOD("add_weights", "weights"), &SurfaceTool::add_weights); ClassDB::bind_method(D_METHOD("add_smooth_group", "smooth"), &SurfaceTool::add_smooth_group); + ClassDB::bind_method(D_METHOD("add_triangle_fan", "vertexes", "uvs", "colors", "uv2s", "normals", "tangents"), &SurfaceTool::add_triangle_fan, DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Color>()), DEFVAL(Vector<Vector2>()), DEFVAL(Vector<Vector3>()), DEFVAL(Vector<Plane>())); - ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &SurfaceTool::set_material); + + ClassDB::bind_method(D_METHOD("add_index", "index"), &SurfaceTool::add_index); + ClassDB::bind_method(D_METHOD("index"), &SurfaceTool::index); ClassDB::bind_method(D_METHOD("deindex"), &SurfaceTool::deindex); - ///ClassDB::bind_method(D_METHOD("generate_flat_normals"),&SurfaceTool::generate_flat_normals); ClassDB::bind_method(D_METHOD("generate_normals"), &SurfaceTool::generate_normals); - ClassDB::bind_method(D_METHOD("add_index", "index"), &SurfaceTool::add_index); - ClassDB::bind_method(D_METHOD("commit:Mesh", "existing:Mesh"), &SurfaceTool::commit, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("generate_tangents"), &SurfaceTool::generate_tangents); + + ClassDB::bind_method(D_METHOD("add_to_format", "flags"), &SurfaceTool::add_to_format); + + ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &SurfaceTool::set_material); + ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); + + ClassDB::bind_method(D_METHOD("create_from", "existing:Mesh", "surface"), &SurfaceTool::create_from); + ClassDB::bind_method(D_METHOD("append_from", "existing:Mesh", "surface", "transform"), &SurfaceTool::append_from); + ClassDB::bind_method(D_METHOD("commit:Mesh", "existing:Mesh"), &SurfaceTool::commit, DEFVAL(Variant())); } SurfaceTool::SurfaceTool() { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 9bbbd1d091..6c20c71af0 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -414,7 +414,7 @@ public: void set_width(int p_width); int get_width() const; - void ensure_default_setup(float p_min=0, float p_max=1); + void ensure_default_setup(float p_min = 0, float p_max = 1); void set_curve(Ref<Curve> p_curve); Ref<Curve> get_curve() const; diff --git a/servers/SCsub b/servers/SCsub index eefa6278c4..df55010a36 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -7,12 +7,11 @@ env.add_source_files(env.servers_sources, "*.cpp") Export('env') +SConscript('arvr/SCsub') SConscript('physics/SCsub') SConscript('physics_2d/SCsub') SConscript('visual/SCsub') SConscript('audio/SCsub') -SConscript('spatial_sound/SCsub') -SConscript('spatial_sound_2d/SCsub') lib = env.Library("servers", env.servers_sources) diff --git a/servers/arvr/SCsub b/servers/arvr/SCsub new file mode 100644 index 0000000000..ccc76e823f --- /dev/null +++ b/servers/arvr/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import('env') + +env.add_source_files(env.servers_sources, "*.cpp") + +Export('env') diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp new file mode 100644 index 0000000000..81eb011932 --- /dev/null +++ b/servers/arvr/arvr_interface.cpp @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* arvr_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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. */ +/*************************************************************************/ +#include "arvr_interface.h" + +void ARVRInterface::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_name"), &ARVRInterface::get_name); + + ClassDB::bind_method(D_METHOD("is_primary"), &ARVRInterface::is_primary); + ClassDB::bind_method(D_METHOD("set_is_primary", "enable"), &ARVRInterface::set_is_primary); + + ClassDB::bind_method(D_METHOD("is_installed"), &ARVRInterface::is_installed); + ClassDB::bind_method(D_METHOD("hmd_is_present"), &ARVRInterface::hmd_is_present); + ClassDB::bind_method(D_METHOD("supports_hmd"), &ARVRInterface::supports_hmd); + ClassDB::bind_method(D_METHOD("is_initialized"), &ARVRInterface::is_initialized); + ClassDB::bind_method(D_METHOD("initialize"), &ARVRInterface::initialize); + ClassDB::bind_method(D_METHOD("uninitialize"), &ARVRInterface::uninitialize); + + ClassDB::bind_method(D_METHOD("get_recommended_render_targetsize"), &ARVRInterface::get_recommended_render_targetsize); + + // These are now purely used internally, we may expose them again if we expose CameraMatrix through Variant but reduz is not a fan for good reasons :) + // ClassDB::bind_method(D_METHOD("get_transform_for_eye", "eye", "cam_transform"), &ARVRInterface::get_transform_for_eye); + // ClassDB::bind_method(D_METHOD("get_projection_for_eye", "eye"), &ARVRInterface::get_projection_for_eye); + // ClassDB::bind_method(D_METHOD("commit_for_eye", "node:viewport"), &ARVRInterface::commit_for_eye); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "primary"), "set_is_primary", "is_primary"); + + BIND_CONSTANT(EYE_MONO); + BIND_CONSTANT(EYE_LEFT); + BIND_CONSTANT(EYE_RIGHT); +}; + +StringName ARVRInterface::get_name() const { + return "Unknown"; +}; + +bool ARVRInterface::is_primary() { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, false); + + return arvr_server->get_primary_interface() == this; +}; + +void ARVRInterface::set_is_primary(bool p_is_primary) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + if (p_is_primary) { + ERR_FAIL_COND(!is_initialized()); + ERR_FAIL_COND(!supports_hmd()); + + arvr_server->set_primary_interface(this); + } else { + arvr_server->clear_primary_interface_if(this); + }; +}; diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h new file mode 100644 index 0000000000..e405499fbb --- /dev/null +++ b/servers/arvr/arvr_interface.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* arvr_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 ARVR_INTERFACE_H +#define ARVR_INTERFACE_H + +#include "core/math/camera_matrix.h" +#include "os/thread_safe.h" +#include "scene/main/viewport.h" +#include "servers/arvr_server.h" + +/** + @author Bastiaan Olij <mux213@gmail.com> + + The ARVR interface is a template class ontop of which we build interface to differt AR, VR and tracking SDKs. + The idea is that we subclass this class, implement the logic, and then instantiate a singleton of each interface + when Godot starts. These instances do not initialize themselves but register themselves with the AR/VR server. + + If the user wants to enable AR/VR the choose the interface they want to use and initialize it. + + Note that we may make this into a fully instantiable class for GDNative support. +*/ + +class ARVRInterface : public Reference { + GDCLASS(ARVRInterface, Reference); + +protected: + _THREAD_SAFE_CLASS_ + + static void _bind_methods(); + +public: + enum Eyes { + EYE_MONO, /* my son says we should call this EYE_CYCLOPS */ + EYE_LEFT, + EYE_RIGHT + }; + + virtual StringName get_name() const; + + bool is_primary(); + void set_is_primary(bool p_is_primary); + + virtual bool is_installed() = 0; /* returns true if the middle ware related to this interface has been installed */ + virtual bool hmd_is_present() = 0; /* returns true if our HMD is connected */ + virtual bool supports_hmd() = 0; /* returns true is this interface handles output to an HMD or only handles positioning */ + + virtual bool is_initialized() = 0; /* returns true if we've initialized this interface */ + virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */ + virtual void uninitialize() = 0; /* deinitialize this interface */ + + virtual Size2 get_recommended_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */ + virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */ + virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */ + virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */ + virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */ + + virtual void process() = 0; +}; + +VARIANT_ENUM_CAST(ARVRInterface::Eyes); + +#endif diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp new file mode 100644 index 0000000000..4215363d16 --- /dev/null +++ b/servers/arvr/arvr_positional_tracker.cpp @@ -0,0 +1,142 @@ +/*************************************************************************/ +/* arvr_postional_tracker.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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. */ +/*************************************************************************/ +#include "arvr_positional_tracker.h" +#include "core/os/input.h" + +void ARVRPositionalTracker::_bind_methods() { + // this class is read only from GDScript, so we only have access to getters.. + ClassDB::bind_method(D_METHOD("get_type"), &ARVRPositionalTracker::get_type); + ClassDB::bind_method(D_METHOD("get_name"), &ARVRPositionalTracker::get_name); + ClassDB::bind_method(D_METHOD("get_joy_id"), &ARVRPositionalTracker::get_joy_id); + ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &ARVRPositionalTracker::get_tracks_orientation); + ClassDB::bind_method(D_METHOD("get_orientation"), &ARVRPositionalTracker::get_orientation); + ClassDB::bind_method(D_METHOD("get_tracks_position"), &ARVRPositionalTracker::get_tracks_position); + ClassDB::bind_method(D_METHOD("get_position"), &ARVRPositionalTracker::get_position); + ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &ARVRPositionalTracker::get_transform); +}; + +void ARVRPositionalTracker::set_type(ARVRServer::TrackerType p_type) { + if (type != p_type) { + type = p_type; + + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL(arvr_server); + + // get a tracker id for our type + tracker_id = arvr_server->get_free_tracker_id_for_type(p_type); + } +}; + +ARVRServer::TrackerType ARVRPositionalTracker::get_type() const { + return type; +}; + +void ARVRPositionalTracker::set_name(const String p_name) { + name = p_name; +}; + +StringName ARVRPositionalTracker::get_name() const { + return name; +}; + +int ARVRPositionalTracker::get_tracker_id() const { + return tracker_id; +}; + +void ARVRPositionalTracker::set_joy_id(int p_joy_id) { + joy_id = p_joy_id; +}; + +int ARVRPositionalTracker::get_joy_id() const { + return joy_id; +}; + +bool ARVRPositionalTracker::get_tracks_orientation() const { + return tracks_orientation; +}; + +void ARVRPositionalTracker::set_orientation(const Basis &p_orientation) { + _THREAD_SAFE_METHOD_ + + tracks_orientation = true; // obviously we have this + orientation = p_orientation; +}; + +Basis ARVRPositionalTracker::get_orientation() const { + _THREAD_SAFE_METHOD_ + + return orientation; +}; + +bool ARVRPositionalTracker::get_tracks_position() const { + return tracks_position; +}; + +void ARVRPositionalTracker::set_position(const Vector3 &p_position) { + _THREAD_SAFE_METHOD_ + + tracks_position = true; // obviously we have this + position = p_position; +}; + +Vector3 ARVRPositionalTracker::get_position() const { + _THREAD_SAFE_METHOD_ + + return position; +}; + +Transform ARVRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const { + Transform new_transform; + + new_transform.basis = get_orientation(); + new_transform.origin = get_position(); + + if (p_adjust_by_reference_frame) { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + ERR_FAIL_NULL_V(arvr_server, new_transform); + + new_transform = arvr_server->get_reference_frame() * new_transform; + }; + + return new_transform; +}; + +ARVRPositionalTracker::ARVRPositionalTracker() { + type = ARVRServer::TRACKER_UNKNOWN; + name = "Unknown"; + joy_id = -1; + tracker_id = 0; + tracks_orientation = false; + tracks_position = false; +}; + +ARVRPositionalTracker::~ARVRPositionalTracker(){ + +}; diff --git a/servers/arvr/arvr_positional_tracker.h b/servers/arvr/arvr_positional_tracker.h new file mode 100644 index 0000000000..e8c613b29d --- /dev/null +++ b/servers/arvr/arvr_positional_tracker.h @@ -0,0 +1,85 @@ +/*************************************************************************/ +/* arvr_positional_tracker.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 ARVR_POSITIONAL_TRACKER_H +#define ARVR_POSITIONAL_TRACKER_H + +#include "os/thread_safe.h" +#include "servers/arvr_server.h" + +/** + @author Bastiaan Olij <mux213@gmail.com> + + The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset. + An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation. + This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking. + + @TODO: + - create subclass of spatial node that uses one of our positional trackers to automatically determine its position +*/ + +class ARVRPositionalTracker : public Object { + GDCLASS(ARVRPositionalTracker, Object); + _THREAD_SAFE_CLASS_ + +private: + ARVRServer::TrackerType type; // type of tracker + StringName name; // (unique) name of the tracker + int tracker_id; // tracker index id that is unique per type + int joy_id; // if we also have a related joystick entity, the id of the joystick + bool tracks_orientation; // do we track orientation? + Basis orientation; // our orientation + bool tracks_position; // do we track position? + Vector3 position; // our position + +protected: + static void _bind_methods(); + +public: + void set_type(ARVRServer::TrackerType p_type); + ARVRServer::TrackerType get_type() const; + void set_name(const String p_name); + StringName get_name() const; + int get_tracker_id() const; + void set_joy_id(int p_joy_id); + int get_joy_id() const; + bool get_tracks_orientation() const; + void set_orientation(const Basis &p_orientation); + Basis get_orientation() const; + bool get_tracks_position() const; + void set_position(const Vector3 &p_position); + Vector3 get_position() const; + + Transform get_transform(bool p_adjust_by_reference_frame) const; + + ARVRPositionalTracker(); + ~ARVRPositionalTracker(); +}; + +#endif diff --git a/servers/arvr/arvr_script_interface.cpp b/servers/arvr/arvr_script_interface.cpp new file mode 100644 index 0000000000..16e607920e --- /dev/null +++ b/servers/arvr/arvr_script_interface.cpp @@ -0,0 +1,127 @@ +#include "arvr_script_interface.h" + +ARVRScriptInterface::ARVRScriptInterface() { + // testing + printf("Construct script interface"); +} + +ARVRScriptInterface::~ARVRScriptInterface() { + if (is_initialized()) { + uninitialize(); + }; + + // testing + printf("Destruct script interface"); +} + +StringName ARVRScriptInterface::get_name() const { + if (get_script_instance() && get_script_instance()->has_method("get_name")) { + return get_script_instance()->call("get_name"); + } else { + // just return something for now + return "ARVR Script interface"; + } +} + +bool ARVRScriptInterface::is_installed() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("is_installed")), false); + return get_script_instance()->call("is_installed"); +} + +bool ARVRScriptInterface::hmd_is_present() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("hmd_is_present")), false); + return get_script_instance()->call("hmd_is_present"); +} + +bool ARVRScriptInterface::supports_hmd() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("supports_hmd")), false); + return get_script_instance()->call("supports_hmd"); +} + +bool ARVRScriptInterface::is_stereo() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("is_stereo")), false); + return get_script_instance()->call("is_stereo"); +} + +bool ARVRScriptInterface::is_initialized() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("is_initialized")), false); + return get_script_instance()->call("is_initialized"); +} + +bool ARVRScriptInterface::initialize() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("initialize")), false); + return get_script_instance()->call("initialize"); +} + +void ARVRScriptInterface::uninitialize() { + ARVRServer *arvr_server = ARVRServer::get_singleton(); + if (arvr_server != NULL) { + // Whatever happens, make sure this is no longer our primary interface + arvr_server->clear_primary_interface_if(this); + } + + ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("uninitialize"))); + get_script_instance()->call("uninitialize"); +} + +Size2 ARVRScriptInterface::get_recommended_render_targetsize() { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_recommended_render_targetsize")), Size2()); + return get_script_instance()->call("get_recommended_render_targetsize"); +} + +Transform ARVRScriptInterface::get_transform_for_eye(Eyes p_eye, const Transform &p_cam_transform) { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_transform_for_eye")), Transform()); + return get_script_instance()->call("get_transform_for_eye", p_eye, p_cam_transform); +} + +// Suggestion from Reduz, as we can't return a CameraMatrix, return a PoolVector with our 16 floats +PoolVector<float> ARVRScriptInterface::_get_projection_for_eye(Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_projection_for_eye")), PoolVector<float>()); + return get_script_instance()->call("_get_projection_for_eye", p_eye, p_aspect, p_z_near, p_z_far); +} + +CameraMatrix ARVRScriptInterface::get_projection_for_eye(Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { + CameraMatrix cm; + int i = 0; + int j = 0; + + PoolVector<float> cm_as_floats = _get_projection_for_eye(p_eye, p_aspect, p_z_near, p_z_far); + + for (int k = 0; k < cm_as_floats.size() && i < 4; k++) { + cm.matrix[i][j] = cm_as_floats[k]; + j++; + if (j == 4) { + j = 0; + i++; + }; + }; + + return cm; +} + +void ARVRScriptInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) { + ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("commit_for_eye"))); + get_script_instance()->call("commit_for_eye"); +} + +void ARVRScriptInterface::process() { + ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("process"))); + get_script_instance()->call("process"); +} + +void ARVRScriptInterface::_bind_methods() { + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "is_installed")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "hmd_is_present")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "supports_hmd")); + + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "is_initialized")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "initialize")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("uninitialize")); + + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "is_stereo")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::VECTOR2, "get_recommended_render_targetsize")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::TRANSFORM, "get_transform_for_eye", PropertyInfo(Variant::INT, "eye"), PropertyInfo(Variant::TRANSFORM, "cam_transform"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("_get_projection_for_eye")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("commit_for_eye", PropertyInfo(Variant::INT, "eye"), PropertyInfo(Variant::_RID, "render_target"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("process")); +} diff --git a/servers/arvr/arvr_script_interface.h b/servers/arvr/arvr_script_interface.h new file mode 100644 index 0000000000..04ca33901a --- /dev/null +++ b/servers/arvr/arvr_script_interface.h @@ -0,0 +1,47 @@ +#ifndef SCRIPT_INTERFACE_H +#define SCRIPT_INTERFACE_H + +#include "arvr_interface.h" + +/** + @authors Hinsbart & Karroffel + + This subclass of our AR/VR interface forms a bridge to GDNative. +*/ + +class ARVRScriptInterface : public ARVRInterface { + GDCLASS(ARVRScriptInterface, ARVRInterface); + +protected: + static void _bind_methods(); + +public: + ARVRScriptInterface(); + ~ARVRScriptInterface(); + + virtual StringName get_name() const; + + virtual bool is_installed(); + virtual bool hmd_is_present(); + virtual bool supports_hmd(); + + virtual bool is_initialized(); + virtual bool initialize(); + virtual void uninitialize(); + + virtual Size2 get_recommended_render_targetsize(); + virtual bool is_stereo(); + virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform); + + // we expose a PoolVector<float> version of this function to GDNative + PoolVector<float> _get_projection_for_eye(Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); + + // and a CameraMatrix version to ARVRServer + virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); + + virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect); + + virtual void process(); +}; + +#endif // SCRIPT_INTERFACE_H diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp new file mode 100644 index 0000000000..78b3e514e6 --- /dev/null +++ b/servers/arvr_server.cpp @@ -0,0 +1,313 @@ +/*************************************************************************/ +/* arvr_server.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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. */ +/*************************************************************************/ + +#include "arvr_server.h" +#include "arvr/arvr_interface.h" +#include "arvr/arvr_positional_tracker.h" +#include "project_settings.h" + +ARVRServer *ARVRServer::singleton = NULL; + +ARVRServer *ARVRServer::get_singleton() { + return singleton; +}; + +void ARVRServer::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVRServer::get_world_scale); + ClassDB::bind_method(D_METHOD("set_world_scale"), &ARVRServer::set_world_scale); + ClassDB::bind_method(D_METHOD("get_reference_frame"), &ARVRServer::get_reference_frame); + ClassDB::bind_method(D_METHOD("request_reference_frame", "ignore_tilt", "keep_height"), &ARVRServer::request_reference_frame); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "world_scale"), "set_world_scale", "get_world_scale"); + + ClassDB::bind_method(D_METHOD("get_interface_count"), &ARVRServer::get_interface_count); + ClassDB::bind_method(D_METHOD("get_interface:ARVRInterface", "idx"), &ARVRServer::get_interface); + ClassDB::bind_method(D_METHOD("find_interface:ARVRInterface", "name"), &ARVRServer::find_interface); + ClassDB::bind_method(D_METHOD("get_tracker_count"), &ARVRServer::get_tracker_count); + ClassDB::bind_method(D_METHOD("get_tracker:ARVRPositionalTracker", "idx"), &ARVRServer::get_tracker); + + ClassDB::bind_method(D_METHOD("set_primary_interface"), &ARVRServer::set_primary_interface); + + ClassDB::bind_method(D_METHOD("add_interface"), &ARVRServer::add_interface); + ClassDB::bind_method(D_METHOD("remove_interface"), &ARVRServer::remove_interface); + + BIND_CONSTANT(TRACKER_CONTROLLER); + BIND_CONSTANT(TRACKER_BASESTATION); + BIND_CONSTANT(TRACKER_ANCHOR); + BIND_CONSTANT(TRACKER_UNKNOWN); + BIND_CONSTANT(TRACKER_ANY_KNOWN); + BIND_CONSTANT(TRACKER_ANY); + + ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING, "name"))); + ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING, "name"))); + + ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::INT, "type"))); + ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING, "name"))); +}; + +real_t ARVRServer::get_world_scale() const { + return world_scale; +}; + +void ARVRServer::set_world_scale(real_t p_world_scale) { + if (world_scale < 0.01) { + world_scale = 0.01; + } else if (world_scale > 1000.0) { + world_scale = 1000.0; + }; + + world_scale = p_world_scale; +}; + +Transform ARVRServer::get_world_origin() const { + return world_origin; +}; + +void ARVRServer::set_world_origin(const Transform p_world_origin) { + world_origin = p_world_origin; +}; + +Transform ARVRServer::get_reference_frame() const { + return reference_frame; +}; + +void ARVRServer::request_reference_frame(bool p_ignore_tilt, bool p_keep_height) { + if (primary_interface != NULL) { + // clear our current reference frame or we'll end up double adjusting it + reference_frame = Transform(); + + // requesting our EYE_MONO transform should return our current HMD position + Transform new_reference_frame = primary_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, Transform()); + + // remove our tilt + if (p_ignore_tilt) { + // take the Y out of our Z + new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized()); + + // Y is straight up + new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0)); + + // and X is our cross reference + new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized()); + }; + + // don't negate our height + if (p_keep_height) { + new_reference_frame.origin.y = 0.0; + }; + + reference_frame = new_reference_frame.inverse(); + }; +}; + +void ARVRServer::add_interface(const Ref<ARVRInterface> &p_interface) { + ERR_FAIL_COND(p_interface.is_null()); + + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + + if (interfaces[i] == p_interface) { + ERR_PRINT("Interface was already added"); + return; + }; + }; + + print_line("Registered interface " + p_interface->get_name()); + + interfaces.push_back(p_interface); + emit_signal("interface_added", p_interface->get_name()); +}; + +void ARVRServer::remove_interface(const Ref<ARVRInterface> &p_interface) { + ERR_FAIL_COND(p_interface.is_null()); + + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + + if (interfaces[i] == p_interface) { + + idx = i; + break; + }; + }; + + ERR_FAIL_COND(idx == -1); + + print_line("Removed interface" + p_interface->get_name()); + + emit_signal("interface_removed", p_interface->get_name()); + interfaces.remove(idx); +}; + +int ARVRServer::get_interface_count() const { + return interfaces.size(); +}; + +Ref<ARVRInterface> ARVRServer::get_interface(int p_index) const { + ERR_FAIL_INDEX_V(p_index, interfaces.size(), NULL); + + return interfaces[p_index]; +}; + +Ref<ARVRInterface> ARVRServer::find_interface(const String &p_name) const { + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + + if (interfaces[i]->get_name() == p_name) { + + idx = i; + break; + }; + }; + + ERR_FAIL_COND_V(idx == -1, NULL); + + return interfaces[idx]; +}; + +/* + A little extra info on the tracker ids, these are unique per tracker type so we get soem consistency in recognising our trackers, specifically controllers. + + The first controller that is turned of will get ID 1, the second will get ID 2, etc. + The magic happens when one of the controllers is turned off, say controller 1 turns off, controller 2 will remain controller 2, controller 3 will remain controller 3. + If controller number 1 is turned on again it again gets ID 1 unless another new controller was turned on since. + + The most likely scenario however is a controller that runs out of battery and another controller being used to replace it. + Because the controllers are often linked to physical objects, say you're holding a shield in controller 1, your left hand, and a gun in controller 2, your right hand, and controller 1 dies: + - using our tracker index would suddenly make the gun disappear and the shield jump into your right hand because controller 2 becomes controller 1. + - using this approach the shield disappears or is no longer tracked, but the gun stays firmly in your right hand because that is still controller 2, further more, if controller 1 is replaced the shield will return. +*/ + +bool ARVRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { + for (int i = 0; i < trackers.size(); i++) { + if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + return true; + }; + }; + + // all good + return false; +}; + +int ARVRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) { + // we start checking at 1, 0 means that it's not a controller.. + int tracker_id = 1; + + while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) { + // try the next one + tracker_id++; + }; + + return tracker_id; +}; + +void ARVRServer::add_tracker(ARVRPositionalTracker *p_tracker) { + ERR_FAIL_NULL(p_tracker); + + trackers.push_back(p_tracker); + emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type()); +}; + +void ARVRServer::remove_tracker(ARVRPositionalTracker *p_tracker) { + ERR_FAIL_NULL(p_tracker); + + int idx = -1; + for (int i = 0; i < trackers.size(); i++) { + + if (trackers[i] == p_tracker) { + + idx = i; + break; + }; + }; + + ERR_FAIL_COND(idx == -1); + + emit_signal("tracker_removed", p_tracker->get_name()); + trackers.remove(idx); +}; + +int ARVRServer::get_tracker_count() const { + return trackers.size(); +}; + +ARVRPositionalTracker *ARVRServer::get_tracker(int p_index) const { + ERR_FAIL_INDEX_V(p_index, trackers.size(), NULL); + + return trackers[p_index]; +}; + +ARVRPositionalTracker *ARVRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const { + ERR_FAIL_COND_V(p_tracker_id == 0, NULL); + + for (int i = 0; i < trackers.size(); i++) { + if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + return trackers[i]; + }; + }; + + return NULL; +}; + +Ref<ARVRInterface> ARVRServer::get_primary_interface() const { + return primary_interface; +}; + +void ARVRServer::set_primary_interface(const Ref<ARVRInterface> &p_primary_interface) { + primary_interface = p_primary_interface; + + print_line("Primary interface set to: " + primary_interface->get_name()); +}; + +void ARVRServer::clear_primary_interface_if(const Ref<ARVRInterface> &p_primary_interface) { + if (primary_interface == p_primary_interface) { + print_line("Clearing primary interface"); + primary_interface.unref(); + }; +}; + +ARVRServer::ARVRServer() { + singleton = this; + world_scale = 1.0; +}; + +ARVRServer::~ARVRServer() { + primary_interface.unref(); + + while (interfaces.size() > 0) { + interfaces.remove(0); + } + + while (trackers.size() > 0) { + trackers.remove(0); + } + + singleton = NULL; +}; diff --git a/servers/arvr_server.h b/servers/arvr_server.h new file mode 100644 index 0000000000..fd7c5470c3 --- /dev/null +++ b/servers/arvr_server.h @@ -0,0 +1,167 @@ +/*************************************************************************/ +/* arvr_server.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 ARVR_SERVER_H +#define ARVR_SERVER_H + +#include "os/thread_safe.h" +#include "reference.h" +#include "rid.h" +#include "variant.h" + +class ARVRInterface; +class ARVRPositionalTracker; + +/** + @author Bastiaan Olij <mux213@gmail.com> + + The ARVR server is a singleton object that gives access to the various + objects and SDKs that are available on the system. + Because there can be multiple SDKs active this is exposed as an array + and our ARVR server object acts as a pass through + Also each positioning tracker is accessible from here. + + I've added some additional info into this header file that should move + into the documention, I will do so when we're close to accepting this PR + or as a separate PR once this has been merged into the master branch. +**/ + +class ARVRServer : public Object { + GDCLASS(ARVRServer, Object); + _THREAD_SAFE_CLASS_ + +public: + enum TrackerType { + TRACKER_CONTROLLER = 0x01, /* tracks a controller */ + TRACKER_BASESTATION = 0x02, /* tracks location of a base station */ + TRACKER_ANCHOR = 0x04, /* tracks an anchor point, used in AR to track a real live location */ + TRACKER_UNKNOWN = 0x80, /* unknown tracker */ + + TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ + TRACKER_ANY = 0xff /* used by get_connected_trackers to return all types */ + }; + +private: + Vector<Ref<ARVRInterface> > interfaces; + Vector<ARVRPositionalTracker *> trackers; + + Ref<ARVRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ + + real_t world_scale; /* scale by which we multiply our tracker positions */ + Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ + Transform reference_frame; /* our reference frame */ + + bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const; + +protected: + static ARVRServer *singleton; + + static void _bind_methods(); + +public: + static ARVRServer *get_singleton(); + + /* + World scale allows you to specify a scale factor that is applied to all positioning vectors in our VR world in essence scaling up, or scaling down the world. + For stereoscopic rendering specifically this is very important to give an accurate sense of scale. + Add controllers into the mix and an accurate mapping of real world movement to percieved virtual movement becomes very important. + + Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode. + This scale basically effects the unit size relationship to real world size. + + I may remove access to this property in GDScript in favour of exposing it on the ARVROrigin node + */ + real_t get_world_scale() const; + void set_world_scale(real_t p_world_scale); + + /* + The world maps the 0,0,0 coordinate of our real world coordinate system for our tracking volume to a location in our + virtual world. It is this origin point that should be moved when the player is moved through the world by controller + actions be it straffing, teleporting, etc. Movement of the player by moving through the physical space is always tracked + in relation to this point. + + Note that the ARVROrigin spatial node in your scene automatically updates this property and it should be used instead of + direct access to this property and it therefor is not available in GDScript + + Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world + and in the virtual world out of sync + */ + Transform get_world_origin() const; + void set_world_origin(const Transform p_origin); + + /* + Requesting a reference frame results in a matrix being calculated that ensures the HMD is positioned to 0,0,0 facing 0,0,-1 (need to verify this direction) + in the virtual world. + + Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world + and in the virtual world out of sync + */ + Transform get_reference_frame() const; + void request_reference_frame(bool p_ignore_tilt, bool p_keep_height); + + /* + Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc. + */ + void add_interface(const Ref<ARVRInterface> &p_interface); + void remove_interface(const Ref<ARVRInterface> &p_interface); + int get_interface_count() const; + Ref<ARVRInterface> get_interface(int p_index) const; + Ref<ARVRInterface> find_interface(const String &p_name) const; + + /* + note, more then one interface can technically be active, especially on mobile, but only one interface is used for + rendering. This interface identifies itself by calling set_primary_interface when it is initialized + */ + Ref<ARVRInterface> get_primary_interface() const; + void set_primary_interface(const Ref<ARVRInterface> &p_primary_interface); + void clear_primary_interface_if(const Ref<ARVRInterface> &p_primary_interface); /* this is automatically called if an interface destructs */ + + /* + Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc. + They are created and managed by our active AR/VR interfaces. + + Note that for trackers that + */ + int get_free_tracker_id_for_type(TrackerType p_tracker_type); + void add_tracker(ARVRPositionalTracker *p_tracker); + void remove_tracker(ARVRPositionalTracker *p_tracker); + int get_tracker_count() const; + ARVRPositionalTracker *get_tracker(int p_index) const; + ARVRPositionalTracker *find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const; + + ARVRServer(); + ~ARVRServer(); +}; + +#define ARVR ARVRServer + +VARIANT_ENUM_CAST(ARVRServer::TrackerType); + +#endif diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index c407a17bc6..a17d1f6a12 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -553,7 +553,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co const CollisionObject2DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_one_way_collision(j)) { + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); cbk.valid_depth = p_margin; //only valid depth is the collision margin diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index c5029d1e13..092f445c13 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -30,6 +30,10 @@ #include "register_server_types.h" #include "project_settings.h" +#include "arvr/arvr_interface.h" +#include "arvr/arvr_positional_tracker.h" +#include "arvr/arvr_script_interface.h" +#include "arvr_server.h" #include "audio/audio_effect.h" #include "audio/audio_stream.h" #include "audio/effects/audio_effect_amplify.h" @@ -70,16 +74,23 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag } ShaderTypes *shader_types = NULL; +ARVRServer *arvr_server = NULL; void register_server_types() { + arvr_server = memnew(ARVRServer); ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("VisualServer", VisualServer::get_singleton())); ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("AudioServer", AudioServer::get_singleton())); ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("PhysicsServer", PhysicsServer::get_singleton())); ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Physics2DServer", Physics2DServer::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("ARVRServer", ARVRServer::get_singleton())); shader_types = memnew(ShaderTypes); + ClassDB::register_virtual_class<ARVRInterface>(); + ClassDB::register_class<ARVRPositionalTracker>(); + ClassDB::register_class<ARVRScriptInterface>(); + ClassDB::register_virtual_class<AudioStream>(); ClassDB::register_virtual_class<AudioStreamPlayback>(); ClassDB::register_class<AudioStreamRandomPitch>(); @@ -133,5 +144,9 @@ void register_server_types() { void unregister_server_types() { + //@TODO move this into iPhone/Android implementation? just have this here for testing... + // mobile_interface = NULL; + memdelete(shader_types); + memdelete(arvr_server); } diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 58481fc3f6..b13bb904ab 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -908,6 +908,7 @@ public: BIND0R(RID, viewport_create) + BIND2(viewport_set_use_arvr, RID, bool) BIND3(viewport_set_size, RID, int, int) BIND2(viewport_set_active, RID, bool) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 97583dc849..87431a2ce4 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -1658,6 +1658,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons } void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { + // render to mono camera Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); @@ -1697,6 +1698,25 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view _render_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), -1); } +void VisualServerScene::render_camera(Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { + // render for AR/VR interface + + Camera *camera = camera_owner.getornull(p_camera); + ERR_FAIL_COND(!camera); + + /* SETUP CAMERA, we are ignoring type and FOV here */ + bool ortho = false; + float aspect = p_viewport_size.width / (float)p_viewport_size.height; + CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); + + // We also ignore our camera position, it will have been positioned with a slightly old tracking position. + // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! + Transform world_origin = ARVRServer::get_singleton()->get_world_origin(); + Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); + + _render_scene(cam_transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), -1); +}; + void VisualServerScene::_render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { Scenario *scenario = scenario_owner.getornull(p_scenario); @@ -2716,8 +2736,8 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co success_count++; } } - print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0)); - print_line("valid cells: " + itos(success_count)); + //print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0)); + //print_line("valid cells: " + itos(success_count)); } break; case VS::LIGHT_OMNI: @@ -2822,7 +2842,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co light->energy[2] += int32_t(light_b * att * ((cell->albedo) & 0xFF) / 255.0); } } - print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0)); + //print_line("BAKE TIME: " + rtos((OS::get_singleton()->get_ticks_usec() - us) / 1000000.0)); } break; } @@ -2921,7 +2941,7 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { if (stage >= probe_data->dynamic.mipmaps_3d.size()) continue; //no mipmap for this one - print_line("generating mipmap stage: " + itos(stage)); + //print_line("generating mipmap stage: " + itos(stage)); int level_cell_count = probe_data->dynamic.level_cell_lists[i].size(); const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[i].ptr(); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 168dfddfd4..17b95946b3 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -38,6 +38,7 @@ #include "os/semaphore.h" #include "os/thread.h" #include "self_list.h" +#include "servers/arvr/arvr_interface.h" class VisualServerScene { public: @@ -521,6 +522,7 @@ public: void render_empty_scene(RID p_scenario, RID p_shadow_atlas); void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void render_camera(Ref<ARVRInterface> &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); //probes diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 2a37b64759..ad9dec090a 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -33,7 +33,7 @@ #include "visual_server_global.h" #include "visual_server_scene.h" -void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { +void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { /* Camera should always be BEFORE any other 3D */ @@ -90,8 +90,13 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { } if (!scenario_draw_canvas_bg && can_draw_3d) { + Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); - VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + if (p_viewport->use_arvr && arvr_interface.is_valid()) { + VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + } else { + VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + } } if (!p_viewport->hide_canvas) { @@ -260,15 +265,19 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { } void VisualServerViewport::draw_viewports() { - - //sort viewports - - //draw viewports + // get our arvr interface in case we need it + Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + if (arvr_interface.is_valid()) { + // update our positioning information as late as possible... + arvr_interface->process(); + } clear_color = GLOBAL_GET("rendering/environment/default_clear_color"); + //sort viewports active_viewports.sort_custom<ViewportSort>(); + //draw viewports for (int i = 0; i < active_viewports.size(); i++) { Viewport *vp = active_viewports[i]; @@ -286,25 +295,47 @@ void VisualServerViewport::draw_viewports() { VSG::storage->render_target_clear_used(vp->render_target); - VSG::rasterizer->set_current_render_target(vp->render_target); + if (vp->use_arvr && arvr_interface.is_valid()) { + // override our size, make sure it matches our required size + Size2 size = arvr_interface->get_recommended_render_targetsize(); + VSG::storage->render_target_set_size(vp->render_target, size.x, size.y); - VSG::scene_render->set_debug_draw_mode(vp->debug_draw); - VSG::storage->render_info_begin_capture(); + // render mono or left eye first + ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO; + VSG::rasterizer->set_current_render_target(vp->render_target); + _draw_viewport(vp, leftOrMono); + arvr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect); - _draw_viewport(vp); + // render right eye + if (leftOrMono == ARVRInterface::EYE_LEFT) { + // commit for eye may have changed the render target + VSG::rasterizer->set_current_render_target(vp->render_target); - VSG::storage->render_info_end_capture(); - vp->render_info[VS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_OBJECTS_IN_FRAME); - vp->render_info[VS::VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_VERTICES_IN_FRAME); - vp->render_info[VS::VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_MATERIAL_CHANGES_IN_FRAME); - vp->render_info[VS::VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SHADER_CHANGES_IN_FRAME); - vp->render_info[VS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SURFACE_CHANGES_IN_FRAME); - vp->render_info[VS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_DRAW_CALLS_IN_FRAME); - - if (vp->viewport_to_screen_rect != Rect2()) { - //copy to screen if set as such - VSG::rasterizer->set_current_render_target(RID()); - VSG::rasterizer->blit_render_target_to_screen(vp->render_target, vp->viewport_to_screen_rect, vp->viewport_to_screen); + _draw_viewport(vp, ARVRInterface::EYE_RIGHT); + arvr_interface->commit_for_eye(ARVRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect); + } + } else { + VSG::rasterizer->set_current_render_target(vp->render_target); + + VSG::scene_render->set_debug_draw_mode(vp->debug_draw); + VSG::storage->render_info_begin_capture(); + + // render standard mono camera + _draw_viewport(vp); + + VSG::storage->render_info_end_capture(); + vp->render_info[VS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_OBJECTS_IN_FRAME); + vp->render_info[VS::VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_VERTICES_IN_FRAME); + vp->render_info[VS::VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_MATERIAL_CHANGES_IN_FRAME); + vp->render_info[VS::VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SHADER_CHANGES_IN_FRAME); + vp->render_info[VS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_SURFACE_CHANGES_IN_FRAME); + vp->render_info[VS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = VSG::storage->get_captured_render_info(VS::INFO_DRAW_CALLS_IN_FRAME); + + if (vp->viewport_to_screen_rect != Rect2()) { + //copy to screen if set as such + VSG::rasterizer->set_current_render_target(RID()); + VSG::rasterizer->blit_render_target_to_screen(vp->render_target, vp->viewport_to_screen_rect, vp->viewport_to_screen); + } } if (vp->update_mode == VS::VIEWPORT_UPDATE_ONCE) { @@ -329,6 +360,13 @@ RID VisualServerViewport::viewport_create() { return rid; } +void VisualServerViewport::viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) { + Viewport *viewport = viewport_owner.getornull(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->use_arvr = p_use_arvr; +} + void VisualServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { ERR_FAIL_COND(p_width < 0 && p_height < 0); diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index f963ce4aa3..93227d1c31 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -32,6 +32,7 @@ #include "rasterizer.h" #include "self_list.h" +#include "servers/arvr/arvr_interface.h" #include "servers/visual_server.h" class VisualServerViewport { @@ -44,6 +45,8 @@ public: RID self; RID parent; + bool use_arvr; /* use arvr interface to override camera positioning and projection matrices and control output */ + Size2i size; RID camera; RID scenario; @@ -107,6 +110,7 @@ public: for (int i = 0; i < VS::VIEWPORT_RENDER_INFO_MAX; i++) { render_info[i] = 0; } + use_arvr = false; } }; @@ -131,11 +135,13 @@ public: private: Color clear_color; - void _draw_viewport(Viewport *p_viewport); + void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO); public: RID viewport_create(); + void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr); + void viewport_set_size(RID p_viewport, int p_width, int p_height); void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), int p_screen = 0); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 4567d87706..e6ce3f6a54 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -344,6 +344,8 @@ public: FUNC0R(RID, viewport_create) + FUNC2(viewport_set_use_arvr, RID, bool) + FUNC3(viewport_set_size, RID, int, int) FUNC2(viewport_set_active, RID, bool) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 080e538cbf..307f4107eb 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1576,7 +1576,7 @@ VisualServer::VisualServer() { GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048); GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096); GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_0_subdiv", 1); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_1_subdiv", 2); GLOBAL_DEF("rendering/quality/shadow_atlas/quadrant_2_subdiv", 3); diff --git a/servers/visual_server.h b/servers/visual_server.h index f515a7b990..5c9f4202f9 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -532,6 +532,7 @@ public: virtual RID viewport_create() = 0; + virtual void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) = 0; virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0; virtual void viewport_set_active(RID p_viewport, bool p_active) = 0; virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0; diff --git a/thirdparty/zstd/common/zstd_internal.h b/thirdparty/zstd/common/zstd_internal.h index f2c4e6249f..49a4796476 100644 --- a/thirdparty/zstd/common/zstd_internal.h +++ b/thirdparty/zstd/common/zstd_internal.h @@ -331,4 +331,16 @@ size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict); +typedef struct { + blockType_e blockType; + U32 lastBlock; + U32 origSize; +} blockProperties_t; + +/*! ZSTD_getcBlockSize() : + * Provides the size of compressed block from block header `src` */ + size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, + blockProperties_t* bpPtr); + + #endif /* ZSTD_CCOMMON_H_MODULE */ diff --git a/thirdparty/zstd/decompress/zstd_decompress.c b/thirdparty/zstd/decompress/zstd_decompress.c index 003d703a5e..465bcc20b5 100644 --- a/thirdparty/zstd/decompress/zstd_decompress.c +++ b/thirdparty/zstd/decompress/zstd_decompress.c @@ -53,7 +53,7 @@ # include "zstd_legacy.h" #endif -#if defined(_MSC_VER) && !defined(_M_IA64) /* _mm_prefetch() is not defined for ia64 */ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ # include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define ZSTD_PREFETCH(ptr) _mm_prefetch((const char*)ptr, _MM_HINT_T0) #elif defined(__GNUC__) @@ -466,13 +466,6 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he } -typedef struct -{ - blockType_e blockType; - U32 lastBlock; - U32 origSize; -} blockProperties_t; - /*! ZSTD_getcBlockSize() : * Provides the size of compressed block from block header `src` */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, |