diff options
587 files changed, 23793 insertions, 7230 deletions
diff --git a/.editorconfig b/.editorconfig index e51d0d4c60..d4b7fbb471 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ insert_final_newline = true [*.{cpp,hpp,c,h,mm}] trim_trailing_whitespace = true -[*.py] +[*.{py,cs}] indent_style = space indent_size = 4 diff --git a/SConstruct b/SConstruct index cb1e9fd567..1135f7a3bd 100644 --- a/SConstruct +++ b/SConstruct @@ -145,6 +145,7 @@ opts.Add(EnumVariable('bits', "Target platform bits", 'default', ('default', '32 opts.Add('p', "Platform (alias for 'platform')", '') opts.Add('platform', "Target platform (%s)" % ('|'.join(platform_list), ), '') opts.Add(EnumVariable('target', "Compilation target", 'debug', ('debug', 'release_debug', 'release'))) +opts.Add(EnumVariable('optimize', "Optimization type", 'speed', ('speed', 'size'))) opts.Add(BoolVariable('tools', "Build the tools (a.k.a. the Godot editor)", True)) opts.Add(BoolVariable('use_lto', 'Use link-time optimization', False)) @@ -408,6 +409,11 @@ if selected_platform in platform_list: env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"] env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] + # (SH)LIBSUFFIX will be used for our own built libraries + # LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default, + # so we need to append the default suffixes to keep the ability + # to link against thirdparty libraries (.a, .so, .dll, etc.). + env["LIBSUFFIXES"] += [env["LIBSUFFIX"], env["SHLIBSUFFIX"]] env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"] env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"] @@ -416,11 +422,19 @@ if selected_platform in platform_list: if env['tools']: env.Append(CPPDEFINES=['TOOLS_ENABLED']) if env['disable_3d']: - env.Append(CPPDEFINES=['_3D_DISABLED']) + if env['tools']: + print("Build option 'disable_3d=yes' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template).") + sys.exit(255) + else: + env.Append(CPPDEFINES=['_3D_DISABLED']) if env['gdscript']: env.Append(CPPDEFINES=['GDSCRIPT_ENABLED']) if env['disable_advanced_gui']: - env.Append(CPPDEFINES=['ADVANCED_GUI_DISABLED']) + if env['tools']: + print("Build option 'disable_advanced_gui=yes' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template).") + sys.exit(255) + else: + env.Append(CPPDEFINES=['ADVANCED_GUI_DISABLED']) if env['minizip']: env.Append(CPPDEFINES=['MINIZIP_ENABLED']) if env['xml']: diff --git a/core/array.cpp b/core/array.cpp index 9e3250fd47..96e64294ed 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -72,7 +72,7 @@ void Array::_unref() const { Variant &Array::operator[](int p_idx) { - return _p->array[p_idx]; + return _p->array.write[p_idx]; } const Variant &Array::operator[](int p_idx) const { diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 7a14e85f20..af1d49ae8c 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -221,6 +221,10 @@ String _OS::get_audio_driver_name(int p_driver) const { return OS::get_singleton()->get_audio_driver_name(p_driver); } +PoolStringArray _OS::get_connected_midi_inputs() { + return OS::get_singleton()->get_connected_midi_inputs(); +} + void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen) { OS::VideoMode vm; @@ -1058,6 +1062,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name); ClassDB::bind_method(D_METHOD("get_audio_driver_count"), &_OS::get_audio_driver_count); ClassDB::bind_method(D_METHOD("get_audio_driver_name", "driver"), &_OS::get_audio_driver_name); + ClassDB::bind_method(D_METHOD("get_connected_midi_inputs"), &_OS::get_connected_midi_inputs); ClassDB::bind_method(D_METHOD("get_screen_count"), &_OS::get_screen_count); ClassDB::bind_method(D_METHOD("get_current_screen"), &_OS::get_current_screen); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 48b7b74005..1729c23779 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -152,6 +152,8 @@ public: virtual int get_audio_driver_count() const; virtual String get_audio_driver_name(int p_driver) const; + virtual PoolStringArray get_connected_midi_inputs(); + virtual int get_screen_count() const; virtual int get_current_screen() const; virtual void set_current_screen(int p_screen); diff --git a/core/class_db.cpp b/core/class_db.cpp index f97eaf6099..03b214aa41 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -58,8 +58,8 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(2); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); return md; } @@ -68,9 +68,9 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(3); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); return md; } @@ -79,10 +79,10 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(4); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); return md; } @@ -91,11 +91,11 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(5); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); return md; } @@ -104,12 +104,12 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(6); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); return md; } @@ -118,13 +118,13 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(7); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); return md; } @@ -133,14 +133,14 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(8); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); - md.args[7] = StaticCString::create(p_arg8); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); + md.args.write[7] = StaticCString::create(p_arg8); return md; } @@ -149,15 +149,15 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(9); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); - md.args[7] = StaticCString::create(p_arg8); - md.args[8] = StaticCString::create(p_arg9); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); + md.args.write[7] = StaticCString::create(p_arg8); + md.args.write[8] = StaticCString::create(p_arg9); return md; } @@ -166,16 +166,16 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(10); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); - md.args[7] = StaticCString::create(p_arg8); - md.args[8] = StaticCString::create(p_arg9); - md.args[9] = StaticCString::create(p_arg10); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); + md.args.write[7] = StaticCString::create(p_arg8); + md.args.write[8] = StaticCString::create(p_arg9); + md.args.write[9] = StaticCString::create(p_arg10); return md; } @@ -184,17 +184,17 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(11); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); - md.args[7] = StaticCString::create(p_arg8); - md.args[8] = StaticCString::create(p_arg9); - md.args[9] = StaticCString::create(p_arg10); - md.args[10] = StaticCString::create(p_arg11); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); + md.args.write[7] = StaticCString::create(p_arg8); + md.args.write[8] = StaticCString::create(p_arg9); + md.args.write[9] = StaticCString::create(p_arg10); + md.args.write[10] = StaticCString::create(p_arg11); return md; } @@ -203,18 +203,18 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(12); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); - md.args[7] = StaticCString::create(p_arg8); - md.args[8] = StaticCString::create(p_arg9); - md.args[9] = StaticCString::create(p_arg10); - md.args[10] = StaticCString::create(p_arg11); - md.args[11] = StaticCString::create(p_arg12); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); + md.args.write[7] = StaticCString::create(p_arg8); + md.args.write[8] = StaticCString::create(p_arg9); + md.args.write[9] = StaticCString::create(p_arg10); + md.args.write[10] = StaticCString::create(p_arg11); + md.args.write[11] = StaticCString::create(p_arg12); return md; } @@ -223,19 +223,19 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition md; md.name = StaticCString::create(p_name); md.args.resize(13); - md.args[0] = StaticCString::create(p_arg1); - md.args[1] = StaticCString::create(p_arg2); - md.args[2] = StaticCString::create(p_arg3); - md.args[3] = StaticCString::create(p_arg4); - md.args[4] = StaticCString::create(p_arg5); - md.args[5] = StaticCString::create(p_arg6); - md.args[6] = StaticCString::create(p_arg7); - md.args[7] = StaticCString::create(p_arg8); - md.args[8] = StaticCString::create(p_arg9); - md.args[9] = StaticCString::create(p_arg10); - md.args[10] = StaticCString::create(p_arg11); - md.args[11] = StaticCString::create(p_arg12); - md.args[12] = StaticCString::create(p_arg13); + md.args.write[0] = StaticCString::create(p_arg1); + md.args.write[1] = StaticCString::create(p_arg2); + md.args.write[2] = StaticCString::create(p_arg3); + md.args.write[3] = StaticCString::create(p_arg4); + md.args.write[4] = StaticCString::create(p_arg5); + md.args.write[5] = StaticCString::create(p_arg6); + md.args.write[6] = StaticCString::create(p_arg7); + md.args.write[7] = StaticCString::create(p_arg8); + md.args.write[8] = StaticCString::create(p_arg9); + md.args.write[9] = StaticCString::create(p_arg10); + md.args.write[10] = StaticCString::create(p_arg11); + md.args.write[11] = StaticCString::create(p_arg12); + md.args.write[12] = StaticCString::create(p_arg13); return md; } @@ -1246,7 +1246,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c defvals.resize(p_defcount); for (int i = 0; i < p_defcount; i++) { - defvals[i] = *p_defs[p_defcount - i - 1]; + defvals.write[i] = *p_defs[p_defcount - i - 1]; } p_bind->set_default_arguments(defvals); diff --git a/core/color.cpp b/core/color.cpp index 88e57ec6e2..fcfcf20355 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -49,6 +49,7 @@ uint32_t Color::to_argb32() const { } uint32_t Color::to_abgr32() const { + uint32_t c = (uint8_t)Math::round(a * 255); c <<= 8; c |= (uint8_t)Math::round(b * 255); @@ -73,6 +74,45 @@ uint32_t Color::to_rgba32() const { return c; } +uint64_t Color::to_abgr64() const { + + uint64_t c = (uint16_t)Math::round(a * 65535); + c <<= 16; + c |= (uint16_t)Math::round(b * 65535); + c <<= 16; + c |= (uint16_t)Math::round(g * 65535); + c <<= 16; + c |= (uint16_t)Math::round(r * 65535); + + return c; +} + +uint64_t Color::to_argb64() const { + + uint64_t c = (uint16_t)Math::round(a * 65535); + c <<= 16; + c |= (uint16_t)Math::round(r * 65535); + c <<= 16; + c |= (uint16_t)Math::round(g * 65535); + c <<= 16; + c |= (uint16_t)Math::round(b * 65535); + + return c; +} + +uint64_t Color::to_rgba64() const { + + uint64_t c = (uint16_t)Math::round(r * 65535); + c <<= 16; + c |= (uint16_t)Math::round(g * 65535); + c <<= 16; + c |= (uint16_t)Math::round(b * 65535); + c <<= 16; + c |= (uint16_t)Math::round(a * 65535); + + return c; +} + float Color::get_h() const { float min = MIN(r, g); @@ -200,6 +240,19 @@ Color Color::hex(uint32_t p_hex) { return Color(r, g, b, a); } +Color Color::hex64(uint64_t p_hex) { + + float a = (p_hex & 0xFFFF) / 65535.0; + p_hex >>= 16; + float b = (p_hex & 0xFFFF) / 65535.0; + p_hex >>= 16; + float g = (p_hex & 0xFFFF) / 65535.0; + p_hex >>= 16; + float r = (p_hex & 0xFFFF) / 65535.0; + + return Color(r, g, b, a); +} + static float _parse_col(const String &p_str, int p_ofs) { int ig = 0; diff --git a/core/color.h b/core/color.h index a2015a34d6..c0516e55fe 100644 --- a/core/color.h +++ b/core/color.h @@ -55,6 +55,9 @@ struct Color { uint32_t to_rgba32() const; uint32_t to_argb32() const; uint32_t to_abgr32() const; + uint64_t to_rgba64() const; + uint64_t to_argb64() const; + uint64_t to_abgr64() const; float gray() const; float get_h() const; float get_s() const; @@ -186,6 +189,7 @@ struct Color { } static Color hex(uint32_t p_hex); + static Color hex64(uint64_t p_hex); static Color html(const String &p_color); static bool html_is_valid(const String &p_color); static Color named(const String &p_name); diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp index 266d793af7..5c1fd26e2a 100644 --- a/core/compressed_translation.cpp +++ b/core/compressed_translation.cpp @@ -73,7 +73,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) { Pair<int, CharString> p; p.first = idx; p.second = cs; - buckets[h % size].push_back(p); + buckets.write[h % size].push_back(p); //compress string CharString src_s = p_from->get_message(E->get()).operator String().utf8(); @@ -100,7 +100,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) { ps.compressed[0] = 0; } - compressed[idx] = ps; + compressed.write[idx] = ps; total_compression_size += ps.compressed.size(); total_string_size += src_s.size(); idx++; @@ -111,8 +111,8 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) { for (int i = 0; i < size; i++) { - Vector<Pair<int, CharString> > &b = buckets[i]; - Map<uint32_t, int> &t = table[i]; + const Vector<Pair<int, CharString> > &b = buckets[i]; + Map<uint32_t, int> &t = table.write[i]; if (b.size() == 0) continue; @@ -136,7 +136,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) { } } - hfunc_table[i] = d; + hfunc_table.write[i] = d; bucket_table_size += 2 + b.size() * 4; } @@ -157,7 +157,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) { for (int i = 0; i < size; i++) { - Map<uint32_t, int> &t = table[i]; + const Map<uint32_t, int> &t = table[i]; if (t.size() == 0) { htw[i] = 0xFFFFFFFF; //nothing continue; diff --git a/core/cowdata.h b/core/cowdata.h new file mode 100644 index 0000000000..66e7d1c343 --- /dev/null +++ b/core/cowdata.h @@ -0,0 +1,332 @@ +/*************************************************************************/ +/* cowdata.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 COWDATA_H_ +#define COWDATA_H_ + +#include "os/memory.h" +#include "safe_refcount.h" + +template <class T> +class Vector; +class String; +class CharString; +template <class T, class V> +class VMap; + +template <class T> +class CowData { + template <class TV> + friend class Vector; + friend class String; + friend class CharString; + template <class TV, class VV> + friend class VMap; + +private: + mutable T *_ptr; + + // internal helpers + + _FORCE_INLINE_ uint32_t *_get_refcount() const { + + if (!_ptr) + return NULL; + + return reinterpret_cast<uint32_t *>(_ptr) - 2; + } + + _FORCE_INLINE_ uint32_t *_get_size() const { + + if (!_ptr) + return NULL; + + return reinterpret_cast<uint32_t *>(_ptr) - 1; + } + + _FORCE_INLINE_ T *_get_data() const { + + if (!_ptr) + return NULL; + return reinterpret_cast<T *>(_ptr); + } + + _FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { + //return nearest_power_of_2_templated(p_elements*sizeof(T)+sizeof(SafeRefCount)+sizeof(int)); + return next_power_of_2(p_elements * sizeof(T)); + } + + _FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const { +#if defined(_add_overflow) && defined(_mul_overflow) + size_t o; + size_t p; + if (_mul_overflow(p_elements, sizeof(T), &o)) return false; + *out = next_power_of_2(o); + if (_add_overflow(o, static_cast<size_t>(32), &p)) return false; //no longer allocated here + return true; +#else + // Speed is more important than correctness here, do the operations unchecked + // and hope the best + *out = _get_alloc_size(p_elements); + return true; +#endif + } + + void _unref(void *p_data); + void _ref(const CowData &p_from); + void _copy_on_write(); + +public: + void operator=(const CowData<T> &p_from) { _ref(p_from); } + + _FORCE_INLINE_ T *ptrw() { + _copy_on_write(); + return (T *)_get_data(); + } + + _FORCE_INLINE_ const T *ptr() const { + return _get_data(); + } + + _FORCE_INLINE_ int size() const { + uint32_t *size = (uint32_t *)_get_size(); + if (size) + return *size; + else + return 0; + } + + _FORCE_INLINE_ void clear() { resize(0); } + _FORCE_INLINE_ bool empty() const { return _ptr == 0; } + + _FORCE_INLINE_ void set(int p_index, const T &p_elem) { + + CRASH_BAD_INDEX(p_index, size()); + _copy_on_write(); + _get_data()[p_index] = p_elem; + } + + _FORCE_INLINE_ T &get_m(int p_index) { + + CRASH_BAD_INDEX(p_index, size()); + _copy_on_write(); + return _get_data()[p_index]; + } + + _FORCE_INLINE_ const T &get(int p_index) const { + + CRASH_BAD_INDEX(p_index, size()); + + return _get_data()[p_index]; + } + + Error resize(int p_size); + + _FORCE_INLINE_ void remove(int p_index) { + + ERR_FAIL_INDEX(p_index, size()); + T *p = ptrw(); + int len = size(); + for (int i = p_index; i < len - 1; i++) { + + p[i] = p[i + 1]; + }; + + resize(len - 1); + }; + + Error insert(int p_pos, const T &p_val) { + + ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER); + resize(size() + 1); + for (int i = (size() - 1); i > p_pos; i--) + set(i, get(i - 1)); + set(p_pos, p_val); + + return OK; + }; + + _FORCE_INLINE_ CowData(); + _FORCE_INLINE_ ~CowData(); + _FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); }; +}; + +template <class T> +void CowData<T>::_unref(void *p_data) { + + if (!p_data) + return; + + uint32_t *refc = _get_refcount(); + + if (atomic_decrement(refc) > 0) + return; // still in use + // clean up + + uint32_t *count = _get_size(); + T *data = (T *)(count + 1); + + for (uint32_t i = 0; i < *count; ++i) { + // call destructors + data[i].~T(); + } + + // free mem + Memory::free_static((uint8_t *)p_data, true); +} + +template <class T> +void CowData<T>::_copy_on_write() { + + if (!_ptr) + return; + + uint32_t *refc = _get_refcount(); + + if (unlikely(*refc > 1)) { + /* in use by more than me */ + uint32_t current_size = *_get_size(); + + uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true); + + *(mem_new - 2) = 1; //refcount + *(mem_new - 1) = current_size; //size + + T *_data = (T *)(mem_new); + + // initialize new elements + for (uint32_t i = 0; i < current_size; i++) { + + memnew_placement(&_data[i], T(_get_data()[i])); + } + + _unref(_ptr); + _ptr = _data; + } +} + +template <class T> +Error CowData<T>::resize(int p_size) { + + ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER); + + if (p_size == size()) + return OK; + + if (p_size == 0) { + // wants to clean up + _unref(_ptr); + _ptr = NULL; + return OK; + } + + // possibly changing size, copy on write + _copy_on_write(); + + size_t alloc_size; + ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY); + + if (p_size > size()) { + + if (size() == 0) { + // alloc from scratch + uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true); + ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY); + *(ptr - 1) = 0; //size, currently none + *(ptr - 2) = 1; //refcount + + _ptr = (T *)ptr; + + } else { + void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true); + ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY); + _ptr = (T *)(_ptrnew); + } + + // construct the newly created elements + T *elems = _get_data(); + + for (int i = *_get_size(); i < p_size; i++) { + + memnew_placement(&elems[i], T); + } + + *_get_size() = p_size; + + } else if (p_size < size()) { + + // deinitialize no longer needed elements + for (uint32_t i = p_size; i < *_get_size(); i++) { + + T *t = &_get_data()[i]; + t->~T(); + } + + void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true); + ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY); + + _ptr = (T *)(_ptrnew); + + *_get_size() = p_size; + } + + return OK; +} + +template <class T> +void CowData<T>::_ref(const CowData &p_from) { + + if (_ptr == p_from._ptr) + return; // self assign, do nothing. + + _unref(_ptr); + _ptr = NULL; + + if (!p_from._ptr) + return; //nothing to do + + if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference + _ptr = p_from._ptr; + } +} + +template <class T> +CowData<T>::CowData() { + + _ptr = NULL; +} + +template <class T> +CowData<T>::~CowData() { + + _unref(_ptr); +} + +#endif /* COW_H_ */ diff --git a/core/dictionary.cpp b/core/dictionary.cpp index d68411a572..42d9eab310 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -140,6 +140,11 @@ void Dictionary::erase(const Variant &p_key) { _p->variant_map.erase(p_key); } +bool Dictionary::erase_checked(const Variant &p_key) { + + return _p->variant_map.erase(p_key); +} + bool Dictionary::operator==(const Dictionary &p_dictionary) const { return _p == p_dictionary._p; diff --git a/core/dictionary.h b/core/dictionary.h index 84a5cafe1d..00ec67fb99 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -66,6 +66,7 @@ public: bool has_all(const Array &p_keys) const; void erase(const Variant &p_key); + bool erase_checked(const Variant &p_key); bool operator==(const Dictionary &p_dictionary) const; diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 5b4dd05dbf..187813f9d0 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -89,6 +89,7 @@ VARIANT_ENUM_CAST(KeyList); VARIANT_ENUM_CAST(KeyModifierMask); VARIANT_ENUM_CAST(ButtonList); VARIANT_ENUM_CAST(JoystickList); +VARIANT_ENUM_CAST(MidiMessageList); void register_global_constants() { @@ -458,6 +459,15 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_L2); BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_R2); + // midi + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_OFF); + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_ON); + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_AFTERTOUCH); + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CONTROL_CHANGE); + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PROGRAM_CHANGE); + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CHANNEL_PRESSURE); + BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PITCH_BEND); + // error list BIND_GLOBAL_ENUM_CONSTANT(OK); diff --git a/core/image.cpp b/core/image.cpp index b0bed80a6f..19440d1718 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -33,6 +33,7 @@ #include "core/io/image_loader.h" #include "core/os/copymem.h" #include "hash_map.h" +#include "math_funcs.h" #include "print_string.h" #include "thirdparty/misc/hq2x.h" @@ -525,7 +526,7 @@ static double _bicubic_interp_kernel(double x) { } template <int CC> -static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { +static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { // get source image size int width = p_src_width; @@ -555,7 +556,7 @@ static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_wi // initial pixel value - uint8_t *dst = p_dst + (y * p_dst_width + x) * CC; + uint8_t *__restrict dst = p_dst + (y * p_dst_width + x) * CC; double color[CC]; for (int i = 0; i < CC; i++) { @@ -583,7 +584,7 @@ static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_wi ox2 = xmax; // get pixel of original image - const uint8_t *p = p_src + (oy2 * p_src_width + ox2) * CC; + const uint8_t *__restrict p = p_src + (oy2 * p_src_width + ox2) * CC; for (int i = 0; i < CC; i++) { @@ -600,7 +601,7 @@ static void _scale_cubic(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_wi } template <int CC> -static void _scale_bilinear(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { +static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { enum { FRAC_BITS = 8, @@ -655,7 +656,7 @@ static void _scale_bilinear(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src } template <int CC> -static void _scale_nearest(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { +static void _scale_nearest(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) { for (uint32_t i = 0; i < p_dst_height; i++) { @@ -676,6 +677,16 @@ static void _scale_nearest(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_src_ } } +static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, float p_alpha, uint32_t p_width, uint32_t p_height, uint32_t p_pixel_size) { + + uint16_t alpha = CLAMP((uint16_t)(p_alpha * 256.0f), 0, 256); + + for (uint32_t i = 0; i < p_width * p_height * p_pixel_size; i++) { + + p_dst[i] = (p_dst[i] * (256 - alpha) + p_src[i] * alpha) >> 8; + } +} + void Image::resize_to_po2(bool p_square) { if (!_can_modify(format)) { @@ -707,6 +718,8 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { ERR_FAIL(); } + bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */; + ERR_FAIL_COND(p_width <= 0); ERR_FAIL_COND(p_height <= 0); ERR_FAIL_COND(p_width > MAX_WIDTH); @@ -717,6 +730,32 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { Image dst(p_width, p_height, 0, format); + // Setup mipmap-aware scaling + Image dst2; + int mip1; + int mip2; + float mip1_weight; + if (mipmap_aware) { + float avg_scale = ((float)p_width / width + (float)p_height / height) * 0.5f; + if (avg_scale >= 1.0f) { + mipmap_aware = false; + } else { + float level = Math::log(1.0f / avg_scale) / Math::log(2.0f); + mip1 = CLAMP((int)Math::floor(level), 0, get_mipmap_count()); + mip2 = CLAMP((int)Math::ceil(level), 0, get_mipmap_count()); + mip1_weight = 1.0f - (level - mip1); + } + } + bool interpolate_mipmaps = mipmap_aware && mip1 != mip2; + if (interpolate_mipmaps) { + dst2.create(p_width, p_height, 0, format); + } + bool had_mipmaps = mipmaps; + if (interpolate_mipmaps && !had_mipmaps) { + generate_mipmaps(); + } + // -- + PoolVector<uint8_t>::Read r = data.read(); const unsigned char *r_ptr = r.ptr(); @@ -734,13 +773,57 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { case 4: _scale_nearest<4>(r_ptr, w_ptr, width, height, p_width, p_height); break; } } break; - case INTERPOLATE_BILINEAR: { + case INTERPOLATE_BILINEAR: + case INTERPOLATE_TRILINEAR: { + + for (int i = 0; i < 2; ++i) { + int src_width; + int src_height; + const unsigned char *src_ptr; + + if (!mipmap_aware) { + if (i == 0) { + // Standard behavior + src_width = width; + src_height = height; + src_ptr = r_ptr; + } else { + // No need for a second iteration + break; + } + } else { + if (i == 0) { + // Read from the first mipmap that will be interpolated + // (if both levels are the same, we will not interpolate, but at least we'll sample from the right level) + int offs; + _get_mipmap_offset_and_size(mip1, offs, src_width, src_height); + src_ptr = r_ptr + offs; + } else if (!interpolate_mipmaps) { + // No need generate a second image + break; + } else { + // Switch to read from the second mipmap that will be interpolated + int offs; + _get_mipmap_offset_and_size(mip2, offs, src_width, src_height); + src_ptr = r_ptr + offs; + // Switch to write to the second destination image + w = dst2.data.write(); + w_ptr = w.ptr(); + } + } - switch (get_format_pixel_size(format)) { - case 1: _scale_bilinear<1>(r_ptr, w_ptr, width, height, p_width, p_height); break; - case 2: _scale_bilinear<2>(r_ptr, w_ptr, width, height, p_width, p_height); break; - case 3: _scale_bilinear<3>(r_ptr, w_ptr, width, height, p_width, p_height); break; - case 4: _scale_bilinear<4>(r_ptr, w_ptr, width, height, p_width, p_height); break; + switch (get_format_pixel_size(format)) { + case 1: _scale_bilinear<1>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; + case 2: _scale_bilinear<2>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; + case 3: _scale_bilinear<3>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; + case 4: _scale_bilinear<4>(src_ptr, w_ptr, src_width, src_height, p_width, p_height); break; + } + } + + if (interpolate_mipmaps) { + // Switch to read again from the first scaled mipmap to overlay it over the second + r = dst.data.read(); + _overlay(r.ptr(), w.ptr(), mip1_weight, p_width, p_height, get_format_pixel_size(format)); } } break; @@ -759,7 +842,11 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { r = PoolVector<uint8_t>::Read(); w = PoolVector<uint8_t>::Write(); - if (mipmaps > 0) + if (interpolate_mipmaps) { + dst._copy_internals_from(dst2); + } + + if (had_mipmaps) dst.generate_mipmaps(); _copy_internals_from(dst); @@ -1898,8 +1985,9 @@ void Image::fill(const Color &c) { unlock(); } -Ref<Image> (*Image::_png_mem_loader_func)(const uint8_t *, int) = NULL; -Ref<Image> (*Image::_jpg_mem_loader_func)(const uint8_t *, int) = NULL; +ImageMemLoadFunc Image::_png_mem_loader_func = NULL; +ImageMemLoadFunc Image::_jpg_mem_loader_func = NULL; +ImageMemLoadFunc Image::_webp_mem_loader_func = NULL; void (*Image::_image_compress_bc_func)(Image *, Image::CompressSource) = NULL; void (*Image::_image_compress_pvrtc2_func)(Image *) = NULL; @@ -2357,6 +2445,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer); ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer); + ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data"); @@ -2402,6 +2491,7 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST); BIND_ENUM_CONSTANT(INTERPOLATE_BILINEAR); BIND_ENUM_CONSTANT(INTERPOLATE_CUBIC); + BIND_ENUM_CONSTANT(INTERPOLATE_TRILINEAR); BIND_ENUM_CONSTANT(ALPHA_NONE); BIND_ENUM_CONSTANT(ALPHA_BIT); @@ -2649,32 +2739,26 @@ String Image::get_format_name(Format p_format) { } Error Image::load_png_from_buffer(const PoolVector<uint8_t> &p_array) { - - int buffer_size = p_array.size(); - - ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!_png_mem_loader_func, ERR_INVALID_PARAMETER); - - PoolVector<uint8_t>::Read r = p_array.read(); - - Ref<Image> image = _png_mem_loader_func(r.ptr(), buffer_size); - ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR); - - copy_internals_from(image); - - return OK; + return _load_from_buffer(p_array, _png_mem_loader_func); } Error Image::load_jpg_from_buffer(const PoolVector<uint8_t> &p_array) { + return _load_from_buffer(p_array, _jpg_mem_loader_func); +} + +Error Image::load_webp_from_buffer(const PoolVector<uint8_t> &p_array) { + return _load_from_buffer(p_array, _webp_mem_loader_func); +} +Error Image::_load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader) { int buffer_size = p_array.size(); ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!_jpg_mem_loader_func, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!p_loader, ERR_INVALID_PARAMETER); PoolVector<uint8_t>::Read r = p_array.read(); - Ref<Image> image = _jpg_mem_loader_func(r.ptr(), buffer_size); + Ref<Image> image = p_loader(r.ptr(), buffer_size); ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR); copy_internals_from(image); diff --git a/core/image.h b/core/image.h index 43516e2c0b..8c4854e053 100644 --- a/core/image.h +++ b/core/image.h @@ -47,6 +47,7 @@ class Image; typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img); +typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size); class Image : public Resource { GDCLASS(Image, Resource); @@ -107,6 +108,8 @@ public: INTERPOLATE_NEAREST, INTERPOLATE_BILINEAR, INTERPOLATE_CUBIC, + INTERPOLATE_TRILINEAR, + /* INTERPOLATE_TRICUBIC, */ /* INTERPOLATE GAUSS */ }; @@ -118,8 +121,9 @@ public: //some functions provided by something else - static Ref<Image> (*_png_mem_loader_func)(const uint8_t *p_png, int p_size); - static Ref<Image> (*_jpg_mem_loader_func)(const uint8_t *p_png, int p_size); + static ImageMemLoadFunc _png_mem_loader_func; + static ImageMemLoadFunc _jpg_mem_loader_func; + static ImageMemLoadFunc _webp_mem_loader_func; static void (*_image_compress_bc_func)(Image *, CompressSource p_source); static void (*_image_compress_pvrtc2_func)(Image *); @@ -175,6 +179,8 @@ private: void _set_data(const Dictionary &p_data); Dictionary _get_data() const; + Error _load_from_buffer(const PoolVector<uint8_t> &p_array, ImageMemLoadFunc p_loader); + public: int get_width() const; ///< Get image width int get_height() const; ///< Get image height @@ -302,6 +308,7 @@ public: Error load_png_from_buffer(const PoolVector<uint8_t> &p_array); Error load_jpg_from_buffer(const PoolVector<uint8_t> &p_array); + Error load_webp_from_buffer(const PoolVector<uint8_t> &p_array); Image(const uint8_t *p_mem_png_jpg, int p_len = -1); Image(const char **p_xpm); diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 221f457b78..bb7a444ccc 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -89,7 +89,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8 for (size_t i = 0; i < ds; i += 16) { - aes256_decrypt_ecb(&ctx, &data[i]); + aes256_decrypt_ecb(&ctx, &data.write[i]); } aes256_done(&ctx); @@ -117,7 +117,7 @@ Error FileAccessEncrypted::open_and_parse_password(FileAccess *p_base, const Str key.resize(32); for (int i = 0; i < 32; i++) { - key[i] = cs[i]; + key.write[i] = cs[i]; } return open_and_parse(p_base, key, p_mode); @@ -148,7 +148,7 @@ void FileAccessEncrypted::close() { compressed.resize(len); zeromem(compressed.ptrw(), len); for (int i = 0; i < data.size(); i++) { - compressed[i] = data[i]; + compressed.write[i] = data[i]; } aes256_context ctx; @@ -156,7 +156,7 @@ void FileAccessEncrypted::close() { for (size_t i = 0; i < len; i += 16) { - aes256_encrypt_ecb(&ctx, &compressed[i]); + aes256_encrypt_ecb(&ctx, &compressed.write[i]); } aes256_done(&ctx); @@ -263,7 +263,7 @@ void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) { data.resize(pos + p_length); for (int i = 0; i < p_length; i++) { - data[pos + i] = p_src[i]; + data.write[pos + i] = p_src[i]; } pos += p_length; } @@ -280,7 +280,7 @@ void FileAccessEncrypted::store_8(uint8_t p_dest) { ERR_FAIL_COND(!writing); if (pos < data.size()) { - data[pos] = p_dest; + data.write[pos] = p_dest; pos++; } else if (pos == data.size()) { data.push_back(p_dest); diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 1aa1e4a595..c4eb2848b1 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -92,7 +92,7 @@ Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) { Map<String, Vector<uint8_t> >::Element *E = files->find(name); ERR_FAIL_COND_V(!E, ERR_FILE_NOT_FOUND); - data = &(E->get()[0]); + data = E->get().ptrw(); length = E->get().size(); pos = 0; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 21e3a4172b..e0a2dbf507 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -258,8 +258,8 @@ void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) } buffer_mutex->lock(); - pages[page].buffer = p_block; - pages[page].queued = false; + pages.write[page].buffer = p_block; + pages.write[page].queued = false; buffer_mutex->unlock(); if (waiting_on_page == page) { @@ -389,7 +389,7 @@ void FileAccessNetwork::_queue_page(int p_page) const { br.offset = size_t(p_page) * page_size; br.size = page_size; nc->block_requests.push_back(br); - pages[p_page].queued = true; + pages.write[p_page].queued = true; nc->blockrequest_mutex->unlock(); DEBUG_PRINT("QUEUE PAGE POST"); nc->sem->post(); @@ -433,12 +433,12 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const { _queue_page(page + j); } - buff = pages[page].buffer.ptrw(); + buff = pages.write[page].buffer.ptrw(); //queue pages buffer_mutex->unlock(); } - buff = pages[page].buffer.ptrw(); + buff = pages.write[page].buffer.ptrw(); last_page_buff = buff; last_page = page; } diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index f1620f1493..2425bb6d69 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -552,7 +552,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { } else { int rec = 0; - err = _get_http_data(&chunk[chunk.size() - chunk_left], chunk_left, rec); + err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec); if (rec == 0) { break; } diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index ffd3ecaed0..8e67f1c97a 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -282,10 +282,10 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ ERR_FAIL_COND(p_offset >= p_packet_len); int vlen; - Error err = decode_variant(args[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); + Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); ERR_FAIL_COND(err != OK); //args[i]=p_packet[3+i]; - argp[i] = &args[i]; + argp.write[i] = &args[i]; p_offset += vlen; } @@ -354,8 +354,8 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, Vector<uint8_t> packet; packet.resize(1 + len); - packet[0] = NETWORK_COMMAND_CONFIRM_PATH; - encode_cstring(pname.get_data(), &packet[1]); + packet.write[0] = NETWORK_COMMAND_CONFIRM_PATH; + encode_cstring(pname.get_data(), &packet.write[1]); network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); network_peer->set_target_peer(p_from); @@ -415,9 +415,9 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int Vector<uint8_t> packet; packet.resize(1 + 4 + len); - packet[0] = NETWORK_COMMAND_SIMPLIFY_PATH; - encode_uint32(psc->id, &packet[1]); - encode_cstring(pname.get_data(), &packet[5]); + packet.write[0] = NETWORK_COMMAND_SIMPLIFY_PATH; + encode_uint32(psc->id, &packet.write[1]); + encode_cstring(pname.get_data(), &packet.write[5]); network_peer->set_target_peer(E->get()); //to all of you network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); @@ -482,19 +482,19 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p //encode type MAKE_ROOM(1); - packet_cache[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + packet_cache.write[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; ofs += 1; //encode ID MAKE_ROOM(ofs + 4); - encode_uint32(psc->id, &(packet_cache[ofs])); + encode_uint32(psc->id, &(packet_cache.write[ofs])); ofs += 4; //encode function name CharString name = String(p_name).utf8(); int len = encode_cstring(name.get_data(), NULL); MAKE_ROOM(ofs + len); - encode_cstring(name.get_data(), &(packet_cache[ofs])); + encode_cstring(name.get_data(), &(packet_cache.write[ofs])); ofs += len; if (p_set) { @@ -502,19 +502,19 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p Error err = encode_variant(*p_arg[0], NULL, len); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); - encode_variant(*p_arg[0], &(packet_cache[ofs]), len); + encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len); ofs += len; } else { //call arguments MAKE_ROOM(ofs + 1); - packet_cache[ofs] = p_argcount; + packet_cache.write[ofs] = p_argcount; ofs += 1; for (int i = 0; i < p_argcount; i++) { Error err = encode_variant(*p_arg[i], NULL, len); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); - encode_variant(*p_arg[i], &(packet_cache[ofs]), len); + encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len); ofs += len; } } @@ -537,7 +537,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p CharString pname = String(from_path).utf8(); int path_len = encode_cstring(pname.get_data(), NULL); MAKE_ROOM(ofs + path_len); - encode_cstring(pname.get_data(), &(packet_cache[ofs])); + encode_cstring(pname.get_data(), &(packet_cache.write[ofs])); for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { @@ -554,11 +554,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p if (F->get() == true) { //this one confirmed path, so use id - encode_uint32(psc->id, &(packet_cache[1])); + encode_uint32(psc->id, &(packet_cache.write[1])); network_peer->put_packet(packet_cache.ptr(), ofs); } else { //this one did not confirm path yet, so use entire path (sorry!) - encode_uint32(0x80000000 | ofs, &(packet_cache[1])); //offset to path and flag + encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); //offset to path and flag network_peer->put_packet(packet_cache.ptr(), ofs + path_len); } } @@ -712,8 +712,8 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, Networked MAKE_ROOM(p_data.size() + 1); PoolVector<uint8_t>::Read r = p_data.read(); - packet_cache[0] = NETWORK_COMMAND_RAW; - memcpy(&packet_cache[1], &r[0], p_data.size()); + packet_cache.write[0] = NETWORK_COMMAND_RAW; + memcpy(&packet_cache.write[1], &r[0], p_data.size()); network_peer->set_target_peer(p_to); network_peer->set_transfer_mode(p_mode); @@ -773,7 +773,7 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const { void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); - ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); + ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id); diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index b777a9f960..dc4997dfc2 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -173,7 +173,7 @@ Error PacketPeerStream::_poll_buffer() const { int read = 0; ERR_FAIL_COND_V(input_buffer.size() < ring_buffer.space_left(), ERR_UNAVAILABLE); - Error err = peer->get_partial_data(&input_buffer[0], ring_buffer.space_left(), read); + Error err = peer->get_partial_data(input_buffer.ptrw(), ring_buffer.space_left(), read); if (err) return err; if (read == 0) @@ -226,7 +226,7 @@ Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) ERR_FAIL_COND_V(input_buffer.size() < len, ERR_UNAVAILABLE); ring_buffer.read(lbuf, 4); //get rid of first 4 bytes - ring_buffer.read(&input_buffer[0], len); // read packet + ring_buffer.read(input_buffer.ptrw(), len); // read packet *r_buffer = &input_buffer[0]; r_buffer_size = len; @@ -247,8 +247,8 @@ Error PacketPeerStream::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(p_buffer_size < 0, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_buffer_size + 4 > output_buffer.size(), ERR_INVALID_PARAMETER); - encode_uint32(p_buffer_size, &output_buffer[0]); - uint8_t *dst = &output_buffer[4]; + encode_uint32(p_buffer_size, output_buffer.ptrw()); + uint8_t *dst = &output_buffer.write[4]; for (int i = 0; i < p_buffer_size; i++) dst[i] = p_buffer[i]; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index b6377662de..2fd73db27d 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -120,7 +120,7 @@ Error PCKPacker::flush(bool p_verbose) { for (int i = 0; i < files.size(); i++) { file->store_pascal_string(files[i].path); - files[i].offset_offset = file->get_position(); + files.write[i].offset_offset = file->get_position(); file->store_64(0); // offset file->store_64(files[i].size); // size diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 0c626c197b..02c2c6ce1a 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -894,7 +894,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { for (uint32_t i = 0; i < string_table_size; i++) { StringName s = get_unicode_string(); - string_map[i] = s; + string_map.write[i] = s; } print_bl("strings: " + itos(string_table_size)); @@ -1834,7 +1834,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p save_order.resize(external_resources.size()); for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) { - save_order[E->get()] = E->key(); + save_order.write[E->get()] = E->key(); } for (int i = 0; i < save_order.size(); i++) { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 1351030d1e..c44d2597a7 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -556,7 +556,7 @@ void ResourceLoader::load_translation_remaps() { Vector<String> lang_remaps; lang_remaps.resize(langs.size()); for (int i = 0; i < langs.size(); i++) { - lang_remaps[i] = langs[i]; + lang_remaps.write[i] = langs[i]; } translation_remaps[String(E->get())] = lang_remaps; diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index 927b9f6366..3e0ee088c2 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -331,7 +331,7 @@ String StreamPeer::get_string(int p_bytes) { ERR_FAIL_COND_V(err != OK, String()); err = get_data((uint8_t *)&buf[0], p_bytes); ERR_FAIL_COND_V(err != OK, String()); - buf[p_bytes] = 0; + buf.write[p_bytes] = 0; return buf.ptr(); } String StreamPeer::get_utf8_string(int p_bytes) { diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp index c71af6b641..e7e9662d24 100644 --- a/core/io/stream_peer_ssl.cpp +++ b/core/io/stream_peer_ssl.cpp @@ -92,7 +92,7 @@ PoolByteArray StreamPeerSSL::get_project_cert_array() { void StreamPeerSSL::_bind_methods() { ClassDB::bind_method(D_METHOD("poll"), &StreamPeerSSL::poll); - ClassDB::bind_method(D_METHOD("accept_stream"), &StreamPeerSSL::accept_stream); + ClassDB::bind_method(D_METHOD("accept_stream", "base"), &StreamPeerSSL::accept_stream); ClassDB::bind_method(D_METHOD("connect_to_stream", "stream", "validate_certs", "for_hostname"), &StreamPeerSSL::connect_to_stream, DEFVAL(false), DEFVAL(String())); ClassDB::bind_method(D_METHOD("get_status"), &StreamPeerSSL::get_status); ClassDB::bind_method(D_METHOD("disconnect_from_stream"), &StreamPeerSSL::disconnect_from_stream); diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 16d5e3c282..85c1fc5ddf 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -54,32 +54,25 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S int line = 1; bool skip_this = false; bool skip_next = false; + bool is_eof = false; - while (true) { + while (!is_eof) { - String l = f->get_line(); + String l = f->get_line().strip_edges(); + is_eof = f->eof_reached(); - if (f->eof_reached()) { + // If we reached last line and it's not a content line, break, otherwise let processing that last loop + if (is_eof && l.empty()) { - if (status == STATUS_READING_STRING) { - - if (msg_id != "") { - if (!skip_this) - translation->add_message(msg_id, msg_str); - } else if (config == "") - config = msg_str; - break; - - } else if (status == STATUS_NONE) + if (status == STATUS_READING_ID) { + memdelete(f); + ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: "); + ERR_FAIL_V(RES()); + } else { break; - - memdelete(f); - ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: "); - ERR_FAIL_V(RES()); + } } - l = l.strip_edges(); - if (l.begins_with("msgid")) { if (status == STATUS_READING_ID) { @@ -160,6 +153,15 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S f->close(); memdelete(f); + if (status == STATUS_READING_STRING) { + + if (msg_id != "") { + if (!skip_this) + translation->add_message(msg_id, msg_str); + } else if (config == "") + config = msg_str; + } + if (config == "") { ERR_EXPLAIN("No config found in file: " + p_path); ERR_FAIL_V(RES()); diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index cff19f990c..e2e71dda92 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -245,7 +245,6 @@ Vector3 AABB::get_longest_axis() const { if (size.z > max_size) { axis = Vector3(0, 0, 1); - max_size = size.z; } return axis; @@ -262,7 +261,6 @@ int AABB::get_longest_axis_index() const { if (size.z > max_size) { axis = 2; - max_size = size.z; } return axis; @@ -280,7 +278,6 @@ Vector3 AABB::get_shortest_axis() const { if (size.z < max_size) { axis = Vector3(0, 0, 1); - max_size = size.z; } return axis; @@ -297,7 +294,6 @@ int AABB::get_shortest_axis_index() const { if (size.z < max_size) { axis = 2; - max_size = size.z; } return axis; diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index b1424e1d78..24096de551 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -244,10 +244,8 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const { const Node *nodesptr = &nodes[0]; const Plane *planesptr = &planes[0]; - int plane_count = planes.size(); int idx = node_count - 1; - int steps = 0; while (true) { @@ -259,21 +257,19 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const { return true; } - uint16_t plane = nodesptr[idx].plane; #ifdef DEBUG_ENABLED - + int plane_count = planes.size(); + uint16_t plane = nodesptr[idx].plane; ERR_FAIL_INDEX_V(plane, plane_count, false); #endif + bool over = planesptr[nodesptr[idx].plane].is_point_over(p_point); idx = over ? nodes[idx].over : nodes[idx].under; #ifdef DEBUG_ENABLED - ERR_FAIL_COND_V(idx < MAX_NODES && idx >= node_count, false); #endif - - steps++; } return false; @@ -453,10 +449,10 @@ BSP_Tree::operator Variant() const { for (int i = 0; i < planes.size(); i++) { - plane_values[i * 4 + 0] = planes[i].normal.x; - plane_values[i * 4 + 1] = planes[i].normal.y; - plane_values[i * 4 + 2] = planes[i].normal.z; - plane_values[i * 4 + 3] = planes[i].d; + plane_values.write[i * 4 + 0] = planes[i].normal.x; + plane_values.write[i * 4 + 1] = planes[i].normal.y; + plane_values.write[i * 4 + 2] = planes[i].normal.z; + plane_values.write[i * 4 + 3] = planes[i].d; } d["planes"] = plane_values; @@ -502,10 +498,10 @@ BSP_Tree::BSP_Tree(const Variant &p_variant) { PoolVector<real_t>::Read r = src_planes.read(); for (int i = 0; i < plane_count / 4; i++) { - planes[i].normal.x = r[i * 4 + 0]; - planes[i].normal.y = r[i * 4 + 1]; - planes[i].normal.z = r[i * 4 + 2]; - planes[i].d = r[i * 4 + 3]; + planes.write[i].normal.x = r[i * 4 + 0]; + planes.write[i].normal.y = r[i * 4 + 1]; + planes.write[i].normal.z = r[i * 4 + 2]; + planes.write[i].d = r[i * 4 + 3]; } } @@ -524,9 +520,9 @@ BSP_Tree::BSP_Tree(const Variant &p_variant) { for (int i = 0; i < nodes.size(); i++) { - nodes[i].over = r[i * 3 + 0]; - nodes[i].under = r[i * 3 + 1]; - nodes[i].plane = r[i * 3 + 2]; + nodes.write[i].over = r[i * 3 + 0]; + nodes.write[i].under = r[i * 3 + 1]; + nodes.write[i].plane = r[i * 3 + 2]; } } diff --git a/core/math/delaunay.h b/core/math/delaunay.h index 09aebc773f..13fbc0c6ae 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -92,7 +92,7 @@ public: for (int j = 0; j < triangles.size(); j++) { if (circum_circle_contains(points, triangles[j], i)) { - triangles[j].bad = true; + triangles.write[j].bad = true; polygon.push_back(Edge(triangles[j].points[0], triangles[j].points[1])); polygon.push_back(Edge(triangles[j].points[1], triangles[j].points[2])); polygon.push_back(Edge(triangles[j].points[2], triangles[j].points[0])); @@ -109,8 +109,8 @@ public: for (int j = 0; j < polygon.size(); j++) { for (int k = j + 1; k < polygon.size(); k++) { if (edge_compare(points, polygon[j], polygon[k])) { - polygon[j].bad = true; - polygon[k].bad = true; + polygon.write[j].bad = true; + polygon.write[k].bad = true; } } } diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index 24f077a4ca..7ab28daf20 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -56,7 +56,7 @@ void Geometry::MeshData::optimize_vertices() { vtx_remap[idx] = ni; } - faces[i].indices[j] = vtx_remap[idx]; + faces.write[i].indices.write[j] = vtx_remap[idx]; } } @@ -74,8 +74,8 @@ void Geometry::MeshData::optimize_vertices() { vtx_remap[b] = ni; } - edges[i].a = vtx_remap[a]; - edges[i].b = vtx_remap[b]; + edges.write[i].a = vtx_remap[a]; + edges.write[i].b = vtx_remap[b]; } Vector<Vector3> new_vertices; @@ -84,7 +84,7 @@ void Geometry::MeshData::optimize_vertices() { for (int i = 0; i < vertices.size(); i++) { if (vtx_remap.has(i)) - new_vertices[vtx_remap[i]] = vertices[i]; + new_vertices.write[vtx_remap[i]] = vertices[i]; } vertices = new_vertices; } @@ -1014,8 +1014,8 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu Vector<_AtlasWorkRect> wrects; wrects.resize(p_rects.size()); for (int i = 0; i < p_rects.size(); i++) { - wrects[i].s = p_rects[i]; - wrects[i].idx = i; + wrects.write[i].s = p_rects[i]; + wrects.write[i].idx = i; } wrects.sort(); int widest = wrects[0].s.width; @@ -1033,7 +1033,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu Vector<int> hmax; hmax.resize(w); for (int j = 0; j < w; j++) - hmax[j] = 0; + hmax.write[j] = 0; //place them int ofs = 0; @@ -1052,8 +1052,8 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu from_y = hmax[ofs + k]; } - wrects[j].p.x = ofs; - wrects[j].p.y = from_y; + wrects.write[j].p.x = ofs; + wrects.write[j].p.y = from_y; int end_h = from_y + wrects[j].s.height; int end_w = ofs + wrects[j].s.width; if (ofs == 0) @@ -1061,7 +1061,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu for (int k = 0; k < wrects[j].s.width; k++) { - hmax[ofs + k] = end_h; + hmax.write[ofs + k] = end_h; } if (end_h > max_h) @@ -1101,7 +1101,7 @@ void Geometry::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_resu for (int i = 0; i < p_rects.size(); i++) { - r_result[results[best].result[i].idx] = results[best].result[i].p; + r_result.write[results[best].result[i].idx] = results[best].result[i].p; } r_size = Size2(results[best].max_w, results[best].max_h); diff --git a/core/math/geometry.h b/core/math/geometry.h index be998aef0b..186a05fb37 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -890,14 +890,14 @@ public: for (int i = 0; i < n; ++i) { while (k >= 2 && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0) k--; - H[k++] = P[i]; + H.write[k++] = P[i]; } // Build upper hull for (int i = n - 2, t = k + 1; i >= 0; i--) { while (k >= t && vec2_cross(H[k - 2], H[k - 1], P[i]) <= 0) k--; - H[k++] = P[i]; + H.write[k++] = P[i]; } H.resize(k); diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index 2371f49561..7db41756ed 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -242,18 +242,11 @@ void Basis::scale_local(const Vector3 &p_scale) { Basis Basis::scaled_local(const Vector3 &p_scale) const { Basis b; - b.set_scale(p_scale); + b.set_diagonal(p_scale); return (*this) * b; } -void Basis::set_scale(const Vector3 &p_scale) { - - set_axis(0, get_axis(0).normalized() * p_scale.x); - set_axis(1, get_axis(1).normalized() * p_scale.y); - set_axis(2, get_axis(2).normalized() * p_scale.z); -} - Vector3 Basis::get_scale_abs() const { return Vector3( diff --git a/core/math/matrix3.h b/core/math/matrix3.h index cd1b51baa6..9ff1a97dc9 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -112,7 +112,6 @@ public: void scale_local(const Vector3 &p_scale); Basis scaled_local(const Vector3 &p_scale) const; - void set_scale(const Vector3 &p_scale); Vector3 get_scale() const; Vector3 get_scale_abs() const; Vector3 get_scale_local() const; @@ -232,10 +231,13 @@ public: operator Quat() const { return get_quat(); } Basis(const Quat &p_quat) { set_quat(p_quat); }; + Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } + Basis(const Vector3 &p_euler) { set_euler(p_euler); } + Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); } + Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); } Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); } - Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) { elements[0] = row0; diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index fc90417413..cb923d264e 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -61,10 +61,10 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me Vector3 sp = p_points[i].snapped(Vector3(0.0001, 0.0001, 0.0001)); if (valid_cache.has(sp)) { - valid_points[i] = false; + valid_points.write[i] = false; //print_line("INVALIDATED: "+itos(i)); } else { - valid_points[i] = true; + valid_points.write[i] = true; valid_cache.insert(sp); } } @@ -452,7 +452,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me int idx = 0; for (List<Geometry::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) { - r_mesh.faces[idx++] = E->get(); + r_mesh.faces.write[idx++] = E->get(); } r_mesh.edges.resize(ret_edges.size()); idx = 0; @@ -461,7 +461,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me Geometry::MeshData::Edge e; e.a = E->key().vertices[0]; e.b = E->key().vertices[1]; - r_mesh.edges[idx++] = e; + r_mesh.edges.write[idx++] = e; } r_mesh.vertices = p_points; diff --git a/core/math/transform.cpp b/core/math/transform.cpp index d1e190f4b9..976e0f174e 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -127,12 +127,11 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) Quat dst_rot = p_transform.basis.get_rotation_quat(); Vector3 dst_loc = p_transform.origin; - Transform dst; //this could be made faster by using a single function in Basis.. - dst.basis = src_rot.slerp(dst_rot, p_c).normalized(); - dst.basis.set_scale(src_scale.linear_interpolate(dst_scale, p_c)); - dst.origin = src_loc.linear_interpolate(dst_loc, p_c); + Transform interp; + interp.basis.set_quat_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.linear_interpolate(dst_scale, p_c)); + interp.origin = src_loc.linear_interpolate(dst_loc, p_c); - return dst; + return interp; } void Transform::scale(const Vector3 &p_scale) { diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp index 563ba7268f..0edc0ea039 100644 --- a/core/math/triangulate.cpp +++ b/core/math/triangulate.cpp @@ -128,10 +128,10 @@ bool Triangulate::triangulate(const Vector<Vector2> &contour, Vector<int> &resul if (0.0 < get_area(contour)) for (int v = 0; v < n; v++) - V[v] = v; + V.write[v] = v; else for (int v = 0; v < n; v++) - V[v] = (n - 1) - v; + V.write[v] = (n - 1) - v; bool relaxed = false; @@ -182,7 +182,7 @@ bool Triangulate::triangulate(const Vector<Vector2> &contour, Vector<int> &resul /* remove v from remaining polygon */ for (s = v, t = v + 1; t < nv; s++, t++) - V[s] = V[t]; + V.write[s] = V[t]; nv--; diff --git a/core/method_bind.h b/core/method_bind.h index 41b500c401..7ee687ee40 100644 --- a/core/method_bind.h +++ b/core/method_bind.h @@ -354,7 +354,7 @@ public: for (int i = 0; i < p_info.arguments.size(); i++) { at[i + 1] = p_info.arguments[i].type; - names[i] = p_info.arguments[i].name; + names.write[i] = p_info.arguments[i].name; } set_argument_names(names); diff --git a/core/method_ptrcall.h b/core/method_ptrcall.h index 677e8e1fb2..2f6dcb3178 100644 --- a/core/method_ptrcall.h +++ b/core/method_ptrcall.h @@ -180,7 +180,7 @@ struct PtrToArg<const T *> { { \ PoolVector<m_type>::Read r = dvs->read(); \ for (int i = 0; i < len; i++) { \ - ret[i] = r[i]; \ + ret.write[i] = r[i]; \ } \ } \ return ret; \ @@ -207,7 +207,7 @@ struct PtrToArg<const T *> { { \ PoolVector<m_type>::Read r = dvs->read(); \ for (int i = 0; i < len; i++) { \ - ret[i] = r[i]; \ + ret.write[i] = r[i]; \ } \ } \ return ret; \ @@ -225,7 +225,7 @@ struct PtrToArg<const T *> { { \ PoolVector<m_type>::Read r = dvs->read(); \ for (int i = 0; i < len; i++) { \ - ret[i] = r[i]; \ + ret.write[i] = r[i]; \ } \ } \ return ret; \ @@ -252,7 +252,7 @@ struct PtrToArg<const T *> { { \ PoolVector<m_type>::Read r = dvs->read(); \ for (int i = 0; i < len; i++) { \ - ret[i] = r[i]; \ + ret.write[i] = r[i]; \ } \ } \ return ret; \ @@ -277,7 +277,7 @@ MAKE_VECARG_ALT(String, StringName); int len = arr->size(); \ ret.resize(len); \ for (int i = 0; i < len; i++) { \ - ret[i] = (*arr)[i]; \ + ret.write[i] = (*arr)[i]; \ } \ return ret; \ } \ @@ -298,7 +298,7 @@ MAKE_VECARG_ALT(String, StringName); int len = arr->size(); \ ret.resize(len); \ for (int i = 0; i < len; i++) { \ - ret[i] = (*arr)[i]; \ + ret.write[i] = (*arr)[i]; \ } \ return ret; \ } \ diff --git a/core/node_path.cpp b/core/node_path.cpp index 487d5ee8c6..7d4116fa1e 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -427,7 +427,7 @@ NodePath::NodePath(const String &p_path) { String name = path.substr(from, i - from); ERR_FAIL_INDEX(slice, data->path.size()); - data->path[slice++] = name; + data->path.write[slice++] = name; } from = i + 1; last_is_slash = true; diff --git a/core/object.cpp b/core/object.cpp index d86c60a3b8..8c9d3557f8 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -818,8 +818,8 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) { argptrs.resize(p_args.size()); for (int i = 0; i < p_args.size(); i++) { - args[i] = p_args[i]; - argptrs[i] = &args[i]; + args.write[i] = p_args[i]; + argptrs.write[i] = &args[i]; } Variant::CallError ce; @@ -1182,10 +1182,10 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int bind_mem.resize(p_argcount + c.binds.size()); for (int j = 0; j < p_argcount; j++) { - bind_mem[j] = p_args[j]; + bind_mem.write[j] = p_args[j]; } for (int j = 0; j < c.binds.size(); j++) { - bind_mem[p_argcount + j] = &c.binds[j]; + bind_mem.write[p_argcount + j] = &c.binds[j]; } args = (const Variant **)bind_mem.ptr(); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 033b4b12b9..3eac4428da 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -262,15 +262,15 @@ String FileAccess::get_token() const { while (!eof_reached()) { if (c <= ' ') { - if (!token.empty()) + if (token.length()) break; } else { - token.push_back(c); + token += c; } c = get_8(); } - token.push_back(0); + token += '0'; return String::utf8(token.get_data()); } @@ -293,7 +293,7 @@ class CharBuffer { for (int i = 0; i < written; i++) { - vector[i] = stack_buffer[i]; + vector.write[i] = stack_buffer[i]; } } diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index ca6446d015..e94ccb4f48 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -1080,3 +1080,122 @@ InputEventPanGesture::InputEventPanGesture() { delta = Vector2(0, 0); } +///////////////////////////// + +void InputEventMIDI::set_channel(const int p_channel) { + + channel = p_channel; +} + +int InputEventMIDI::get_channel() const { + return channel; +} + +void InputEventMIDI::set_message(const int p_message) { + + message = p_message; +} + +int InputEventMIDI::get_message() const { + return message; +} + +void InputEventMIDI::set_pitch(const int p_pitch) { + + pitch = p_pitch; +} + +int InputEventMIDI::get_pitch() const { + return pitch; +} + +void InputEventMIDI::set_velocity(const int p_velocity) { + + velocity = p_velocity; +} + +int InputEventMIDI::get_velocity() const { + return velocity; +} + +void InputEventMIDI::set_instrument(const int p_instrument) { + + instrument = p_instrument; +} + +int InputEventMIDI::get_instrument() const { + return instrument; +} + +void InputEventMIDI::set_pressure(const int p_pressure) { + + pressure = p_pressure; +} + +int InputEventMIDI::get_pressure() const { + return pressure; +} + +void InputEventMIDI::set_controller_number(const int p_controller_number) { + + controller_number = p_controller_number; +} + +int InputEventMIDI::get_controller_number() const { + return controller_number; +} + +void InputEventMIDI::set_controller_value(const int p_controller_value) { + + controller_value = p_controller_value; +} + +int InputEventMIDI::get_controller_value() const { + return controller_value; +} + +String InputEventMIDI::as_text() const { + + return "InputEventMIDI : channel=(" + itos(get_channel()) + "), message=(" + itos(get_message()) + ")"; +} + +void InputEventMIDI::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_channel", "channel"), &InputEventMIDI::set_channel); + ClassDB::bind_method(D_METHOD("get_channel"), &InputEventMIDI::get_channel); + ClassDB::bind_method(D_METHOD("set_message", "message"), &InputEventMIDI::set_message); + ClassDB::bind_method(D_METHOD("get_message"), &InputEventMIDI::get_message); + ClassDB::bind_method(D_METHOD("set_pitch", "pitch"), &InputEventMIDI::set_pitch); + ClassDB::bind_method(D_METHOD("get_pitch"), &InputEventMIDI::get_pitch); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &InputEventMIDI::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventMIDI::get_velocity); + ClassDB::bind_method(D_METHOD("set_instrument", "instrument"), &InputEventMIDI::set_instrument); + ClassDB::bind_method(D_METHOD("get_instrument"), &InputEventMIDI::get_instrument); + ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMIDI::set_pressure); + ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMIDI::get_pressure); + ClassDB::bind_method(D_METHOD("set_controller_number", "controller_number"), &InputEventMIDI::set_controller_number); + ClassDB::bind_method(D_METHOD("get_controller_number"), &InputEventMIDI::get_controller_number); + ClassDB::bind_method(D_METHOD("set_controller_value", "controller_value"), &InputEventMIDI::set_controller_value); + ClassDB::bind_method(D_METHOD("get_controller_value"), &InputEventMIDI::get_controller_value); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "channel"), "set_channel", "get_channel"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "message"), "set_message", "get_message"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "pitch"), "set_pitch", "get_pitch"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "velocity"), "set_velocity", "get_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "instrument"), "set_instrument", "get_instrument"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "pressure"), "set_pressure", "get_pressure"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_number"), "set_controller_number", "get_controller_number"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_value"), "set_controller_value", "get_controller_value"); +} + +InputEventMIDI::InputEventMIDI() { + + channel = 0; + message = 0; + pitch = 0; + velocity = 0; + instrument = 0; + pressure = 0; + controller_number = 0; + controller_value = 0; +} diff --git a/core/os/input_event.h b/core/os/input_event.h index bd1a85ce29..04126fee77 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -140,6 +140,16 @@ enum JoystickList { JOY_ANALOG_R2 = JOY_AXIS_7, }; +enum MidiMessageList { + MIDI_MESSAGE_NOTE_OFF = 0x8, + MIDI_MESSAGE_NOTE_ON = 0x9, + MIDI_MESSAGE_AFTERTOUCH = 0xA, + MIDI_MESSAGE_CONTROL_CHANGE = 0xB, + MIDI_MESSAGE_PROGRAM_CHANGE = 0xC, + MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD, + MIDI_MESSAGE_PITCH_BEND = 0xE, +}; + /** * Input Modifier Status * for keyboard/mouse events. @@ -525,4 +535,50 @@ public: InputEventPanGesture(); }; + +class InputEventMIDI : public InputEvent { + GDCLASS(InputEventMIDI, InputEvent) + + int channel; + int message; + int pitch; + int velocity; + int instrument; + int pressure; + int controller_number; + int controller_value; + +protected: + static void _bind_methods(); + +public: + void set_channel(const int p_channel); + int get_channel() const; + + void set_message(const int p_message); + int get_message() const; + + void set_pitch(const int p_pitch); + int get_pitch() const; + + void set_velocity(const int p_velocity); + int get_velocity() const; + + void set_instrument(const int p_instrument); + int get_instrument() const; + + void set_pressure(const int p_pressure); + int get_pressure() const; + + void set_controller_number(const int p_controller_number); + int get_controller_number() const; + + void set_controller_value(const int p_controller_value); + int get_controller_value() const; + + virtual String as_text() const; + + InputEventMIDI(); +}; + #endif diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp new file mode 100644 index 0000000000..7b4f84473c --- /dev/null +++ b/core/os/midi_driver.cpp @@ -0,0 +1,107 @@ +/*************************************************************************/ +/* midi_driver.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "midi_driver.h" + +#include "main/input_default.h" +#include "os/os.h" + +MIDIDriver *MIDIDriver::singleton = NULL; +MIDIDriver *MIDIDriver::get_singleton() { + + return singleton; +} + +void MIDIDriver::set_singleton() { + + singleton = this; +} + +void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) { + + Ref<InputEventMIDI> event; + event.instance(); + + if (length >= 1) { + event->set_channel(data[0] & 0xF); + event->set_message(data[0] >> 4); + } + + switch (event->get_message()) { + case MIDI_MESSAGE_AFTERTOUCH: + if (length >= 3) { + event->set_pitch(data[1]); + event->set_pressure(data[2]); + } + break; + + case MIDI_MESSAGE_CONTROL_CHANGE: + if (length >= 3) { + event->set_controller_number(data[1]); + event->set_controller_value(data[2]); + } + break; + + case MIDI_MESSAGE_NOTE_ON: + case MIDI_MESSAGE_NOTE_OFF: + case MIDI_MESSAGE_PITCH_BEND: + if (length >= 3) { + event->set_pitch(data[1]); + event->set_velocity(data[2]); + } + break; + + case MIDI_MESSAGE_PROGRAM_CHANGE: + if (length >= 2) { + event->set_instrument(data[1]); + } + break; + + case MIDI_MESSAGE_CHANNEL_PRESSURE: + if (length >= 2) { + event->set_pressure(data[1]); + } + break; + } + + InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); + id->parse_input_event(event); +} + +PoolStringArray MIDIDriver::get_connected_inputs() { + + PoolStringArray list; + return list; +} + +MIDIDriver::MIDIDriver() { + + set_singleton(); +} diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h new file mode 100644 index 0000000000..1a3a67a411 --- /dev/null +++ b/core/os/midi_driver.h @@ -0,0 +1,59 @@ +/*************************************************************************/ +/* midi_driver.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 MIDI_DRIVER_H +#define MIDI_DRIVER_H + +#include "core/variant.h" +#include "typedefs.h" +/** + * Multi-Platform abstraction for accessing to MIDI. + */ + +class MIDIDriver { + + static MIDIDriver *singleton; + +public: + static MIDIDriver *get_singleton(); + void set_singleton(); + + virtual Error open() = 0; + virtual void close() = 0; + + virtual PoolStringArray get_connected_inputs(); + + static void receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length); + + MIDIDriver(); + virtual ~MIDIDriver() {} +}; + +#endif diff --git a/core/os/os.cpp b/core/os/os.cpp index 89866e4044..8dcf0990fc 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -33,6 +33,7 @@ #include "dir_access.h" #include "input.h" #include "os/file_access.h" +#include "os/midi_driver.h" #include "project_settings.h" #include "servers/audio_server.h" #include "version_generated.gen.h" @@ -672,6 +673,15 @@ List<String> OS::get_restart_on_exit_arguments() const { return restart_commandline; } +PoolStringArray OS::get_connected_midi_inputs() { + + if (MIDIDriver::get_singleton()) + return MIDIDriver::get_singleton()->get_connected_inputs(); + + PoolStringArray list; + return list; +} + OS::OS() { void *volatile stack_bottom; diff --git a/core/os/os.h b/core/os/os.h index 4e0cb003fb..dd783408e8 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -189,6 +189,8 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual PoolStringArray get_connected_midi_inputs(); + virtual int get_screen_count() const { return 1; } virtual int get_current_screen() const { return 0; } virtual void set_current_screen(int p_screen) {} diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h index e0fb589767..3ff7db2a44 100644 --- a/core/os/threaded_array_processor.h +++ b/core/os/threaded_array_processor.h @@ -80,7 +80,7 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us threads.resize(OS::get_singleton()->get_processor_count()); for (int i = 0; i < threads.size(); i++) { - threads[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U> >, &data); + threads.write[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U> >, &data); } for (int i = 0; i < threads.size(); i++) { diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp index eaccdba9bf..45e060fa4a 100644 --- a/core/packed_data_container.cpp +++ b/core/packed_data_container.cpp @@ -251,7 +251,7 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd int len; encode_variant(p_data, NULL, len); tmpdata.resize(tmpdata.size() + len); - encode_variant(p_data, &tmpdata[pos], len); + encode_variant(p_data, &tmpdata.write[pos], len); return pos; } break; @@ -268,8 +268,8 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd uint32_t pos = tmpdata.size(); int len = d.size(); tmpdata.resize(tmpdata.size() + len * 12 + 8); - encode_uint32(TYPE_DICT, &tmpdata[pos + 0]); - encode_uint32(len, &tmpdata[pos + 4]); + encode_uint32(TYPE_DICT, &tmpdata.write[pos + 0]); + encode_uint32(len, &tmpdata.write[pos + 4]); List<Variant> keys; d.get_key_list(&keys); @@ -288,11 +288,11 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd int idx = 0; for (List<DictKey>::Element *E = sortk.front(); E; E = E->next()) { - encode_uint32(E->get().hash, &tmpdata[pos + 8 + idx * 12 + 0]); + encode_uint32(E->get().hash, &tmpdata.write[pos + 8 + idx * 12 + 0]); uint32_t ofs = _pack(E->get().key, tmpdata, string_cache); - encode_uint32(ofs, &tmpdata[pos + 8 + idx * 12 + 4]); + encode_uint32(ofs, &tmpdata.write[pos + 8 + idx * 12 + 4]); ofs = _pack(d[E->get().key], tmpdata, string_cache); - encode_uint32(ofs, &tmpdata[pos + 8 + idx * 12 + 8]); + encode_uint32(ofs, &tmpdata.write[pos + 8 + idx * 12 + 8]); idx++; } @@ -306,13 +306,13 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd uint32_t pos = tmpdata.size(); int len = a.size(); tmpdata.resize(tmpdata.size() + len * 4 + 8); - encode_uint32(TYPE_ARRAY, &tmpdata[pos + 0]); - encode_uint32(len, &tmpdata[pos + 4]); + encode_uint32(TYPE_ARRAY, &tmpdata.write[pos + 0]); + encode_uint32(len, &tmpdata.write[pos + 4]); for (int i = 0; i < len; i++) { uint32_t ofs = _pack(a[i], tmpdata, string_cache); - encode_uint32(ofs, &tmpdata[pos + 8 + i * 4]); + encode_uint32(ofs, &tmpdata.write[pos + 8 + i * 4]); } return pos; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 60e8933751..146b4870e8 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -627,7 +627,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str Vector<uint8_t> buff; buff.resize(len); - err = encode_variant(p_custom_features, &buff[0], len); + err = encode_variant(p_custom_features, buff.ptrw(), len); if (err != OK) { memdelete(file); ERR_FAIL_V(err); @@ -664,7 +664,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str Vector<uint8_t> buff; buff.resize(len); - err = encode_variant(value, &buff[0], len); + err = encode_variant(value, buff.ptrw(), len); if (err != OK) memdelete(file); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); @@ -959,7 +959,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("application/config/name", ""); GLOBAL_DEF("application/run/main_scene", ""); - custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "tscn,scn,res"); + custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"); GLOBAL_DEF("application/run/disable_stdout", false); GLOBAL_DEF("application/run/disable_stderr", false); GLOBAL_DEF("application/config/use_custom_user_dir", false); diff --git a/core/ring_buffer.h b/core/ring_buffer.h index de4757612a..00628a4ab3 100644 --- a/core/ring_buffer.h +++ b/core/ring_buffer.h @@ -137,7 +137,7 @@ public: Error write(const T &p_v) { ERR_FAIL_COND_V(space_left() < 1, FAILED); - data[inc(write_pos, 1)] = p_v; + data.write[inc(write_pos, 1)] = p_v; return OK; }; @@ -156,7 +156,7 @@ public: int total = end - pos; for (int i = 0; i < total; i++) { - data[pos + i] = p_buf[src++]; + data.write[pos + i] = p_buf[src++]; }; to_write -= total; pos = 0; @@ -196,7 +196,7 @@ public: data.resize(1 << p_power); if (old_size < new_size && read_pos > write_pos) { for (int i = 0; i < write_pos; i++) { - data[(old_size + i) & mask] = data[i]; + data.write[(old_size + i) & mask] = data[i]; }; write_pos = (old_size + write_pos) & mask; } else { diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp index 3b203f6977..692ff722f3 100644 --- a/core/safe_refcount.cpp +++ b/core/safe_refcount.cpp @@ -57,113 +57,113 @@ return m_val; \ } -_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(register uint32_t *pw){ +_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){ ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t) } -_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(register uint32_t *pw) { +_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) { return InterlockedDecrement((LONG volatile *)pw); } -_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(register uint32_t *pw) { +_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) { return InterlockedIncrement((LONG volatile *)pw); } -_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(register uint32_t *pw, register uint32_t val) { +_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) { return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val; } -_ALWAYS_INLINE_ uint32_t _atomic_add_impl(register uint32_t *pw, register uint32_t val) { +_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) { return InterlockedAdd((LONG volatile *)pw, val); } -_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(register uint32_t *pw, register uint32_t val){ +_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){ ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t) } -_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(register uint64_t *pw){ +_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){ ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t) } -_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(register uint64_t *pw) { +_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) { return InterlockedDecrement64((LONGLONG volatile *)pw); } -_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(register uint64_t *pw) { +_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) { return InterlockedIncrement64((LONGLONG volatile *)pw); } -_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(register uint64_t *pw, register uint64_t val) { +_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) { return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val; } -_ALWAYS_INLINE_ uint64_t _atomic_add_impl(register uint64_t *pw, register uint64_t val) { +_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) { return InterlockedAdd64((LONGLONG volatile *)pw, val); } -_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(register uint64_t *pw, register uint64_t val){ +_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){ ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t) } // The actual advertised functions; they'll call the right implementation -uint32_t atomic_conditional_increment(register uint32_t *pw) { +uint32_t atomic_conditional_increment(volatile uint32_t *pw) { return _atomic_conditional_increment_impl(pw); } -uint32_t atomic_decrement(register uint32_t *pw) { +uint32_t atomic_decrement(volatile uint32_t *pw) { return _atomic_decrement_impl(pw); } -uint32_t atomic_increment(register uint32_t *pw) { +uint32_t atomic_increment(volatile uint32_t *pw) { return _atomic_increment_impl(pw); } -uint32_t atomic_sub(register uint32_t *pw, register uint32_t val) { +uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) { return _atomic_sub_impl(pw, val); } -uint32_t atomic_add(register uint32_t *pw, register uint32_t val) { +uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) { return _atomic_add_impl(pw, val); } -uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val) { +uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) { return _atomic_exchange_if_greater_impl(pw, val); } -uint64_t atomic_conditional_increment(register uint64_t *pw) { +uint64_t atomic_conditional_increment(volatile uint64_t *pw) { return _atomic_conditional_increment_impl(pw); } -uint64_t atomic_decrement(register uint64_t *pw) { +uint64_t atomic_decrement(volatile uint64_t *pw) { return _atomic_decrement_impl(pw); } -uint64_t atomic_increment(register uint64_t *pw) { +uint64_t atomic_increment(volatile uint64_t *pw) { return _atomic_increment_impl(pw); } -uint64_t atomic_sub(register uint64_t *pw, register uint64_t val) { +uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) { return _atomic_sub_impl(pw, val); } -uint64_t atomic_add(register uint64_t *pw, register uint64_t val) { +uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) { return _atomic_add_impl(pw, val); } -uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val) { +uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) { return _atomic_exchange_if_greater_impl(pw, val); } #endif diff --git a/core/safe_refcount.h b/core/safe_refcount.h index eff209c2db..36bcf5e576 100644 --- a/core/safe_refcount.h +++ b/core/safe_refcount.h @@ -44,7 +44,7 @@ /* Bogus implementation unaware of multiprocessing */ template <class T> -static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) { +static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) { if (*pw == 0) return 0; @@ -55,7 +55,7 @@ static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) { } template <class T> -static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) { +static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) { (*pw)--; @@ -63,7 +63,7 @@ static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) { } template <class T> -static _ALWAYS_INLINE_ T atomic_increment(register T *pw) { +static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) { (*pw)++; @@ -71,7 +71,7 @@ static _ALWAYS_INLINE_ T atomic_increment(register T *pw) { } template <class T, class V> -static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) { +static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) { (*pw) -= val; @@ -79,7 +79,7 @@ static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) { } template <class T, class V> -static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) { +static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) { (*pw) += val; @@ -87,7 +87,7 @@ static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) { } template <class T, class V> -static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) { +static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) { if (val > *pw) *pw = val; @@ -103,7 +103,7 @@ static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V v // Clang states it supports GCC atomic builtins. template <class T> -static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) { +static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) { while (true) { T tmp = static_cast<T const volatile &>(*pw); @@ -115,31 +115,31 @@ static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) { } template <class T> -static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) { +static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) { return __sync_sub_and_fetch(pw, 1); } template <class T> -static _ALWAYS_INLINE_ T atomic_increment(register T *pw) { +static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) { return __sync_add_and_fetch(pw, 1); } template <class T, class V> -static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) { +static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) { return __sync_sub_and_fetch(pw, val); } template <class T, class V> -static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) { +static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) { return __sync_add_and_fetch(pw, val); } template <class T, class V> -static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) { +static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) { while (true) { T tmp = static_cast<T const volatile &>(*pw); @@ -153,19 +153,19 @@ static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V v #elif defined(_MSC_VER) // For MSVC use a separate compilation unit to prevent windows.h from polluting // the global namespace. -uint32_t atomic_conditional_increment(register uint32_t *pw); -uint32_t atomic_decrement(register uint32_t *pw); -uint32_t atomic_increment(register uint32_t *pw); -uint32_t atomic_sub(register uint32_t *pw, register uint32_t val); -uint32_t atomic_add(register uint32_t *pw, register uint32_t val); -uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val); - -uint64_t atomic_conditional_increment(register uint64_t *pw); -uint64_t atomic_decrement(register uint64_t *pw); -uint64_t atomic_increment(register uint64_t *pw); -uint64_t atomic_sub(register uint64_t *pw, register uint64_t val); -uint64_t atomic_add(register uint64_t *pw, register uint64_t val); -uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val); +uint32_t atomic_conditional_increment(volatile uint32_t *pw); +uint32_t atomic_decrement(volatile uint32_t *pw); +uint32_t atomic_increment(volatile uint32_t *pw); +uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val); +uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val); +uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val); + +uint64_t atomic_conditional_increment(volatile uint64_t *pw); +uint64_t atomic_decrement(volatile uint64_t *pw); +uint64_t atomic_increment(volatile uint64_t *pw); +uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val); +uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val); +uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val); #else //no threads supported? diff --git a/core/script_debugger_local.cpp b/core/script_debugger_local.cpp index 55d7270473..6949b5802b 100644 --- a/core/script_debugger_local.cpp +++ b/core/script_debugger_local.cpp @@ -325,7 +325,7 @@ void ScriptDebuggerLocal::idle_poll() { int ofs = 0; for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&pinfo[ofs], pinfo.size() - ofs); + ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&pinfo.write[ofs], pinfo.size() - ofs); } SortArray<ScriptLanguage::ProfilingInfo, _ScriptDebuggerLocalProfileInfoSort> sort; @@ -377,7 +377,7 @@ void ScriptDebuggerLocal::profiling_end() { int ofs = 0; for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&pinfo[ofs], pinfo.size() - ofs); + ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&pinfo.write[ofs], pinfo.size() - ofs); } SortArray<ScriptLanguage::ProfilingInfo, _ScriptDebuggerLocalProfileInfoSort> sort; diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 3955f222f9..c5daaeea47 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -783,13 +783,13 @@ void ScriptDebuggerRemote::_send_profiling_data(bool p_for_frame) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { if (p_for_frame) - ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&profile_info[ofs], profile_info.size() - ofs); + ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&profile_info.write[ofs], profile_info.size() - ofs); else - ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&profile_info[ofs], profile_info.size() - ofs); + ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&profile_info.write[ofs], profile_info.size() - ofs); } for (int i = 0; i < ofs; i++) { - profile_info_ptrs[i] = &profile_info[i]; + profile_info_ptrs.write[i] = &profile_info.write[i]; } SortArray<ScriptLanguage::ProfilingInfo *, ProfileInfoSort> sa; @@ -1054,7 +1054,7 @@ void ScriptDebuggerRemote::add_profiling_frame_data(const StringName &p_name, co if (idx == -1) { profile_frame_data.push_back(fd); } else { - profile_frame_data[idx] = fd; + profile_frame_data.write[idx] = fd; } } diff --git a/core/script_language.h b/core/script_language.h index 2950b35109..4e81b9b626 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -213,7 +213,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0; virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {} virtual bool is_using_templates() { return false; } - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const = 0; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const = 0; virtual String validate_path(const String &p_path) const { return ""; } virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; diff --git a/core/string_buffer.h b/core/string_buffer.h index 7e9b151bea..5d3be0ecf1 100644 --- a/core/string_buffer.h +++ b/core/string_buffer.h @@ -42,7 +42,7 @@ class StringBuffer { int string_length; _FORCE_INLINE_ CharType *current_buffer_ptr() { - return static_cast<Vector<CharType> &>(buffer).empty() ? short_buffer : buffer.ptrw(); + return static_cast<String &>(buffer).empty() ? short_buffer : buffer.ptrw(); } public: diff --git a/core/translation.cpp b/core/translation.cpp index aaa4de5912..78115c3749 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -1171,13 +1171,11 @@ void TranslationServer::_bind_methods() { void TranslationServer::load_translations() { String locale = get_locale(); - bool found = _load_translations("locale/translations"); //all + _load_translations("locale/translations"); //all + _load_translations("locale/translations_" + locale.substr(0, 2)); - if (_load_translations("locale/translations_" + locale.substr(0, 2))) - found = true; if (locale.substr(0, 2) != locale) { - if (_load_translations("locale/translations_" + locale)) - found = true; + _load_translations("locale/translations_" + locale); } } diff --git a/core/typedefs.h b/core/typedefs.h index 71771ea4e6..57afa3bdb4 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -58,12 +58,8 @@ #endif #ifndef _FORCE_INLINE_ -#ifdef DEBUG_ENABLED -#define _FORCE_INLINE_ inline -#else #define _FORCE_INLINE_ _ALWAYS_INLINE_ #endif -#endif //custom, gcc-safe offsetof, because gcc complains a lot. template <class T> @@ -267,7 +263,7 @@ static inline uint64_t BSWAP64(uint64_t x) { template <class T> struct Comparator { - inline bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); } + _ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); } }; void _global_lock(); diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index b9a2fdd0ac..3d90608dd7 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -39,7 +39,7 @@ void UndoRedo::_discard_redo() { for (int i = current_action + 1; i < actions.size(); i++) { - for (List<Operation>::Element *E = actions[i].do_ops.front(); E; E = E->next()) { + for (List<Operation>::Element *E = actions.write[i].do_ops.front(); E; E = E->next()) { if (E->get().type == Operation::TYPE_REFERENCE) { @@ -70,7 +70,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { if (p_mode == MERGE_ENDS) { // Clear all do ops from last action, and delete all object references - List<Operation>::Element *E = actions[current_action + 1].do_ops.front(); + List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); while (E) { @@ -83,11 +83,11 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { } E = E->next(); - actions[current_action + 1].do_ops.pop_front(); + actions.write[current_action + 1].do_ops.pop_front(); } } - actions[actions.size() - 1].last_tick = ticks; + actions.write[actions.size() - 1].last_tick = ticks; merge_mode = p_mode; @@ -122,7 +122,7 @@ void UndoRedo::add_do_method(Object *p_object, const String &p_method, VARIANT_A for (int i = 0; i < VARIANT_ARG_MAX; i++) { do_op.args[i] = *argptr[i]; } - actions[current_action + 1].do_ops.push_back(do_op); + actions.write[current_action + 1].do_ops.push_back(do_op); } void UndoRedo::add_undo_method(Object *p_object, const String &p_method, VARIANT_ARG_DECLARE) { @@ -147,7 +147,7 @@ void UndoRedo::add_undo_method(Object *p_object, const String &p_method, VARIANT for (int i = 0; i < VARIANT_ARG_MAX; i++) { undo_op.args[i] = *argptr[i]; } - actions[current_action + 1].undo_ops.push_back(undo_op); + actions.write[current_action + 1].undo_ops.push_back(undo_op); } void UndoRedo::add_do_property(Object *p_object, const String &p_property, const Variant &p_value) { @@ -162,7 +162,7 @@ void UndoRedo::add_do_property(Object *p_object, const String &p_property, const do_op.type = Operation::TYPE_PROPERTY; do_op.name = p_property; do_op.args[0] = p_value; - actions[current_action + 1].do_ops.push_back(do_op); + actions.write[current_action + 1].do_ops.push_back(do_op); } void UndoRedo::add_undo_property(Object *p_object, const String &p_property, const Variant &p_value) { @@ -182,7 +182,7 @@ void UndoRedo::add_undo_property(Object *p_object, const String &p_property, con undo_op.type = Operation::TYPE_PROPERTY; undo_op.name = p_property; undo_op.args[0] = p_value; - actions[current_action + 1].undo_ops.push_back(undo_op); + actions.write[current_action + 1].undo_ops.push_back(undo_op); } void UndoRedo::add_do_reference(Object *p_object) { @@ -195,7 +195,7 @@ void UndoRedo::add_do_reference(Object *p_object) { do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object)); do_op.type = Operation::TYPE_REFERENCE; - actions[current_action + 1].do_ops.push_back(do_op); + actions.write[current_action + 1].do_ops.push_back(do_op); } void UndoRedo::add_undo_reference(Object *p_object) { @@ -213,7 +213,7 @@ void UndoRedo::add_undo_reference(Object *p_object) { undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object)); undo_op.type = Operation::TYPE_REFERENCE; - actions[current_action + 1].undo_ops.push_back(undo_op); + actions.write[current_action + 1].undo_ops.push_back(undo_op); } void UndoRedo::_pop_history_tail() { @@ -223,7 +223,7 @@ void UndoRedo::_pop_history_tail() { if (!actions.size()) return; - for (List<Operation>::Element *E = actions[0].undo_ops.front(); E; E = E->next()) { + for (List<Operation>::Element *E = actions.write[0].undo_ops.front(); E; E = E->next()) { if (E->get().type == Operation::TYPE_REFERENCE) { @@ -307,7 +307,7 @@ bool UndoRedo::redo() { return false; //nothing to redo current_action++; - _process_operation_list(actions[current_action].do_ops.front()); + _process_operation_list(actions.write[current_action].do_ops.front()); version++; return true; @@ -318,7 +318,7 @@ bool UndoRedo::undo() { ERR_FAIL_COND_V(action_level > 0, false); if (current_action < 0) return false; //nothing to redo - _process_operation_list(actions[current_action].undo_ops.front()); + _process_operation_list(actions.write[current_action].undo_ops.front()); current_action--; version--; diff --git a/core/ustring.cpp b/core/ustring.cpp index bee5f5ffdb..84613610a9 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -102,6 +102,15 @@ bool CharString::operator<(const CharString &p_right) const { return is_str_less(get_data(), p_right.get_data()); } +CharString &CharString::operator+=(char p_char) { + + resize(size() ? size() + 1 : 2); + set(length(), 0); + set(length() - 1, p_char); + + return *this; +} + const char *CharString::get_data() const { if (size()) @@ -161,14 +170,21 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) { return; } - resize(len + 1); - set(len, 0); + copy_from_unchecked(p_cstr, len); +} - CharType *dst = &operator[](0); +// assumes the following have already been validated: +// p_char != NULL +// p_length > 0 +// p_length <= p_char strlen +void String::copy_from_unchecked(const CharType *p_char, int p_length) { + resize(p_length + 1); + set(p_length, 0); - for (int i = 0; i < len; i++) { + CharType *dst = &operator[](0); - dst[i] = p_cstr[i]; + for (int i = 0; i < p_length; i++) { + dst[i] = p_char[i]; } } @@ -921,8 +937,8 @@ String String::to_upper() const { for (int i = 0; i < upper.size(); i++) { - const char s = upper[i]; - const char t = _find_upper(s); + const CharType s = upper[i]; + const CharType t = _find_upper(s); if (s != t) // avoid copy on write upper[i] = t; } @@ -936,8 +952,8 @@ String String::to_lower() const { for (int i = 0; i < lower.size(); i++) { - const char s = lower[i]; - const char t = _find_lower(s); + const CharType s = lower[i]; + const CharType t = _find_lower(s); if (s != t) // avoid copy on write lower[i] = t; } @@ -1571,6 +1587,7 @@ String::String(const char *p_str) { copy_from(p_str); } + String::String(const CharType *p_str, int p_clip_to_len) { copy_from(p_str, p_clip_to_len); @@ -2190,7 +2207,7 @@ Vector<uint8_t> String::md5_buffer() const { Vector<uint8_t> ret; ret.resize(16); for (int i = 0; i < 16; i++) { - ret[i] = ctx.digest[i]; + ret.write[i] = ctx.digest[i]; }; return ret; @@ -2207,7 +2224,7 @@ Vector<uint8_t> String::sha256_buffer() const { Vector<uint8_t> ret; ret.resize(32); for (int i = 0; i < 32; i++) { - ret[i] = hash[i]; + ret.write[i] = hash[i]; } return ret; @@ -2246,7 +2263,9 @@ String String::substr(int p_from, int p_chars) const { return String(*this); } - return String(&c_str()[p_from], p_chars); + String s = String(); + s.copy_from_unchecked(&c_str()[p_from], p_chars); + return s; } int String::find_last(const String &p_str) const { @@ -2664,7 +2683,7 @@ Vector<String> String::bigrams() const { } b.resize(n_pairs); for (int i = 0; i < n_pairs; i++) { - b[i] = substr(i, 2); + b.write[i] = substr(i, 2); } return b; } @@ -2759,7 +2778,7 @@ String String::format(const Variant &values, String placeholder) const { val = val.substr(1, val.length() - 2); } - new_string = new_string.replacen(placeholder.replace("_", key), val); + new_string = new_string.replace(placeholder.replace("_", key), val); } else { ERR_PRINT(String("STRING.format Inner Array size != 2 ").ascii().get_data()); } @@ -2772,7 +2791,7 @@ String String::format(const Variant &values, String placeholder) const { val = val.substr(1, val.length() - 2); } - new_string = new_string.replacen(placeholder.replace("_", i_as_str), val); + new_string = new_string.replace(placeholder.replace("_", i_as_str), val); } } } else if (values.get_type() == Variant::DICTIONARY) { @@ -2792,7 +2811,7 @@ String String::format(const Variant &values, String placeholder) const { val = val.substr(1, val.length() - 2); } - new_string = new_string.replacen(placeholder.replace("_", key), val); + new_string = new_string.replace(placeholder.replace("_", key), val); } } else { ERR_PRINT(String("Invalid type: use Array or Dictionary.").ascii().get_data()); @@ -3023,14 +3042,14 @@ String String::strip_escapes() const { return substr(beg, end - beg); } -String String::lstrip(const Vector<CharType> &p_chars) const { +String String::lstrip(const String &p_chars) const { int len = length(); int beg; for (beg = 0; beg < len; beg++) { - if (p_chars.find(operator[](beg)) == -1) + if (p_chars.find(&ptr()[beg]) == -1) break; } @@ -3040,14 +3059,14 @@ String String::lstrip(const Vector<CharType> &p_chars) const { return substr(beg, len - beg); } -String String::rstrip(const Vector<CharType> &p_chars) const { +String String::rstrip(const String &p_chars) const { int len = length(); int end; for (end = len - 1; end >= 0; end--) { - if (p_chars.find(operator[](end)) == -1) + if (p_chars.find(&ptr()[end]) == -1) break; } @@ -3859,10 +3878,10 @@ String String::percent_decode() const { c += d; i += 2; } - pe.push_back(c); + pe += c; } - pe.push_back(0); + pe += '0'; return String::utf8(pe.ptr()); } diff --git a/core/ustring.h b/core/ustring.h index b57e9629d9..3b4405833c 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -32,6 +32,7 @@ #define RSTRING_H #include "array.h" +#include "cowdata.h" #include "typedefs.h" #include "vector.h" @@ -39,9 +40,27 @@ @author red <red@killy> */ -class CharString : public Vector<char> { +class CharString { + + CowData<char> _cowdata; + public: + _FORCE_INLINE_ char *ptrw() { return _cowdata.ptrw(); } + _FORCE_INLINE_ const char *ptr() const { return _cowdata.ptr(); } + _FORCE_INLINE_ int size() const { return _cowdata.size(); } + Error resize(int p_size) { return _cowdata.resize(p_size); } + + _FORCE_INLINE_ char get(int p_index) { return _cowdata.get(p_index); } + _FORCE_INLINE_ const char get(int p_index) const { return _cowdata.get(p_index); } + _FORCE_INLINE_ void set(int p_index, const char &p_elem) { _cowdata.set(p_index, p_elem); } + _FORCE_INLINE_ char &operator[](int p_index) { return _cowdata.get_m(p_index); } + _FORCE_INLINE_ const char &operator[](int p_index) const { return _cowdata.get(p_index); } + + _FORCE_INLINE_ CharString() {} + _FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); } + bool operator<(const CharString &p_right) const; + CharString &operator+=(char p_char); int length() const { return size() ? size() - 1 : 0; } const char *get_data() const; operator const char *() { return get_data(); }; @@ -60,11 +79,14 @@ struct StrRange { } }; -class String : public Vector<CharType> { +class String { + + CowData<CharType> _cowdata; void copy_from(const char *p_cstr); void copy_from(const CharType *p_cstr, int p_clip_to = -1); void copy_from(const CharType &p_char); + void copy_from_unchecked(const CharType *p_char, int p_length); bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const; public: @@ -73,6 +95,21 @@ public: npos = -1 ///<for "some" compatibility with std::string (npos is a huge value in std::string) }; + _FORCE_INLINE_ CharType *ptrw() { return _cowdata.ptrw(); } + _FORCE_INLINE_ const CharType *ptr() const { return _cowdata.ptr(); } + + void remove(int p_index) { _cowdata.remove(p_index); } + + _FORCE_INLINE_ void clear() { resize(0); } + + _FORCE_INLINE_ CharType get(int p_index) { return _cowdata.get(p_index); } + _FORCE_INLINE_ const CharType get(int p_index) const { return _cowdata.get(p_index); } + _FORCE_INLINE_ void set(int p_index, const CharType &p_elem) { _cowdata.set(p_index, p_elem); } + _FORCE_INLINE_ int size() const { return _cowdata.size(); } + Error resize(int p_size) { return _cowdata.resize(p_size); } + _FORCE_INLINE_ CharType &operator[](int p_index) { return _cowdata.get_m(p_index); } + _FORCE_INLINE_ const CharType &operator[](int p_index) const { return _cowdata.get(p_index); } + bool operator==(const String &p_str) const; bool operator!=(const String &p_str) const; String operator+(const String &p_str) const; @@ -191,8 +228,8 @@ public: String dedent() const; String strip_edges(bool left = true, bool right = true) const; String strip_escapes() const; - String lstrip(const Vector<CharType> &p_chars) const; - String rstrip(const Vector<CharType> &p_chars) const; + String lstrip(const String &p_chars) const; + String rstrip(const String &p_chars) const; String get_extension() const; String get_basename() const; String plus_file(const String &p_file) const; @@ -253,9 +290,10 @@ public: * The constructors must not depend on other overloads */ /* String(CharType p_char);*/ - inline String() {} - inline String(const String &p_str) : - Vector(p_str) {} + + _FORCE_INLINE_ String() {} + _FORCE_INLINE_ String(const String &p_str) { _cowdata._ref(p_str._cowdata); } + String(const char *p_str); String(const CharType *p_str, int p_clip_to_len = -1); String(const StrRange &p_range); diff --git a/core/variant.cpp b/core/variant.cpp index c48aa57652..e4be5520bc 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1878,7 +1878,7 @@ Variant::operator Vector<RID>() const { Vector<RID> rids; rids.resize(va.size()); for (int i = 0; i < rids.size(); i++) - rids[i] = va[i]; + rids.write[i] = va[i]; return rids; } @@ -1891,7 +1891,7 @@ Variant::operator Vector<Vector2>() const { return Vector<Vector2>(); to.resize(len); PoolVector<Vector2>::Read r = from.read(); - Vector2 *w = &to[0]; + Vector2 *w = to.ptrw(); for (int i = 0; i < len; i++) { w[i] = r[i]; @@ -1945,7 +1945,7 @@ Variant::operator Vector<Plane>() const { planes.resize(va_size); for (int i = 0; i < va_size; i++) - planes[i] = va[i]; + planes.write[i] = va[i]; return planes; } @@ -1958,7 +1958,7 @@ Variant::operator Vector<Variant>() const { to.resize(len); for (int i = 0; i < len; i++) { - to[i] = from[i]; + to.write[i] = from[i]; } return to; } @@ -1971,7 +1971,7 @@ Variant::operator Vector<uint8_t>() const { to.resize(len); for (int i = 0; i < len; i++) { - to[i] = from[i]; + to.write[i] = from[i]; } return to; } @@ -1983,7 +1983,7 @@ Variant::operator Vector<int>() const { to.resize(len); for (int i = 0; i < len; i++) { - to[i] = from[i]; + to.write[i] = from[i]; } return to; } @@ -1995,7 +1995,7 @@ Variant::operator Vector<real_t>() const { to.resize(len); for (int i = 0; i < len; i++) { - to[i] = from[i]; + to.write[i] = from[i]; } return to; } @@ -2008,7 +2008,7 @@ Variant::operator Vector<String>() const { to.resize(len); for (int i = 0; i < len; i++) { - to[i] = from[i]; + to.write[i] = from[i]; } return to; } @@ -2020,7 +2020,7 @@ Variant::operator Vector<StringName>() const { to.resize(len); for (int i = 0; i < len; i++) { - to[i] = from[i]; + to.write[i] = from[i]; } return to; } @@ -2034,7 +2034,7 @@ Variant::operator Vector<Vector3>() const { return Vector<Vector3>(); to.resize(len); PoolVector<Vector3>::Read r = from.read(); - Vector3 *w = &to[0]; + Vector3 *w = to.ptrw(); for (int i = 0; i < len; i++) { w[i] = r[i]; @@ -2050,7 +2050,7 @@ Variant::operator Vector<Color>() const { return Vector<Color>(); to.resize(len); PoolVector<Color>::Read r = from.read(); - Color *w = &to[0]; + Color *w = to.ptrw(); for (int i = 0; i < len; i++) { w[i] = r[i]; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index e6f36ecbf1..20a2929dc0 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -64,7 +64,7 @@ struct _VariantCall { if (arg_count == 0) return true; - Variant::Type *tptr = &arg_types[0]; + const Variant::Type *tptr = &arg_types[0]; for (int i = 0; i < arg_count; i++) { @@ -446,8 +446,12 @@ struct _VariantCall { VCALL_LOCALMEM1(Quat, set_euler); VCALL_LOCALMEM2(Quat, set_axis_angle); - VCALL_LOCALMEM0R(Color, to_rgba32); VCALL_LOCALMEM0R(Color, to_argb32); + VCALL_LOCALMEM0R(Color, to_abgr32); + VCALL_LOCALMEM0R(Color, to_rgba32); + VCALL_LOCALMEM0R(Color, to_argb64); + VCALL_LOCALMEM0R(Color, to_abgr64); + VCALL_LOCALMEM0R(Color, to_rgba64); VCALL_LOCALMEM0R(Color, gray); VCALL_LOCALMEM0R(Color, inverted); VCALL_LOCALMEM0R(Color, contrasted); @@ -1613,8 +1617,12 @@ void register_variant_methods() { ADDFUNC1(QUAT, NIL, Quat, set_euler, VECTOR3, "euler", varray()); ADDFUNC2(QUAT, NIL, Quat, set_axis_angle, VECTOR3, "axis", REAL, "angle", varray()); - ADDFUNC0R(COLOR, INT, Color, to_rgba32, varray()); ADDFUNC0R(COLOR, INT, Color, to_argb32, varray()); + ADDFUNC0R(COLOR, INT, Color, to_abgr32, varray()); + ADDFUNC0R(COLOR, INT, Color, to_rgba32, varray()); + ADDFUNC0R(COLOR, INT, Color, to_argb64, varray()); + ADDFUNC0R(COLOR, INT, Color, to_abgr64, varray()); + ADDFUNC0R(COLOR, INT, Color, to_rgba64, varray()); ADDFUNC0R(COLOR, REAL, Color, gray, varray()); ADDFUNC0R(COLOR, COLOR, Color, inverted, varray()); ADDFUNC0R(COLOR, COLOR, Color, contrasted, varray()); diff --git a/core/vector.h b/core/vector.h index f586471e27..7e3da34be0 100644 --- a/core/vector.h +++ b/core/vector.h @@ -36,129 +36,69 @@ * @author Juan Linietsky * Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use PoolVector for large arrays. */ +#include "cowdata.h" #include "error_macros.h" #include "os/memory.h" -#include "safe_refcount.h" #include "sort.h" template <class T> -class Vector { - - mutable T *_ptr; - - // internal helpers +class VectorWriteProxy { + friend class Vector<T>; + Vector<T> &_parent; - _FORCE_INLINE_ uint32_t *_get_refcount() const { + _FORCE_INLINE_ VectorWriteProxy(Vector<T> &parent) : + _parent(parent){}; + VectorWriteProxy(const VectorWriteProxy<T> &p_other); - if (!_ptr) - return NULL; - - return reinterpret_cast<uint32_t *>(_ptr) - 2; - } - - _FORCE_INLINE_ uint32_t *_get_size() const { - - if (!_ptr) - return NULL; - - return reinterpret_cast<uint32_t *>(_ptr) - 1; - } - _FORCE_INLINE_ T *_get_data() const { - - if (!_ptr) - return NULL; - return reinterpret_cast<T *>(_ptr); - } - - _FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const { - //return nearest_power_of_2_templated(p_elements*sizeof(T)+sizeof(SafeRefCount)+sizeof(int)); - return next_power_of_2(p_elements * sizeof(T)); - } +public: + _FORCE_INLINE_ T &operator[](int p_index) { + CRASH_BAD_INDEX(p_index, _parent.size()); - _FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const { -#if defined(_add_overflow) && defined(_mul_overflow) - size_t o; - size_t p; - if (_mul_overflow(p_elements, sizeof(T), &o)) return false; - *out = next_power_of_2(o); - if (_add_overflow(o, static_cast<size_t>(32), &p)) return false; //no longer allocated here - return true; -#else - // Speed is more important than correctness here, do the operations unchecked - // and hope the best - *out = _get_alloc_size(p_elements); - return true; -#endif + return _parent.ptrw()[p_index]; } +}; - void _unref(void *p_data); +template <class T> +class Vector { + friend class VectorWriteProxy<T>; - void _copy_from(const Vector &p_from); - void _copy_on_write(); + CowData<T> _cowdata; public: - _FORCE_INLINE_ T *ptrw() { - if (!_ptr) return NULL; - _copy_on_write(); - return (T *)_get_data(); - } - _FORCE_INLINE_ const T *ptr() const { - if (!_ptr) return NULL; - return _get_data(); - } - - _FORCE_INLINE_ void clear() { resize(0); } + VectorWriteProxy<T> write; - _FORCE_INLINE_ int size() const { - uint32_t *size = (uint32_t *)_get_size(); - if (size) - return *size; - else - return 0; - } - _FORCE_INLINE_ bool empty() const { return _ptr == 0; } - Error resize(int p_size); bool push_back(const T &p_elem); - void remove(int p_index); + void remove(int p_index) { _cowdata.remove(p_index); } void erase(const T &p_val) { int idx = find(p_val); if (idx >= 0) remove(idx); }; void invert(); - template <class T_val> - int find(const T_val &p_val, int p_from = 0) const; - - void set(int p_index, const T &p_elem); - T get(int p_index) const; - - inline T &operator[](int p_index) { - - CRASH_BAD_INDEX(p_index, size()); - - _copy_on_write(); // wants to write, so copy on write. - - return _get_data()[p_index]; - } - - inline const T &operator[](int p_index) const { - - CRASH_BAD_INDEX(p_index, size()); + _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } + _FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); } + _FORCE_INLINE_ void clear() { resize(0); } + _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); } - // no cow needed, since it's reading - return _get_data()[p_index]; - } + _FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); } + _FORCE_INLINE_ const T get(int p_index) const { return _cowdata.get(p_index); } + _FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } + _FORCE_INLINE_ int size() const { return _cowdata.size(); } + Error resize(int p_size) { return _cowdata.resize(p_size); } + _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } + Error insert(int p_pos, const T &p_val) { return _cowdata.insert(p_pos, p_val); } - Error insert(int p_pos, const T &p_val); + void append_array(const Vector<T> &p_other); template <class C> void sort_custom() { - int len = size(); + int len = _cowdata.size(); if (len == 0) return; - T *data = &operator[](0); + + T *data = ptrw(); SortArray<T, C> sorter; sorter.sort(data, len); } @@ -170,7 +110,7 @@ public: void ordered_insert(const T &p_val) { int i; - for (i = 0; i < size(); i++) { + for (i = 0; i < _cowdata.size(); i++) { if (p_val < operator[](i)) { break; @@ -179,173 +119,50 @@ public: insert(i, p_val); } - void operator=(const Vector &p_from); - Vector(const Vector &p_from); + int find(const T &p_val, int p_from = 0) const { + int ret = -1; + if (p_from < 0 || size() == 0) + return ret; - _FORCE_INLINE_ Vector(); - _FORCE_INLINE_ ~Vector(); -}; - -template <class T> -void Vector<T>::_unref(void *p_data) { - - if (!p_data) - return; - - uint32_t *refc = _get_refcount(); - - if (atomic_decrement(refc) > 0) - return; // still in use - // clean up - - uint32_t *count = _get_size(); - T *data = (T *)(count + 1); - - for (uint32_t i = 0; i < *count; i++) { - // call destructors - data[i].~T(); - } - - // free mem - Memory::free_static((uint8_t *)p_data, true); -} - -template <class T> -void Vector<T>::_copy_on_write() { - - if (!_ptr) - return; - - uint32_t *refc = _get_refcount(); + for (int i = p_from; i < size(); i++) { - if (*refc > 1) { - /* in use by more than me */ - uint32_t current_size = *_get_size(); - - uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true); - - *(mem_new - 2) = 1; //refcount - *(mem_new - 1) = current_size; //size - - T *_data = (T *)(mem_new); - - // initialize new elements - for (uint32_t i = 0; i < current_size; i++) { - - memnew_placement(&_data[i], T(_get_data()[i])); - } - - _unref(_ptr); - _ptr = _data; - } -} - -template <class T> -template <class T_val> -int Vector<T>::find(const T_val &p_val, int p_from) const { - - int ret = -1; - if (p_from < 0 || size() == 0) - return ret; - - for (int i = p_from; i < size(); i++) { - - if (operator[](i) == p_val) { - ret = i; - break; + if (ptr()[i] == p_val) { + ret = i; + break; + }; }; - }; - return ret; -} - -template <class T> -Error Vector<T>::resize(int p_size) { - - ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER); - - if (p_size == size()) - return OK; - - if (p_size == 0) { - // wants to clean up - _unref(_ptr); - _ptr = NULL; - return OK; + return ret; } - // possibly changing size, copy on write - _copy_on_write(); - - size_t alloc_size; - ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY); - - if (p_size > size()) { - - if (size() == 0) { - // alloc from scratch - uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true); - ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY); - *(ptr - 1) = 0; //size, currently none - *(ptr - 2) = 1; //refcount - - _ptr = (T *)ptr; - - } else { - void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true); - ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY); - _ptr = (T *)(_ptrnew); - } - - // construct the newly created elements - T *elems = _get_data(); - - for (int i = *_get_size(); i < p_size; i++) { - - memnew_placement(&elems[i], T); - } - - *_get_size() = p_size; - - } else if (p_size < size()) { - - // deinitialize no longer needed elements - for (uint32_t i = p_size; i < *_get_size(); i++) { - - T *t = &_get_data()[i]; - t->~T(); - } - - void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true); - ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY); - - _ptr = (T *)(_ptrnew); - - *_get_size() = p_size; + _FORCE_INLINE_ Vector() : + write(VectorWriteProxy<T>(*this)) {} + _FORCE_INLINE_ Vector(const Vector &p_from) : + write(VectorWriteProxy<T>(*this)) { _cowdata._ref(p_from._cowdata); } + inline Vector &operator=(const Vector &p_from) { + _cowdata._ref(p_from._cowdata); + return *this; } - - return OK; -} +}; template <class T> void Vector<T>::invert() { for (int i = 0; i < size() / 2; i++) { - - SWAP(operator[](i), operator[](size() - i - 1)); + T *p = ptrw(); + SWAP(p[i], p[size() - i - 1]); } } template <class T> -void Vector<T>::set(int p_index, const T &p_elem) { - - operator[](p_index) = p_elem; -} - -template <class T> -T Vector<T>::get(int p_index) const { - - return operator[](p_index); +void Vector<T>::append_array(const Vector<T> &p_other) { + const int ds = p_other.size(); + if (ds == 0) + return; + const int bs = size(); + resize(bs + ds); + for (int i = 0; i < ds; ++i) + ptrw()[bs + i] = p_other[i]; } template <class T> @@ -358,72 +175,4 @@ bool Vector<T>::push_back(const T &p_elem) { return false; } -template <class T> -void Vector<T>::remove(int p_index) { - - ERR_FAIL_INDEX(p_index, size()); - T *p = ptrw(); - int len = size(); - for (int i = p_index; i < len - 1; i++) { - - p[i] = p[i + 1]; - }; - - resize(len - 1); -}; - -template <class T> -void Vector<T>::_copy_from(const Vector &p_from) { - - if (_ptr == p_from._ptr) - return; // self assign, do nothing. - - _unref(_ptr); - _ptr = NULL; - - if (!p_from._ptr) - return; //nothing to do - - if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference - _ptr = p_from._ptr; - } -} - -template <class T> -void Vector<T>::operator=(const Vector &p_from) { - - _copy_from(p_from); -} - -template <class T> -Error Vector<T>::insert(int p_pos, const T &p_val) { - - ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER); - resize(size() + 1); - for (int i = (size() - 1); i > p_pos; i--) - set(i, get(i - 1)); - set(p_pos, p_val); - - return OK; -} - -template <class T> -Vector<T>::Vector(const Vector &p_from) { - - _ptr = NULL; - _copy_from(p_from); -} - -template <class T> -Vector<T>::Vector() { - - _ptr = NULL; -} - -template <class T> -Vector<T>::~Vector() { - - _unref(_ptr); -} - #endif diff --git a/core/vmap.h b/core/vmap.h index 8636c02997..ce0ddc4ec6 100644 --- a/core/vmap.h +++ b/core/vmap.h @@ -31,8 +31,8 @@ #ifndef VMAP_H #define VMAP_H +#include "cowdata.h" #include "typedefs.h" -#include "vector.h" template <class T, class V> class VMap { @@ -51,17 +51,17 @@ class VMap { } }; - Vector<_Pair> _data; + CowData<_Pair> _cowdata; _FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const { r_exact = false; - if (_data.empty()) + if (_cowdata.empty()) return 0; int low = 0; - int high = _data.size() - 1; - const _Pair *a = &_data[0]; + int high = _cowdata.size() - 1; + const _Pair *a = _cowdata.ptr(); int middle = 0; #if DEBUG_ENABLED @@ -89,13 +89,13 @@ class VMap { _FORCE_INLINE_ int _find_exact(const T &p_val) const { - if (_data.empty()) + if (_cowdata.empty()) return -1; int low = 0; - int high = _data.size() - 1; + int high = _cowdata.size() - 1; int middle; - const _Pair *a = &_data[0]; + const _Pair *a = _cowdata.ptr(); while (low <= high) { middle = (low + high) / 2; @@ -118,10 +118,10 @@ public: bool exact; int pos = _find(p_key, exact); if (exact) { - _data[pos].value = p_val; + _cowdata.get_m(pos).value = p_val; return pos; } - _data.insert(pos, _Pair(p_key, p_val)); + _cowdata.insert(pos, _Pair(p_key, p_val)); return pos; } @@ -135,7 +135,7 @@ public: int pos = _find_exact(p_val); if (pos < 0) return; - _data.remove(pos); + _cowdata.remove(pos); } int find(const T &p_val) const { @@ -149,37 +149,37 @@ public: return _find(p_val, exact); } - _FORCE_INLINE_ int size() const { return _data.size(); } - _FORCE_INLINE_ bool empty() const { return _data.empty(); } + _FORCE_INLINE_ int size() const { return _cowdata.size(); } + _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); } const _Pair *get_array() const { - return _data.ptr(); + return _cowdata.ptr(); } _Pair *get_array() { - return _data.ptr(); + return _cowdata.ptrw(); } const V &getv(int p_index) const { - return _data[p_index].value; + return _cowdata.get(p_index).value; } V &getv(int p_index) { - return _data[p_index].value; + return _cowdata.get_m(p_index).value; } const T &getk(int p_index) const { - return _data[p_index].key; + return _cowdata.get(p_index).key; } T &getk(int p_index) { - return _data[p_index].key; + return _cowdata.get_m(p_index).key; } inline const V &operator[](const T &p_key) const { @@ -188,7 +188,7 @@ public: CRASH_COND(pos < 0); - return _data[pos].value; + return _cowdata.get(pos).value; } inline V &operator[](const T &p_key) { @@ -199,7 +199,14 @@ public: pos = insert(p_key, val); } - return _data[pos].value; + return _cowdata.get_m(pos).value; + } + + _FORCE_INLINE_ VMap(){}; + _FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); } + inline VMap &operator=(const VMap &p_from) { + _cowdata._ref(p_from._cowdata); + return *this; } }; #endif // VMAP_H diff --git a/core/vset.h b/core/vset.h index 449943b4a1..7f4d8e7f62 100644 --- a/core/vset.h +++ b/core/vset.h @@ -133,7 +133,7 @@ public: inline T &operator[](int p_index) { - return _data[p_index]; + return _data.write[p_index]; } inline const T &operator[](int p_index) const { diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml index b5f5fed3f9..3ebe350700 100644 --- a/doc/classes/@GDScript.xml +++ b/doc/classes/@GDScript.xml @@ -202,7 +202,7 @@ </description> </method> <method name="convert"> - <return type="Object"> + <return type="Variant"> </return> <argument index="0" name="what" type="Variant"> </argument> @@ -394,7 +394,7 @@ </description> </method> <method name="funcref"> - <return type="Object"> + <return type="FuncRef"> </return> <argument index="0" name="instance" type="Object"> </argument> @@ -411,6 +411,12 @@ [/codeblock] </description> </method> + <method name="get_stack"> + <return type="void"> + </return> + <description> + </description> + </method> <method name="hash"> <return type="int"> </return> @@ -541,7 +547,7 @@ </description> </method> <method name="load"> - <return type="Object"> + <return type="Resource"> </return> <argument index="0" name="path" type="String"> </argument> @@ -676,6 +682,12 @@ [/codeblock] </description> </method> + <method name="print_debug" qualifiers="vararg"> + <return type="void"> + </return> + <description> + </description> + </method> <method name="print_stack"> <return type="void"> </return> @@ -1076,7 +1088,7 @@ </description> </method> <method name="weakref"> - <return type="Object"> + <return type="WeakRef"> </return> <argument index="0" name="obj" type="Object"> </argument> diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 7f94676e93..47553659c9 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -883,6 +883,10 @@ <constant name="BUTTON_MIDDLE" value="3" enum="ButtonList"> Middle Mouse Button </constant> + <constant name="BUTTON_XBUTTON1" value="8" enum="ButtonList"> + </constant> + <constant name="BUTTON_XBUTTON2" value="9" enum="ButtonList"> + </constant> <constant name="BUTTON_WHEEL_UP" value="4" enum="ButtonList"> Mouse wheel up </constant> @@ -904,6 +908,10 @@ <constant name="BUTTON_MASK_MIDDLE" value="4" enum="ButtonList"> Middle Mouse Button Mask </constant> + <constant name="BUTTON_MASK_XBUTTON1" value="128" enum="ButtonList"> + </constant> + <constant name="BUTTON_MASK_XBUTTON2" value="256" enum="ButtonList"> + </constant> <constant name="JOY_BUTTON_0" value="0" enum="JoystickList"> Joypad Button 0 </constant> @@ -1073,6 +1081,20 @@ <constant name="JOY_ANALOG_R2" value="7" enum="JoystickList"> Joypad Right Analog Trigger </constant> + <constant name="MIDI_MESSAGE_NOTE_OFF" value="8" enum="MidiMessageList"> + </constant> + <constant name="MIDI_MESSAGE_NOTE_ON" value="9" enum="MidiMessageList"> + </constant> + <constant name="MIDI_MESSAGE_AFTERTOUCH" value="10" enum="MidiMessageList"> + </constant> + <constant name="MIDI_MESSAGE_CONTROL_CHANGE" value="11" enum="MidiMessageList"> + </constant> + <constant name="MIDI_MESSAGE_PROGRAM_CHANGE" value="12" enum="MidiMessageList"> + </constant> + <constant name="MIDI_MESSAGE_CHANNEL_PRESSURE" value="13" enum="MidiMessageList"> + </constant> + <constant name="MIDI_MESSAGE_PITCH_BEND" value="14" enum="MidiMessageList"> + </constant> <constant name="OK" value="0" enum="Error"> Functions that return Error return OK when no error occurred. Most functions don't return errors and/or just print errors to STDOUT. </constant> diff --git a/doc/classes/AnimatedTexture.xml b/doc/classes/AnimatedTexture.xml new file mode 100644 index 0000000000..f874c43ef1 --- /dev/null +++ b/doc/classes/AnimatedTexture.xml @@ -0,0 +1,1045 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimatedTexture" inherits="Texture" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="fps" type="float" setter="set_fps" getter="get_fps"> + </member> + <member name="frame_0/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_0/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_1/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_1/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_10/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_10/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_100/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_100/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_101/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_101/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_102/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_102/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_103/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_103/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_104/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_104/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_105/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_105/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_106/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_106/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_107/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_107/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_108/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_108/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_109/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_109/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_11/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_11/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_110/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_110/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_111/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_111/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_112/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_112/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_113/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_113/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_114/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_114/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_115/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_115/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_116/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_116/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_117/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_117/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_118/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_118/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_119/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_119/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_12/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_12/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_120/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_120/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_121/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_121/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_122/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_122/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_123/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_123/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_124/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_124/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_125/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_125/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_126/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_126/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_127/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_127/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_128/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_128/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_129/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_129/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_13/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_13/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_130/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_130/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_131/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_131/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_132/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_132/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_133/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_133/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_134/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_134/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_135/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_135/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_136/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_136/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_137/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_137/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_138/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_138/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_139/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_139/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_14/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_14/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_140/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_140/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_141/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_141/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_142/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_142/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_143/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_143/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_144/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_144/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_145/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_145/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_146/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_146/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_147/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_147/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_148/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_148/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_149/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_149/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_15/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_15/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_150/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_150/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_151/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_151/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_152/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_152/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_153/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_153/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_154/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_154/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_155/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_155/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_156/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_156/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_157/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_157/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_158/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_158/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_159/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_159/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_16/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_16/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_160/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_160/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_161/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_161/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_162/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_162/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_163/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_163/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_164/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_164/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_165/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_165/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_166/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_166/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_167/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_167/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_168/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_168/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_169/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_169/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_17/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_17/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_170/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_170/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_171/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_171/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_172/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_172/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_173/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_173/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_174/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_174/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_175/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_175/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_176/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_176/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_177/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_177/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_178/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_178/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_179/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_179/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_18/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_18/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_180/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_180/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_181/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_181/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_182/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_182/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_183/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_183/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_184/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_184/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_185/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_185/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_186/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_186/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_187/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_187/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_188/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_188/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_189/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_189/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_19/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_19/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_190/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_190/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_191/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_191/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_192/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_192/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_193/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_193/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_194/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_194/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_195/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_195/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_196/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_196/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_197/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_197/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_198/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_198/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_199/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_199/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_2/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_2/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_20/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_20/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_200/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_200/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_201/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_201/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_202/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_202/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_203/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_203/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_204/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_204/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_205/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_205/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_206/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_206/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_207/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_207/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_208/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_208/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_209/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_209/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_21/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_21/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_210/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_210/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_211/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_211/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_212/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_212/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_213/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_213/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_214/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_214/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_215/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_215/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_216/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_216/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_217/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_217/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_218/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_218/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_219/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_219/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_22/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_22/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_220/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_220/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_221/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_221/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_222/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_222/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_223/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_223/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_224/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_224/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_225/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_225/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_226/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_226/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_227/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_227/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_228/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_228/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_229/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_229/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_23/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_23/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_230/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_230/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_231/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_231/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_232/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_232/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_233/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_233/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_234/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_234/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_235/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_235/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_236/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_236/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_237/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_237/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_238/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_238/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_239/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_239/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_24/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_24/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_240/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_240/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_241/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_241/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_242/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_242/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_243/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_243/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_244/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_244/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_245/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_245/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_246/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_246/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_247/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_247/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_248/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_248/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_249/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_249/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_25/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_25/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_250/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_250/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_251/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_251/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_252/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_252/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_253/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_253/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_254/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_254/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_255/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_255/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_26/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_26/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_27/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_27/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_28/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_28/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_29/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_29/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_3/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_3/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_30/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_30/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_31/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_31/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_32/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_32/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_33/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_33/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_34/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_34/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_35/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_35/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_36/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_36/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_37/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_37/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_38/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_38/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_39/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_39/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_4/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_4/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_40/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_40/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_41/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_41/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_42/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_42/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_43/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_43/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_44/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_44/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_45/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_45/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_46/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_46/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_47/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_47/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_48/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_48/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_49/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_49/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_5/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_5/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_50/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_50/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_51/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_51/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_52/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_52/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_53/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_53/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_54/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_54/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_55/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_55/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_56/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_56/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_57/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_57/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_58/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_58/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_59/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_59/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_6/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_6/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_60/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_60/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_61/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_61/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_62/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_62/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_63/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_63/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_64/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_64/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_65/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_65/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_66/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_66/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_67/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_67/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_68/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_68/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_69/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_69/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_7/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_7/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_70/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_70/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_71/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_71/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_72/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_72/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_73/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_73/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_74/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_74/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_75/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_75/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_76/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_76/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_77/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_77/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_78/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_78/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_79/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_79/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_8/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_8/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_80/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_80/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_81/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_81/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_82/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_82/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_83/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_83/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_84/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_84/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_85/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_85/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_86/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_86/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_87/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_87/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_88/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_88/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_89/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_89/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_9/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_9/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_90/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_90/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_91/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_91/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_92/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_92/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_93/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_93/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_94/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_94/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_95/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_95/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_96/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_96/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_97/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_97/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_98/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_98/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frame_99/delay_sec" type="float" setter="set_frame_delay" getter="get_frame_delay"> + </member> + <member name="frame_99/texture" type="Texture" setter="set_frame_texture" getter="get_frame_texture"> + </member> + <member name="frames" type="int" setter="set_frames" getter="get_frames"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml new file mode 100644 index 0000000000..2f991699d6 --- /dev/null +++ b/doc/classes/AnimationNode.xml @@ -0,0 +1,213 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNode" inherits="Resource" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="_parent_set" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="parent" type="Object"> + </argument> + <description> + </description> + </method> + <method name="add_input"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="blend_animation"> + <return type="void"> + </return> + <argument index="0" name="animation" type="String"> + </argument> + <argument index="1" name="time" type="float"> + </argument> + <argument index="2" name="delta" type="float"> + </argument> + <argument index="3" name="seeked" type="bool"> + </argument> + <argument index="4" name="blend" type="float"> + </argument> + <description> + </description> + </method> + <method name="blend_input"> + <return type="float"> + </return> + <argument index="0" name="input_index" type="int"> + </argument> + <argument index="1" name="time" type="float"> + </argument> + <argument index="2" name="seek" type="bool"> + </argument> + <argument index="3" name="blend" type="float"> + </argument> + <argument index="4" name="filter" type="int" enum="AnimationNode.FilterAction" default="0"> + </argument> + <argument index="5" name="optimize" type="bool" default="true"> + </argument> + <description> + </description> + </method> + <method name="blend_node"> + <return type="float"> + </return> + <argument index="0" name="node" type="AnimationNode"> + </argument> + <argument index="1" name="time" type="float"> + </argument> + <argument index="2" name="seek" type="bool"> + </argument> + <argument index="3" name="blend" type="float"> + </argument> + <argument index="4" name="filter" type="int" enum="AnimationNode.FilterAction" default="0"> + </argument> + <argument index="5" name="optimize" type="bool" default="true"> + </argument> + <description> + </description> + </method> + <method name="get_caption" qualifiers="virtual"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_input_activity" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="input" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_input_connection"> + <return type="String"> + </return> + <argument index="0" name="input" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_input_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_input_name"> + <return type="String"> + </return> + <argument index="0" name="input" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_parent" qualifiers="const"> + <return type="AnimationNode"> + </return> + <description> + </description> + </method> + <method name="get_position" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="get_tree" qualifiers="const"> + <return type="AnimationTree"> + </return> + <description> + </description> + </method> + <method name="has_filter" qualifiers="virtual"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="is_path_filtered" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="path" type="NodePath"> + </argument> + <description> + </description> + </method> + <method name="process" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="time" type="float"> + </argument> + <argument index="1" name="seek" type="bool"> + </argument> + <description> + </description> + </method> + <method name="remove_input"> + <return type="void"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_filter_path"> + <return type="void"> + </return> + <argument index="0" name="path" type="NodePath"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_parent"> + <return type="void"> + </return> + <argument index="0" name="parent" type="Object"> + </argument> + <description> + </description> + </method> + <method name="set_position"> + <return type="void"> + </return> + <argument index="0" name="position" type="Vector2"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="filter_enabled" type="bool" setter="set_filter_enabled" getter="is_filter_enabled"> + </member> + </members> + <signals> + <signal name="removed_from_graph"> + <description> + </description> + </signal> + </signals> + <constants> + <constant name="FILTER_IGNORE" value="0" enum="FilterAction"> + </constant> + <constant name="FILTER_PASS" value="1" enum="FilterAction"> + </constant> + <constant name="FILTER_STOP" value="2" enum="FilterAction"> + </constant> + <constant name="FILTER_BLEND" value="3" enum="FilterAction"> + </constant> + </constants> +</class> diff --git a/doc/classes/AnimationNodeAdd2.xml b/doc/classes/AnimationNodeAdd2.xml new file mode 100644 index 0000000000..267eec6406 --- /dev/null +++ b/doc/classes/AnimationNodeAdd2.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeAdd2" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="amount" type="float" setter="set_amount" getter="get_amount"> + </member> + <member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeAdd3.xml b/doc/classes/AnimationNodeAdd3.xml new file mode 100644 index 0000000000..6596b76f85 --- /dev/null +++ b/doc/classes/AnimationNodeAdd3.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeAdd3" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="amount" type="float" setter="set_amount" getter="get_amount"> + </member> + <member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml new file mode 100644 index 0000000000..22f5e0838e --- /dev/null +++ b/doc/classes/AnimationNodeAnimation.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeAnimation" inherits="AnimationRootNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_playback_time" qualifiers="const"> + <return type="float"> + </return> + <description> + </description> + </method> + </methods> + <members> + <member name="animation" type="String" setter="set_animation" getter="get_animation"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeBlend2.xml b/doc/classes/AnimationNodeBlend2.xml new file mode 100644 index 0000000000..8ef114f69b --- /dev/null +++ b/doc/classes/AnimationNodeBlend2.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeBlend2" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="amount" type="float" setter="set_amount" getter="get_amount"> + </member> + <member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeBlend3.xml b/doc/classes/AnimationNodeBlend3.xml new file mode 100644 index 0000000000..094810d008 --- /dev/null +++ b/doc/classes/AnimationNodeBlend3.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeBlend3" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="amount" type="float" setter="set_amount" getter="get_amount"> + </member> + <member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeBlendSpace1D.xml b/doc/classes/AnimationNodeBlendSpace1D.xml new file mode 100644 index 0000000000..96c94a8972 --- /dev/null +++ b/doc/classes/AnimationNodeBlendSpace1D.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeBlendSpace1D" inherits="AnimationRootNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="add_blend_point"> + <return type="void"> + </return> + <argument index="0" name="node" type="AnimationRootNode"> + </argument> + <argument index="1" name="pos" type="float"> + </argument> + <argument index="2" name="at_index" type="int" default="-1"> + </argument> + <description> + </description> + </method> + <method name="get_blend_point_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_blend_point_node" qualifiers="const"> + <return type="AnimationRootNode"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_blend_point_position" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="remove_blend_point"> + <return type="void"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_blend_point_node"> + <return type="void"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <argument index="1" name="node" type="AnimationRootNode"> + </argument> + <description> + </description> + </method> + <method name="set_blend_point_position"> + <return type="void"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <argument index="1" name="pos" type="float"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="blend_pos" type="float" setter="set_blend_pos" getter="get_blend_pos"> + </member> + <member name="max_space" type="float" setter="set_max_space" getter="get_max_space"> + </member> + <member name="min_space" type="float" setter="set_min_space" getter="get_min_space"> + </member> + <member name="snap" type="float" setter="set_snap" getter="get_snap"> + </member> + <member name="value_label" type="String" setter="set_value_label" getter="get_value_label"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeBlendSpace2D.xml b/doc/classes/AnimationNodeBlendSpace2D.xml new file mode 100644 index 0000000000..31dc7eebac --- /dev/null +++ b/doc/classes/AnimationNodeBlendSpace2D.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeBlendSpace2D" inherits="AnimationRootNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="add_blend_point"> + <return type="void"> + </return> + <argument index="0" name="node" type="AnimationRootNode"> + </argument> + <argument index="1" name="pos" type="Vector2"> + </argument> + <argument index="2" name="at_index" type="int" default="-1"> + </argument> + <description> + </description> + </method> + <method name="add_triangle"> + <return type="void"> + </return> + <argument index="0" name="x" type="int"> + </argument> + <argument index="1" name="y" type="int"> + </argument> + <argument index="2" name="z" type="int"> + </argument> + <argument index="3" name="at_index" type="int" default="-1"> + </argument> + <description> + </description> + </method> + <method name="get_blend_point_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_blend_point_node" qualifiers="const"> + <return type="AnimationRootNode"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_blend_point_position" qualifiers="const"> + <return type="Vector2"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_triangle_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_triangle_point"> + <return type="int"> + </return> + <argument index="0" name="triangle" type="int"> + </argument> + <argument index="1" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="remove_blend_point"> + <return type="void"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <description> + </description> + </method> + <method name="remove_triangle"> + <return type="void"> + </return> + <argument index="0" name="triangle" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_blend_point_node"> + <return type="void"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <argument index="1" name="node" type="AnimationRootNode"> + </argument> + <description> + </description> + </method> + <method name="set_blend_point_position"> + <return type="void"> + </return> + <argument index="0" name="point" type="int"> + </argument> + <argument index="1" name="pos" type="Vector2"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="auto_triangles" type="bool" setter="set_auto_triangles" getter="get_auto_triangles"> + </member> + <member name="blend_position" type="Vector2" setter="set_blend_position" getter="get_blend_position"> + </member> + <member name="max_space" type="Vector2" setter="set_max_space" getter="get_max_space"> + </member> + <member name="min_space" type="Vector2" setter="set_min_space" getter="get_min_space"> + </member> + <member name="snap" type="Vector2" setter="set_snap" getter="get_snap"> + </member> + <member name="x_label" type="String" setter="set_x_label" getter="get_x_label"> + </member> + <member name="y_label" type="String" setter="set_y_label" getter="get_y_label"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml new file mode 100644 index 0000000000..88257883a3 --- /dev/null +++ b/doc/classes/AnimationNodeBlendTree.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeBlendTree" inherits="AnimationRootNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="add_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="node" type="AnimationNode"> + </argument> + <description> + </description> + </method> + <method name="connect_node"> + <return type="void"> + </return> + <argument index="0" name="input_node" type="String"> + </argument> + <argument index="1" name="input_index" type="int"> + </argument> + <argument index="2" name="output_node" type="String"> + </argument> + <description> + </description> + </method> + <method name="disconnect_node"> + <return type="void"> + </return> + <argument index="0" name="input_node" type="String"> + </argument> + <argument index="1" name="input_index" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_node" qualifiers="const"> + <return type="AnimationNode"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="has_node" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="remove_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="rename_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="new_name" type="String"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset"> + </member> + </members> + <constants> + <constant name="CONNECTION_OK" value="0"> + </constant> + <constant name="CONNECTION_ERROR_NO_INPUT" value="1"> + </constant> + <constant name="CONNECTION_ERROR_NO_INPUT_INDEX" value="2"> + </constant> + <constant name="CONNECTION_ERROR_NO_OUTPUT" value="3"> + </constant> + <constant name="CONNECTION_ERROR_SAME_NODE" value="4"> + </constant> + <constant name="CONNECTION_ERROR_CONNECTION_EXISTS" value="5"> + </constant> + </constants> +</class> diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml new file mode 100644 index 0000000000..b59b6e2b83 --- /dev/null +++ b/doc/classes/AnimationNodeOneShot.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeOneShot" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_mix_mode" qualifiers="const"> + <return type="int" enum="AnimationNodeOneShot.MixMode"> + </return> + <description> + </description> + </method> + <method name="is_active" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="set_mix_mode"> + <return type="void"> + </return> + <argument index="0" name="mode" type="int" enum="AnimationNodeOneShot.MixMode"> + </argument> + <description> + </description> + </method> + <method name="start"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="stop"> + <return type="void"> + </return> + <description> + </description> + </method> + </methods> + <members> + <member name="autorestart" type="bool" setter="set_autorestart" getter="has_autorestart"> + </member> + <member name="autorestart_delay" type="float" setter="set_autorestart_delay" getter="get_autorestart_delay"> + </member> + <member name="autorestart_random_delay" type="float" setter="set_autorestart_random_delay" getter="get_autorestart_random_delay"> + </member> + <member name="fadein_time" type="float" setter="set_fadein_time" getter="get_fadein_time"> + </member> + <member name="fadeout_time" type="float" setter="set_fadeout_time" getter="get_fadeout_time"> + </member> + <member name="sync" type="bool" setter="set_use_sync" getter="is_using_sync"> + </member> + </members> + <constants> + <constant name="MIX_MODE_BLEND" value="0" enum="MixMode"> + </constant> + <constant name="MIX_MODE_ADD" value="1" enum="MixMode"> + </constant> + </constants> +</class> diff --git a/doc/classes/AnimationNodeOutput.xml b/doc/classes/AnimationNodeOutput.xml new file mode 100644 index 0000000000..98a41bc9cb --- /dev/null +++ b/doc/classes/AnimationNodeOutput.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeOutput" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml new file mode 100644 index 0000000000..ad40f20db1 --- /dev/null +++ b/doc/classes/AnimationNodeStateMachine.xml @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeStateMachine" inherits="AnimationRootNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="add_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="node" type="AnimationNode"> + </argument> + <description> + </description> + </method> + <method name="add_transition"> + <return type="void"> + </return> + <argument index="0" name="from" type="String"> + </argument> + <argument index="1" name="to" type="String"> + </argument> + <argument index="2" name="transition" type="AnimationNodeStateMachineTransition"> + </argument> + <description> + </description> + </method> + <method name="get_current_node" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_end_node" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_graph_offset" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="get_node" qualifiers="const"> + <return type="AnimationNode"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="get_node_name" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="node" type="AnimationNode"> + </argument> + <description> + </description> + </method> + <method name="get_start_node" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> + <method name="get_transition" qualifiers="const"> + <return type="AnimationNodeStateMachineTransition"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_transition_count" qualifiers="const"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="get_transition_from" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_transition_to" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_travel_path" qualifiers="const"> + <return type="PoolStringArray"> + </return> + <description> + </description> + </method> + <method name="has_node" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="has_transition"> + <return type="void"> + </return> + <argument index="0" name="from" type="String"> + </argument> + <argument index="1" name="to" type="String"> + </argument> + <argument index="2" name="arg2" type="AnimationNodeStateMachineTransition"> + </argument> + <description> + </description> + </method> + <method name="is_playing" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="remove_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="remove_transition"> + <return type="void"> + </return> + <argument index="0" name="from" type="String"> + </argument> + <argument index="1" name="to" type="String"> + </argument> + <description> + </description> + </method> + <method name="remove_transition_by_index"> + <return type="void"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> + <method name="rename_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="new_name" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_end_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="set_graph_offset"> + <return type="void"> + </return> + <argument index="0" name="name" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="set_start_node"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + </description> + </method> + <method name="start"> + <return type="void"> + </return> + <argument index="0" name="node" type="String"> + </argument> + <description> + </description> + </method> + <method name="stop"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="travel"> + <return type="bool"> + </return> + <argument index="0" name="to_node" type="String"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml new file mode 100644 index 0000000000..280a1413b8 --- /dev/null +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeStateMachineTransition" inherits="Resource" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="auto_advance" type="bool" setter="set_auto_advance" getter="has_auto_advance"> + </member> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled"> + </member> + <member name="priority" type="int" setter="set_priority" getter="get_priority"> + </member> + <member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode"> + </member> + <member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time"> + </member> + </members> + <constants> + <constant name="SWITCH_MODE_IMMEDIATE" value="0" enum="SwitchMode"> + </constant> + <constant name="SWITCH_MODE_SYNC" value="1" enum="SwitchMode"> + </constant> + <constant name="SWITCH_MODE_AT_END" value="2" enum="SwitchMode"> + </constant> + </constants> +</class> diff --git a/doc/classes/AnimationNodeTimeScale.xml b/doc/classes/AnimationNodeTimeScale.xml new file mode 100644 index 0000000000..b3e90d190b --- /dev/null +++ b/doc/classes/AnimationNodeTimeScale.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeTimeScale" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="scale" type="float" setter="set_scale" getter="get_scale"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml new file mode 100644 index 0000000000..a479208128 --- /dev/null +++ b/doc/classes/AnimationNodeTimeSeek.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeTimeSeek" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="seek_pos" type="float" setter="set_seek_pos" getter="get_seek_pos"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml new file mode 100644 index 0000000000..3731fc05ed --- /dev/null +++ b/doc/classes/AnimationNodeTransition.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationNodeTransition" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="current" type="int" setter="set_current" getter="get_current"> + </member> + <member name="input_0/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_0/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_1/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_1/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_10/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_10/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_11/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_11/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_12/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_12/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_13/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_13/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_14/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_14/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_15/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_15/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_16/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_16/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_17/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_17/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_18/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_18/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_19/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_19/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_2/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_2/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_20/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_20/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_21/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_21/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_22/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_22/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_23/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_23/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_24/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_24/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_25/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_25/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_26/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_26/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_27/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_27/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_28/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_28/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_29/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_29/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_3/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_3/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_30/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_30/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_31/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_31/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_4/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_4/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_5/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_5/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_6/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_6/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_7/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_7/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_8/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_8/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_9/auto_advance" type="bool" setter="set_input_as_auto_advance" getter="is_input_set_as_auto_advance"> + </member> + <member name="input_9/name" type="String" setter="set_input_caption" getter="get_input_caption"> + </member> + <member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs"> + </member> + <member name="xfade_time" type="float" setter="set_cross_fade_time" getter="get_cross_fade_time"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index e1b3c7a9c9..f93590bb9d 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -271,6 +271,10 @@ Notifies when an animation starts playing. </description> </signal> + <signal name="caches_cleared"> + <description> + </description> + </signal> </signals> <constants> <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessMode"> diff --git a/doc/classes/AnimationRootNode.xml b/doc/classes/AnimationRootNode.xml new file mode 100644 index 0000000000..dab2c12373 --- /dev/null +++ b/doc/classes/AnimationRootNode.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationRootNode" inherits="AnimationNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml new file mode 100644 index 0000000000..a8e3a821b1 --- /dev/null +++ b/doc/classes/AnimationTree.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationTree" inherits="Node" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_root_motion_transform" qualifiers="const"> + <return type="Transform"> + </return> + <description> + </description> + </method> + </methods> + <members> + <member name="active" type="bool" setter="set_active" getter="is_active"> + </member> + <member name="anim_player" type="NodePath" setter="set_animation_player" getter="get_animation_player"> + </member> + <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="AnimationTree.AnimationProcessMode"> + </member> + <member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track"> + </member> + <member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root"> + </member> + </members> + <constants> + <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessMode"> + </constant> + <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode"> + </constant> + </constants> +</class> diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index 80d7b7783f..d805629b3d 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -26,7 +26,7 @@ </argument> <argument index="2" name="blend_shapes" type="Array" default="[ ]"> </argument> - <argument index="3" name="compress_flags" type="int" default="97792"> + <argument index="3" name="compress_flags" type="int" default="97280"> </argument> <description> Creates a new surface. diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index 00d03d2b20..d6e75f8377 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -65,6 +65,8 @@ <member name="stream" type="AudioStream" setter="set_stream" getter="get_stream"> The [AudioStream] object to be played. </member> + <member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused"> + </member> <member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db"> Volume of sound, in dB. </member> diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index 03b0a3aa81..5cc87e0e7a 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -71,6 +71,8 @@ <member name="stream" type="AudioStream" setter="set_stream" getter="get_stream"> The [AudioStream] object to be played. </member> + <member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused"> + </member> <member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db"> Base volume without dampening. </member> diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index 2746938c1d..e61515ffc0 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -95,6 +95,8 @@ <member name="stream" type="AudioStream" setter="set_stream" getter="get_stream"> The [AudioStream] object to be played. </member> + <member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused"> + </member> <member name="unit_db" type="float" setter="set_unit_db" getter="get_unit_db"> Base sound level unaffected by dampening, in dB. </member> diff --git a/doc/classes/CPUParticles.xml b/doc/classes/CPUParticles.xml new file mode 100644 index 0000000000..9d3dc5d70a --- /dev/null +++ b/doc/classes/CPUParticles.xml @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="CPUParticles" inherits="GeometryInstance" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="convert_from_particles"> + <return type="void"> + </return> + <argument index="0" name="particles" type="Node"> + </argument> + <description> + </description> + </method> + <method name="restart"> + <return type="void"> + </return> + <description> + </description> + </method> + </methods> + <members> + <member name="amount" type="int" setter="set_amount" getter="get_amount"> + </member> + <member name="angle" type="float" setter="set_param" getter="get_param"> + </member> + <member name="angle_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="angle_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="angular_velocity" type="float" setter="set_param" getter="get_param"> + </member> + <member name="angular_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="angular_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="anim_loop" type="bool" setter="set_particle_flag" getter="get_particle_flag"> + </member> + <member name="anim_offset" type="float" setter="set_param" getter="get_param"> + </member> + <member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="anim_offset_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="anim_speed" type="float" setter="set_param" getter="get_param"> + </member> + <member name="anim_speed_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="anim_speed_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="color" type="Color" setter="set_color" getter="get_color"> + </member> + <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> + </member> + <member name="damping" type="float" setter="set_param" getter="get_param"> + </member> + <member name="damping_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="damping_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="CPUParticles.DrawOrder"> + </member> + <member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents"> + </member> + <member name="emission_colors" type="PoolColorArray" setter="set_emission_colors" getter="get_emission_colors"> + </member> + <member name="emission_normals" type="PoolVector3Array" setter="set_emission_normals" getter="get_emission_normals"> + </member> + <member name="emission_points" type="PoolVector3Array" setter="set_emission_points" getter="get_emission_points"> + </member> + <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="CPUParticles.EmissionShape"> + </member> + <member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius"> + </member> + <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting"> + </member> + <member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio"> + </member> + <member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps"> + </member> + <member name="flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag"> + </member> + <member name="flag_disable_z" type="bool" setter="set_particle_flag" getter="get_particle_flag"> + </member> + <member name="flag_rotate_y" type="bool" setter="set_particle_flag" getter="get_particle_flag"> + </member> + <member name="flatness" type="float" setter="set_flatness" getter="get_flatness"> + </member> + <member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta"> + </member> + <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity"> + </member> + <member name="hue_variation" type="float" setter="set_param" getter="get_param"> + </member> + <member name="hue_variation_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="hue_variation_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="initial_velocity" type="float" setter="set_param" getter="get_param"> + </member> + <member name="initial_velocity_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime"> + </member> + <member name="linear_accel" type="float" setter="set_param" getter="get_param"> + </member> + <member name="linear_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="linear_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates"> + </member> + <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> + </member> + <member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot"> + </member> + <member name="preprocess" type="float" setter="set_pre_process_time" getter="get_pre_process_time"> + </member> + <member name="radial_accel" type="float" setter="set_param" getter="get_param"> + </member> + <member name="radial_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="radial_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio"> + </member> + <member name="scale" type="float" setter="set_param" getter="get_param"> + </member> + <member name="scale_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="scale_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + <member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale"> + </member> + <member name="spread" type="float" setter="set_spread" getter="get_spread"> + </member> + <member name="tangential_accel" type="float" setter="set_param" getter="get_param"> + </member> + <member name="tangential_accel_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> + </member> + <member name="tangential_accel_random" type="float" setter="set_param_randomness" getter="get_param_randomness"> + </member> + </members> + <constants> + <constant name="DRAW_ORDER_INDEX" value="0" enum="DrawOrder"> + </constant> + <constant name="DRAW_ORDER_LIFETIME" value="1" enum="DrawOrder"> + </constant> + <constant name="DRAW_ORDER_VIEW_DEPTH" value="2" enum="DrawOrder"> + </constant> + <constant name="PARAM_INITIAL_LINEAR_VELOCITY" value="0" enum="Parameter"> + </constant> + <constant name="PARAM_ANGULAR_VELOCITY" value="1" enum="Parameter"> + </constant> + <constant name="PARAM_LINEAR_ACCEL" value="2" enum="Parameter"> + </constant> + <constant name="PARAM_RADIAL_ACCEL" value="3" enum="Parameter"> + </constant> + <constant name="PARAM_TANGENTIAL_ACCEL" value="4" enum="Parameter"> + </constant> + <constant name="PARAM_DAMPING" value="5" enum="Parameter"> + </constant> + <constant name="PARAM_ANGLE" value="6" enum="Parameter"> + </constant> + <constant name="PARAM_SCALE" value="7" enum="Parameter"> + </constant> + <constant name="PARAM_HUE_VARIATION" value="8" enum="Parameter"> + </constant> + <constant name="PARAM_ANIM_SPEED" value="9" enum="Parameter"> + </constant> + <constant name="PARAM_ANIM_OFFSET" value="10" enum="Parameter"> + </constant> + <constant name="PARAM_MAX" value="11" enum="Parameter"> + </constant> + <constant name="FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="Flags"> + </constant> + <constant name="FLAG_ROTATE_Y" value="1" enum="Flags"> + </constant> + <constant name="FLAG_MAX" value="4" enum="Flags"> + </constant> + <constant name="EMISSION_SHAPE_POINT" value="0" enum="EmissionShape"> + </constant> + <constant name="EMISSION_SHAPE_SPHERE" value="1" enum="EmissionShape"> + </constant> + <constant name="EMISSION_SHAPE_BOX" value="2" enum="EmissionShape"> + </constant> + <constant name="EMISSION_SHAPE_POINTS" value="3" enum="EmissionShape"> + </constant> + <constant name="EMISSION_SHAPE_DIRECTED_POINTS" value="4" enum="EmissionShape"> + </constant> + </constants> +</class> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 104c9e0a98..3d74bd7ab0 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -15,67 +15,67 @@ <method name="Color"> <return type="Color"> </return> - <argument index="0" name="r" type="float"> - </argument> - <argument index="1" name="g" type="float"> - </argument> - <argument index="2" name="b" type="float"> - </argument> - <argument index="3" name="a" type="float"> + <argument index="0" name="from" type="String"> </argument> <description> - Constructs a color from an RGBA profile using values between 0 and 1 (float). + Constructs a color from an HTML hexadecimal color string in ARGB or RGB format. See also [method @GDScript.ColorN]. + The following string formats are supported: + [code]"#ff00ff00"[/code] - ARGB format with '#' + [code]"ff00ff00"[/code] - ARGB format + [code]"#ff00ff"[/code] - RGB format with '#' + [code]"ff00ff"[/code] - RGB format [codeblock] - var c = Color(0.2, 1.0, .7, .8) # a color of an RGBA(51, 255, 178, 204) + # The following code creates the same color of an RGBA(178, 217, 10, 255) + var c1 = Color("#ffb2d90a") # ARGB format with '#' + var c2 = Color("ffb2d90a") # ARGB format + var c3 = Color("#b2d90a") # RGB format with '#' + var c4 = Color("b2d90a") # RGB format [/codeblock] </description> </method> <method name="Color"> <return type="Color"> </return> - <argument index="0" name="r" type="float"> - </argument> - <argument index="1" name="g" type="float"> - </argument> - <argument index="2" name="b" type="float"> + <argument index="0" name="from" type="int"> </argument> <description> - Constructs a color from an RGB profile using values between 0 and 1 (float). Alpha will always be 1. + Constructs a color from a 32-bit integer (each byte represents a component of the RGBA profile). [codeblock] - var c = Color(0.2, 1.0, .7) # a color of an RGBA(51, 255, 178, 255) + var c = Color(274) # a color of an RGBA(0, 0, 1, 18) [/codeblock] </description> </method> <method name="Color"> <return type="Color"> </return> - <argument index="0" name="from" type="int"> + <argument index="0" name="r" type="float"> + </argument> + <argument index="1" name="g" type="float"> + </argument> + <argument index="2" name="b" type="float"> </argument> <description> - Constructs a color from a 32-bit integer (each byte represents a component of the RGBA profile). + Constructs a color from an RGB profile using values between 0 and 1 (float). Alpha will always be 1. [codeblock] - var c = Color(274) # a color of an RGBA(0, 0, 1, 18) + var c = Color(0.2, 1.0, .7) # a color of an RGBA(51, 255, 178, 255) [/codeblock] </description> </method> <method name="Color"> <return type="Color"> </return> - <argument index="0" name="from" type="String"> + <argument index="0" name="r" type="float"> + </argument> + <argument index="1" name="g" type="float"> + </argument> + <argument index="2" name="b" type="float"> + </argument> + <argument index="3" name="a" type="float"> </argument> <description> - Constructs a color from an HTML hexadecimal color string in ARGB or RGB format. See also [method @GDScript.ColorN]. - The following string formats are supported: - [code]"#ff00ff00"[/code] - ARGB format with '#' - [code]"ff00ff00"[/code] - ARGB format - [code]"#ff00ff"[/code] - RGB format with '#' - [code]"ff00ff"[/code] - RGB format + Constructs a color from an RGBA profile using values between 0 and 1 (float). [codeblock] - # The following code creates the same color of an RGBA(178, 217, 10, 255) - var c1 = Color("#ffb2d90a") # ARGB format with '#' - var c2 = Color("ffb2d90a") # ARGB format - var c3 = Color("#b2d90a") # RGB format with '#' - var c4 = Color("b2d90a") # RGB format + var c = Color(0.2, 1.0, .7, .8) # a color of an RGBA(51, 255, 178, 204) [/codeblock] </description> </method> @@ -187,14 +187,47 @@ [/codeblock] </description> </method> + <method name="to_abgr32"> + <return type="int"> + </return> + <description> + Returns the color's 32-bit integer in ABGR format (each byte represents a component of the ABGR profile). ABGR is the reversed version of the default format. + [codeblock] + var c = Color(1, .5, .2) + print(c.to_abgr32()) # Prints 4281565439 + [/codeblock] + </description> + </method> + <method name="to_abgr64"> + <return type="int"> + </return> + <description> + Returns the color's 64-bit integer in ABGR format (each word represents a component of the ABGR profile). ABGR is the reversed version of the default format. + [codeblock] + var c = Color(1, .5, .2) + print(c.to_abgr64()) # Prints -225178692812801 + [/codeblock] + </description> + </method> <method name="to_argb32"> <return type="int"> </return> <description> - Returns the color's 32-bit integer in ARGB format (each byte represents a component of the ARGB profile). More compatible with DirectX. + Returns the color's 32-bit integer in ARGB format (each byte represents a component of the ARGB profile). ARGB is more compatible with DirectX. [codeblock] var c = Color(1, .5, .2) - print(str(c.to_32())) # prints 4294934323 + print(c.to_argb32()) # Prints 4294934323 + [/codeblock] + </description> + </method> + <method name="to_argb64"> + <return type="int"> + </return> + <description> + Returns the color's 64-bit integer in ARGB format (each word represents a component of the ARGB profile). ARGB is more compatible with DirectX. + [codeblock] + var c = Color(1, .5, .2) + print(c.to_argb64()) # Prints -2147470541 [/codeblock] </description> </method> @@ -217,12 +250,22 @@ <return type="int"> </return> <description> - Returns the color's 32-bit integer in ARGB format (each byte represents a component of the ARGB profile). + Returns the color's 32-bit integer in RGBA format (each byte represents a component of the RGBA profile). RGBA is the format that Godot uses by default. + [codeblock] + var c = Color(1, .5, .2) + print(c.to_rgba32()) # Prints 4286526463 + [/codeblock] + </description> + </method> + <method name="to_rgba64"> + <return type="int"> + </return> + <description> + Returns the color's 64-bit integer in RGBA format (each word represents a component of the RGBA profile). RGBA is the format that Godot uses by default. [codeblock] var c = Color(1, .5, .2) - print(str(c.to_32())) # prints 4294934323 + print(c.to_rgba64()) # Prints -140736629309441 [/codeblock] - [i]This is same as [method to_argb32] but may be changed later to support RGBA format instead[/i]. </description> </method> </methods> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 1bd902c20e..232357f822 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -25,15 +25,15 @@ <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color"> The currently selected color. </member> + <member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode"> + If [code]true[/code], the color will apply only after user releases mouse button, otherwise it will apply immediatly even in mouse motion event (which can cause performance issues). + </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha"> If [code]true[/code], shows an alpha channel slider (transparency). </member> <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode"> If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). </member> - <member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode"> - If [code]true[/code], the color will apply only after user releases mouse button, otherwise it will apply immediatly even in mouse motion event (which can cause performance issues). - </member> </members> <signals> <signal name="color_changed"> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index 9d7df14014..d049e936a8 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -18,7 +18,7 @@ Returns the [code]ColorPicker[/code] that this [code]ColorPickerButton[/code] toggles. </description> </method> - <method name="get_popup" qualifiers="const"> + <method name="get_popup"> <return type="PopupPanel"> </return> <description> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 52382337cf..8c65f44259 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -36,6 +36,14 @@ Replaces Godot 2's [code]_input_event[/code]. </description> </method> + <method name="_make_custom_tooltip" qualifiers="virtual"> + <return type="Object"> + </return> + <argument index="0" name="for_text" type="String"> + </argument> + <description> + </description> + </method> <method name="accept_event"> <return type="void"> </return> diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml index 347acce2dd..5a8b506f9e 100644 --- a/doc/classes/EditorFileSystem.xml +++ b/doc/classes/EditorFileSystem.xml @@ -73,6 +73,12 @@ Update a file information. Call this if an external program (not Godot) modified the file. </description> </method> + <method name="update_script_classes"> + <return type="void"> + </return> + <description> + </description> + </method> </methods> <signals> <signal name="filesystem_changed"> diff --git a/doc/classes/EditorFileSystemDirectory.xml b/doc/classes/EditorFileSystemDirectory.xml index f5d0471037..bb3ff91639 100644 --- a/doc/classes/EditorFileSystemDirectory.xml +++ b/doc/classes/EditorFileSystemDirectory.xml @@ -63,6 +63,22 @@ Returns the path to the file at index [code]idx[/code]. </description> </method> + <method name="get_file_script_class_extends" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_file_script_class_name" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="idx" type="int"> + </argument> + <description> + </description> + </method> <method name="get_file_type" qualifiers="const"> <return type="String"> </return> diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index e48eb82691..b21d402468 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -35,19 +35,20 @@ func get_import_options(i): return [{"name": "my_option", "default_value": false}] - func load(src, dst, opts, r_platform_variants, r_gen_files): + func import(source_file, save_path, options, r_platform_variants, r_gen_files): var file = File.new() - if file.open(src, File.READ) != OK: + if file.open(source_file, File.READ) != OK: return FAILED var mesh = Mesh.new() - var save = dst + "." + get_save_extension() - ResourceSaver.save(file, mesh) + var filename = save_path + "." + get_save_extension() + ResourceSaver.save(filename, mesh) return OK [/codeblock] </description> <tutorials> + <link>http://docs.godotengine.org/en/3.0/tutorials/plugins/editor/import_plugins.html</link> </tutorials> <demos> </demos> @@ -119,7 +120,7 @@ <return type="String"> </return> <description> - Get the godot resource type associated with this loader. e.g. "Mesh" or "Animation". + Get the Godot resource type associated with this loader. e.g. "Mesh" or "Animation". </description> </method> <method name="get_save_extension" qualifiers="virtual"> diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml index 381eef5a40..a2a39fc8b6 100644 --- a/doc/classes/EditorInspector.xml +++ b/doc/classes/EditorInspector.xml @@ -9,6 +9,12 @@ <demos> </demos> <methods> + <method name="refresh"> + <return type="void"> + </return> + <description> + </description> + </method> </methods> <signals> <signal name="object_id_selected"> @@ -17,12 +23,24 @@ <description> </description> </signal> + <signal name="property_edited"> + <argument index="0" name="property" type="String"> + </argument> + <description> + </description> + </signal> <signal name="property_keyed"> <argument index="0" name="property" type="String"> </argument> <description> </description> </signal> + <signal name="property_selected"> + <argument index="0" name="property" type="String"> + </argument> + <description> + </description> + </signal> <signal name="resource_selected"> <argument index="0" name="res" type="Object"> </argument> @@ -31,6 +49,10 @@ <description> </description> </signal> + <signal name="restart_requested"> + <description> + </description> + </signal> </signals> <constants> </constants> diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 9b5452ec14..32d3a2703d 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -21,6 +21,12 @@ <description> </description> </method> + <method name="get_tooltip_text" qualifiers="const"> + <return type="String"> + </return> + <description> + </description> + </method> <method name="update_property" qualifiers="virtual"> <return type="void"> </return> diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml index f95c26c2b0..09cae25403 100644 --- a/doc/classes/EditorScenePostImport.xml +++ b/doc/classes/EditorScenePostImport.xml @@ -7,7 +7,7 @@ The imported scene can be automatically modified right after import by specifying a 'custom script' that inherits from this class. The [method post_import]-method receives the imported scene's root-node and returns the modified version of the scene </description> <tutorials> - http://docs.godotengine.org/en/latest/learning/workflow/assets/importing_scenes.html?highlight=post%20import + <link>http://docs.godotengine.org/en/latest/learning/workflow/assets/importing_scenes.html?highlight=post%20import</link> </tutorials> <demos> [codeblock] diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index cd2584ed43..566322e6c5 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -203,6 +203,8 @@ </member> <member name="ss_reflections_roughness" type="bool" setter="set_ssr_rough" getter="is_ssr_rough"> </member> + <member name="ssao_ao_channel_affect" type="float" setter="set_ssao_ao_channel_affect" getter="get_ssao_ao_channel_affect"> + </member> <member name="ssao_bias" type="float" setter="set_ssao_bias" getter="get_ssao_bias"> </member> <member name="ssao_blur" type="int" setter="set_ssao_blur" getter="is_ssao_blur_enabled" enum="Environment.SSAOBlur"> diff --git a/doc/classes/GeometryInstance.xml b/doc/classes/GeometryInstance.xml index aea1882dae..8831805dde 100644 --- a/doc/classes/GeometryInstance.xml +++ b/doc/classes/GeometryInstance.xml @@ -59,7 +59,7 @@ Will allow the GeometryInstance to be used when baking lights using a [GIProbe] and/or any other form of baked lighting. Added documentation for GeometryInstance and VisualInstance </constant> - <constant name="FLAG_MAX" value="1" enum="Flags"> + <constant name="FLAG_MAX" value="2" enum="Flags"> </constant> </constants> </class> diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 605efd9114..48e3c295f1 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -85,6 +85,12 @@ Return an Array containing the list of connections. A connection consists in a structure of the form {from_slot: 0, from: "GraphNode name 0", to_slot: 1, to: "GraphNode name 1" } </description> </method> + <method name="get_zoom_hbox"> + <return type="HBoxContainer"> + </return> + <description> + </description> + </method> <method name="is_node_connected"> <return type="bool"> </return> @@ -140,6 +146,22 @@ Removes the possibility to disconnect nodes when dragging from the slot at the right if it has the specified type. </description> </method> + <method name="set_connection_activity"> + <return type="void"> + </return> + <argument index="0" name="from" type="String"> + </argument> + <argument index="1" name="from_port" type="int"> + </argument> + <argument index="2" name="to" type="String"> + </argument> + <argument index="3" name="to_port" type="int"> + </argument> + <argument index="4" name="amount" type="float"> + </argument> + <description> + </description> + </method> <method name="set_selected"> <return type="void"> </return> @@ -248,6 +270,8 @@ <constants> </constants> <theme_items> + <theme_item name="activity" type="Color"> + </theme_item> <theme_item name="bezier_len_neg" type="int"> </theme_item> <theme_item name="bezier_len_pos" type="int"> @@ -262,6 +286,10 @@ </theme_item> <theme_item name="more" type="Texture"> </theme_item> + <theme_item name="port_grab_distance_horizontal" type="int"> + </theme_item> + <theme_item name="port_grab_distance_vertical" type="int"> + </theme_item> <theme_item name="reset" type="Texture"> </theme_item> <theme_item name="snap" type="Texture"> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 9fc7672a80..55693bd49c 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -350,6 +350,15 @@ Loads an image from the binary contents of a PNG file. </description> </method> + <method name="load_webp_from_buffer"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="buffer" type="PoolByteArray"> + </argument> + <description> + Loads an image from the binary contents of a WebP file. + </description> + </method> <method name="lock"> <return type="void"> </return> @@ -584,6 +593,12 @@ </constant> <constant name="INTERPOLATE_CUBIC" value="2" enum="Interpolation"> </constant> + <constant name="INTERPOLATE_TRILINEAR" value="3" enum="Interpolation"> + Performs bilinear separately on the two most suited mipmap levels, then linearly interpolates between them. + It's slower than [code]INTERPOLATE_BILINEAR[/code], but produces higher quality results, with much less aliasing artifacts. + If the image does not have mipmaps, they will be generated and used internally, but no mipmaps will be generated on the resulting image. (Note that if you intend to scale multiple copies of the original image, it's better to call [code]generate_mipmaps[/code] on it in advance, to avoid wasting processing power in generating them again and again.) + On the other hand, if the image already has mipmaps, they will be used, and a new set will be generated for the resulting image. + </constant> <constant name="ALPHA_NONE" value="0" enum="AlphaMode"> </constant> <constant name="ALPHA_BIT" value="1" enum="AlphaMode"> diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml index ae33ed5205..e6d537b895 100644 --- a/doc/classes/KinematicBody.xml +++ b/doc/classes/KinematicBody.xml @@ -76,13 +76,13 @@ </argument> <argument index="1" name="floor_normal" type="Vector3" default="Vector3( 0, 0, 0 )"> </argument> - <argument index="2" name="infinite_inertia" type="bool" default="true"> + <argument index="2" name="slope_stop_min_velocity" type="float" default="0.05"> </argument> - <argument index="3" name="slope_stop_min_velocity" type="float" default="0.05"> + <argument index="3" name="max_slides" type="int" default="4"> </argument> - <argument index="4" name="max_slides" type="int" default="4"> + <argument index="4" name="floor_max_angle" type="float" default="0.785398"> </argument> - <argument index="5" name="floor_max_angle" type="float" default="0.785398"> + <argument index="5" name="infinite_inertia" type="bool" default="true"> </argument> <description> Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [code]KinematicBody[/code] or [RigidBody], it will also be affected by the motion of the other body. You can use this to make moving or rotating platforms, or to make nodes push other nodes. diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml index 0448707c2e..fdc974630f 100644 --- a/doc/classes/KinematicBody2D.xml +++ b/doc/classes/KinematicBody2D.xml @@ -64,6 +64,10 @@ </argument> <argument index="1" name="infinite_inertia" type="bool" default="true"> </argument> + <argument index="2" name="exclude_raycast_shapes" type="bool" default="true"> + </argument> + <argument index="3" name="test_only" type="bool" default="false"> + </argument> <description> Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision. </description> @@ -93,6 +97,26 @@ Returns the movement that remained when the body stopped. To get more detailed information about collisions that occurred, use [method get_slide_collision]. </description> </method> + <method name="move_and_slide_with_snap"> + <return type="Vector2"> + </return> + <argument index="0" name="linear_velocity" type="Vector2"> + </argument> + <argument index="1" name="snap" type="Vector2"> + </argument> + <argument index="2" name="floor_normal" type="Vector2" default="Vector2( 0, 0 )"> + </argument> + <argument index="3" name="infinite_inertia" type="bool" default="true"> + </argument> + <argument index="4" name="slope_stop_min_velocity" type="float" default="5"> + </argument> + <argument index="5" name="max_bounces" type="int" default="4"> + </argument> + <argument index="6" name="floor_max_angle" type="float" default="0.785398"> + </argument> + <description> + </description> + </method> <method name="test_move"> <return type="bool"> </return> @@ -111,6 +135,8 @@ <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin"> If the body is at least this close to another body, this body will consider them to be colliding. </member> + <member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled"> + </member> </members> <constants> </constants> diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index 8c2aa01f81..9454a16988 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -134,5 +134,7 @@ </constant> <constant name="NOTIFICATION_WM_ABOUT" value="91"> </constant> + <constant name="NOTIFICATION_CRASH" value="92"> + </constant> </constants> </class> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index 83cadf959c..afb5d7db93 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -121,7 +121,7 @@ </constant> <constant name="ARRAY_FLAG_USE_16_BIT_BONES" value="524288" enum="ArrayFormat"> </constant> - <constant name="ARRAY_COMPRESS_DEFAULT" value="97792" enum="ArrayFormat"> + <constant name="ARRAY_COMPRESS_DEFAULT" value="97280" enum="ArrayFormat"> </constant> <constant name="ARRAY_VERTEX" value="0" enum="ArrayType"> </constant> diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index 8c114a55c9..10e7f1b172 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -71,6 +71,8 @@ </argument> <argument index="1" name="id" type="int" default="0"> </argument> + <argument index="2" name="mode" type="int" enum="NetworkedMultiplayerPeer.TransferMode" default="2"> + </argument> <description> Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers. </description> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 8bae412053..7f8a43fda2 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -733,6 +733,14 @@ Enables or disabled internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). Only useful for advanced uses to manipulate built-in nodes behaviour. </description> </method> + <method name="set_process_priority"> + <return type="void"> + </return> + <argument index="0" name="priority" type="int"> + </argument> + <description> + </description> + </method> <method name="set_process_unhandled_input"> <return type="void"> </return> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 1526b1be8c..cf86176086 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -147,6 +147,12 @@ Returns the command line arguments passed to the engine. </description> </method> + <method name="get_connected_midi_inputs"> + <return type="PoolStringArray"> + </return> + <description> + </description> + </method> <method name="get_date" qualifiers="const"> <return type="Dictionary"> </return> diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml index de3a251a79..3b11d9e47f 100644 --- a/doc/classes/Performance.xml +++ b/doc/classes/Performance.xml @@ -106,7 +106,9 @@ <constant name="PHYSICS_3D_ISLAND_COUNT" value="26" enum="Monitor"> Number of islands in the 3D physics engine. </constant> - <constant name="MONITOR_MAX" value="27" enum="Monitor"> + <constant name="AUDIO_OUTPUT_LATENCY" value="27" enum="Monitor"> + </constant> + <constant name="MONITOR_MAX" value="28" enum="Monitor"> </constant> </constants> </class> diff --git a/doc/classes/Physics2DDirectBodyState.xml b/doc/classes/Physics2DDirectBodyState.xml index 73a2d792ab..52c89248ff 100644 --- a/doc/classes/Physics2DDirectBodyState.xml +++ b/doc/classes/Physics2DDirectBodyState.xml @@ -11,6 +11,58 @@ <demos> </demos> <methods> + <method name="add_central_force"> + <return type="void"> + </return> + <argument index="0" name="force" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="add_force"> + <return type="void"> + </return> + <argument index="0" name="offset" type="Vector2"> + </argument> + <argument index="1" name="force" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="add_torque"> + <return type="void"> + </return> + <argument index="0" name="torque" type="float"> + </argument> + <description> + </description> + </method> + <method name="apply_central_impulse"> + <return type="void"> + </return> + <argument index="0" name="impulse" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="apply_impulse"> + <return type="void"> + </return> + <argument index="0" name="offset" type="Vector2"> + </argument> + <argument index="1" name="impulse" type="Vector2"> + </argument> + <description> + </description> + </method> + <method name="apply_torque_impulse"> + <return type="void"> + </return> + <argument index="0" name="impulse" type="float"> + </argument> + <description> + </description> + </method> <method name="get_contact_collider" qualifiers="const"> <return type="RID"> </return> diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml index c302797704..a473de4ce8 100644 --- a/doc/classes/Physics2DServer.xml +++ b/doc/classes/Physics2DServer.xml @@ -287,6 +287,16 @@ Sets the transform matrix for an area. </description> </method> + <method name="body_add_central_force"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="force" type="Vector2"> + </argument> + <description> + </description> + </method> <method name="body_add_collision_exception"> <return type="void"> </return> @@ -324,6 +334,26 @@ Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index. </description> </method> + <method name="body_add_torque"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="torque" type="float"> + </argument> + <description> + </description> + </method> + <method name="body_apply_central_impulse"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="impulse" type="Vector2"> + </argument> + <description> + </description> + </method> <method name="body_apply_impulse"> <return type="void"> </return> @@ -337,6 +367,16 @@ Adds a positioned impulse to the applied force and torque. Both the force and the offset from the body origin are in global coordinates. </description> </method> + <method name="body_apply_torque_impulse"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="impulse" type="float"> + </argument> + <description> + </description> + </method> <method name="body_attach_object_instance_id"> <return type="void"> </return> diff --git a/doc/classes/PhysicsDirectBodyState.xml b/doc/classes/PhysicsDirectBodyState.xml index 74190d0780..5117c9ef6c 100644 --- a/doc/classes/PhysicsDirectBodyState.xml +++ b/doc/classes/PhysicsDirectBodyState.xml @@ -35,6 +35,14 @@ <description> </description> </method> + <method name="apply_central_impulse"> + <return type="void"> + </return> + <argument index="0" name="j" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="apply_impulse"> <return type="void"> </return> @@ -107,6 +115,15 @@ <description> </description> </method> + <method name="get_contact_impulse" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="contact_idx" type="int"> + </argument> + <description> + Impulse created by the contact. Only implemented for Bullet physics. + </description> + </method> <method name="get_contact_local_normal" qualifiers="const"> <return type="Vector3"> </return> diff --git a/doc/classes/PhysicsMaterial.xml b/doc/classes/PhysicsMaterial.xml new file mode 100644 index 0000000000..5512c4605a --- /dev/null +++ b/doc/classes/PhysicsMaterial.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PhysicsMaterial" inherits="Resource" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml index d45a3adc9c..88a104cb11 100644 --- a/doc/classes/PhysicsServer.xml +++ b/doc/classes/PhysicsServer.xml @@ -294,6 +294,16 @@ Sets the transform matrix for an area. </description> </method> + <method name="body_add_central_force"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="force" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="body_add_collision_exception"> <return type="void"> </return> @@ -305,6 +315,18 @@ Adds a body to the list of bodies exempt from collisions. </description> </method> + <method name="body_add_force"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="force" type="Vector3"> + </argument> + <argument index="2" name="position" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="body_add_shape"> <return type="void"> </return> @@ -318,6 +340,26 @@ Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index. </description> </method> + <method name="body_add_torque"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="torque" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="body_apply_central_impulse"> + <return type="void"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="impulse" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="body_apply_impulse"> <return type="void"> </return> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index 83d1246e2a..0c8769714b 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -136,6 +136,8 @@ <method name="add_separator"> <return type="void"> </return> + <argument index="0" name="label" type="String" default=""""> + </argument> <description> Add a separator between items. Separators also occupy an index. </description> @@ -507,7 +509,7 @@ </member> <member name="hide_on_state_item_selection" type="bool" setter="set_hide_on_state_item_selection" getter="is_hide_on_state_item_selection"> </member> - <member name="submenu_popup_delay" type="real" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay"> + <member name="submenu_popup_delay" type="float" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay"> Sets the delay time for the submenu item to popup on mouse hovering. If the popup menu is added as a child of another (acting as a submenu), it will inherit the delay time of the parent menu item. Default value: [code]0.3[/code] seconds. </member> </members> @@ -553,6 +555,10 @@ </theme_item> <theme_item name="hseparation" type="int"> </theme_item> + <theme_item name="labeled_separator_left" type="StyleBox"> + </theme_item> + <theme_item name="labeled_separator_right" type="StyleBox"> + </theme_item> <theme_item name="panel" type="StyleBox"> </theme_item> <theme_item name="panel_disabled" type="StyleBox"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 666f6b4710..a4af5509a6 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -559,6 +559,8 @@ <member name="physics/2d/thread_model" type="int" setter="" getter=""> Set whether physics is run on the main thread or a separate one. Running the server on a thread increases performance, but restricts API Access to only physics process. </member> + <member name="physics/3d/active_soft_world" type="bool" setter="" getter=""> + </member> <member name="physics/3d/physics_engine" type="String" setter="" getter=""> </member> <member name="physics/common/physics_fps" type="int" setter="" getter=""> @@ -615,8 +617,6 @@ </member> <member name="rendering/quality/intended_usage/framebuffer_allocation.mobile" type="int" setter="" getter=""> </member> - <member name="rendering/quality/intended_usage/framebuffer_mode" type="int" setter="" getter=""> - </member> <member name="rendering/quality/reflections/high_quality_ggx" type="bool" setter="" getter=""> For reflection probes and panorama backgrounds (sky), use a high amount of samples to create ggx blurred versions (used for roughness). </member> diff --git a/doc/classes/RigidBody.xml b/doc/classes/RigidBody.xml index 4253560f67..038464e127 100644 --- a/doc/classes/RigidBody.xml +++ b/doc/classes/RigidBody.xml @@ -24,6 +24,40 @@ Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default it works in addition to the usual physics behavior, but [method set_use_custom_integrator] allows you to disable the default behavior and do fully custom force integration for a body. </description> </method> + <method name="add_central_force"> + <return type="void"> + </return> + <argument index="0" name="force" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="add_force"> + <return type="void"> + </return> + <argument index="0" name="force" type="Vector3"> + </argument> + <argument index="1" name="position" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="add_torque"> + <return type="void"> + </return> + <argument index="0" name="torque" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="apply_central_impulse"> + <return type="void"> + </return> + <argument index="0" name="impulse" type="Vector3"> + </argument> + <description> + </description> + </method> <method name="apply_impulse"> <return type="void"> </return> @@ -117,6 +151,8 @@ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidBody.Mode"> The body mode from the MODE_* enum. Modes include: MODE_STATIC, MODE_KINEMATIC, MODE_RIGID, and MODE_CHARACTER. </member> + <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + </member> <member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping"> If [code]true[/code] RigidBody is sleeping and will not calculate forces until woken up by a collision or the [code]apply_impulse[/code] method. </member> diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml index 75fbb48454..2265c777c8 100644 --- a/doc/classes/RigidBody2D.xml +++ b/doc/classes/RigidBody2D.xml @@ -23,6 +23,14 @@ Allows you to read and safely modify the simulation state for the object. Use this instead of [Node._physics_process] if you need to directly change the body's [code]position[/code] or other physics properties. By default it works in addition to the usual physics behavior, but [member custom_integrator] allows you to disable the default behavior and write custom force integration for a body. </description> </method> + <method name="add_central_force"> + <return type="void"> + </return> + <argument index="0" name="force" type="Vector2"> + </argument> + <description> + </description> + </method> <method name="add_force"> <return type="void"> </return> @@ -34,6 +42,22 @@ Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates. </description> </method> + <method name="add_torque"> + <return type="void"> + </return> + <argument index="0" name="torque" type="float"> + </argument> + <description> + </description> + </method> + <method name="apply_central_impulse"> + <return type="void"> + </return> + <argument index="0" name="impulse" type="Vector2"> + </argument> + <description> + </description> + </method> <method name="apply_impulse"> <return type="void"> </return> @@ -45,6 +69,14 @@ Applies a positioned impulse to the body (which will be affected by the body mass and shape). This is the equivalent of hitting a billiard ball with a cue: a force that is applied instantaneously. Both the impulse and the offset from the body origin are in global coordinates. </description> </method> + <method name="apply_torque_impulse"> + <return type="void"> + </return> + <argument index="0" name="torque" type="float"> + </argument> + <description> + </description> + </method> <method name="get_colliding_bodies" qualifiers="const"> <return type="Array"> </return> @@ -130,6 +162,8 @@ <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidBody2D.Mode"> The body's mode. See [code]MODE_*[/code] constants. Default value: [code]MODE_RIGID[/code]. </member> + <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + </member> <member name="sleeping" type="bool" setter="set_sleeping" getter="is_sleeping"> If [code]true[/code] the body is sleeping and will not calculate forces until woken up by a collision or by using [method apply_impulse] or [method add_force]. </member> diff --git a/doc/classes/RootMotionView.xml b/doc/classes/RootMotionView.xml new file mode 100644 index 0000000000..97008f05ff --- /dev/null +++ b/doc/classes/RootMotionView.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="RootMotionView" inherits="VisualInstance" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="animation_path" type="NodePath" setter="set_animation_path" getter="get_animation_path"> + </member> + <member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size"> + </member> + <member name="color" type="Color" setter="set_color" getter="get_color"> + </member> + <member name="radius" type="float" setter="set_radius" getter="get_radius"> + </member> + <member name="zero_y" type="bool" setter="set_zero_y" getter="get_zero_y"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/ScriptCreateDialog.xml b/doc/classes/ScriptCreateDialog.xml index f09d282026..a3ad3a778e 100644 --- a/doc/classes/ScriptCreateDialog.xml +++ b/doc/classes/ScriptCreateDialog.xml @@ -21,10 +21,8 @@ <return type="void"> </return> <argument index="0" name="inherits" type="String"> - The dialog's "Inherits" field content. </argument> <argument index="1" name="path" type="String"> - The dialog's "Path" field content. </argument> <description> Prefills required fields to configure the ScriptCreateDialog for use. diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml index a0ab4fe878..1e6ed65b48 100644 --- a/doc/classes/Slider.xml +++ b/doc/classes/Slider.xml @@ -15,10 +15,10 @@ <members> <member name="editable" type="bool" setter="set_editable" getter="is_editable"> </member> - <member name="scrollable" type="bool" setter="set_scrollable" getter="is_scrollable"> - </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode"> </member> + <member name="scrollable" type="bool" setter="set_scrollable" getter="is_scrollable"> + </member> <member name="tick_count" type="int" setter="set_ticks" getter="get_ticks"> </member> <member name="ticks_on_borders" type="bool" setter="set_ticks_on_borders" getter="get_ticks_on_borders"> diff --git a/doc/classes/SoftBody.xml b/doc/classes/SoftBody.xml new file mode 100644 index 0000000000..c3c789a6de --- /dev/null +++ b/doc/classes/SoftBody.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SoftBody" inherits="MeshInstance" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="add_collision_exception_with"> + <return type="void"> + </return> + <argument index="0" name="body" type="Node"> + </argument> + <description> + </description> + </method> + <method name="get_collision_layer_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_collision_mask_bit" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <description> + </description> + </method> + <method name="is_ray_pickable" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="remove_collision_exception_with"> + <return type="void"> + </return> + <argument index="0" name="body" type="Node"> + </argument> + <description> + </description> + </method> + <method name="set_collision_layer_bit"> + <return type="void"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_collision_mask_bit"> + <return type="void"> + </return> + <argument index="0" name="bit" type="int"> + </argument> + <argument index="1" name="value" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_ray_pickable"> + <return type="void"> + </return> + <argument index="0" name="ray_pickable" type="bool"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="areaAngular_stiffness" type="float" setter="set_areaAngular_stiffness" getter="get_areaAngular_stiffness"> + </member> + <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer"> + </member> + <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask"> + </member> + <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient"> + </member> + <member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient"> + </member> + <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness"> + </member> + <member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore"> + </member> + <member name="pose_matching_coefficient" type="float" setter="set_pose_matching_coefficient" getter="get_pose_matching_coefficient"> + </member> + <member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient"> + </member> + <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision"> + </member> + <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass"> + </member> + <member name="volume_stiffness" type="float" setter="set_volume_stiffness" getter="get_volume_stiffness"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml index d9242d8c42..ef1bcc30b3 100644 --- a/doc/classes/Spatial.xml +++ b/doc/classes/Spatial.xml @@ -69,6 +69,12 @@ Returns whether node notifies about its local transformation changes. Spatial will not propagate this by default. </description> </method> + <method name="is_scale_disabled" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> <method name="is_set_as_toplevel" qualifiers="const"> <return type="bool"> </return> @@ -190,6 +196,14 @@ Makes the node ignore its parents transformations. Node transformations are only in global space. </description> </method> + <method name="set_disable_scale"> + <return type="void"> + </return> + <argument index="0" name="disable" type="bool"> + </argument> + <description> + </description> + </method> <method name="set_identity"> <return type="void"> </return> diff --git a/doc/classes/SpatialMaterial.xml b/doc/classes/SpatialMaterial.xml index b45f2a13d4..4f48889531 100644 --- a/doc/classes/SpatialMaterial.xml +++ b/doc/classes/SpatialMaterial.xml @@ -84,8 +84,12 @@ </member> <member name="flags_albedo_tex_force_srgb" type="bool" setter="set_flag" getter="get_flag"> </member> + <member name="flags_disable_ambient_light" type="bool" setter="set_flag" getter="get_flag"> + </member> <member name="flags_do_not_receive_shadows" type="bool" setter="set_flag" getter="get_flag"> </member> + <member name="flags_ensure_correct_normals" type="bool" setter="set_flag" getter="get_flag"> + </member> <member name="flags_fixed_size" type="bool" setter="set_flag" getter="get_flag"> </member> <member name="flags_no_depth_test" type="bool" setter="set_flag" getter="get_flag"> @@ -116,6 +120,8 @@ </member> <member name="params_alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold"> </member> + <member name="params_billboard_keep_scale" type="bool" setter="set_flag" getter="get_flag"> + </member> <member name="params_billboard_mode" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="SpatialMaterial.BillboardMode"> </member> <member name="params_blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="SpatialMaterial.BlendMode"> @@ -304,23 +310,29 @@ </constant> <constant name="FLAG_FIXED_SIZE" value="6" enum="Flags"> </constant> - <constant name="FLAG_UV1_USE_TRIPLANAR" value="7" enum="Flags"> + <constant name="FLAG_BILLBOARD_KEEP_SCALE" value="7" enum="Flags"> + </constant> + <constant name="FLAG_UV1_USE_TRIPLANAR" value="8" enum="Flags"> + </constant> + <constant name="FLAG_UV2_USE_TRIPLANAR" value="9" enum="Flags"> + </constant> + <constant name="FLAG_AO_ON_UV2" value="11" enum="Flags"> </constant> - <constant name="FLAG_UV2_USE_TRIPLANAR" value="8" enum="Flags"> + <constant name="FLAG_EMISSION_ON_UV2" value="12" enum="Flags"> </constant> - <constant name="FLAG_AO_ON_UV2" value="10" enum="Flags"> + <constant name="FLAG_USE_ALPHA_SCISSOR" value="13" enum="Flags"> </constant> - <constant name="FLAG_EMISSION_ON_UV2" value="11" enum="Flags"> + <constant name="FLAG_TRIPLANAR_USE_WORLD" value="10" enum="Flags"> </constant> - <constant name="FLAG_USE_ALPHA_SCISSOR" value="12" enum="Flags"> + <constant name="FLAG_ALBEDO_TEXTURE_FORCE_SRGB" value="14" enum="Flags"> </constant> - <constant name="FLAG_TRIPLANAR_USE_WORLD" value="9" enum="Flags"> + <constant name="FLAG_DONT_RECEIVE_SHADOWS" value="15" enum="Flags"> </constant> - <constant name="FLAG_ALBEDO_TEXTURE_FORCE_SRGB" value="13" enum="Flags"> + <constant name="FLAG_DISABLE_AMBIENT_LIGHT" value="17" enum="Flags"> </constant> - <constant name="FLAG_DONT_RECEIVE_SHADOWS" value="14" enum="Flags"> + <constant name="FLAG_ENSURE_CORRECT_NORMALS" value="16" enum="Flags"> </constant> - <constant name="FLAG_MAX" value="15" enum="Flags"> + <constant name="FLAG_MAX" value="18" enum="Flags"> </constant> <constant name="DIFFUSE_BURLEY" value="0" enum="DiffuseMode"> </constant> diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml index 68373ebc4f..0e11d797e4 100644 --- a/doc/classes/SpriteFrames.xml +++ b/doc/classes/SpriteFrames.xml @@ -58,6 +58,13 @@ If [code]true[/code] the given animation will loop. </description> </method> + <method name="get_animation_names" qualifiers="const"> + <return type="PoolStringArray"> + </return> + <description> + Returns an array containing the names associated to each animation. Values are placed in alphabetical order. + </description> + </method> <method name="get_animation_speed" qualifiers="const"> <return type="float"> </return> @@ -127,13 +134,6 @@ Changes the animation's name to [code]newname[/code]. </description> </method> - <method name="get_animation_names"> - <return type="PoolStringArray"> - </return> - <description> - Returns an array containing the names associated to each animation. Values are placed in alphabetical order. - </description> - </method> <method name="set_animation_loop"> <return type="void"> </return> diff --git a/doc/classes/StaticBody.xml b/doc/classes/StaticBody.xml index 26b4857670..442a520e30 100644 --- a/doc/classes/StaticBody.xml +++ b/doc/classes/StaticBody.xml @@ -27,6 +27,8 @@ <member name="friction" type="float" setter="set_friction" getter="get_friction"> The body friction, from 0 (frictionless) to 1 (full friction). </member> + <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + </member> </members> <constants> </constants> diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml index 95acda79df..917773d502 100644 --- a/doc/classes/StaticBody2D.xml +++ b/doc/classes/StaticBody2D.xml @@ -26,6 +26,8 @@ <member name="friction" type="float" setter="set_friction" getter="get_friction"> The body's friction. Values range from [code]0[/code] (no friction) to [code]1[/code] (full friction). </member> + <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> + </member> </members> <constants> </constants> diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml index 3081abd5c4..cf8769d22b 100644 --- a/doc/classes/StreamPeerSSL.xml +++ b/doc/classes/StreamPeerSSL.xml @@ -15,7 +15,7 @@ <method name="accept_stream"> <return type="int" enum="Error"> </return> - <argument index="0" name="stream" type="StreamPeer"> + <argument index="0" name="base" type="StreamPeer"> </argument> <description> </description> @@ -55,17 +55,20 @@ </description> </method> </methods> + <members> + <member name="blocking_handshake" type="bool" setter="set_blocking_handshake_enabled" getter="is_blocking_handshake_enabled"> + </member> + </members> <constants> <constant name="STATUS_DISCONNECTED" value="0" enum="Status"> A status representing a [code]StreamPeerSSL[/code] that is disconnected. </constant> - <constant name="STATUS_CONNECTED" value="1" enum="Status"> + <constant name="STATUS_CONNECTED" value="2" enum="Status"> A status representing a [code]StreamPeerSSL[/code] that is connected to a host. </constant> - <constant name="STATUS_ERROR_NO_CERTIFICATE" value="2" enum="Status"> - An errot status that shows the peer did not present a SSL certificate and validation was requested. + <constant name="STATUS_ERROR" value="3" enum="Status"> </constant> - <constant name="STATUS_ERROR_HOSTNAME_MISMATCH" value="3" enum="Status"> + <constant name="STATUS_ERROR_HOSTNAME_MISMATCH" value="4" enum="Status"> An error status that shows a mismatch in the SSL certificate domain presented by the host and the domain requested for validation. </constant> </constants> diff --git a/doc/classes/StyleBoxLine.xml b/doc/classes/StyleBoxLine.xml index c891c8cf83..146b4b0a3d 100644 --- a/doc/classes/StyleBoxLine.xml +++ b/doc/classes/StyleBoxLine.xml @@ -13,7 +13,9 @@ <members> <member name="color" type="Color" setter="set_color" getter="get_color"> </member> - <member name="grow" type="float" setter="set_grow" getter="get_grow"> + <member name="grow_begin" type="float" setter="set_grow_begin" getter="get_grow_begin"> + </member> + <member name="grow_end" type="float" setter="set_grow_end" getter="get_grow_end"> </member> <member name="thickness" type="int" setter="set_thickness" getter="get_thickness"> </member> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 7d78d71330..deda7bc292 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -170,7 +170,7 @@ </return> <argument index="0" name="existing" type="ArrayMesh" default="null"> </argument> - <argument index="1" name="flags" type="int" default="97792"> + <argument index="1" name="flags" type="int" default="97280"> </argument> <description> Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh]. diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index 11e94abc03..5acfd6194e 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TabContainer" inherits="Control" category="Core" version="3.1"> +<class name="TabContainer" inherits="Container" category="Core" version="3.1"> <brief_description> Tabbed Container. </brief_description> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 36408663f6..a958c3fcfa 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -227,12 +227,6 @@ Insert a given text at the cursor position. </description> </method> - <method name="is_breakpoint_gutter_enabled" qualifiers="const"> - <return type="bool"> - </return> - <description> - </description> - </method> <method name="is_folded" qualifiers="const"> <return type="bool"> </return> @@ -322,14 +316,6 @@ Select all the text. </description> </method> - <method name="set_breakpoint_gutter_enabled"> - <return type="void"> - </return> - <argument index="0" name="enable" type="bool"> - </argument> - <description> - </description> - </method> <method name="set_line_as_hidden"> <return type="void"> </return> @@ -541,6 +527,8 @@ </theme_item> <theme_item name="read_only" type="StyleBox"> </theme_item> + <theme_item name="safe_line_number_color" type="Color"> + </theme_item> <theme_item name="selection_color" type="Color"> </theme_item> <theme_item name="symbol_color" type="Color"> diff --git a/doc/classes/TextFile.xml b/doc/classes/TextFile.xml new file mode 100644 index 0000000000..f8c1fd690e --- /dev/null +++ b/doc/classes/TextFile.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="TextFile" inherits="Resource" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/TextureProgress.xml b/doc/classes/TextureProgress.xml index 2ae4ef2cf8..f74420e8b1 100644 --- a/doc/classes/TextureProgress.xml +++ b/doc/classes/TextureProgress.xml @@ -77,5 +77,11 @@ <constant name="FILL_COUNTER_CLOCKWISE" value="5" enum="FillMode"> Turns the node into a radial bar. The [member texture_progress] fills counter-clockwise. See [member radial_center_offset], [member radial_initial_angle] and [member radial_fill_degrees] to refine its behavior. </constant> + <constant name="FILL_BILINEAR_LEFT_AND_RIGHT" value="6" enum="FillMode"> + </constant> + <constant name="FILL_BILINEAR_TOP_AND_BOTTOM" value="7" enum="FillMode"> + </constant> + <constant name="FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE" value="8" enum="FillMode"> + </constant> </constants> </class> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 656063771d..2990906f7c 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -153,6 +153,18 @@ Sets the tile index for the cell given by a Vector2. An index of [code]-1[/code] clears the cell. Optionally, the tile can also be flipped, transposed, or given autotile coordinates. + Note that data such as navigation polygons and collision shapes are not immediately updated for performance reasons. + If you need these to be immediately updated, you can call [method update_dirty_quadrants]. + </description> + </method> + <method name="set_celld"> + <return type="void"> + </return> + <argument index="0" name="position" type="Vector2"> + </argument> + <argument index="1" name="data" type="Dictionary"> + </argument> + <description> </description> </method> <method name="set_cellv"> @@ -172,6 +184,8 @@ Sets the tile index for the given cell. An index of [code]-1[/code] clears the cell. Optionally, the tile can also be flipped or transposed. + Note that data such as navigation polygons and collision shapes are not immediately updated for performance reasons. + If you need these to be immediately updated, you can call [method update_dirty_quadrants]. </description> </method> <method name="set_collision_layer_bit"> @@ -217,6 +231,13 @@ Calling with invalid (or missing) parameters applies autotiling rules for the entire tilemap. </description> </method> + <method name="update_dirty_quadrants"> + <return type="void"> + </return> + <description> + Updates the tile map's quadrants, allowing things such as navigation and collision shapes to be immediately used if modified. + </description> + </method> <method name="world_to_map" qualifiers="const"> <return type="Vector2"> </return> diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index bdf8634a6c..7121bc8b9c 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -136,6 +136,14 @@ Return the material of the tile. </description> </method> + <method name="tile_get_modulate" qualifiers="const"> + <return type="Color"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <description> + </description> + </method> <method name="tile_get_name" qualifiers="const"> <return type="String"> </return> @@ -292,6 +300,16 @@ Set the material of the tile. </description> </method> + <method name="tile_set_modulate"> + <return type="void"> + </return> + <argument index="0" name="id" type="int"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <description> + </description> + </method> <method name="tile_set_name"> <return type="void"> </return> diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index d82694d328..2332c1a7aa 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -181,12 +181,6 @@ Returns [code]true[/code] if any tweens are currently running. Note that this method doesn't consider tweens that have ended. </description> </method> - <method name="is_stopped" qualifiers="const"> - <return type="bool"> - </return> - <description> - </description> - </method> <method name="remove"> <return type="bool"> </return> diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index a1a6d7f465..b9550c17fb 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -117,13 +117,13 @@ </description> </method> <method name="redo"> - <return type="void"> + <return type="bool"> </return> <description> </description> </method> <method name="undo"> - <return type="void"> + <return type="bool"> </return> <description> </description> diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 893db84640..c4ebf7c96f 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -973,8 +973,9 @@ </return> <argument index="0" name="swap_buffers" type="bool" default="true"> </argument> + <argument index="1" name="frame_step" type="float" default="0.0"> + </argument> <description> - Draws a frame. </description> </method> <method name="environment_create"> @@ -1206,13 +1207,15 @@ </argument> <argument index="7" name="light_affect" type="float"> </argument> - <argument index="8" name="color" type="Color"> + <argument index="8" name="ao_channel_affect" type="float"> + </argument> + <argument index="9" name="color" type="Color"> </argument> - <argument index="9" name="quality" type="int" enum="VisualServer.EnvironmentSSAOQuality"> + <argument index="10" name="quality" type="int" enum="VisualServer.EnvironmentSSAOQuality"> </argument> - <argument index="10" name="blur" type="int" enum="VisualServer.EnvironmentSSAOBlur"> + <argument index="11" name="blur" type="int" enum="VisualServer.EnvironmentSSAOBlur"> </argument> - <argument index="11" name="bilateral_sharpness" type="float"> + <argument index="12" name="bilateral_sharpness" type="float"> </argument> <description> </description> @@ -1273,8 +1276,9 @@ </return> <argument index="0" name="swap_buffers" type="bool" default="true"> </argument> + <argument index="1" name="frame_step" type="float" default="0.0"> + </argument> <description> - Draws a frame. Same as [method draw]. </description> </method> <method name="force_sync"> @@ -2258,7 +2262,7 @@ </argument> <argument index="3" name="blend_shapes" type="Array" default="[ ]"> </argument> - <argument index="4" name="compress_format" type="int" default="97792"> + <argument index="4" name="compress_format" type="int" default="97280"> </argument> <description> Adds a surface generated from the Arrays to a mesh. See PRIMITIVE_TYPE_* constants for types. @@ -2437,6 +2441,32 @@ Returns the format of a mesh's surface. </description> </method> + <method name="mesh_surface_get_format_offset" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="format" type="int"> + </argument> + <argument index="1" name="vertex_len" type="int"> + </argument> + <argument index="2" name="index_len" type="int"> + </argument> + <argument index="3" name="array_index" type="int"> + </argument> + <description> + </description> + </method> + <method name="mesh_surface_get_format_stride" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="format" type="int"> + </argument> + <argument index="1" name="vertex_len" type="int"> + </argument> + <argument index="2" name="index_len" type="int"> + </argument> + <description> + </description> + </method> <method name="mesh_surface_get_index_array" qualifiers="const"> <return type="PoolByteArray"> </return> @@ -2494,6 +2524,20 @@ Sets a mesh's surface's material. </description> </method> + <method name="mesh_surface_update_region"> + <return type="void"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="surface" type="int"> + </argument> + <argument index="2" name="offset" type="int"> + </argument> + <argument index="3" name="data" type="PoolByteArray"> + </argument> + <description> + </description> + </method> <method name="multimesh_allocate"> <return type="void"> </return> @@ -2505,6 +2549,8 @@ </argument> <argument index="3" name="color_format" type="int" enum="VisualServer.MultimeshColorFormat"> </argument> + <argument index="4" name="custom_data_format" type="int" enum="VisualServer.MultimeshCustomDataFormat" default="0"> + </argument> <description> </description> </method> @@ -2550,6 +2596,16 @@ <description> </description> </method> + <method name="multimesh_instance_get_custom_data" qualifiers="const"> + <return type="Color"> + </return> + <argument index="0" name="multimesh" type="RID"> + </argument> + <argument index="1" name="index" type="int"> + </argument> + <description> + </description> + </method> <method name="multimesh_instance_get_transform" qualifiers="const"> <return type="Transform"> </return> @@ -2582,6 +2638,18 @@ <description> </description> </method> + <method name="multimesh_instance_set_custom_data"> + <return type="void"> + </return> + <argument index="0" name="multimesh" type="RID"> + </argument> + <argument index="1" name="index" type="int"> + </argument> + <argument index="2" name="custom_data" type="Color"> + </argument> + <description> + </description> + </method> <method name="multimesh_instance_set_transform"> <return type="void"> </return> @@ -2606,6 +2674,16 @@ <description> </description> </method> + <method name="multimesh_set_as_bulk_array"> + <return type="void"> + </return> + <argument index="0" name="multimesh" type="RID"> + </argument> + <argument index="1" name="array" type="PoolRealArray"> + </argument> + <description> + </description> + </method> <method name="multimesh_set_mesh"> <return type="void"> </return> @@ -3746,7 +3824,11 @@ </method> </methods> <signals> - <signal name="frame_drawn_in_thread"> + <signal name="frame_post_draw"> + <description> + </description> + </signal> + <signal name="frame_pre_draw"> <description> </description> </signal> @@ -3919,7 +4001,7 @@ <constant name="ARRAY_FLAG_USE_16_BIT_BONES" value="524288" enum="ArrayFormat"> Flag used to mark that the array uses 16 bit bones instead of 8 bit. </constant> - <constant name="ARRAY_COMPRESS_DEFAULT" value="97792" enum="ArrayFormat"> + <constant name="ARRAY_COMPRESS_DEFAULT" value="97280" enum="ArrayFormat"> Used to set flags ARRAY_COMPRESS_VERTEX, ARRAY_COMPRESS_NORMAL, ARRAY_COMPRESS_TANGENT, ARRAY_COMPRESS_COLOR, ARRAY_COMPRESS_TEX_UV, ARRAY_COMPRESS_TEX_UV2 and ARRAY_COMPRESS_WEIGHTS quickly. </constant> <constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType"> @@ -4126,7 +4208,9 @@ </constant> <constant name="INSTANCE_FLAG_USE_BAKED_LIGHT" value="0" enum="InstanceFlags"> </constant> - <constant name="INSTANCE_FLAG_MAX" value="1" enum="InstanceFlags"> + <constant name="INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE" value="1" enum="InstanceFlags"> + </constant> + <constant name="INSTANCE_FLAG_MAX" value="2" enum="InstanceFlags"> </constant> <constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting"> </constant> diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml new file mode 100644 index 0000000000..ab00080fef --- /dev/null +++ b/doc/classes/VisualShader.xml @@ -0,0 +1,183 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShader" inherits="Shader" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="add_node"> + <return type="void"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="node" type="VisualShaderNode"> + </argument> + <argument index="2" name="position" type="Vector2"> + </argument> + <argument index="3" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="can_connect_nodes" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="from_node" type="int"> + </argument> + <argument index="2" name="from_port" type="int"> + </argument> + <argument index="3" name="to_node" type="int"> + </argument> + <argument index="4" name="to_port" type="int"> + </argument> + <description> + </description> + </method> + <method name="connect_nodes"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="from_node" type="int"> + </argument> + <argument index="2" name="from_port" type="int"> + </argument> + <argument index="3" name="to_node" type="int"> + </argument> + <argument index="4" name="to_port" type="int"> + </argument> + <description> + </description> + </method> + <method name="disconnect_nodes"> + <return type="void"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="from_node" type="int"> + </argument> + <argument index="2" name="from_port" type="int"> + </argument> + <argument index="3" name="to_node" type="int"> + </argument> + <argument index="4" name="to_port" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_node" qualifiers="const"> + <return type="VisualShaderNode"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_node_connections" qualifiers="const"> + <return type="Array"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <description> + </description> + </method> + <method name="get_node_list" qualifiers="const"> + <return type="PoolIntArray"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <description> + </description> + </method> + <method name="get_node_position" qualifiers="const"> + <return type="Vector2"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="get_valid_node_id" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <description> + </description> + </method> + <method name="is_node_connection" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="from_node" type="int"> + </argument> + <argument index="2" name="from_port" type="int"> + </argument> + <argument index="3" name="to_node" type="int"> + </argument> + <argument index="4" name="to_port" type="int"> + </argument> + <description> + </description> + </method> + <method name="remove_node"> + <return type="void"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="id" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_mode"> + <return type="void"> + </return> + <argument index="0" name="mode" type="int" enum="Shader.Mode"> + </argument> + <description> + </description> + </method> + <method name="set_node_position"> + <return type="void"> + </return> + <argument index="0" name="type" type="int" enum="VisualShader.Type"> + </argument> + <argument index="1" name="id" type="int"> + </argument> + <argument index="2" name="position" type="Vector2"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset"> + </member> + </members> + <constants> + <constant name="TYPE_VERTEX" value="0" enum="Type"> + </constant> + <constant name="TYPE_FRAGMENT" value="1" enum="Type"> + </constant> + <constant name="TYPE_LIGHT" value="2" enum="Type"> + </constant> + <constant name="TYPE_MAX" value="3" enum="Type"> + </constant> + <constant name="NODE_ID_INVALID" value="-1"> + </constant> + <constant name="NODE_ID_OUTPUT" value="0"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml new file mode 100644 index 0000000000..ffcaf85eea --- /dev/null +++ b/doc/classes/VisualShaderNode.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNode" inherits="Resource" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + <method name="get_input_port_default_value" qualifiers="const"> + <return type="Variant"> + </return> + <argument index="0" name="port" type="int"> + </argument> + <description> + </description> + </method> + <method name="set_input_port_default_value"> + <return type="void"> + </return> + <argument index="0" name="port" type="int"> + </argument> + <argument index="1" name="value" type="Variant"> + </argument> + <description> + </description> + </method> + </methods> + <members> + <member name="default_input_values" type="Array" setter="_set_default_input_values" getter="_get_default_input_values"> + </member> + <member name="output_port_for_preview" type="int" setter="set_output_port_for_preview" getter="get_output_port_for_preview"> + </member> + </members> + <signals> + <signal name="editor_refresh_request"> + <description> + </description> + </signal> + </signals> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeColorConstant.xml b/doc/classes/VisualShaderNodeColorConstant.xml new file mode 100644 index 0000000000..f1079e0056 --- /dev/null +++ b/doc/classes/VisualShaderNodeColorConstant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeColorConstant" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="constant" type="Color" setter="set_constant" getter="get_constant"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeColorOp.xml b/doc/classes/VisualShaderNodeColorOp.xml new file mode 100644 index 0000000000..d23c674503 --- /dev/null +++ b/doc/classes/VisualShaderNodeColorOp.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeColorOp" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="VisualShaderNodeColorOp.Operator"> + </member> + </members> + <constants> + <constant name="OP_SCREEN" value="0" enum="Operator"> + </constant> + <constant name="OP_DIFFERENCE" value="1" enum="Operator"> + </constant> + <constant name="OP_DARKEN" value="2" enum="Operator"> + </constant> + <constant name="OP_LIGHTEN" value="3" enum="Operator"> + </constant> + <constant name="OP_OVERLAY" value="4" enum="Operator"> + </constant> + <constant name="OP_DODGE" value="5" enum="Operator"> + </constant> + <constant name="OP_BURN" value="6" enum="Operator"> + </constant> + <constant name="OP_SOFT_LIGHT" value="7" enum="Operator"> + </constant> + <constant name="OP_HARD_LIGHT" value="8" enum="Operator"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeColorUniform.xml b/doc/classes/VisualShaderNodeColorUniform.xml new file mode 100644 index 0000000000..0b97c104a2 --- /dev/null +++ b/doc/classes/VisualShaderNodeColorUniform.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeColorUniform" inherits="VisualShaderNodeUniform" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeCubeMap.xml b/doc/classes/VisualShaderNodeCubeMap.xml new file mode 100644 index 0000000000..9c56a23b7f --- /dev/null +++ b/doc/classes/VisualShaderNodeCubeMap.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeCubeMap" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="cube_map" type="CubeMap" setter="set_cube_map" getter="get_cube_map"> + </member> + <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeCubeMap.TextureType"> + </member> + </members> + <constants> + <constant name="TYPE_DATA" value="0" enum="TextureType"> + </constant> + <constant name="TYPE_COLOR" value="1" enum="TextureType"> + </constant> + <constant name="TYPE_NORMALMAP" value="2" enum="TextureType"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeCubeMapUniform.xml b/doc/classes/VisualShaderNodeCubeMapUniform.xml new file mode 100644 index 0000000000..fc95e4ddd9 --- /dev/null +++ b/doc/classes/VisualShaderNodeCubeMapUniform.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeCubeMapUniform" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeDotProduct.xml b/doc/classes/VisualShaderNodeDotProduct.xml new file mode 100644 index 0000000000..c82f4cec3b --- /dev/null +++ b/doc/classes/VisualShaderNodeDotProduct.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeDotProduct" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeInput.xml b/doc/classes/VisualShaderNodeInput.xml new file mode 100644 index 0000000000..29de7f81d1 --- /dev/null +++ b/doc/classes/VisualShaderNodeInput.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeInput" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="input_name" type="String" setter="set_input_name" getter="get_input_name"> + </member> + </members> + <signals> + <signal name="input_type_changed"> + <description> + </description> + </signal> + </signals> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeOutput.xml b/doc/classes/VisualShaderNodeOutput.xml new file mode 100644 index 0000000000..7b65c6fd5e --- /dev/null +++ b/doc/classes/VisualShaderNodeOutput.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeOutput" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarConstant.xml b/doc/classes/VisualShaderNodeScalarConstant.xml new file mode 100644 index 0000000000..424fb2b3bd --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarConstant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarConstant" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="constant" type="float" setter="set_constant" getter="get_constant"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarFunc.xml b/doc/classes/VisualShaderNodeScalarFunc.xml new file mode 100644 index 0000000000..7362ededce --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarFunc.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarFunc" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeScalarFunc.Function"> + </member> + </members> + <constants> + <constant name="FUNC_SIN" value="0" enum="Function"> + </constant> + <constant name="FUNC_COS" value="1" enum="Function"> + </constant> + <constant name="FUNC_TAN" value="2" enum="Function"> + </constant> + <constant name="FUNC_ASIN" value="3" enum="Function"> + </constant> + <constant name="FUNC_ACOS" value="4" enum="Function"> + </constant> + <constant name="FUNC_ATAN" value="5" enum="Function"> + </constant> + <constant name="FUNC_SINH" value="6" enum="Function"> + </constant> + <constant name="FUNC_COSH" value="7" enum="Function"> + </constant> + <constant name="FUNC_TANH" value="8" enum="Function"> + </constant> + <constant name="FUNC_LOG" value="9" enum="Function"> + </constant> + <constant name="FUNC_EXP" value="10" enum="Function"> + </constant> + <constant name="FUNC_SQRT" value="11" enum="Function"> + </constant> + <constant name="FUNC_ABS" value="12" enum="Function"> + </constant> + <constant name="FUNC_SIGN" value="13" enum="Function"> + </constant> + <constant name="FUNC_FLOOR" value="14" enum="Function"> + </constant> + <constant name="FUNC_ROUND" value="15" enum="Function"> + </constant> + <constant name="FUNC_CEIL" value="16" enum="Function"> + </constant> + <constant name="FUNC_FRAC" value="17" enum="Function"> + </constant> + <constant name="FUNC_SATURATE" value="18" enum="Function"> + </constant> + <constant name="FUNC_NEGATE" value="19" enum="Function"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarInterp.xml b/doc/classes/VisualShaderNodeScalarInterp.xml new file mode 100644 index 0000000000..8420b34dd3 --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarInterp.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarInterp" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarOp.xml b/doc/classes/VisualShaderNodeScalarOp.xml new file mode 100644 index 0000000000..0ab0a46d0a --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarOp.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarOp" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="VisualShaderNodeScalarOp.Operator"> + </member> + </members> + <constants> + <constant name="OP_ADD" value="0" enum="Operator"> + </constant> + <constant name="OP_SUB" value="1" enum="Operator"> + </constant> + <constant name="OP_MUL" value="2" enum="Operator"> + </constant> + <constant name="OP_DIV" value="3" enum="Operator"> + </constant> + <constant name="OP_MOD" value="4" enum="Operator"> + </constant> + <constant name="OP_POW" value="5" enum="Operator"> + </constant> + <constant name="OP_MAX" value="6" enum="Operator"> + </constant> + <constant name="OP_MIN" value="7" enum="Operator"> + </constant> + <constant name="OP_ATAN2" value="8" enum="Operator"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarUniform.xml b/doc/classes/VisualShaderNodeScalarUniform.xml new file mode 100644 index 0000000000..352355b475 --- /dev/null +++ b/doc/classes/VisualShaderNodeScalarUniform.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeScalarUniform" inherits="VisualShaderNodeUniform" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTexture.xml b/doc/classes/VisualShaderNodeTexture.xml new file mode 100644 index 0000000000..18b2fc3b3f --- /dev/null +++ b/doc/classes/VisualShaderNodeTexture.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTexture" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="source" type="int" setter="set_source" getter="get_source" enum="VisualShaderNodeTexture.Source"> + </member> + <member name="texture" type="Texture" setter="set_texture" getter="get_texture"> + </member> + <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTexture.TextureType"> + </member> + </members> + <constants> + <constant name="SOURCE_TEXTURE" value="0" enum="Source"> + </constant> + <constant name="SOURCE_SCREEN" value="1" enum="Source"> + </constant> + <constant name="SOURCE_2D_TEXTURE" value="2" enum="Source"> + </constant> + <constant name="SOURCE_2D_NORMAL" value="3" enum="Source"> + </constant> + <constant name="TYPE_DATA" value="0" enum="TextureType"> + </constant> + <constant name="TYPE_COLOR" value="1" enum="TextureType"> + </constant> + <constant name="TYPE_NORMALMAP" value="2" enum="TextureType"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTextureUniform.xml b/doc/classes/VisualShaderNodeTextureUniform.xml new file mode 100644 index 0000000000..1b5df52060 --- /dev/null +++ b/doc/classes/VisualShaderNodeTextureUniform.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTextureUniform" inherits="VisualShaderNodeUniform" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="color_default" type="int" setter="set_color_default" getter="get_color_default" enum="VisualShaderNodeTextureUniform.ColorDefault"> + </member> + <member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureUniform.TextureType"> + </member> + </members> + <constants> + <constant name="TYPE_DATA" value="0" enum="TextureType"> + </constant> + <constant name="TYPE_COLOR" value="1" enum="TextureType"> + </constant> + <constant name="TYPE_NORMALMAP" value="2" enum="TextureType"> + </constant> + <constant name="TYPE_ANISO" value="3" enum="TextureType"> + </constant> + <constant name="COLOR_DEFAULT_WHITE" value="0" enum="ColorDefault"> + </constant> + <constant name="COLOR_DEFAULT_BLACK" value="1" enum="ColorDefault"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformCompose.xml b/doc/classes/VisualShaderNodeTransformCompose.xml new file mode 100644 index 0000000000..e1bda001e3 --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformCompose.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformCompose" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformConstant.xml b/doc/classes/VisualShaderNodeTransformConstant.xml new file mode 100644 index 0000000000..e86444563c --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformConstant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="constant" type="Transform" setter="set_constant" getter="get_constant"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformDecompose.xml b/doc/classes/VisualShaderNodeTransformDecompose.xml new file mode 100644 index 0000000000..ee6d5c5d74 --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformDecompose.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformDecompose" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformMult.xml b/doc/classes/VisualShaderNodeTransformMult.xml new file mode 100644 index 0000000000..31aa40db96 --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformMult.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformMult" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="VisualShaderNodeTransformMult.Operator"> + </member> + </members> + <constants> + <constant name="OP_AxB" value="0" enum="Operator"> + </constant> + <constant name="OP_BxA" value="1" enum="Operator"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformUniform.xml b/doc/classes/VisualShaderNodeTransformUniform.xml new file mode 100644 index 0000000000..65b1088247 --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformUniform.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformUniform" inherits="VisualShaderNodeUniform" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeTransformVecMult.xml b/doc/classes/VisualShaderNodeTransformVecMult.xml new file mode 100644 index 0000000000..d3fb445717 --- /dev/null +++ b/doc/classes/VisualShaderNodeTransformVecMult.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeTransformVecMult" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="VisualShaderNodeTransformVecMult.Operator"> + </member> + </members> + <constants> + <constant name="OP_AxB" value="0" enum="Operator"> + </constant> + <constant name="OP_BxA" value="1" enum="Operator"> + </constant> + <constant name="OP_3x3_AxB" value="2" enum="Operator"> + </constant> + <constant name="OP_3x3_BxA" value="3" enum="Operator"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeUniform.xml b/doc/classes/VisualShaderNodeUniform.xml new file mode 100644 index 0000000000..2c02afd0a7 --- /dev/null +++ b/doc/classes/VisualShaderNodeUniform.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeUniform" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="uniform_name" type="String" setter="set_uniform_name" getter="get_uniform_name"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVec3Constant.xml b/doc/classes/VisualShaderNodeVec3Constant.xml new file mode 100644 index 0000000000..7492f56223 --- /dev/null +++ b/doc/classes/VisualShaderNodeVec3Constant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVec3Constant" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="constant" type="Vector3" setter="set_constant" getter="get_constant"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVec3Uniform.xml b/doc/classes/VisualShaderNodeVec3Uniform.xml new file mode 100644 index 0000000000..79a21680fb --- /dev/null +++ b/doc/classes/VisualShaderNodeVec3Uniform.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVec3Uniform" inherits="VisualShaderNodeUniform" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorCompose.xml b/doc/classes/VisualShaderNodeVectorCompose.xml new file mode 100644 index 0000000000..39798a82d1 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorCompose.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorCompose" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorDecompose.xml b/doc/classes/VisualShaderNodeVectorDecompose.xml new file mode 100644 index 0000000000..8df12d8ba9 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorDecompose.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorDecompose" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorFunc.xml b/doc/classes/VisualShaderNodeVectorFunc.xml new file mode 100644 index 0000000000..850b089645 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorFunc.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorFunc" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeVectorFunc.Function"> + </member> + </members> + <constants> + <constant name="FUNC_NORMALIZE" value="0" enum="Function"> + </constant> + <constant name="FUNC_SATURATE" value="1" enum="Function"> + </constant> + <constant name="FUNC_NEGATE" value="2" enum="Function"> + </constant> + <constant name="FUNC_RECIPROCAL" value="3" enum="Function"> + </constant> + <constant name="FUNC_RGB2HSV" value="4" enum="Function"> + </constant> + <constant name="FUNC_HSV2RGB" value="5" enum="Function"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorInterp.xml b/doc/classes/VisualShaderNodeVectorInterp.xml new file mode 100644 index 0000000000..909cd7eacc --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorInterp.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorInterp" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorLen.xml b/doc/classes/VisualShaderNodeVectorLen.xml new file mode 100644 index 0000000000..ad87d0bd0a --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorLen.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorLen" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVectorOp.xml b/doc/classes/VisualShaderNodeVectorOp.xml new file mode 100644 index 0000000000..3e20168f15 --- /dev/null +++ b/doc/classes/VisualShaderNodeVectorOp.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeVectorOp" inherits="VisualShaderNode" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <members> + <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="VisualShaderNodeVectorOp.Operator"> + </member> + </members> + <constants> + <constant name="OP_ADD" value="0" enum="Operator"> + </constant> + <constant name="OP_SUB" value="1" enum="Operator"> + </constant> + <constant name="OP_MUL" value="2" enum="Operator"> + </constant> + <constant name="OP_DIV" value="3" enum="Operator"> + </constant> + <constant name="OP_MOD" value="4" enum="Operator"> + </constant> + <constant name="OP_POW" value="5" enum="Operator"> + </constant> + <constant name="OP_MAX" value="6" enum="Operator"> + </constant> + <constant name="OP_MIN" value="7" enum="Operator"> + </constant> + <constant name="OP_CROSS" value="8" enum="Operator"> + </constant> + </constants> +</class> diff --git a/drivers/SCsub b/drivers/SCsub index 2c5e9434e8..f9cfa3fb05 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -21,6 +21,11 @@ if (env["platform"] == "windows"): if env['xaudio2']: SConscript("xaudio2/SCsub") +# Midi drivers +SConscript('alsamidi/SCsub') +SConscript('coremidi/SCsub') +SConscript('winmidi/SCsub') + # Graphics drivers if (env["platform"] != "server"): SConscript('gles3/SCsub') diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index ae85ee50d1..a44a11a46d 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -58,7 +58,10 @@ Error AudioDriverALSA::init_device() { #define CHECK_FAIL(m_cond) \ if (m_cond) { \ fprintf(stderr, "ALSA ERR: %s\n", snd_strerror(status)); \ - snd_pcm_close(pcm_handle); \ + if (pcm_handle) { \ + snd_pcm_close(pcm_handle); \ + pcm_handle = NULL; \ + } \ ERR_FAIL_COND_V(m_cond, ERR_CANT_OPEN); \ } @@ -150,7 +153,6 @@ Error AudioDriverALSA::init() { active = false; thread_exited = false; exit_thread = false; - pcm_open = false; Error err = init_device(); if (err == OK) { @@ -172,14 +174,14 @@ void AudioDriverALSA::thread_func(void *p_udata) { if (!ad->active) { for (unsigned int i = 0; i < ad->period_size * ad->channels; i++) { - ad->samples_out[i] = 0; + ad->samples_out.write[i] = 0; } } else { ad->audio_server_process(ad->period_size, ad->samples_in.ptrw()); for (unsigned int i = 0; i < ad->period_size * ad->channels; i++) { - ad->samples_out[i] = ad->samples_in[i] >> 16; + ad->samples_out.write[i] = ad->samples_in[i] >> 16; } } @@ -313,9 +315,9 @@ void AudioDriverALSA::unlock() { void AudioDriverALSA::finish_device() { - if (pcm_open) { + if (pcm_handle) { snd_pcm_close(pcm_handle); - pcm_open = NULL; + pcm_handle = NULL; } } diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index 2878e100a2..e2a2325cf3 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -66,7 +66,6 @@ class AudioDriverALSA : public AudioDriver { bool active; bool thread_exited; mutable bool exit_thread; - bool pcm_open; public: const char *get_name() const { diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub new file mode 100644 index 0000000000..233593b0f9 --- /dev/null +++ b/drivers/alsamidi/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') + +# Driver source files +env.add_source_files(env.drivers_sources, "*.cpp") + +Export('env') diff --git a/drivers/alsamidi/alsa_midi.cpp b/drivers/alsamidi/alsa_midi.cpp new file mode 100644 index 0000000000..599470d7e0 --- /dev/null +++ b/drivers/alsamidi/alsa_midi.cpp @@ -0,0 +1,201 @@ +/*************************************************************************/ +/* alsa_midi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef ALSAMIDI_ENABLED + +#include <errno.h> + +#include "alsa_midi.h" +#include "os/os.h" +#include "print_string.h" + +static int get_message_size(uint8_t message) { + switch (message & 0xF0) { + case 0x80: // note off + case 0x90: // note on + case 0xA0: // aftertouch + case 0xB0: // continuous controller + return 3; + + case 0xC0: // patch change + case 0xD0: // channel pressure + case 0xE0: // pitch bend + return 2; + } + + return 256; +} + +void MIDIDriverALSAMidi::thread_func(void *p_udata) { + MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata; + uint64_t timestamp = 0; + uint8_t buffer[256]; + int expected_size = 255; + int bytes = 0; + + while (!md->exit_thread) { + int ret; + + md->lock(); + + for (int i = 0; i < md->connected_inputs.size(); i++) { + snd_rawmidi_t *midi_in = md->connected_inputs[i]; + do { + uint8_t byte = 0; + ret = snd_rawmidi_read(midi_in, &byte, 1); + if (ret < 0) { + if (ret != -EAGAIN) { + ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret))); + } + } else { + if (byte & 0x80) { + // Flush previous packet if there is any + if (bytes) { + md->receive_input_packet(timestamp, buffer, bytes); + bytes = 0; + } + expected_size = get_message_size(byte); + } + + if (bytes < 256) { + buffer[bytes++] = byte; + // If we know the size of the current packet receive it if it reached the expected size + if (bytes >= expected_size) { + md->receive_input_packet(timestamp, buffer, bytes); + bytes = 0; + } + } + } + } while (ret > 0); + } + + md->unlock(); + + OS::get_singleton()->delay_usec(1000); + } +} + +Error MIDIDriverALSAMidi::open() { + + void **hints; + + if (snd_device_name_hint(-1, "rawmidi", &hints) < 0) + return ERR_CANT_OPEN; + + int i = 0; + for (void **n = hints; *n != NULL; n++) { + char *name = snd_device_name_get_hint(*n, "NAME"); + + if (name != NULL) { + snd_rawmidi_t *midi_in; + int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK); + if (ret >= 0) { + connected_inputs.insert(i++, midi_in); + } + } + + if (name != NULL) + free(name); + } + snd_device_name_free_hint(hints); + + mutex = Mutex::create(); + thread = Thread::create(MIDIDriverALSAMidi::thread_func, this); + + return OK; +} + +void MIDIDriverALSAMidi::close() { + + if (thread) { + exit_thread = true; + Thread::wait_to_finish(thread); + + memdelete(thread); + thread = NULL; + } + + if (mutex) { + memdelete(mutex); + mutex = NULL; + } + + for (int i = 0; i < connected_inputs.size(); i++) { + snd_rawmidi_t *midi_in = connected_inputs[i]; + snd_rawmidi_close(midi_in); + } + connected_inputs.clear(); +} + +void MIDIDriverALSAMidi::lock() const { + + if (mutex) + mutex->lock(); +} + +void MIDIDriverALSAMidi::unlock() const { + + if (mutex) + mutex->unlock(); +} + +PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() { + + PoolStringArray list; + + lock(); + for (int i = 0; i < connected_inputs.size(); i++) { + snd_rawmidi_t *midi_in = connected_inputs[i]; + snd_rawmidi_info_t *info; + + snd_rawmidi_info_malloc(&info); + snd_rawmidi_info(midi_in, info); + list.push_back(snd_rawmidi_info_get_name(info)); + snd_rawmidi_info_free(info); + } + unlock(); + + return list; +} + +MIDIDriverALSAMidi::MIDIDriverALSAMidi() { + + mutex = NULL; + thread = NULL; + + exit_thread = false; +} + +MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { + + close(); +} + +#endif diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/alsa_midi.h new file mode 100644 index 0000000000..90e458a365 --- /dev/null +++ b/drivers/alsamidi/alsa_midi.h @@ -0,0 +1,69 @@ +/*************************************************************************/ +/* alsa_midi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef ALSAMIDI_ENABLED + +#ifndef ALSA_MIDI_H +#define ALSA_MIDI_H + +#include <alsa/asoundlib.h> +#include <stdio.h> + +#include "core/os/mutex.h" +#include "core/os/thread.h" +#include "core/vector.h" +#include "os/midi_driver.h" + +class MIDIDriverALSAMidi : public MIDIDriver { + + Thread *thread; + Mutex *mutex; + + Vector<snd_rawmidi_t *> connected_inputs; + + bool exit_thread; + + static void thread_func(void *p_udata); + + void lock() const; + void unlock() const; + +public: + virtual Error open(); + virtual void close(); + + virtual PoolStringArray get_connected_inputs(); + + MIDIDriverALSAMidi(); + virtual ~MIDIDriverALSAMidi(); +}; + +#endif +#endif diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub new file mode 100644 index 0000000000..233593b0f9 --- /dev/null +++ b/drivers/coremidi/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') + +# Driver source files +env.add_source_files(env.drivers_sources, "*.cpp") + +Export('env') diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp new file mode 100644 index 0000000000..3619be4a8e --- /dev/null +++ b/drivers/coremidi/core_midi.cpp @@ -0,0 +1,105 @@ +/*************************************************************************/ +/* core_midi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef COREMIDI_ENABLED + +#include "core_midi.h" +#include "print_string.h" + +#include <CoreAudio/HostTime.h> +#include <CoreServices/CoreServices.h> + +void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) { + MIDIPacket *packet = const_cast<MIDIPacket *>(packet_list->packet); + for (int i = 0; i < packet_list->numPackets; i++) { + receive_input_packet(packet->timeStamp, packet->data, packet->length); + packet = MIDIPacketNext(packet); + } +} + +Error MIDIDriverCoreMidi::open() { + + CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII); + OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); + CFRelease(name); + if (result != noErr) { + ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(result))); + return ERR_CANT_OPEN; + } + + result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); + if (result != noErr) { + ERR_PRINTS("MIDIInputPortCreate failed: " + String(GetMacOSStatusErrorString(result))); + return ERR_CANT_OPEN; + } + + int sources = MIDIGetNumberOfSources(); + for (int i = 0; i < sources; i++) { + + MIDIEndpointRef source = MIDIGetSource(i); + if (source != NULL) { + MIDIPortConnectSource(port_in, source, (void *)this); + connected_sources.insert(i, source); + } + } + + return OK; +} + +void MIDIDriverCoreMidi::close() { + + for (int i = 0; i < connected_sources.size(); i++) { + MIDIEndpointRef source = connected_sources[i]; + MIDIPortDisconnectSource(port_in, source); + } + connected_sources.clear(); + + if (port_in != 0) { + MIDIPortDispose(port_in); + port_in = 0; + } + + if (client != 0) { + MIDIClientDispose(client); + client = 0; + } +} + +MIDIDriverCoreMidi::MIDIDriverCoreMidi() { + + client = 0; +} + +MIDIDriverCoreMidi::~MIDIDriverCoreMidi() { + + close(); +} + +#endif diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/core_midi.h new file mode 100644 index 0000000000..fd35e12f4b --- /dev/null +++ b/drivers/coremidi/core_midi.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* core_midi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef COREMIDI_ENABLED + +#ifndef CORE_MIDI_H +#define CORE_MIDI_H + +#include <stdio.h> + +#include <CoreMIDI/CoreMIDI.h> + +#include "core/vector.h" +#include "os/midi_driver.h" + +class MIDIDriverCoreMidi : public MIDIDriver { + + MIDIClientRef client; + MIDIPortRef port_in; + + Vector<MIDIEndpointRef> connected_sources; + + static void read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con); + +public: + virtual Error open(); + virtual void close(); + + MIDIDriverCoreMidi(); + virtual ~MIDIDriverCoreMidi(); +}; + +#endif +#endif diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index bab89f649a..e045d4cd39 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -289,7 +289,7 @@ public: ERR_FAIL_COND(!m); m->surfaces.push_back(DummySurface()); - DummySurface *s = &m->surfaces[m->surfaces.size() - 1]; + DummySurface *s = &m->surfaces.write[m->surfaces.size() - 1]; s->format = p_format; s->primitive = p_primitive; s->array = p_array; @@ -777,7 +777,7 @@ public: void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {} void initialize() {} - void begin_frame() {} + void begin_frame(double frame_step) {} void set_current_render_target(RID p_render_target) {} void restore_render_target() {} void clear_render_target(const Color &p_color) {} diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp index 6d3e176bbb..b099019d17 100644 --- a/drivers/dummy/texture_loader_dummy.cpp +++ b/drivers/dummy/texture_loader_dummy.cpp @@ -45,10 +45,6 @@ RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_origi dstbuff.resize(rowsize * height); - PoolVector<uint8_t>::Write dstbuff_write = dstbuff.write(); - - uint8_t *data = dstbuff_write.ptr(); - uint8_t **row_p = memnew_arr(uint8_t *, height); for (unsigned int i = 0; i < height; i++) { diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index daa421d45c..fb150d6820 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -409,8 +409,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - if (dst_rect.size.width < 0) { dst_rect.position.x += dst_rect.size.width; dst_rect.size.width *= -1; @@ -663,6 +661,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (state.canvas_shader.bind()) _set_uniforms(); + _bind_canvas_texture(RID(), RID()); + if (pline->triangles.size()) { _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); } else { diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 9ea20ff15a..5de1d5f1dc 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -227,21 +227,14 @@ void RasterizerGLES2::initialize() { scene->initialize(); } -void RasterizerGLES2::begin_frame() { - uint64_t tick = OS::get_singleton()->get_ticks_usec(); +void RasterizerGLES2::begin_frame(double frame_step) { + time_total += frame_step; - double delta = double(tick - prev_ticks) / 1000000.0; - delta *= Engine::get_singleton()->get_time_scale(); - - time_total += delta; - - if (delta == 0) { + if (frame_step == 0) { //to avoid hiccups - delta = 0.001; + frame_step = 0.001; } - prev_ticks = tick; - // double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); // if (time_total > time_roll_over) // time_total = 0; //roll over every day (should be customz @@ -251,9 +244,7 @@ void RasterizerGLES2::begin_frame() { storage->frame.time[2] = Math::fmod(time_total, 900); storage->frame.time[3] = Math::fmod(time_total, 60); storage->frame.count++; - storage->frame.delta = delta; - - storage->frame.prev_tick = tick; + storage->frame.delta = frame_step; storage->update_dirty_resources(); @@ -344,28 +335,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c storage->free(texture); - if (OS::get_singleton()->is_layered_allowed()) { - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) - Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); - uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); - if (data) { - glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data); - OS::get_singleton()->swap_layered_buffer(); - - return; - } -#endif - } else { - //clear alpha - glColorMask(false, false, false, true); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(true, true, true, true); - } - } - - OS::get_singleton()->swap_buffers(); + end_frame(true); } void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) { @@ -452,7 +422,6 @@ RasterizerGLES2::RasterizerGLES2() { scene->storage = storage; storage->scene = scene; - prev_ticks = 0; time_total = 0; } diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 8d57275449..f727af39dd 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -43,7 +43,6 @@ class RasterizerGLES2 : public Rasterizer { RasterizerCanvasGLES2 *canvas; RasterizerSceneGLES2 *scene; - uint64_t prev_ticks; double time_total; public: @@ -54,7 +53,7 @@ public: virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale); virtual void initialize(); - virtual void begin_frame(); + virtual void begin_frame(double frame_step); virtual void set_current_render_target(RID p_render_target); virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 2da496d4b7..fc80436efb 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -2005,8 +2005,9 @@ void RasterizerStorageGLES2::initialize() { } } + config.shrink_textures_x2 = false; + frame.count = 0; - frame.prev_tick = 0; frame.delta = 0; frame.current_rt = NULL; frame.clear_request = false; diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 30e13a9f65..c2e1144128 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -824,7 +824,6 @@ public: int canvas_draw_commands; float time[4]; float delta; - uint64_t prev_tick; uint64_t count; } frame; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index aa55e72083..16d4412802 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -325,10 +325,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener uniform_code += ";\n"; if (SL::is_sampler_type(E->get().type)) { - r_gen_code.texture_uniforms[E->get().texture_order] = _mkid(E->key()); - r_gen_code.texture_hints[E->get().texture_order] = E->get().hint; + r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key()); + r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; } else { - r_gen_code.uniforms[E->get().order] = E->key(); + r_gen_code.uniforms.write[E->get().order] = E->key(); } vertex_global += uniform_code.as_string(); @@ -721,8 +721,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; - actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp"; - actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; @@ -736,7 +734,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height"; actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color"; actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; - //actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_SHADOW_COLOR"]="light_shadow_color"; actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; @@ -768,7 +765,8 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize"; - //actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"]=ShaderLanguage::TYPE_INT; + // gl_InstanceID is not available in OpenGL ES 2.0 + actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; //builtins @@ -790,13 +788,11 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - //actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread"; actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; actions[VS::SHADER_SPATIAL].renames["AO"] = "ao"; actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; - //actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2; actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; @@ -838,8 +834,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index fa9562877d..baada9331e 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -288,7 +288,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { if (cc) { for (int i = 0; i < cc->custom_defines.size(); i++) { - strings.push_back(cc->custom_defines[i]); + strings.push_back(cc->custom_defines.write[i]); DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i])); } } @@ -502,7 +502,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { if (cc) { v.custom_uniform_locations.resize(cc->custom_uniforms.size()); for (int i = 0; i < cc->custom_uniforms.size(); i++) { - v.custom_uniform_locations[i] = glGetUniformLocation(v.id, String(cc->custom_uniforms[i]).ascii().get_data()); + v.custom_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->custom_uniforms[i]).ascii().get_data()); } } diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 1abdaa5f80..97c4a98aab 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -192,22 +192,15 @@ void RasterizerGLES3::initialize() { scene->initialize(); } -void RasterizerGLES3::begin_frame() { +void RasterizerGLES3::begin_frame(double frame_step) { - uint64_t tick = OS::get_singleton()->get_ticks_usec(); + time_total += frame_step; - double delta = double(tick - prev_ticks) / 1000000.0; - delta *= Engine::get_singleton()->get_time_scale(); - - time_total += delta; - - if (delta == 0) { + if (frame_step == 0) { //to avoid hiccups - delta = 0.001; + frame_step = 0.001; } - prev_ticks = tick; - double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); if (time_total > time_roll_over) time_total = 0; //roll over every day (should be customz @@ -217,9 +210,7 @@ void RasterizerGLES3::begin_frame() { storage->frame.time[2] = Math::fmod(time_total, 900); storage->frame.time[3] = Math::fmod(time_total, 60); storage->frame.count++; - storage->frame.delta = delta; - - storage->frame.prev_tick = tick; + storage->frame.delta = frame_step; storage->update_dirty_resources(); @@ -281,7 +272,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c if (p_image.is_null() || p_image->empty()) return; - begin_frame(); + begin_frame(0.0); int window_w = OS::get_singleton()->get_video_mode(0).width; int window_h = OS::get_singleton()->get_video_mode(0).height; @@ -333,28 +324,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c storage->free(texture); // free since it's only one frame that stays there - if (OS::get_singleton()->is_layered_allowed()) { - if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) - Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); - uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); - if (data) { - glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data); - OS::get_singleton()->swap_layered_buffer(); - - return; - } -#endif - } else { - //clear alpha - glColorMask(false, false, false, true); - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - glColorMask(true, true, true, true); - } - } - - OS::get_singleton()->swap_buffers(); + end_frame(true); } void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) { @@ -451,7 +421,6 @@ RasterizerGLES3::RasterizerGLES3() { scene->storage = storage; storage->scene = scene; - prev_ticks = 0; time_total = 0; } diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 5213101778..f4449ac0f9 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -44,7 +44,6 @@ class RasterizerGLES3 : public Rasterizer { RasterizerCanvasGLES3 *canvas; RasterizerSceneGLES3 *scene; - uint64_t prev_ticks; double time_total; public: @@ -55,7 +54,7 @@ public: virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale); virtual void initialize(); - virtual void begin_frame(); + virtual void begin_frame(double frame_step); virtual void set_current_render_target(RID p_render_target); virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 85b63a6481..d01ba2ddcc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -355,7 +355,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version; if (!should_realloc) { - shadow_atlas->quadrants[q].shadows[s].version = p_light_version; + shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; //already existing, see if it should redraw or it's just OK return should_redraw; } @@ -365,7 +365,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in //find a better place if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) { //found a better place! - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows[new_shadow]; + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; if (sh->owner.is_valid()) { //is taken, but is invalid, erasing it shadow_atlas->shadow_owners.erase(sh->owner); @@ -374,8 +374,8 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in } //erase previous - shadow_atlas->quadrants[q].shadows[s].version = 0; - shadow_atlas->quadrants[q].shadows[s].owner = RID(); + shadow_atlas->quadrants[q].shadows.write[s].version = 0; + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); sh->owner = p_light_intance; sh->alloc_tick = tick; @@ -395,7 +395,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in //already existing, see if it should redraw or it's just OK - shadow_atlas->quadrants[q].shadows[s].version = p_light_version; + shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version; return should_redraw; } @@ -405,7 +405,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in //find a better place if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) { //found a better place! - ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows[new_shadow]; + ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow]; if (sh->owner.is_valid()) { //is taken, but is invalid, erasing it shadow_atlas->shadow_owners.erase(sh->owner); @@ -502,7 +502,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_size //erase probes reference to this if (reflection_atlas->reflections[i].owner.is_valid()) { ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); - reflection_atlas->reflections[i].owner = RID(); + reflection_atlas->reflections.write[i].owner = RID(); ERR_CONTINUE(!reflection_probe_instance); reflection_probe_instance->reflection_atlas_index = -1; @@ -574,7 +574,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas, int //erase probes reference to this if (reflection_atlas->reflections[i].owner.is_valid()) { ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); - reflection_atlas->reflections[i].owner = RID(); + reflection_atlas->reflections.write[i].owner = RID(); ERR_CONTINUE(!reflection_probe_instance); reflection_probe_instance->reflection_atlas_index = -1; @@ -629,7 +629,7 @@ void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) ERR_FAIL_COND(reflection_atlas->reflections[rpi->reflection_atlas_index].owner != rpi->self); - reflection_atlas->reflections[rpi->reflection_atlas_index].owner = RID(); + reflection_atlas->reflections.write[rpi->reflection_atlas_index].owner = RID(); rpi->reflection_atlas_index = -1; rpi->atlas = RID(); @@ -701,8 +701,8 @@ bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance victim_rpi->reflection_atlas_index = -1; } - reflection_atlas->reflections[best_free].owner = p_instance; - reflection_atlas->reflections[best_free].last_frame = storage->frame.count; + reflection_atlas->reflections.write[best_free].owner = p_instance; + reflection_atlas->reflections.write[best_free].last_frame = storage->frame.count; rpi->reflection_atlas_index = best_free; rpi->atlas = p_reflection_atlas; @@ -3848,8 +3848,8 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_END, false); //last step, swap with the framebuffer exposure, so the right exposure is kept int he framebuffer - SWAP(exposure_shrink[exposure_shrink.size() - 1].fbo, storage->frame.current_rt->exposure.fbo); - SWAP(exposure_shrink[exposure_shrink.size() - 1].color, storage->frame.current_rt->exposure.color); + SWAP(exposure_shrink.write[exposure_shrink.size() - 1].fbo, storage->frame.current_rt->exposure.fbo); + SWAP(exposure_shrink.write[exposure_shrink.size() - 1].color, storage->frame.current_rt->exposure.color); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); @@ -4086,6 +4086,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.ubo_data.z_slope_scale = 0; state.ubo_data.shadow_dual_paraboloid_render_side = 0; state.ubo_data.shadow_dual_paraboloid_render_zfar = 0; + state.ubo_data.opaque_prepass_threshold = 0.99; p_cam_projection.get_viewport_size(state.ubo_data.viewport_size[0], state.ubo_data.viewport_size[1]); @@ -4698,6 +4699,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ state.ubo_data.z_slope_scale = normal_bias; state.ubo_data.shadow_dual_paraboloid_render_side = dp_direction; state.ubo_data.shadow_dual_paraboloid_render_zfar = zfar; + state.ubo_data.opaque_prepass_threshold = 0.1; _setup_environment(NULL, light_projection, light_transform); @@ -4776,7 +4778,7 @@ bool RasterizerSceneGLES3::free(RID p_rid) { uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - shadow_atlas->quadrants[q].shadows[s].owner = RID(); + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); shadow_atlas->shadow_owners.erase(p_rid); } diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 524212b9c1..cf387a69bc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -141,6 +141,7 @@ public: float subsurface_scatter_width; float ambient_occlusion_affect_light; float ambient_occlusion_affect_ssao; + float opaque_prepass_threshold; uint32_t fog_depth_enabled; float fog_depth_begin; @@ -152,7 +153,7 @@ public: float fog_height_max; float fog_height_curve; // make sure this struct is padded to be a multiple of 16 bytes for webgl - float pad[3]; + float pad[2]; } ubo_data; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index e67b0bea21..c1c1b2a009 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -2670,7 +2670,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { } } - material->textures[E->get().texture_order] = texture; + material->textures.write[E->get().texture_order] = texture; } } else { @@ -2975,9 +2975,9 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: for (int i = 0; i < surface->skeleton_bone_used.size(); i++) { if (surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0) { - surface->skeleton_bone_used[i] = false; + surface->skeleton_bone_used.write[i] = false; } else { - surface->skeleton_bone_used[i] = true; + surface->skeleton_bone_used.write[i] = true; } } @@ -3240,7 +3240,7 @@ void RasterizerStorageGLES3::mesh_surface_update_region(RID p_mesh, int p_surfac PoolVector<uint8_t>::Read r = p_data.read(); - glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->array_id); + glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_id); glBufferSubData(GL_ARRAY_BUFFER, p_offset, total_size, r.ptr()); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind } @@ -3404,6 +3404,7 @@ Vector<PoolVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shap return bsarr; } + Vector<AABB> RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); @@ -3455,6 +3456,7 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface) { mesh->instance_change_notify(); } + int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); @@ -3468,6 +3470,7 @@ void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb ERR_FAIL_COND(!mesh); mesh->custom_aabb = p_aabb; + mesh->instance_change_notify(); } AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const { @@ -3875,29 +3878,29 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances int custom_data_from = 0; if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) { - multimesh->data[i + 0] = 1.0; - multimesh->data[i + 1] = 0.0; - multimesh->data[i + 2] = 0.0; - multimesh->data[i + 3] = 0.0; - multimesh->data[i + 4] = 0.0; - multimesh->data[i + 5] = 1.0; - multimesh->data[i + 6] = 0.0; - multimesh->data[i + 7] = 0.0; + multimesh->data.write[i + 0] = 1.0; + multimesh->data.write[i + 1] = 0.0; + multimesh->data.write[i + 2] = 0.0; + multimesh->data.write[i + 3] = 0.0; + multimesh->data.write[i + 4] = 0.0; + multimesh->data.write[i + 5] = 1.0; + multimesh->data.write[i + 6] = 0.0; + multimesh->data.write[i + 7] = 0.0; color_from = 8; custom_data_from = 8; } else { - multimesh->data[i + 0] = 1.0; - multimesh->data[i + 1] = 0.0; - multimesh->data[i + 2] = 0.0; - multimesh->data[i + 3] = 0.0; - multimesh->data[i + 4] = 0.0; - multimesh->data[i + 5] = 1.0; - multimesh->data[i + 6] = 0.0; - multimesh->data[i + 7] = 0.0; - multimesh->data[i + 8] = 0.0; - multimesh->data[i + 9] = 0.0; - multimesh->data[i + 10] = 1.0; - multimesh->data[i + 11] = 0.0; + multimesh->data.write[i + 0] = 1.0; + multimesh->data.write[i + 1] = 0.0; + multimesh->data.write[i + 2] = 0.0; + multimesh->data.write[i + 3] = 0.0; + multimesh->data.write[i + 4] = 0.0; + multimesh->data.write[i + 5] = 1.0; + multimesh->data.write[i + 6] = 0.0; + multimesh->data.write[i + 7] = 0.0; + multimesh->data.write[i + 8] = 0.0; + multimesh->data.write[i + 9] = 0.0; + multimesh->data.write[i + 10] = 1.0; + multimesh->data.write[i + 11] = 0.0; color_from = 12; custom_data_from = 12; } @@ -3912,14 +3915,14 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances } cu; cu.colu = 0xFFFFFFFF; - multimesh->data[i + color_from + 0] = cu.colf; + multimesh->data.write[i + color_from + 0] = cu.colf; custom_data_from = color_from + 1; } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - multimesh->data[i + color_from + 0] = 1.0; - multimesh->data[i + color_from + 1] = 1.0; - multimesh->data[i + color_from + 2] = 1.0; - multimesh->data[i + color_from + 3] = 1.0; + multimesh->data.write[i + color_from + 0] = 1.0; + multimesh->data.write[i + color_from + 1] = 1.0; + multimesh->data.write[i + color_from + 2] = 1.0; + multimesh->data.write[i + color_from + 3] = 1.0; custom_data_from = color_from + 4; } @@ -3933,13 +3936,13 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances } cu; cu.colu = 0; - multimesh->data[i + custom_data_from + 0] = cu.colf; + multimesh->data.write[i + custom_data_from + 0] = cu.colf; } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - multimesh->data[i + custom_data_from + 0] = 0.0; - multimesh->data[i + custom_data_from + 1] = 0.0; - multimesh->data[i + custom_data_from + 2] = 0.0; - multimesh->data[i + custom_data_from + 3] = 0.0; + multimesh->data.write[i + custom_data_from + 0] = 0.0; + multimesh->data.write[i + custom_data_from + 1] = 0.0; + multimesh->data.write[i + custom_data_from + 2] = 0.0; + multimesh->data.write[i + custom_data_from + 3] = 0.0; } } @@ -4001,7 +4004,7 @@ void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh, i ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index]; + float *dataptr = &multimesh->data.write[stride * p_index]; dataptr[0] = p_transform.basis.elements[0][0]; dataptr[1] = p_transform.basis.elements[0][1]; @@ -4032,7 +4035,7 @@ void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index]; + float *dataptr = &multimesh->data.write[stride * p_index]; dataptr[0] = p_transform.elements[0][0]; dataptr[1] = p_transform.elements[1][0]; @@ -4058,7 +4061,7 @@ void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p ERR_FAIL_COND(multimesh->color_format == VS::MULTIMESH_COLOR_NONE); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats]; + float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats]; if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { @@ -4091,7 +4094,7 @@ void RasterizerStorageGLES3::multimesh_instance_set_custom_data(RID p_multimesh, ERR_FAIL_COND(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; + float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { @@ -4131,7 +4134,7 @@ Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multime ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D, Transform()); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index]; + float *dataptr = &multimesh->data.write[stride * p_index]; Transform xform; @@ -4158,7 +4161,7 @@ Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_mu ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D, Transform2D()); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index]; + float *dataptr = &multimesh->data.write[stride * p_index]; Transform2D xform; @@ -4180,7 +4183,7 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int ERR_FAIL_COND_V(multimesh->color_format == VS::MULTIMESH_COLOR_NONE, Color()); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats]; + float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats]; if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { union { @@ -4213,7 +4216,7 @@ Color RasterizerStorageGLES3::multimesh_instance_get_custom_data(RID p_multimesh ERR_FAIL_COND_V(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE, Color()); int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; - float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; + float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats]; if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { union { @@ -5769,7 +5772,7 @@ void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); - particles->draw_passes[p_pass] = p_mesh; + particles->draw_passes.write[p_pass] = p_mesh; } void RasterizerStorageGLES3::particles_restart(RID p_particles) { @@ -6643,7 +6646,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) { - RenderTarget::Effects::MipMaps::Size &mm = rt->effects.mip_maps[i].sizes[j]; + RenderTarget::Effects::MipMaps::Size &mm = rt->effects.mip_maps[i].sizes.write[j]; glGenFramebuffers(1, &mm.fbo); glBindFramebuffer(GL_FRAMEBUFFER, mm.fbo); @@ -7055,7 +7058,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { for (int i = 0; i < ins->materials.size(); i++) { if (ins->materials[i] == p_rid) { - ins->materials[i] = RID(); + ins->materials.write[i] = RID(); } } } @@ -7486,7 +7489,6 @@ void RasterizerStorageGLES3::initialize() { #endif frame.count = 0; - frame.prev_tick = 0; frame.delta = 0; frame.current_rt = NULL; config.keep_original_textures = false; diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 80df21941b..d9c770d1b7 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -693,7 +693,6 @@ public: AABB custom_aabb; mutable uint64_t last_pass; SelfList<MultiMesh>::List multimeshes; - _FORCE_INLINE_ void update_multimeshes() { SelfList<MultiMesh> *mm = multimeshes.first(); @@ -1428,7 +1427,6 @@ public: int canvas_draw_commands; float time[4]; float delta; - uint64_t prev_tick; uint64_t count; } frame; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 3f6fe3ec61..4ff8c72e13 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -365,17 +365,17 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener if (SL::is_sampler_type(E->get().type)) { r_gen_code.vertex_global += ucode; r_gen_code.fragment_global += ucode; - r_gen_code.texture_uniforms[E->get().texture_order] = _mkid(E->key()); - r_gen_code.texture_hints[E->get().texture_order] = E->get().hint; + r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key()); + r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; } else { if (!uses_uniforms) { r_gen_code.defines.push_back(String("#define USE_MATERIAL\n").ascii()); uses_uniforms = true; } - uniform_defines[E->get().order] = ucode; - uniform_sizes[E->get().order] = _get_datatype_size(E->get().type); - uniform_alignments[E->get().order] = _get_datatype_alignment(E->get().type); + uniform_defines.write[E->get().order] = ucode; + uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type); + uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type); } p_actions.uniforms->insert(E->key(), E->get()); @@ -780,8 +780,6 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; - actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp"; - actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; @@ -824,7 +822,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize"; - //actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"]=ShaderLanguage::TYPE_INT; + actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID"; //builtins @@ -846,13 +844,11 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - //actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread"; actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; actions[VS::SHADER_SPATIAL].renames["AO"] = "ao"; actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; - //actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2; actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; @@ -894,8 +890,6 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 08b8a1cc26..ca0ce5cd3e 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -554,7 +554,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { v.texture_uniform_locations.resize(cc->texture_uniforms.size()); for (int i = 0; i < cc->texture_uniforms.size(); i++) { - v.texture_uniform_locations[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data()); + v.texture_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data()); glUniform1i(v.texture_uniform_locations[i], i + base_material_tex_index); } } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index abb236138f..6fd85cc1dd 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -91,6 +91,7 @@ layout(std140) uniform SceneData { //ubo:0 mediump float subsurface_scatter_width; mediump float ambient_occlusion_affect_light; mediump float ambient_occlusion_affect_ao_channel; + mediump float opaque_prepass_threshold; bool fog_depth_enabled; highp float fog_depth_begin; @@ -679,6 +680,7 @@ layout(std140) uniform SceneData { mediump float subsurface_scatter_width; mediump float ambient_occlusion_affect_light; mediump float ambient_occlusion_affect_ao_channel; + mediump float opaque_prepass_threshold; bool fog_depth_enabled; highp float fog_depth_begin; @@ -1026,12 +1028,11 @@ LIGHT_SHADER_CODE diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif -#if defined(TRANSMISSION_USED) - diffuse_light += light_color * diffuse_color * mix(vec3(diffuse_brdf_NL), vec3(M_PI), transmission) * attenuation; -#else diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; -#endif +#if defined(TRANSMISSION_USED) + diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#endif #if defined(LIGHT_USE_RIM) @@ -1628,7 +1629,7 @@ void main() { float alpha = 1.0; #if defined(DO_SIDE_CHECK) - float side=float(gl_FrontFacing)*2.0-1.0; + float side=gl_FrontFacing ? 1.0 : -1.0; #else float side=1.0; #endif @@ -1690,9 +1691,10 @@ FRAGMENT_SHADER_CODE #ifdef USE_OPAQUE_PREPASS - if (alpha<0.99) { + if (alpha<opaque_prepass_threshold) { discard; } + #endif #if defined(ENABLE_NORMALMAP) @@ -2138,6 +2140,8 @@ FRAGMENT_SHADER_CODE #else + + //approximate ambient scale for SSAO, since we will lack full ambient float max_emission=max(emission.r,max(emission.g,emission.b)); float max_ambient=max(ambient_light.r,max(ambient_light.g,ambient_light.b)); @@ -2169,7 +2173,6 @@ FRAGMENT_SHADER_CODE frag_color=vec4(emission+ambient_light+diffuse_light+specular_light,alpha); #endif //SHADELESS - #endif //USE_MULTIPLE_RENDER_TARGETS diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 3622e48ecd..6db0e58737 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -295,7 +295,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { if (!ad->active) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { - ad->samples_out[i] = 0; + ad->samples_out.write[i] = 0; } } else { @@ -303,7 +303,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { if (ad->channels == ad->pa_map.channels) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { - ad->samples_out[i] = ad->samples_in[i] >> 16; + ad->samples_out.write[i] = ad->samples_in[i] >> 16; } } else { // Uneven amount of channels @@ -312,11 +312,11 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { for (unsigned int i = 0; i < ad->buffer_frames; i++) { for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) { - ad->samples_out[out_idx++] = ad->samples_in[in_idx++] >> 16; + ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16; } uint32_t l = ad->samples_in[in_idx++]; uint32_t r = ad->samples_in[in_idx++]; - ad->samples_out[out_idx++] = (l >> 1 + r >> 1) >> 16; + ad->samples_out.write[out_idx++] = (l >> 1 + r >> 1) >> 16; } } } @@ -403,7 +403,6 @@ AudioDriver::SpeakerMode AudioDriverPulseAudio::get_speaker_mode() const { void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) { AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; - int ctr = 0; // If eol is set to a positive number, you're at the end of the list if (eol > 0) { diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 1d96f9ee7d..5982955c4f 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -447,7 +447,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); } else { for (unsigned int i = 0; i < ad->buffer_size; i++) { - ad->samples_in[i] = 0; + ad->samples_in.write[i] = 0; } } diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub new file mode 100644 index 0000000000..233593b0f9 --- /dev/null +++ b/drivers/winmidi/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +Import('env') + +# Driver source files +env.add_source_files(env.drivers_sources, "*.cpp") + +Export('env') diff --git a/drivers/winmidi/win_midi.cpp b/drivers/winmidi/win_midi.cpp new file mode 100644 index 0000000000..6da6e31b2b --- /dev/null +++ b/drivers/winmidi/win_midi.cpp @@ -0,0 +1,100 @@ +/*************************************************************************/ +/* win_midi.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef WINMIDI_ENABLED + +#include "win_midi.h" +#include "print_string.h" + +void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + + if (wMsg == MIM_DATA) { + receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3); + } +} + +Error MIDIDriverWinMidi::open() { + + for (UINT i = 0; i < midiInGetNumDevs(); i++) { + HMIDIIN midi_in; + + MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION); + if (res == MMSYSERR_NOERROR) { + midiInStart(midi_in); + connected_sources.insert(i, midi_in); + } else { + char err[256]; + midiInGetErrorText(res, err, 256); + ERR_PRINTS("midiInOpen error: " + String(err)); + } + } + + return OK; +} + +PoolStringArray MIDIDriverWinMidi::get_connected_inputs() { + + PoolStringArray list; + + for (int i = 0; i < connected_sources.size(); i++) { + HMIDIIN midi_in = connected_sources[i]; + UINT id = 0; + MMRESULT res = midiInGetID(midi_in, &id); + if (res == MMSYSERR_NOERROR) { + MIDIINCAPS caps; + res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS)); + if (res == MMSYSERR_NOERROR) { + list.push_back(caps.szPname); + } + } + } + + return list; +} + +void MIDIDriverWinMidi::close() { + + for (int i = 0; i < connected_sources.size(); i++) { + HMIDIIN midi_in = connected_sources[i]; + midiInStop(midi_in); + midiInClose(midi_in); + } + connected_sources.clear(); +} + +MIDIDriverWinMidi::MIDIDriverWinMidi() { +} + +MIDIDriverWinMidi::~MIDIDriverWinMidi() { + + close(); +} + +#endif diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/win_midi.h new file mode 100644 index 0000000000..1cf9b19b5d --- /dev/null +++ b/drivers/winmidi/win_midi.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* win_midi.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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. */ +/*************************************************************************/ + +#ifdef WINMIDI_ENABLED + +#ifndef WIN_MIDI_H +#define WIN_MIDI_H + +#include <stdio.h> +#include <windows.h> + +#include <mmsystem.h> + +#include "core/vector.h" +#include "os/midi_driver.h" + +class MIDIDriverWinMidi : public MIDIDriver { + + Vector<HMIDIIN> connected_sources; + + static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); + +public: + virtual Error open(); + virtual void close(); + + virtual PoolStringArray get_connected_inputs(); + + MIDIDriverWinMidi(); + virtual ~MIDIDriverWinMidi(); +}; + +#endif +#endif diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index db108f9c6b..a1002ef4f9 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -97,8 +97,6 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata; - uint64_t usdelay = (ad->buffer_size / float(ad->mix_rate)) * 1000000; - while (!ad->exit_thread) { if (!ad->active) { diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 42d5ea120e..4c4830ad7a 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -231,10 +231,10 @@ public: if (Variant::can_convert(args[idx].get_type(), t)) { Variant old = args[idx]; Variant *ptrs[1] = { &old }; - args[idx] = Variant::construct(t, (const Variant **)ptrs, 1, err); + args.write[idx] = Variant::construct(t, (const Variant **)ptrs, 1, err); } else { - args[idx] = Variant::construct(t, NULL, 0, err); + args.write[idx] = Variant::construct(t, NULL, 0, err); } change_notify_deserved = true; d_new["args"] = args; @@ -248,7 +248,7 @@ public: _fix_node_path(value); } - args[idx] = value; + args.write[idx] = value; d_new["args"] = args; mergeable = true; } @@ -3014,12 +3014,12 @@ PropertyInfo AnimationTrackEditor::_find_hint_for_track(int p_idx, NodePath &r_b if (res.is_valid()) { property_info_base = res; if (r_current_val) { - *r_current_val = res->get(leftover_path[leftover_path.size() - 1]); + *r_current_val = res->get_indexed(leftover_path); } } else if (node) { property_info_base = node; if (r_current_val) { - *r_current_val = node->get(leftover_path[leftover_path.size() - 1]); + *r_current_val = node->get_indexed(leftover_path); } } @@ -3053,31 +3053,31 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool subindices.push_back(""); } break; case Variant::VECTOR2: { - subindices.push_back(".x"); - subindices.push_back(".y"); + subindices.push_back(":x"); + subindices.push_back(":y"); } break; case Variant::VECTOR3: { - subindices.push_back(".x"); - subindices.push_back(".y"); - subindices.push_back(".z"); + subindices.push_back(":x"); + subindices.push_back(":y"); + subindices.push_back(":z"); } break; case Variant::QUAT: { - subindices.push_back(".x"); - subindices.push_back(".y"); - subindices.push_back(".z"); - subindices.push_back(".w"); + subindices.push_back(":x"); + subindices.push_back(":y"); + subindices.push_back(":z"); + subindices.push_back(":w"); } break; case Variant::COLOR: { - subindices.push_back(".r"); - subindices.push_back(".g"); - subindices.push_back(".b"); - subindices.push_back(".a"); + subindices.push_back(":r"); + subindices.push_back(":g"); + subindices.push_back(":b"); + subindices.push_back(":a"); } break; case Variant::PLANE: { - subindices.push_back(".x"); - subindices.push_back(".y"); - subindices.push_back(".z"); - subindices.push_back(".d"); + subindices.push_back(":x"); + subindices.push_back(":y"); + subindices.push_back(":z"); + subindices.push_back(":d"); } break; default: { if (r_valid) { @@ -3288,35 +3288,23 @@ void AnimationTrackEditor::_update_tracks() { if (root && root->has_node_and_resource(path)) { RES res; + NodePath base_path; Vector<StringName> leftover_path; Node *node = root->get_node_and_resource(path, res, leftover_path, true); + PropertyInfo pinfo = _find_hint_for_track(i, base_path); Object *object = node; if (res.is_valid()) { object = res.ptr(); - } else { - object = node; } if (object && !leftover_path.empty()) { - //not a property (value track?) - PropertyInfo pinfo; - pinfo.name = leftover_path[leftover_path.size() - 1]; - //now let's see if we can get more info about it - - List<PropertyInfo> plist; - object->get_property_list(&plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - - if (E->get().name == leftover_path[leftover_path.size() - 1]) { - pinfo = E->get(); - break; - } + if (pinfo.name.empty()) { + pinfo.name = leftover_path[leftover_path.size() - 1]; } for (int j = 0; j < track_edit_plugins.size(); j++) { - track_edit = track_edit_plugins[j]->create_value_track_edit(object, pinfo.type, pinfo.name, pinfo.hint, pinfo.hint_string, pinfo.usage); + track_edit = track_edit_plugins.write[j]->create_value_track_edit(object, pinfo.type, pinfo.name, pinfo.hint, pinfo.hint_string, pinfo.usage); if (track_edit) { break; } @@ -3327,7 +3315,7 @@ void AnimationTrackEditor::_update_tracks() { if (animation->track_get_type(i) == Animation::TYPE_AUDIO) { for (int j = 0; j < track_edit_plugins.size(); j++) { - track_edit = track_edit_plugins[j]->create_audio_track_edit(); + track_edit = track_edit_plugins.write[j]->create_audio_track_edit(); if (track_edit) { break; } @@ -3344,7 +3332,7 @@ void AnimationTrackEditor::_update_tracks() { if (node && Object::cast_to<AnimationPlayer>(node)) { for (int j = 0; j < track_edit_plugins.size(); j++) { - track_edit = track_edit_plugins[j]->create_animation_track_edit(node); + track_edit = track_edit_plugins.write[j]->create_animation_track_edit(node); if (track_edit) { break; } diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index d0c91f10d9..6d444c5422 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -271,8 +271,8 @@ void AnimationTrackEditAudio::draw_key(int p_index, float p_pixels_sec, int p_x, float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5; int idx = i - from_x; - lines[idx * 2 + 0] = Vector2(i, rect.position.y + min * rect.size.y); - lines[idx * 2 + 1] = Vector2(i, rect.position.y + max * rect.size.y); + lines.write[idx * 2 + 0] = Vector2(i, rect.position.y + min * rect.size.y); + lines.write[idx * 2 + 1] = Vector2(i, rect.position.y + max * rect.size.y); } Vector<Color> color; @@ -883,8 +883,8 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5; int idx = i - from_x; - lines[idx * 2 + 0] = Vector2(i, rect.position.y + min * rect.size.y); - lines[idx * 2 + 1] = Vector2(i, rect.position.y + max * rect.size.y); + lines.write[idx * 2 + 0] = Vector2(i, rect.position.y + min * rect.size.y); + lines.write[idx * 2 + 1] = Vector2(i, rect.position.y + max * rect.size.y); } Vector<Color> color; diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp index 6ee4d7f4b0..6ae5ec43a9 100644 --- a/editor/audio_stream_preview.cpp +++ b/editor/audio_stream_preview.cpp @@ -118,8 +118,8 @@ void AudioStreamPreviewGenerator::_preview_thread(void *p_preview) { uint8_t pfrom = CLAMP((min * 0.5 + 0.5) * 255, 0, 255); uint8_t pto = CLAMP((max * 0.5 + 0.5) * 255, 0, 255); - preview->preview->preview[(ofs_write + i) * 2 + 0] = pfrom; - preview->preview->preview[(ofs_write + i) * 2 + 1] = pto; + preview->preview->preview.write[(ofs_write + i) * 2 + 0] = pfrom; + preview->preview->preview.write[(ofs_write + i) * 2 + 1] = pto; } frames_todo -= to_read; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 6aec6135f1..4ce8556add 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -725,7 +725,7 @@ void CodeTextEditor::_complete_request() { int i = 0; for (List<String>::Element *E = entries.front(); E; E = E->next()) { - strs[i++] = E->get(); + strs.write[i++] = E->get(); } text_editor->code_complete(strs, forced); @@ -784,6 +784,345 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/open_scripts/v_scroll_speed")); } +void CodeTextEditor::trim_trailing_whitespace() { + bool trimed_whitespace = false; + for (int i = 0; i < text_editor->get_line_count(); i++) { + String line = text_editor->get_line(i); + if (line.ends_with(" ") || line.ends_with("\t")) { + + if (!trimed_whitespace) { + text_editor->begin_complex_operation(); + trimed_whitespace = true; + } + + int end = 0; + for (int j = line.length() - 1; j > -1; j--) { + if (line[j] != ' ' && line[j] != '\t') { + end = j + 1; + break; + } + } + text_editor->set_line(i, line.substr(0, end)); + } + } + + if (trimed_whitespace) { + text_editor->end_complex_operation(); + text_editor->update(); + } +} + +void CodeTextEditor::convert_indent_to_spaces() { + int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); + String indent = ""; + + for (int i = 0; i < indent_size; i++) { + indent += " "; + } + + int cursor_line = text_editor->cursor_get_line(); + int cursor_column = text_editor->cursor_get_column(); + + bool changed_indentation = false; + for (int i = 0; i < text_editor->get_line_count(); i++) { + String line = text_editor->get_line(i); + + if (line.length() <= 0) { + continue; + } + + int j = 0; + while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { + if (line[j] == '\t') { + if (!changed_indentation) { + text_editor->begin_complex_operation(); + changed_indentation = true; + } + if (cursor_line == i && cursor_column > j) { + cursor_column += indent_size - 1; + } + line = line.left(j) + indent + line.right(j + 1); + } + j++; + } + if (changed_indentation) { + text_editor->set_line(i, line); + } + } + if (changed_indentation) { + text_editor->cursor_set_column(cursor_column); + text_editor->end_complex_operation(); + text_editor->update(); + } +} + +void CodeTextEditor::convert_indent_to_tabs() { + int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); + indent_size -= 1; + + int cursor_line = text_editor->cursor_get_line(); + int cursor_column = text_editor->cursor_get_column(); + + bool changed_indentation = false; + for (int i = 0; i < text_editor->get_line_count(); i++) { + String line = text_editor->get_line(i); + + if (line.length() <= 0) { + continue; + } + + int j = 0; + int space_count = -1; + while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { + if (line[j] != '\t') { + space_count++; + + if (space_count == indent_size) { + if (!changed_indentation) { + text_editor->begin_complex_operation(); + changed_indentation = true; + } + if (cursor_line == i && cursor_column > j) { + cursor_column -= indent_size; + } + line = line.left(j - indent_size) + "\t" + line.right(j + 1); + j = 0; + space_count = -1; + } + } else { + space_count = -1; + } + j++; + } + if (changed_indentation) { + text_editor->set_line(i, line); + } + } + if (changed_indentation) { + text_editor->cursor_set_column(cursor_column); + text_editor->end_complex_operation(); + text_editor->update(); + } +} + +void CodeTextEditor::convert_case(CaseStyle p_case) { + if (!text_editor->is_selection_active()) { + return; + } + + text_editor->begin_complex_operation(); + + int begin = text_editor->get_selection_from_line(); + int end = text_editor->get_selection_to_line(); + int begin_col = text_editor->get_selection_from_column(); + int end_col = text_editor->get_selection_to_column(); + + for (int i = begin; i <= end; i++) { + int len = text_editor->get_line(i).length(); + if (i == end) + len -= len - end_col; + if (i == begin) + len -= begin_col; + String new_line = text_editor->get_line(i).substr(i == begin ? begin_col : 0, len); + + switch (p_case) { + case UPPER: { + new_line = new_line.to_upper(); + } break; + case LOWER: { + new_line = new_line.to_lower(); + } break; + case CAPITALIZE: { + new_line = new_line.capitalize(); + } break; + } + + if (i == begin) { + new_line = text_editor->get_line(i).left(begin_col) + new_line; + } + if (i == end) { + new_line = new_line + text_editor->get_line(i).right(end_col); + } + text_editor->set_line(i, new_line); + } + text_editor->end_complex_operation(); +} + +void CodeTextEditor::move_lines_up() { + text_editor->begin_complex_operation(); + if (text_editor->is_selection_active()) { + int from_line = text_editor->get_selection_from_line(); + int from_col = text_editor->get_selection_from_column(); + int to_line = text_editor->get_selection_to_line(); + int to_column = text_editor->get_selection_to_column(); + + for (int i = from_line; i <= to_line; i++) { + int line_id = i; + int next_id = i - 1; + + if (line_id == 0 || next_id < 0) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + int from_line_up = from_line > 0 ? from_line - 1 : from_line; + int to_line_up = to_line > 0 ? to_line - 1 : to_line; + text_editor->select(from_line_up, from_col, to_line_up, to_column); + } else { + int line_id = text_editor->cursor_get_line(); + int next_id = line_id - 1; + + if (line_id == 0 || next_id < 0) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + text_editor->end_complex_operation(); + text_editor->update(); +} + +void CodeTextEditor::move_lines_down() { + text_editor->begin_complex_operation(); + if (text_editor->is_selection_active()) { + int from_line = text_editor->get_selection_from_line(); + int from_col = text_editor->get_selection_from_column(); + int to_line = text_editor->get_selection_to_line(); + int to_column = text_editor->get_selection_to_column(); + + for (int i = to_line; i >= from_line; i--) { + int line_id = i; + int next_id = i + 1; + + if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line; + int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line; + text_editor->select(from_line_down, from_col, to_line_down, to_column); + } else { + int line_id = text_editor->cursor_get_line(); + int next_id = line_id + 1; + + if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + text_editor->end_complex_operation(); + text_editor->update(); +} + +void CodeTextEditor::delete_lines() { + text_editor->begin_complex_operation(); + if (text_editor->is_selection_active()) { + int to_line = text_editor->get_selection_to_line(); + int from_line = text_editor->get_selection_from_line(); + int count = Math::abs(to_line - from_line) + 1; + while (count) { + text_editor->set_line(text_editor->cursor_get_line(), ""); + text_editor->backspace_at_cursor(); + count--; + if (count) + text_editor->unfold_line(from_line); + } + text_editor->cursor_set_line(from_line - 1); + text_editor->deselect(); + } else { + int line = text_editor->cursor_get_line(); + text_editor->set_line(text_editor->cursor_get_line(), ""); + text_editor->backspace_at_cursor(); + text_editor->unfold_line(line); + text_editor->cursor_set_line(line); + } + text_editor->end_complex_operation(); +} + +void CodeTextEditor::code_lines_down() { + int from_line = text_editor->cursor_get_line(); + int to_line = text_editor->cursor_get_line(); + int column = text_editor->cursor_get_column(); + + if (text_editor->is_selection_active()) { + from_line = text_editor->get_selection_from_line(); + to_line = text_editor->get_selection_to_line(); + column = text_editor->cursor_get_column(); + } + int next_line = to_line + 1; + + if (to_line >= text_editor->get_line_count() - 1) { + text_editor->set_line(to_line, text_editor->get_line(to_line) + "\n"); + } + + text_editor->begin_complex_operation(); + for (int i = from_line; i <= to_line; i++) { + + text_editor->unfold_line(i); + if (i >= text_editor->get_line_count() - 1) { + text_editor->set_line(i, text_editor->get_line(i) + "\n"); + } + String line_clone = text_editor->get_line(i); + text_editor->insert_at(line_clone, next_line); + next_line++; + } + + text_editor->cursor_set_column(column); + if (text_editor->is_selection_active()) { + text_editor->select(to_line + 1, text_editor->get_selection_from_column(), next_line - 1, text_editor->get_selection_to_column()); + } + + text_editor->end_complex_operation(); + text_editor->update(); +} + +void CodeTextEditor::goto_line(int p_line) { + text_editor->deselect(); + text_editor->unfold_line(p_line); + text_editor->call_deferred("cursor_set_line", p_line); +} + +void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { + text_editor->unfold_line(p_line); + text_editor->call_deferred("cursor_set_line", p_line); + text_editor->call_deferred("cursor_set_column", p_begin); + text_editor->select(p_line, p_begin, p_line, p_end); +} + +Variant CodeTextEditor::get_edit_state() { + Dictionary state; + + state["scroll_position"] = text_editor->get_v_scroll(); + state["column"] = text_editor->cursor_get_column(); + state["row"] = text_editor->cursor_get_line(); + + return state; +} + +void CodeTextEditor::set_edit_state(const Variant &p_state) { + Dictionary state = p_state; + text_editor->cursor_set_column(state["column"]); + text_editor->cursor_set_line(state["row"]); + text_editor->set_v_scroll(state["scroll_position"]); + text_editor->grab_focus(); +} + void CodeTextEditor::set_error(const String &p_error) { error->set_text(p_error); diff --git a/editor/code_editor.h b/editor/code_editor.h index 2a3bb1ba76..903f61d87d 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -186,6 +186,29 @@ protected: static void _bind_methods(); public: + void trim_trailing_whitespace(); + + void convert_indent_to_spaces(); + void convert_indent_to_tabs(); + + enum CaseStyle { + UPPER, + LOWER, + CAPITALIZE, + }; + void convert_case(CaseStyle p_case); + + void move_lines_up(); + void move_lines_down(); + void delete_lines(); + void code_lines_down(); + + void goto_line(int p_line); + void goto_line_selection(int p_line, int p_begin, int p_end); + + Variant get_edit_state(); + void set_edit_state(const Variant &p_state); + void update_editor_settings(); void set_error(const String &p_error); void update_line_and_column() { _line_col_changed(); } diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index 734229d014..fa7e37eb1f 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -191,7 +191,7 @@ Transform Collada::Node::get_global_transform() const { return default_transform; } -Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) { +Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const { ERR_FAIL_COND_V(keys.size() == 0, Vector<float>()); int i = 0; @@ -225,22 +225,22 @@ Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) { ret.resize(16); Transform tr; // i wonder why collada matrices are transposed, given that's opposed to opengl.. - ret[0] = interp.basis.elements[0][0]; - ret[1] = interp.basis.elements[0][1]; - ret[2] = interp.basis.elements[0][2]; - ret[4] = interp.basis.elements[1][0]; - ret[5] = interp.basis.elements[1][1]; - ret[6] = interp.basis.elements[1][2]; - ret[8] = interp.basis.elements[2][0]; - ret[9] = interp.basis.elements[2][1]; - ret[10] = interp.basis.elements[2][2]; - ret[3] = interp.origin.x; - ret[7] = interp.origin.y; - ret[11] = interp.origin.z; - ret[12] = 0; - ret[13] = 0; - ret[14] = 0; - ret[15] = 1; + ret.write[0] = interp.basis.elements[0][0]; + ret.write[1] = interp.basis.elements[0][1]; + ret.write[2] = interp.basis.elements[0][2]; + ret.write[4] = interp.basis.elements[1][0]; + ret.write[5] = interp.basis.elements[1][1]; + ret.write[6] = interp.basis.elements[1][2]; + ret.write[8] = interp.basis.elements[2][0]; + ret.write[9] = interp.basis.elements[2][1]; + ret.write[10] = interp.basis.elements[2][2]; + ret.write[3] = interp.origin.x; + ret.write[7] = interp.origin.y; + ret.write[11] = interp.origin.z; + ret.write[12] = 0; + ret.write[13] = 0; + ret.write[14] = 0; + ret.write[15] = 1; return ret; } else { @@ -249,7 +249,7 @@ Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) { dest.resize(keys[i].data.size()); for (int j = 0; j < dest.size(); j++) { - dest[j] = keys[i].data[j] * c + keys[i - 1].data[j] * (1.0 - c); + dest.write[j] = keys[i].data[j] * c + keys[i - 1].data[j] * (1.0 - c); } return dest; //interpolate one by one @@ -452,7 +452,7 @@ Transform Collada::_read_transform(XMLParser &parser) { Vector<float> farr; farr.resize(16); for (int i = 0; i < 16; i++) { - farr[i] = array[i].to_double(); + farr.write[i] = array[i].to_double(); } return _read_transform_from_array(farr); @@ -1104,7 +1104,7 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name int from = prim.indices.size(); prim.indices.resize(from + values.size()); for (int i = 0; i < values.size(); i++) - prim.indices[from + i] = values[i]; + prim.indices.write[from + i] = values[i]; } else if (prim.vertex_size > 0) { prim.indices = values; @@ -1884,7 +1884,7 @@ void Collada::_parse_animation(XMLParser &parser) { track.keys.resize(key_count); for (int j = 0; j < key_count; j++) { - track.keys[j].time = time_keys[j]; + track.keys.write[j].time = time_keys[j]; state.animation_length = MAX(state.animation_length, time_keys[j]); } @@ -1905,9 +1905,9 @@ void Collada::_parse_animation(XMLParser &parser) { ERR_CONTINUE((output.size() / stride) != key_count); for (int j = 0; j < key_count; j++) { - track.keys[j].data.resize(output_len); + track.keys.write[j].data.resize(output_len); for (int k = 0; k < output_len; k++) - track.keys[j].data[k] = output[l + j * stride + k]; //super weird but should work: + track.keys.write[j].data.write[k] = output[l + j * stride + k]; //super weird but should work: } if (sampler.has("INTERPOLATION")) { @@ -1919,9 +1919,9 @@ void Collada::_parse_animation(XMLParser &parser) { for (int j = 0; j < key_count; j++) { if (interps[j] == "BEZIER") - track.keys[j].interp_type = AnimationTrack::INTERP_BEZIER; + track.keys.write[j].interp_type = AnimationTrack::INTERP_BEZIER; else - track.keys[j].interp_type = AnimationTrack::INTERP_LINEAR; + track.keys.write[j].interp_type = AnimationTrack::INTERP_LINEAR; } } @@ -1939,8 +1939,8 @@ void Collada::_parse_animation(XMLParser &parser) { ERR_CONTINUE(outangents.size() != key_count * 2 * names.size()); for (int j = 0; j < key_count; j++) { - track.keys[j].in_tangent = Vector2(intangents[j * 2 * names.size() + 0 + l * 2], intangents[j * 2 * names.size() + 1 + l * 2]); - track.keys[j].out_tangent = Vector2(outangents[j * 2 * names.size() + 0 + l * 2], outangents[j * 2 * names.size() + 1 + l * 2]); + track.keys.write[j].in_tangent = Vector2(intangents[j * 2 * names.size() + 0 + l * 2], intangents[j * 2 * names.size() + 1 + l * 2]); + track.keys.write[j].out_tangent = Vector2(outangents[j * 2 * names.size() + 0 + l * 2], outangents[j * 2 * names.size() + 1 + l * 2]); } } @@ -2118,7 +2118,7 @@ void Collada::_joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner) { for (int i = 0; i < nj->children.size(); i++) { - _joint_set_owner(nj->children[i], p_owner); + _joint_set_owner(nj->children.write[i], p_owner); } } } @@ -2147,7 +2147,7 @@ void Collada::_create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton } for (int i = 0; i < node->children.size(); i++) { - _create_skeletons(&node->children[i], p_skeleton); + _create_skeletons(&node->children.write[i], p_skeleton); } } @@ -2314,7 +2314,7 @@ bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) { for (int i = 0; i < gp->children.size(); i++) { if (gp->children[i] == parent) { - gp->children[i] = node; + gp->children.write[i] = node; found = true; break; } @@ -2330,7 +2330,7 @@ bool Collada::_optimize_skeletons(VisualScene *p_vscene, Node *p_node) { if (p_vscene->root_nodes[i] == parent) { - p_vscene->root_nodes[i] = node; + p_vscene->root_nodes.write[i] = node; found = true; break; } @@ -2466,7 +2466,7 @@ void Collada::_optimize() { VisualScene &vs = E->get(); for (int i = 0; i < vs.root_nodes.size(); i++) { - _create_skeletons(&vs.root_nodes[i]); + _create_skeletons(&vs.root_nodes.write[i]); } for (int i = 0; i < vs.root_nodes.size(); i++) { diff --git a/editor/collada/collada.h b/editor/collada/collada.h index ec3284bc5c..7535162f74 100644 --- a/editor/collada/collada.h +++ b/editor/collada/collada.h @@ -312,7 +312,7 @@ public: total += weights[i].weight; if (total) for (int i = 0; i < 4; i++) - weights[i].weight /= total; + weights.write[i].weight /= total; } } @@ -515,7 +515,7 @@ public: Key() { interp_type = INTERP_LINEAR; } }; - Vector<float> get_value_at_time(float p_time); + Vector<float> get_value_at_time(float p_time) const; Vector<Key> keys; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 8933fd7fe8..da73a3930a 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -51,7 +51,7 @@ public: if (name.begins_with("bind/")) { int which = name.get_slice("/", 1).to_int() - 1; ERR_FAIL_INDEX_V(which, params.size(), false); - params[which] = p_value; + params.write[which] = p_value; } else return false; @@ -820,7 +820,9 @@ void ConnectionsDock::update_tree() { if (i > 0) signaldesc += ", "; String tname = "var"; - if (pi.type != Variant::NIL) { + if (pi.type == Variant::OBJECT && pi.class_name != StringName()) { + tname = pi.class_name.operator String(); + } else if (pi.type != Variant::NIL) { tname = Variant::get_type_name(pi.type); } signaldesc += tname + " " + (pi.name == "" ? String("arg " + itos(i)) : pi.name); diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 542dca74e0..2803762973 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -58,7 +58,7 @@ void DocData::merge_from(const DocData &p_data) { for (int i = 0; i < c.methods.size(); i++) { - MethodDoc &m = c.methods[i]; + MethodDoc &m = c.methods.write[i]; for (int j = 0; j < cf.methods.size(); j++) { @@ -72,13 +72,13 @@ void DocData::merge_from(const DocData &p_data) { Vector<bool> arg_used; arg_used.resize(arg_count); for (int l = 0; l < arg_count; ++l) - arg_used[l] = false; + arg_used.write[l] = false; // also there is no guarantee that argument ordering will match, so we // have to check one by one so we make sure we have an exact match for (int k = 0; k < arg_count; ++k) { for (int l = 0; l < arg_count; ++l) if (cf.methods[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) { - arg_used[l] = true; + arg_used.write[l] = true; break; } } @@ -98,7 +98,7 @@ void DocData::merge_from(const DocData &p_data) { for (int i = 0; i < c.signals.size(); i++) { - MethodDoc &m = c.signals[i]; + MethodDoc &m = c.signals.write[i]; for (int j = 0; j < cf.signals.size(); j++) { @@ -113,7 +113,7 @@ void DocData::merge_from(const DocData &p_data) { for (int i = 0; i < c.constants.size(); i++) { - ConstantDoc &m = c.constants[i]; + ConstantDoc &m = c.constants.write[i]; for (int j = 0; j < cf.constants.size(); j++) { @@ -128,7 +128,7 @@ void DocData::merge_from(const DocData &p_data) { for (int i = 0; i < c.properties.size(); i++) { - PropertyDoc &p = c.properties[i]; + PropertyDoc &p = c.properties.write[i]; for (int j = 0; j < cf.properties.size(); j++) { @@ -146,7 +146,7 @@ void DocData::merge_from(const DocData &p_data) { for (int i = 0; i < c.theme_properties.size(); i++) { - PropertyDoc &p = c.theme_properties[i]; + PropertyDoc &p = c.theme_properties.write[i]; for (int j = 0; j < cf.theme_properties.size(); j++) { @@ -1020,7 +1020,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri for (int i = 0; i < c.methods.size(); i++) { - MethodDoc &m = c.methods[i]; + const MethodDoc &m = c.methods[i]; String qualifiers; if (m.qualifiers != "") @@ -1040,7 +1040,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri for (int j = 0; j < m.arguments.size(); j++) { - ArgumentDoc &a = m.arguments[j]; + const ArgumentDoc &a = m.arguments[j]; String enum_text; if (a.enumeration != String()) { @@ -1075,7 +1075,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri if (c.properties[i].enumeration != String()) { enum_text = " enum=\"" + c.properties[i].enumeration + "\""; } - PropertyDoc &p = c.properties[i]; + const PropertyDoc &p = c.properties[i]; _write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\"" + enum_text + ">"); _write_string(f, 3, p.description.strip_edges().xml_escape()); _write_string(f, 2, "</member>"); @@ -1090,11 +1090,11 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri _write_string(f, 1, "<signals>"); for (int i = 0; i < c.signals.size(); i++) { - MethodDoc &m = c.signals[i]; + const MethodDoc &m = c.signals[i]; _write_string(f, 2, "<signal name=\"" + m.name + "\">"); for (int j = 0; j < m.arguments.size(); j++) { - ArgumentDoc &a = m.arguments[j]; + const ArgumentDoc &a = m.arguments[j]; _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\">"); _write_string(f, 3, "</argument>"); } @@ -1113,7 +1113,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri for (int i = 0; i < c.constants.size(); i++) { - ConstantDoc &k = c.constants[i]; + const ConstantDoc &k = c.constants[i]; if (k.enumeration != String()) { _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">"); } else { @@ -1132,7 +1132,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri _write_string(f, 1, "<theme_items>"); for (int i = 0; i < c.theme_properties.size(); i++) { - PropertyDoc &p = c.theme_properties[i]; + const PropertyDoc &p = c.theme_properties[i]; _write_string(f, 2, "<theme_item name=\"" + p.name + "\" type=\"" + p.type + "\">"); _write_string(f, 2, "</theme_item>"); } diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 2f0982e5d9..d12c85861b 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -598,7 +598,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & int i = 0; for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { - orders[i++] = E->get().order; + orders.write[i++] = E->get().order; } orders.sort(); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 4dde893c6d..729f6f50ef 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -62,7 +62,7 @@ void EditorHistory::cleanup_history() { fail = true; } else { //after level, clip - history[i].path.resize(j); + history.write[i].path.resize(j); } break; @@ -100,14 +100,14 @@ void EditorHistory::_add_object(ObjectID p_object, const String &p_property, int if (p_property != "" && has_prev) { //add a sub property - History &pr = history[current]; + History &pr = history.write[current]; h = pr; h.path.resize(h.level + 1); h.path.push_back(o); h.level++; } else if (p_level_change != -1 && has_prev) { //add a sub property - History &pr = history[current]; + History &pr = history.write[current]; h = pr; ERR_FAIL_INDEX(p_level_change, h.path.size()); h.level = p_level_change; @@ -206,7 +206,7 @@ ObjectID EditorHistory::get_current() { if (current < 0 || current >= history.size()) return 0; - History &h = history[current]; + History &h = history.write[current]; Object *obj = ObjectDB::get_instance(h.path[h.level].object); if (!obj) return 0; @@ -558,7 +558,7 @@ void EditorData::move_edited_scene_index(int p_idx, int p_to_idx) { ERR_FAIL_INDEX(p_idx, edited_scene.size()); ERR_FAIL_INDEX(p_to_idx, edited_scene.size()); - SWAP(edited_scene[p_idx], edited_scene[p_to_idx]); + SWAP(edited_scene.write[p_idx], edited_scene.write[p_to_idx]); } void EditorData::remove_scene(int p_idx) { ERR_FAIL_INDEX(p_idx, edited_scene.size()); @@ -644,7 +644,7 @@ bool EditorData::check_and_update_scene(int p_idx) { //transfer selection List<Node *> new_selection; - for (List<Node *>::Element *E = edited_scene[p_idx].selection.front(); E; E = E->next()) { + for (List<Node *>::Element *E = edited_scene.write[p_idx].selection.front(); E; E = E->next()) { NodePath p = edited_scene[p_idx].root->get_path_to(E->get()); Node *new_node = new_scene->get_node(p); if (new_node) @@ -654,8 +654,8 @@ bool EditorData::check_and_update_scene(int p_idx) { new_scene->set_filename(edited_scene[p_idx].root->get_filename()); memdelete(edited_scene[p_idx].root); - edited_scene[p_idx].root = new_scene; - edited_scene[p_idx].selection = new_selection; + edited_scene.write[p_idx].root = new_scene; + edited_scene.write[p_idx].selection = new_selection; return true; } @@ -685,7 +685,7 @@ Node *EditorData::get_edited_scene_root(int p_idx) { void EditorData::set_edited_scene_root(Node *p_root) { ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); - edited_scene[current_edited_scene].root = p_root; + edited_scene.write[current_edited_scene].root = p_root; } int EditorData::get_edited_scene_count() const { @@ -707,10 +707,10 @@ Vector<EditorData::EditedScene> EditorData::get_edited_scenes() const { void EditorData::set_edited_scene_version(uint64_t version, int p_scene_idx) { ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); if (p_scene_idx < 0) { - edited_scene[current_edited_scene].version = version; + edited_scene.write[current_edited_scene].version = version; } else { ERR_FAIL_INDEX(p_scene_idx, edited_scene.size()); - edited_scene[p_scene_idx].version = version; + edited_scene.write[p_scene_idx].version = version; } } @@ -793,7 +793,7 @@ String EditorData::get_scene_path(int p_idx) const { void EditorData::set_edited_scene_live_edit_root(const NodePath &p_root) { ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); - edited_scene[current_edited_scene].live_edit_root = p_root; + edited_scene.write[current_edited_scene].live_edit_root = p_root; } NodePath EditorData::get_edited_scene_live_edit_root() { @@ -806,7 +806,7 @@ void EditorData::save_edited_scene_state(EditorSelection *p_selection, EditorHis ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); - EditedScene &es = edited_scene[current_edited_scene]; + EditedScene &es = edited_scene.write[current_edited_scene]; es.selection = p_selection->get_selected_node_list(); es.history_current = p_history->current; es.history_stored = p_history->history; @@ -817,7 +817,7 @@ void EditorData::save_edited_scene_state(EditorSelection *p_selection, EditorHis Dictionary EditorData::restore_edited_scene_state(EditorSelection *p_selection, EditorHistory *p_history) { ERR_FAIL_INDEX_V(current_edited_scene, edited_scene.size(), Dictionary()); - EditedScene &es = edited_scene[current_edited_scene]; + EditedScene &es = edited_scene.write[current_edited_scene]; p_history->current = es.history_current; p_history->history = es.history_stored; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 317fffad64..5c911a00ca 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -187,7 +187,7 @@ void EditorExportPreset::remove_patch(int p_idx) { void EditorExportPreset::set_patch(int p_index, const String &p_path) { ERR_FAIL_INDEX(p_index, patches.size()); - patches[p_index] = p_path; + patches.write[p_index] = p_path; EditorExport::singleton->save_presets(); } String EditorExportPreset::get_patch(int p_index) { @@ -295,7 +295,7 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa MD5Final(&ctx); sd.md5.resize(16); for (int i = 0; i < 16; i++) { - sd.md5[i] = ctx.digest[i]; + sd.md5.write[i] = ctx.digest[i]; } } @@ -584,9 +584,9 @@ EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_pla //initial export plugin callback for (int i = 0; i < export_plugins.size(); i++) { if (export_plugins[i]->get_script_instance()) { //script based - export_plugins[i]->_export_begin_script(features.features_pv, p_debug, p_path, p_flags); + export_plugins.write[i]->_export_begin_script(features.features_pv, p_debug, p_path, p_flags); } else { - export_plugins[i]->_export_begin(features.features, p_debug, p_path, p_flags); + export_plugins.write[i]->_export_begin(features.features, p_debug, p_path, p_flags); } } } @@ -594,7 +594,7 @@ EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_pla EditorExportPlatform::ExportNotifier::~ExportNotifier() { Vector<Ref<EditorExportPlugin> > export_plugins = EditorExport::get_singleton()->get_export_plugins(); for (int i = 0; i < export_plugins.size(); i++) { - export_plugins[i]->_export_end(); + export_plugins.write[i]->_export_end(); } } @@ -632,7 +632,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & p_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size()); } - export_plugins[i]->_clear(); + export_plugins.write[i]->_clear(); } FeatureContainers feature_containers = get_feature_containers(p_preset); @@ -687,9 +687,9 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & bool do_export = true; for (int i = 0; i < export_plugins.size(); i++) { if (export_plugins[i]->get_script_instance()) { //script based - export_plugins[i]->_export_file_script(path, type, features_pv); + export_plugins.write[i]->_export_file_script(path, type, features_pv); } else { - export_plugins[i]->_export_file(path, type, features); + export_plugins.write[i]->_export_file(path, type, features); } if (p_so_func) { for (int j = 0; j < export_plugins[i]->shared_objects.size(); j++) { @@ -709,7 +709,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & if (export_plugins[i]->skipped) { do_export = false; } - export_plugins[i]->_clear(); + export_plugins.write[i]->_clear(); if (!do_export) break; //apologies, not exporting @@ -751,7 +751,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & Vector<uint8_t> new_file; new_file.resize(utf8.length()); for (int j = 0; j < utf8.length(); j++) { - new_file[j] = utf8[j]; + new_file.write[j] = utf8[j]; } p_func(p_udata, from + ".remap", new_file, idx, total); @@ -1130,7 +1130,7 @@ void EditorExport::load_config() { for (int i = 0; i < export_platforms.size(); i++) { if (export_platforms[i]->get_name() == platform) { - preset = export_platforms[i]->create_preset(); + preset = export_platforms.write[i]->create_preset(); break; } } @@ -1203,7 +1203,7 @@ bool EditorExport::poll_export_platforms() { bool changed = false; for (int i = 0; i < export_platforms.size(); i++) { - if (export_platforms[i]->poll_devices()) { + if (export_platforms.write[i]->poll_devices()) { changed = true; } } diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 8a8a21543b..7d56c4985a 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -1135,7 +1135,7 @@ void EditorFileDialog::_favorite_move_up() { if (a_idx == -1 || b_idx == -1) return; - SWAP(favorited[a_idx], favorited[b_idx]); + SWAP(favorited.write[a_idx], favorited.write[b_idx]); EditorSettings::get_singleton()->set_favorite_dirs(favorited); @@ -1155,7 +1155,7 @@ void EditorFileDialog::_favorite_move_down() { if (a_idx == -1 || b_idx == -1) return; - SWAP(favorited[a_idx], favorited[b_idx]); + SWAP(favorited.write[a_idx], favorited.write[b_idx]); EditorSettings::get_singleton()->set_favorite_dirs(favorited); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 65e50560bc..727383b960 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1900,6 +1900,7 @@ void EditorHelpBit::_meta_clicked(String p_select) { void EditorHelpBit::_bind_methods() { ClassDB::bind_method("_meta_clicked", &EditorHelpBit::_meta_clicked); + ClassDB::bind_method(D_METHOD("set_text", "text"), &EditorHelpBit::set_text); ADD_SIGNAL(MethodInfo("request_hide")); } @@ -1925,7 +1926,7 @@ EditorHelpBit::EditorHelpBit() { rich_text = memnew(RichTextLabel); add_child(rich_text); - rich_text->set_anchors_and_margins_preset(Control::PRESET_WIDE); + //rich_text->set_anchors_and_margins_preset(Control::PRESET_WIDE); rich_text->connect("meta_clicked", this, "_meta_clicked"); rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor")); rich_text->set_override_selected_font_color(false); diff --git a/editor/editor_help.h b/editor/editor_help.h index 514169dc19..dbea97e98b 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -272,9 +272,9 @@ public: ~EditorHelp(); }; -class EditorHelpBit : public Panel { +class EditorHelpBit : public PanelContainer { - GDCLASS(EditorHelpBit, Panel); + GDCLASS(EditorHelpBit, PanelContainer); RichTextLabel *rich_text; void _go_to_help(String p_what); @@ -285,6 +285,7 @@ protected: void _notification(int p_what); public: + RichTextLabel *get_rich_text() { return rich_text; } void set_text(const String &p_text); EditorHelpBit(); }; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 8d5c320743..488980db07 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -719,6 +719,24 @@ void EditorProperty::set_object_and_property(Object *p_object, const StringName property = p_property; } +Control *EditorProperty::make_custom_tooltip(const String &p_text) const { + + tooltip_text = p_text; + EditorHelpBit *help_bit = memnew(EditorHelpBit); + help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel")); + help_bit->get_rich_text()->set_fixed_size_to_width(300); + + String text = TTR("Property: ") + "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n"; + text += p_text.get_slice("::", 1).strip_edges(); + help_bit->set_text(text); + help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene + return help_bit; +} + +String EditorProperty::get_tooltip_text() const { + return tooltip_text; +} + void EditorProperty::_bind_methods() { ClassDB::bind_method(D_METHOD("set_label", "text"), &EditorProperty::set_label); @@ -745,6 +763,8 @@ void EditorProperty::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &EditorProperty::_gui_input); ClassDB::bind_method(D_METHOD("_focusable_focused"), &EditorProperty::_focusable_focused); + ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorProperty::get_tooltip_text); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "checkable"), "set_checkable", "is_checkable"); @@ -919,6 +939,20 @@ void EditorInspectorCategory::_notification(int p_what) { } } +Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const { + + tooltip_text = p_text; + EditorHelpBit *help_bit = memnew(EditorHelpBit); + help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel")); + help_bit->get_rich_text()->set_fixed_size_to_width(300); + + String text = "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n"; + text += p_text.get_slice("::", 1).strip_edges(); + help_bit->set_text(text); + help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene + return help_bit; +} + Size2 EditorInspectorCategory::get_minimum_size() const { Ref<Font> font = get_font("font", "Tree"); @@ -934,6 +968,15 @@ Size2 EditorInspectorCategory::get_minimum_size() const { return ms; } +void EditorInspectorCategory::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorInspectorCategory::get_tooltip_text); +} + +String EditorInspectorCategory::get_tooltip_text() const { + + return tooltip_text; +} + EditorInspectorCategory::EditorInspectorCategory() { } @@ -1395,7 +1438,7 @@ void EditorInspector::update_tree() { class_descr_cache[type] = descr.word_wrap(80); } - category->set_tooltip(TTR("Class:") + " " + p.name + (class_descr_cache[type] == "" ? "" : "\n\n" + class_descr_cache[type])); + category->set_tooltip(p.name + "::" + (class_descr_cache[type] == "" ? "" : class_descr_cache[type])); } for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { @@ -1587,9 +1630,9 @@ void EditorInspector::update_tree() { ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); if (doc_hint != String()) { - ep->set_tooltip(TTR("Property:") + " " + property_prefix + p.name + "\n\n" + doc_hint); + ep->set_tooltip(property_prefix + p.name + "::" + doc_hint); } else { - ep->set_tooltip(TTR("Property:") + " " + property_prefix + p.name); + ep->set_tooltip(property_prefix + p.name); } ep->set_draw_red(draw_red); ep->set_use_folding(use_folding); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index d9b66b05b2..454622d662 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -85,6 +85,8 @@ private: Control *label_reference; Control *bottom_editor; + mutable String tooltip_text; + protected: void _notification(int p_what); static void _bind_methods(); @@ -143,6 +145,10 @@ public: float get_name_split_ratio() const; void set_object_and_property(Object *p_object, const StringName &p_property); + virtual Control *make_custom_tooltip(const String &p_text) const; + + String get_tooltip_text() const; + EditorProperty(); }; @@ -180,12 +186,17 @@ class EditorInspectorCategory : public Control { Ref<Texture> icon; String label; Color bg_color; + mutable String tooltip_text; protected: void _notification(int p_what); + static void _bind_methods(); public: virtual Size2 get_minimum_size() const; + virtual Control *make_custom_tooltip(const String &p_text) const; + + String get_tooltip_text() const; EditorInspectorCategory(); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 88266f468a..05fbf7aa76 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -112,6 +112,7 @@ #include "editor/plugins/sprite_editor_plugin.h" #include "editor/plugins/sprite_frames_editor_plugin.h" #include "editor/plugins/style_box_editor_plugin.h" +#include "editor/plugins/text_editor.h" #include "editor/plugins/texture_editor_plugin.h" #include "editor/plugins/texture_region_editor_plugin.h" #include "editor/plugins/theme_editor_plugin.h" @@ -156,7 +157,6 @@ void EditorNode::_update_scene_tabs() { scene_tabs->set_current_tab(editor_data.get_edited_scene()); - int current = editor_data.get_edited_scene(); if (scene_tabs->get_offset_buttons_visible()) { // move add button to fixed position on the tabbar if (scene_tab_add->get_parent() == scene_tabs) { @@ -1502,7 +1502,7 @@ void EditorNode::_edit_current() { if (main_plugin) { // special case if use of external editor is true - if (main_plugin->get_name() == "Script" && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) { + if (main_plugin->get_name() == "Script" && current_obj->get_class_name() != StringName("VisualScript") && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) { if (!changing_scene) main_plugin->edit(current_obj); } @@ -2047,6 +2047,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { project_settings->popup_project_settings(); } break; + case RUN_PROJECT_DATA_FOLDER: { + + OS::get_singleton()->shell_open(OS::get_singleton()->get_user_data_dir()); + } break; case FILE_QUIT: case RUN_PROJECT_MANAGER: { @@ -2179,6 +2183,14 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { settings_config_dialog->popup_edit_settings(); } break; + case SETTINGS_EDITOR_DATA_FOLDER: { + + OS::get_singleton()->shell_open(EditorSettings::get_singleton()->get_data_dir()); + } break; + case SETTINGS_EDITOR_CONFIG_FOLDER: { + + OS::get_singleton()->shell_open(EditorSettings::get_singleton()->get_settings_dir()); + } break; case SETTINGS_MANAGE_EXPORT_TEMPLATES: { export_template_manager->popup_manager(); @@ -3935,7 +3947,7 @@ void EditorNode::raise_bottom_panel_item(Control *p_item) { if (bottom_panel_items[i].control == p_item) { bottom_panel_items[i].button->raise(); - SWAP(bottom_panel_items[i], bottom_panel_items[bottom_panel_items.size() - 1]); + SWAP(bottom_panel_items.write[i], bottom_panel_items.write[bottom_panel_items.size() - 1]); break; } } @@ -5078,6 +5090,9 @@ EditorNode::EditorNode() { tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES); p->add_separator(); + p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); + p->add_separator(); + #ifdef OSX_ENABLED p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q); #else @@ -5125,6 +5140,7 @@ EditorNode::EditorNode() { p->add_item(TTR("Editor Settings"), SETTINGS_PREFERENCES); p->add_separator(); + editor_layouts = memnew(PopupMenu); editor_layouts->set_name("Layouts"); p->add_child(editor_layouts); @@ -5136,6 +5152,17 @@ EditorNode::EditorNode() { p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN); #endif p->add_separator(); + + if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) { + // Configuration and data folders are located in the same place (Windows/macOS) + p->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER); + } else { + // Separate configuration and data folders (Linux) + p->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER); + p->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER); + } + p->add_separator(); + p->add_item(TTR("Manage Export Templates"), SETTINGS_MANAGE_EXPORT_TEMPLATES); // Help Menu @@ -5270,7 +5297,7 @@ EditorNode::EditorNode() { video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor.")); video_restart_dialog->get_ok()->set_text(TTR("Save & Restart")); video_restart_dialog->connect("confirmed", this, "_menu_option", varray(SET_VIDEO_DRIVER_SAVE_AND_RESTART)); - add_child(video_restart_dialog); + gui_base->add_child(video_restart_dialog); progress_hb = memnew(BackgroundProgress); @@ -5289,8 +5316,8 @@ EditorNode::EditorNode() { update_menu->set_icon(gui_base->get_icon("Progress1", "EditorIcons")); update_menu->get_popup()->connect("id_pressed", this, "_menu_option"); p = update_menu->get_popup(); - p->add_check_item(TTR("Update Always"), SETTINGS_UPDATE_ALWAYS); - p->add_check_item(TTR("Update Changes"), SETTINGS_UPDATE_CHANGES); + p->add_radio_check_item(TTR("Update Always"), SETTINGS_UPDATE_ALWAYS); + p->add_radio_check_item(TTR("Update Changes"), SETTINGS_UPDATE_CHANGES); p->add_separator(); p->add_check_item(TTR("Disable Update Spinner"), SETTINGS_UPDATE_SPINNER_HIDE); int update_always = EditorSettings::get_singleton()->get_project_metadata("editor_options", "update_always", false); @@ -5469,6 +5496,7 @@ EditorNode::EditorNode() { EditorAudioBuses *audio_bus_editor = EditorAudioBuses::register_editor(); ScriptTextEditor::register_editor(); //register one for text scripts + TextEditor::register_editor(); if (StreamPeerSSL::is_available()) { add_editor_plugin(memnew(AssetLibraryEditorPlugin(this))); diff --git a/editor/editor_node.h b/editor/editor_node.h index 38e68b2e09..b7224c9393 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -154,6 +154,7 @@ private: RUN_PLAY_CUSTOM_SCENE, RUN_SCENE_SETTINGS, RUN_SETTINGS, + RUN_PROJECT_DATA_FOLDER, RUN_PROJECT_MANAGER, RUN_FILE_SERVER, RUN_LIVE_DEBUG, @@ -168,6 +169,8 @@ private: SETTINGS_LAYOUT_SAVE, SETTINGS_LAYOUT_DELETE, SETTINGS_LAYOUT_DEFAULT, + SETTINGS_EDITOR_DATA_FOLDER, + SETTINGS_EDITOR_CONFIG_FOLDER, SETTINGS_MANAGE_EXPORT_TEMPLATES, SETTINGS_PICK_MAIN_SCENE, SETTINGS_TOGGLE_FULLSCREEN, diff --git a/editor/editor_profiler.cpp b/editor/editor_profiler.cpp index d4a97b7095..67700b59de 100644 --- a/editor/editor_profiler.cpp +++ b/editor/editor_profiler.cpp @@ -37,9 +37,9 @@ void EditorProfiler::_make_metric_ptrs(Metric &m) { for (int i = 0; i < m.categories.size(); i++) { - m.category_ptrs[m.categories[i].signature] = &m.categories[i]; + m.category_ptrs[m.categories[i].signature] = &m.categories.write[i]; for (int j = 0; j < m.categories[i].items.size(); j++) { - m.item_ptrs[m.categories[i].items[j].signature] = &m.categories[i].items[j]; + m.item_ptrs[m.categories[i].items[j].signature] = &m.categories.write[i].items.write[j]; } } } @@ -50,8 +50,8 @@ void EditorProfiler::add_frame_metric(const Metric &p_metric, bool p_final) { if (last_metric >= frame_metrics.size()) last_metric = 0; - frame_metrics[last_metric] = p_metric; - _make_metric_ptrs(frame_metrics[last_metric]); + frame_metrics.write[last_metric] = p_metric; + _make_metric_ptrs(frame_metrics.write[last_metric]); updating_frame = true; cursor_metric_edit->set_max(frame_metrics[last_metric].frame_number); @@ -108,7 +108,7 @@ static String _get_percent_txt(float p_value, float p_total) { return String::num((p_value / p_total) * 100, 1) + "%"; } -String EditorProfiler::_get_time_as_text(Metric &m, float p_time, int p_calls) { +String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_calls) { int dmode = display_mode->get_selected(); @@ -192,18 +192,18 @@ void EditorProfiler::_update_plot() { float highest = 0; for (int i = 0; i < frame_metrics.size(); i++) { - Metric &m = frame_metrics[i]; + const Metric &m = frame_metrics[i]; if (!m.valid) continue; for (Set<StringName>::Element *E = plot_sigs.front(); E; E = E->next()) { - Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get()); + const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get()); if (F) { highest = MAX(F->get()->total_time, highest); } - Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get()); + const Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get()); if (G) { if (use_self) { highest = MAX(G->get()->self, highest); @@ -256,18 +256,18 @@ void EditorProfiler::_update_plot() { } //get - Metric &m = frame_metrics[idx]; + const Metric &m = frame_metrics[idx]; if (m.valid == false) continue; //skip because invalid float value = 0; - Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get()); + const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get()); if (F) { value = F->get()->total_time; } - Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get()); + const Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get()); if (G) { if (use_self) { value = G->get()->self; @@ -375,7 +375,7 @@ void EditorProfiler::_update_frame() { variables->clear(); TreeItem *root = variables->create_item(); - Metric &m = frame_metrics[cursor_metric]; + const Metric &m = frame_metrics[cursor_metric]; int dtime = display_time->get_selected(); @@ -394,7 +394,7 @@ void EditorProfiler::_update_frame() { } for (int j = 0; j < m.categories[i].items.size(); j++) { - Metric::Category::Item &it = m.categories[i].items[j]; + const Metric::Category::Item &it = m.categories[i].items[j]; TreeItem *item = variables->create_item(category); item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); diff --git a/editor/editor_profiler.h b/editor/editor_profiler.h index cb451475e7..d445ad58aa 100644 --- a/editor/editor_profiler.h +++ b/editor/editor_profiler.h @@ -136,7 +136,7 @@ private: void _activate_pressed(); void _clear_pressed(); - String _get_time_as_text(Metric &m, float p_time, int p_calls); + String _get_time_as_text(const Metric &m, float p_time, int p_calls); void _make_metric_ptrs(Metric &m); void _item_edited(); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 0b49b5a801..4fae8467b4 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -258,6 +258,51 @@ EditorPropertyPath::EditorPropertyPath() { global = false; } +///////////////////// CLASS NAME ///////////////////////// + +void EditorPropertyClassName::setup(const String &p_base_type, const String &p_selected_type) { + + base_type = p_base_type; + dialog->set_base_type(base_type); + selected_type = p_selected_type; + property->set_text(selected_type); +} + +void EditorPropertyClassName::update_property() { + + String s = get_edited_object()->get(get_edited_property()); + property->set_text(s); + selected_type = s; +} + +void EditorPropertyClassName::_property_selected() { + dialog->popup_create(true); +} + +void EditorPropertyClassName::_dialog_created() { + selected_type = dialog->get_selected_type(); + emit_signal("property_changed", get_edited_property(), selected_type); + update_property(); +} + +void EditorPropertyClassName::_bind_methods() { + ClassDB::bind_method(D_METHOD("_dialog_created"), &EditorPropertyClassName::_dialog_created); + ClassDB::bind_method(D_METHOD("_property_selected"), &EditorPropertyClassName::_property_selected); +} + +EditorPropertyClassName::EditorPropertyClassName() { + property = memnew(Button); + property->set_clip_text(true); + add_child(property); + add_focusable(property); + property->set_text(selected_type); + property->connect("pressed", this, "_property_selected"); + dialog = memnew(CreateDialog); + dialog->set_base_type(base_type); + dialog->connect("create", this, "_dialog_created"); + add_child(dialog); +} + ///////////////////// MEMBER ///////////////////////// void EditorPropertyMember::_property_selected(const String &p_selected) { @@ -681,6 +726,7 @@ void EditorPropertyLayers::_menu_pressed(int p_menu) { grid->value |= (1 << p_menu); } grid->update(); + layers->set_item_checked(layers->get_item_index(p_menu), grid->value & (1 << p_menu)); _grid_changed(grid->value); } @@ -706,6 +752,7 @@ EditorPropertyLayers::EditorPropertyLayers() { set_bottom_editor(hb); layers = memnew(PopupMenu); add_child(layers); + layers->set_hide_on_checkable_item_selection(false); layers->connect("id_pressed", this, "_menu_pressed"); } ///////////////////// INT ///////////////////////// @@ -2607,6 +2654,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) { EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText); add_property_editor(p_path, editor); + } else if (p_hint == PROPERTY_HINT_TYPE_STRING) { + EditorPropertyClassName *editor = memnew(EditorPropertyClassName); + editor->setup("Object", p_hint_text); + add_property_editor(p_path, editor); } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) { Vector<String> extensions = p_hint_text.split(","); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 0afb1bf955..ccd73d2539 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -119,6 +119,25 @@ public: EditorPropertyPath(); }; +class EditorPropertyClassName : public EditorProperty { + GDCLASS(EditorPropertyClassName, EditorProperty) +private: + CreateDialog *dialog; + Button *property; + String selected_type; + String base_type; + void _property_selected(); + void _dialog_created(); + +protected: + static void _bind_methods(); + +public: + void setup(const String &p_base_type, const String &p_selected_type); + virtual void update_property(); + EditorPropertyClassName(); +}; + class EditorPropertyMember : public EditorProperty { GDCLASS(EditorPropertyMember, EditorProperty) public: diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index aa67ea03d7..a9eaad47b7 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -46,7 +46,7 @@ bool EditorResourcePreviewGenerator::handles(const String &p_type) const { ERR_EXPLAIN("EditorResourcePreviewGenerator::handles needs to be overridden"); ERR_FAIL_V(false); } -Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from) { +Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from) const { if (get_script_instance() && get_script_instance()->has_method("generate")) { return get_script_instance()->call("generate", p_from); @@ -55,7 +55,7 @@ Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from) { ERR_FAIL_V(Ref<Texture>()); } -Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path) { +Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path) const { if (get_script_instance() && get_script_instance()->has_method("generate_from_path")) { return get_script_instance()->call("generate_from_path", p_path); diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index e2276aa11d..74841b1a1e 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -63,8 +63,8 @@ protected: public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); - virtual Ref<Texture> generate_from_path(const String &p_path); + virtual Ref<Texture> generate(const RES &p_from) const; + virtual Ref<Texture> generate_from_path(const String &p_path) const; EditorResourcePreviewGenerator(); }; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 4cfdb6f6d3..02e121b5f1 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -298,17 +298,17 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/main_font_size", 14); hints["interface/editor/main_font_size"] = PropertyInfo(Variant::INT, "interface/editor/main_font_size", PROPERTY_HINT_RANGE, "10,40,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/code_font_size", 14); - hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/main_font_hinting", 2); - hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/code_font_hinting", 2); - hints["interface/editor/code_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/code_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/editor/code_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/code_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/main_font", ""); - hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/main_font_bold", ""); - hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/code_font", ""); - hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/dim_editor_on_dialog_popup", true); _initial_set("interface/editor/dim_amount", 0.6f); hints["interface/editor/dim_amount"] = PropertyInfo(Variant::REAL, "interface/editor/dim_amount", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT); @@ -364,6 +364,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/highlighting/highlight_all_occurrences", true); _initial_set("text_editor/highlighting/highlight_current_line", true); + _initial_set("text_editor/highlighting/highlight_type_safe_lines", true); _initial_set("text_editor/cursor/scroll_past_end_of_file", false); _initial_set("text_editor/indent/type", 0); @@ -404,6 +405,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/completion/callhint_tooltip_offset", Vector2()); _initial_set("text_editor/files/restore_scripts_on_load", true); _initial_set("text_editor/completion/complete_file_paths", true); + _initial_set("text_editor/completion/add_type_hints", false); _initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false); _initial_set("docks/scene_tree/draw_relationship_lines", false); @@ -592,6 +594,7 @@ void EditorSettings::_load_default_text_editor_theme() { _initial_set("text_editor/highlighting/completion_font_color", Color::html("aaaaaa")); _initial_set("text_editor/highlighting/text_color", Color::html("aaaaaa")); _initial_set("text_editor/highlighting/line_number_color", Color::html("66aaaaaa")); + _initial_set("text_editor/highlighting/safe_line_number_color", Color::html("99aac8aa")); _initial_set("text_editor/highlighting/caret_color", Color::html("aaaaaa")); _initial_set("text_editor/highlighting/caret_background_color", Color::html("000000")); _initial_set("text_editor/highlighting/text_selected_color", Color::html("000000")); @@ -878,7 +881,7 @@ fail: Vector<String> list = extra_config->get_value("init_projects", "list"); for (int i = 0; i < list.size(); i++) { - list[i] = exe_path + "/" + list[i]; + list.write[i] = exe_path + "/" + list[i]; }; extra_config->set_value("init_projects", "list", list); }; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 084caff083..18cc52a5c6 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -237,8 +237,6 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = ImageLoaderSVG::set_convert_colors(NULL); clock_t end_time = clock(); - - double time_d = (double)(end_time - begin_time) / CLOCKS_PER_SEC; #else print_line("Sorry no icons for you"); #endif @@ -257,7 +255,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { String preset = EDITOR_DEF("interface/theme/preset", "Default"); - int icon_font_color_setting = EDITOR_DEF("interface/theme/icon_and_font_color", 0); bool highlight_tabs = EDITOR_DEF("interface/theme/highlight_tabs", false); int border_size = EDITOR_DEF("interface/theme/border_size", 1); @@ -1089,6 +1086,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color completion_font_color = font_color; const Color text_color = font_color; const Color line_number_color = dim_color; + const Color safe_line_number_color = dim_color * Color(1, 1.2, 1, 1.5); const Color caret_color = mono_color; const Color caret_background_color = mono_color.inverted(); const Color text_selected_color = dark_color_3; @@ -1123,6 +1121,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { setting->set_initial_value("text_editor/highlighting/completion_font_color", completion_font_color, true); setting->set_initial_value("text_editor/highlighting/text_color", text_color, true); setting->set_initial_value("text_editor/highlighting/line_number_color", line_number_color, true); + setting->set_initial_value("text_editor/highlighting/safe_line_number_color", safe_line_number_color, true); setting->set_initial_value("text_editor/highlighting/caret_color", caret_color, true); setting->set_initial_value("text_editor/highlighting/caret_background_color", caret_background_color, true); setting->set_initial_value("text_editor/highlighting/text_selected_color", text_selected_color, true); diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index a218070933..b9e0c7d0fa 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/editor/fileserver/editor_file_server.cpp @@ -78,7 +78,7 @@ void EditorFileServer::_subthread_start(void *s) { _close_client(cd); ERR_FAIL_COND(err != OK); } - passutf8[passlen] = 0; + passutf8.write[passlen] = 0; String s; s.parse_utf8(passutf8.ptr()); if (s != cd->efs->password) { @@ -145,7 +145,7 @@ void EditorFileServer::_subthread_start(void *s) { _close_client(cd); ERR_FAIL_COND(err != OK); } - fileutf8[namelen] = 0; + fileutf8.write[namelen] = 0; String s; s.parse_utf8(fileutf8.ptr()); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index f65fb5365b..37f86cc912 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1319,6 +1319,9 @@ void FileSystemDock::_file_option(int p_option) { String fpath = files->get_item_metadata(idx); OS::get_singleton()->set_clipboard(fpath); } break; + case FILE_NEW_RESOURCE: { + new_resource_dialog->popup_create(true); + } break; } } @@ -1393,6 +1396,21 @@ void FileSystemDock::_folder_option(int p_option) { } } +void FileSystemDock::_resource_created() const { + Object *c = new_resource_dialog->instance_selected(); + + ERR_FAIL_COND(!c); + Resource *r = Object::cast_to<Resource>(c); + ERR_FAIL_COND(!r); + + REF res(r); + editor->push_item(c); + + RES current_res = RES(r); + + editor->save_resource_as(current_res); +} + void FileSystemDock::_go_to_file_list() { if (low_height_mode) { @@ -1738,6 +1756,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); + file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER); file_options->set_position(files->get_global_position() + p_pos); @@ -1750,6 +1769,7 @@ void FileSystemDock::_rmb_pressed(const Vector2 &p_pos) { file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); + file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER); file_options->set_position(files->get_global_position() + p_pos); file_options->popup(); @@ -1862,6 +1882,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_file_option"), &FileSystemDock::_file_option); ClassDB::bind_method(D_METHOD("_folder_option"), &FileSystemDock::_folder_option); ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); + ClassDB::bind_method(D_METHOD("_resource_created"), &FileSystemDock::_resource_created); ClassDB::bind_method(D_METHOD("_move_operation_confirm", "to_path", "overwrite"), &FileSystemDock::_move_operation_confirm, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite); ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm); @@ -2087,6 +2108,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { make_script_dialog_text->set_title(TTR("Create Script")); add_child(make_script_dialog_text); + new_resource_dialog = memnew(CreateDialog); + add_child(new_resource_dialog); + new_resource_dialog->set_base_type("Resource"); + new_resource_dialog->connect("create", this, "_resource_created"); + updating_tree = false; initialized = false; import_dock_needs_update = false; diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index e8ab803cca..6a0c73d52e 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -47,6 +47,8 @@ #include "os/dir_access.h" #include "os/thread.h" +#include "create_dialog.h" + #include "dependency_editor.h" #include "editor_dir_dialog.h" #include "editor_file_system.h" @@ -78,7 +80,8 @@ private: FILE_NEW_FOLDER, FILE_NEW_SCRIPT, FILE_SHOW_IN_EXPLORER, - FILE_COPY_PATH + FILE_COPY_PATH, + FILE_NEW_RESOURCE }; enum FolderMenu { @@ -131,6 +134,7 @@ private: LineEdit *make_dir_dialog_text; ConfirmationDialog *overwrite_dialog; ScriptCreateDialog *make_script_dialog_text; + CreateDialog *new_resource_dialog; class FileOrFolder { public: @@ -191,6 +195,7 @@ private: void _update_favorite_dirs_list_after_move(const Map<String, String> &p_renames) const; void _update_project_settings_after_move(const Map<String, String> &p_renames) const; + void _resource_created() const; void _make_dir_confirm(); void _rename_operation_confirm(); void _duplicate_operation_confirm(); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 004a49e2b4..2be1f1644e 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -143,7 +143,7 @@ void FindInFiles::_iterate() { // Scan folders first so we can build a list of files and have progress info later - PoolStringArray &folders_to_scan = _folders_stack[_folders_stack.size() - 1]; + PoolStringArray &folders_to_scan = _folders_stack.write[_folders_stack.size() - 1]; if (folders_to_scan.size() != 0) { // Scan one folder below diff --git a/editor/icons/icon_soft_body.svg b/editor/icons/icon_soft_body.svg new file mode 100644 index 0000000000..9930026b61 --- /dev/null +++ b/editor/icons/icon_soft_body.svg @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg2" + inkscape:version="0.91 r13725" + sodipodi:docname="icon_soft_body.svg"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1027" + id="namedview10" + showgrid="false" + inkscape:zoom="18.792233" + inkscape:cx="2.8961304" + inkscape:cy="4.3816933" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" /> + <path + style="opacity:1;fill:#fc9c9c;fill-opacity:0.99607843;fill-rule:nonzero;stroke:none;stroke-width:1.42799997;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + d="m 2.3447105,1.6091897 c -0.011911,1.9816766 -1.4168958,3.9344766 0,5.9495986 1.4168957,2.0151221 0,6.6693597 0,6.6693597 l 10.9510055,0 c 0,0 1.780829,-4.4523824 0,-6.489075 -1.780829,-2.0366925 -0.183458,-4.119112 0,-6.1298833 z m 1.8894067,0.7549031 7.4390658,0 c -0.431995,1.5996085 -1.62289,4.0426807 0,5.3749802 1.622888,1.3322996 0,5.887932 0,5.887932 l -7.4390658,0 c 0,0 1.3903413,-4.3680495 0,-5.9780743 -1.3903412,-1.6100247 -0.3951213,-3.7149271 0,-5.2848379 z" + id="rect4142" + inkscape:connector-curvature="0" + sodipodi:nodetypes="czcczcccczcczc" /> +</svg> diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index a13f741ee7..22ea5883e8 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -579,12 +579,12 @@ static void _generate_tangents_and_binormals(const PoolVector<int> &p_indices, c .normalized(); } - tangents[index_arrayr[idx * 3 + 0]] += tangent; - binormals[index_arrayr[idx * 3 + 0]] += binormal; - tangents[index_arrayr[idx * 3 + 1]] += tangent; - binormals[index_arrayr[idx * 3 + 1]] += binormal; - tangents[index_arrayr[idx * 3 + 2]] += tangent; - binormals[index_arrayr[idx * 3 + 2]] += binormal; + tangents.write[index_arrayr[idx * 3 + 0]] += tangent; + binormals.write[index_arrayr[idx * 3 + 0]] += binormal; + tangents.write[index_arrayr[idx * 3 + 1]] += tangent; + binormals.write[index_arrayr[idx * 3 + 1]] += binormal; + tangents.write[index_arrayr[idx * 3 + 2]] += tangent; + binormals.write[index_arrayr[idx * 3 + 2]] += binormal; //print_line(itos(idx)+" tangent: "+tangent); //print_line(itos(idx)+" binormal: "+binormal); @@ -800,7 +800,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me total += weights[i].weight; if (total) for (int i = 0; i < weights.size(); i++) - weights[i].weight /= total; + weights.write[i].weight /= total; if (weights.size() == 0 || total == 0) { //if nothing, add a weight to bone 0 //no weights assigned @@ -987,7 +987,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me vertex_array.resize(vertex_set.size()); for (Set<Collada::Vertex>::Element *F = vertex_set.front(); F; F = F->next()) { - vertex_array[F->get().idx] = F->get(); + vertex_array.write[F->get().idx] = F->get(); } if (has_weights) { @@ -996,9 +996,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me Transform local_xform = p_local_xform; for (int i = 0; i < vertex_array.size(); i++) { - vertex_array[i].vertex = local_xform.xform(vertex_array[i].vertex); - vertex_array[i].normal = local_xform.basis.xform(vertex_array[i].normal).normalized(); - vertex_array[i].tangent.normal = local_xform.basis.xform(vertex_array[i].tangent.normal).normalized(); + vertex_array.write[i].vertex = local_xform.xform(vertex_array[i].vertex); + vertex_array.write[i].normal = local_xform.basis.xform(vertex_array[i].normal).normalized(); + vertex_array.write[i].tangent.normal = local_xform.basis.xform(vertex_array[i].tangent.normal).normalized(); if (local_xform_mirror) { //i shouldn't do this? wtf? //vertex_array[i].normal*=-1.0; @@ -1061,13 +1061,13 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me //float sum=0.0; for (int l = 0; l < VS::ARRAY_WEIGHTS_SIZE; l++) { if (l < vertex_array[k].weights.size()) { - weights[l] = vertex_array[k].weights[l].weight; - bones[l] = vertex_array[k].weights[l].bone_idx; + weights.write[l] = vertex_array[k].weights[l].weight; + bones.write[l] = vertex_array[k].weights[l].bone_idx; //sum += vertex_array[k].weights[l].weight; } else { - weights[l] = 0; - bones[l] = 0; + weights.write[l] = 0; + bones.write[l] = 0; } } @@ -1286,7 +1286,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres String str = joint_src->sarray[i]; ERR_FAIL_COND_V(!bone_remap_map.has(str), ERR_INVALID_DATA); - bone_remap[i] = bone_remap_map[str]; + bone_remap.write[i] = bone_remap_map[str]; } } @@ -1506,7 +1506,7 @@ void ColladaImport::_fix_param_animation_tracks() { const Vector<int> &rt = collada.state.referenced_tracks[track_name]; for (int rti = 0; rti < rt.size(); rti++) { - Collada::AnimationTrack *at = &collada.state.animation_tracks[rt[rti]]; + Collada::AnimationTrack *at = &collada.state.animation_tracks.write[rt[rti]]; at->target = E->key(); at->param = "morph/" + collada.state.mesh_name_map[mesh_name]; @@ -1540,7 +1540,7 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones, bool p_im for (int i = 0; i < collada.state.animation_tracks.size(); i++) { - Collada::AnimationTrack &at = collada.state.animation_tracks[i]; + const Collada::AnimationTrack &at = collada.state.animation_tracks[i]; //print_line("CHANNEL: "+at.target+" PARAM: "+at.param); String node; @@ -1698,7 +1698,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones if (nm.anim_tracks.size() == 1) { //use snapshot keys from anim track instead, because this was most likely exported baked - Collada::AnimationTrack &at = collada.state.animation_tracks[nm.anim_tracks.front()->get()]; + const Collada::AnimationTrack &at = collada.state.animation_tracks[nm.anim_tracks.front()->get()]; snapshots.clear(); for (int i = 0; i < at.keys.size(); i++) snapshots.push_back(at.keys[i].time); @@ -1723,7 +1723,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones found_anim = true; - Collada::AnimationTrack &at = collada.state.animation_tracks[ET->get()]; + const Collada::AnimationTrack &at = collada.state.animation_tracks[ET->get()]; int xform_idx = -1; for (int j = 0; j < cn->xform_list.size(); j++) { @@ -1745,18 +1745,18 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones Vector<float> data = at.get_value_at_time(snapshots[i]); ERR_CONTINUE(data.empty()); - Collada::Node::XForm &xf = cn->xform_list[xform_idx]; + Collada::Node::XForm &xf = cn->xform_list.write[xform_idx]; if (at.component == "ANGLE") { ERR_CONTINUE(data.size() != 1); ERR_CONTINUE(xf.op != Collada::Node::XForm::OP_ROTATE); ERR_CONTINUE(xf.data.size() < 4); - xf.data[3] = data[0]; + xf.data.write[3] = data[0]; } else if (at.component == "X" || at.component == "Y" || at.component == "Z") { int cn = at.component[0] - 'X'; ERR_CONTINUE(cn >= xf.data.size()); ERR_CONTINUE(data.size() > 1); - xf.data[cn] = data[0]; + xf.data.write[cn] = data[0]; } else if (data.size() == xf.data.size()) { xf.data = data; @@ -1862,7 +1862,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones continue; } - Collada::AnimationTrack &at = collada.state.animation_tracks[ti]; + const Collada::AnimationTrack &at = collada.state.animation_tracks[ti]; // take snapshots if (!collada.state.scene_map.has(at.target)) @@ -1965,7 +1965,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_ if (p_flags & IMPORT_ANIMATION_DETECT_LOOP) { if (name.begins_with("loop") || name.ends_with("loop") || name.begins_with("cycle") || name.ends_with("cycle")) { - state.animations[i]->set_loop(true); + state.animations.write[i]->set_loop(true); } } diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index eb0bc0f782..7cfaa9070f 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -651,7 +651,7 @@ Vector<double> EditorSceneImporterGLTF::_decode_accessor(GLTFState &state, int p } else { //fill with zeros, as bufferview is not defined. for (int i = 0; i < (a.count * component_count); i++) { - dst_buffer[i] = 0; + dst_buffer.write[i] = 0; } } @@ -794,7 +794,7 @@ Vector<Quat> EditorSceneImporterGLTF::_decode_accessor_as_quat(GLTFState &state, ret.resize(ret_size); { for (int i = 0; i < ret_size; i++) { - ret[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]); + ret.write[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]); } } return ret; @@ -808,8 +808,8 @@ Vector<Transform2D> EditorSceneImporterGLTF::_decode_accessor_as_xform2d(GLTFSta ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret); ret.resize(attribs.size() / 4); for (int i = 0; i < ret.size(); i++) { - ret[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]); - ret[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]); + ret.write[i][0] = Vector2(attribs[i * 4 + 0], attribs[i * 4 + 1]); + ret.write[i][1] = Vector2(attribs[i * 4 + 2], attribs[i * 4 + 3]); } return ret; } @@ -823,9 +823,9 @@ Vector<Basis> EditorSceneImporterGLTF::_decode_accessor_as_basis(GLTFState &stat ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret); ret.resize(attribs.size() / 9); for (int i = 0; i < ret.size(); i++) { - ret[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); - ret[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); - ret[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); + ret.write[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2])); + ret.write[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5])); + ret.write[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8])); } return ret; } @@ -838,10 +838,10 @@ Vector<Transform> EditorSceneImporterGLTF::_decode_accessor_as_xform(GLTFState & ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret); ret.resize(attribs.size() / 16); for (int i = 0; i < ret.size(); i++) { - ret[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); - ret[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); - ret[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); - ret[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); + ret.write[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2])); + ret.write[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6])); + ret.write[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10])); + ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14])); } return ret; } @@ -1085,7 +1085,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { ERR_FAIL_COND_V(mesh.mesh->get_blend_shape_count() != weights.size(), ERR_PARSE_ERROR); mesh.blend_weights.resize(weights.size()); for (int j = 0; j < weights.size(); j++) { - mesh.blend_weights[j] = weights[j]; + mesh.blend_weights.write[j] = weights[j]; } } @@ -1139,7 +1139,7 @@ Error EditorSceneImporterGLTF::_parse_images(GLTFState &state, const String &p_b ERR_FAIL_INDEX_V(bvi, state.buffer_views.size(), ERR_PARAMETER_RANGE_ERROR); - GLTFBufferView &bv = state.buffer_views[bvi]; + const GLTFBufferView &bv = state.buffer_views[bvi]; int bi = bv.buffer; ERR_FAIL_INDEX_V(bi, state.buffers.size(), ERR_PARAMETER_RANGE_ERROR); @@ -1596,7 +1596,7 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) { PoolVector<float> weights = _decode_accessor_as_floats(state, output, false); ERR_FAIL_INDEX_V(state.nodes[node]->mesh, state.meshes.size(), ERR_PARSE_ERROR); - GLTFMesh *mesh = &state.meshes[state.nodes[node]->mesh]; + const GLTFMesh *mesh = &state.meshes[state.nodes[node]->mesh]; ERR_FAIL_COND_V(mesh->blend_weights.size() == 0, ERR_PARSE_ERROR); int wc = mesh->blend_weights.size(); @@ -1611,11 +1611,11 @@ Error EditorSceneImporterGLTF::_parse_animations(GLTFState &state) { Vector<float> wdata; wdata.resize(wlen); for (int l = 0; l < wlen; l++) { - wdata[l] = r[l * wc + k]; + wdata.write[l] = r[l * wc + k]; } cf.values = wdata; - track->weight_tracks[k] = cf; + track->weight_tracks.write[k] = cf; } } else { WARN_PRINTS("Invalid path: " + path); @@ -1657,7 +1657,7 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node if (n->mesh >= 0) { ERR_FAIL_INDEX(n->mesh, state.meshes.size()); MeshInstance *mi = memnew(MeshInstance); - GLTFMesh &mesh = state.meshes[n->mesh]; + GLTFMesh &mesh = state.meshes.write[n->mesh]; mi->set_mesh(mesh.mesh); if (mesh.mesh->get_name() == "") { mesh.mesh->set_name(n->name); @@ -1711,14 +1711,14 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node #endif for (int i = 0; i < n->children.size(); i++) { if (state.nodes[n->children[i]]->joints.size()) { - _generate_bone(state, n->children[i], skeletons, Vector<int>(), node); + _generate_bone(state, n->children[i], skeletons, node); } else { _generate_node(state, n->children[i], node, p_owner, skeletons); } } } -void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, const Vector<int> &p_parent_bones, Node *p_parent_node) { +void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, Node *p_parent_node) { ERR_FAIL_INDEX(p_node, state.nodes.size()); if (state.skeleton_nodes.has(p_node)) { @@ -1733,30 +1733,28 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto } GLTFNode *n = state.nodes[p_node]; - Vector<int> parent_bones; for (int i = 0; i < n->joints.size(); i++) { - ERR_FAIL_COND(n->joints[i].skin < 0); + const int skin = n->joints[i].skin; + ERR_FAIL_COND(skin < 0); - int bone_index = n->joints[i].bone; + Skeleton *s = skeletons[skin]; + const GLTFNode *gltf_bone_node = state.nodes[state.skins[skin].bones[n->joints[i].bone].node]; + const String bone_name = gltf_bone_node->name; + const int parent = gltf_bone_node->parent; + const int parent_index = s->find_bone(state.nodes[parent]->name); - Skeleton *s = skeletons[n->joints[i].skin]; - while (s->get_bone_count() <= bone_index) { - s->add_bone("Bone " + itos(s->get_bone_count())); - } - - if (p_parent_bones.size()) { - s->set_bone_parent(bone_index, p_parent_bones[i]); - } - s->set_bone_rest(bone_index, state.skins[n->joints[i].skin].bones[n->joints[i].bone].inverse_bind.affine_inverse()); + s->add_bone(bone_name); + const int bone_index = s->find_bone(bone_name); + s->set_bone_parent(bone_index, parent_index); + s->set_bone_rest(bone_index, state.skins[skin].bones[n->joints[i].bone].inverse_bind.affine_inverse()); n->godot_nodes.push_back(s); - n->joints[i].godot_bone_index = bone_index; - parent_bones.push_back(bone_index); + n->joints.write[i].godot_bone_index = bone_index; } for (int i = 0; i < n->children.size(); i++) { - _generate_bone(state, n->children[i], skeletons, parent_bones, p_parent_node); + _generate_bone(state, n->children[i], skeletons, p_parent_node); } } @@ -2070,7 +2068,7 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f } for (int i = 0; i < state.root_nodes.size(); i++) { if (state.nodes[state.root_nodes[i]]->joints.size()) { - _generate_bone(state, state.root_nodes[i], skeletons, Vector<int>(), root); + _generate_bone(state, state.root_nodes[i], skeletons, root); } else { _generate_node(state, state.root_nodes[i], root, root, skeletons); } diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index 088036ce75..e8f3bdff62 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -311,7 +311,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Vector<Basis> _decode_accessor_as_basis(GLTFState &state, int p_accessor, bool p_for_vertex); Vector<Transform> _decode_accessor_as_xform(GLTFState &state, int p_accessor, bool p_for_vertex); - void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, const Vector<int> &p_parent_bones, Node *p_parent_node); + void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, Node *p_parent_node); void _generate_node(GLTFState &state, int p_node, Node *p_parent, Node *p_owner, Vector<Skeleton *> &skeletons); void _import_animation(GLTFState &state, AnimationPlayer *ap, int index, int bake_fps, Vector<Skeleton *> skeletons); diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index ec0500361d..cf850eef03 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -119,7 +119,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const if (key != "") { for (int i = 1; i < line.size(); i++) { - translations[i - 1]->add_message(key, line[i]); + translations.write[i - 1]->add_message(key, line[i]); } } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index a5ad34f377..b5e3466b12 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -750,7 +750,7 @@ void ResourceImporterScene::_filter_tracks(Node *scene, const String &p_text) { Vector<String> strings = p_text.split("\n"); for (int i = 0; i < strings.size(); i++) { - strings[i] = strings[i].strip_edges(); + strings.write[i] = strings[i].strip_edges(); } List<StringName> anim_names; diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 72ec81ed46..41f5a892eb 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -215,19 +215,19 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s for (int i = 0; i < frames * format_channels; i++) { // 8 bit samples are UNSIGNED - data[i] = int8_t(file->get_8() - 128) / 128.f; + data.write[i] = int8_t(file->get_8() - 128) / 128.f; } } else if (format_bits == 32 && compression_code == 3) { for (int i = 0; i < frames * format_channels; i++) { //32 bit IEEE Float - data[i] = file->get_float(); + data.write[i] = file->get_float(); } } else if (format_bits == 16) { for (int i = 0; i < frames * format_channels; i++) { //16 bit SIGNED - data[i] = int16_t(file->get_16()) / 32768.f; + data.write[i] = int16_t(file->get_16()) / 32768.f; } } else { for (int i = 0; i < frames * format_channels; i++) { @@ -241,7 +241,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } s <<= (32 - format_bits); - data[i] = (int32_t(s) >> 16) / 32768.f; + data.write[i] = (int32_t(s) >> 16) / 32768.f; } } @@ -335,7 +335,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s float res = (a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3); - new_data[i * format_channels + c] = res; + new_data.write[i * format_channels + c] = res; // update position and always keep fractional part within ]0...1] // in order to avoid 32bit floating point precision errors @@ -374,7 +374,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s float mult = 1.0 / max; for (int i = 0; i < data.size(); i++) { - data[i] *= mult; + data.write[i] *= mult; } } } @@ -408,7 +408,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s Vector<float> new_data; new_data.resize((last - first + 1) * format_channels); for (int i = first * format_channels; i < (last + 1) * format_channels; i++) { - new_data[i - first * format_channels] = data[i]; + new_data.write[i - first * format_channels] = data[i]; } data = new_data; @@ -433,7 +433,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s Vector<float> new_data; new_data.resize(data.size() / 2); for (int i = 0; i < frames; i++) { - new_data[i] = (data[i * 2 + 0] + data[i * 2 + 1]) / 2.0; + new_data.write[i] = (data[i * 2 + 0] + data[i * 2 + 1]) / 2.0; } data = new_data; @@ -465,8 +465,8 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s right.resize(tframes); for (int i = 0; i < tframes; i++) { - left[i] = data[i * 2 + 0]; - right[i] = data[i * 2 + 1]; + left.write[i] = data[i * 2 + 0]; + right.write[i] = data[i * 2 + 1]; } PoolVector<uint8_t> bleft; diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 0d0b12c911..43baabe2f5 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -140,6 +140,7 @@ void InspectorDock::_load_resource(const String &p_type) { void InspectorDock::_resource_file_selected(String p_file) { RES res = ResourceLoader::load(p_file); + if (res.is_null()) { warning_dialog->get_ok()->set_text("Ugh"); warning_dialog->set_text(TTR("Failed to load resource.")); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 5052b69e24..2d341cdd93 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -345,7 +345,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector<Vector2> vertices = _get_polygon(edited_point.polygon); ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false); - vertices[edited_point.vertex] = edited_point.pos - _get_offset(edited_point.polygon); + vertices.write[edited_point.vertex] = edited_point.pos - _get_offset(edited_point.polygon); undo_redo->create_action(TTR("Edit Poly")); _action_set_polygon(edited_point.polygon, pre_move_edit, vertices); @@ -445,7 +445,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) Vector<Vector2> vertices = _get_polygon(edited_point.polygon); ERR_FAIL_INDEX_V(edited_point.vertex, vertices.size(), false); - vertices[edited_point.vertex] = cpoint - _get_offset(edited_point.polygon); + vertices.write[edited_point.vertex] = cpoint - _get_offset(edited_point.polygon); _set_polygon(edited_point.polygon, vertices); } diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index 8d17062248..27df60f87a 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -414,7 +414,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); point *= s; point.y = s.height - point.y; - points[j] = point; + points.write[j] = point; } for (int j = 0; j < 3; j++) { diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 23eeef9f20..9ab5436de8 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1333,7 +1333,7 @@ void AnimationPlayerEditor::_allocate_onion_layers() { bool is_present = onion.differences_only && i == captures - 1; // Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport - onion.captures[i] = VS::get_singleton()->viewport_create(); + onion.captures.write[i] = VS::get_singleton()->viewport_create(); VS::get_singleton()->viewport_set_usage(onion.captures[i], VS::VIEWPORT_USAGE_2D); VS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height); VS::get_singleton()->viewport_set_update_mode(onion.captures[i], VS::VIEWPORT_UPDATE_ALWAYS); @@ -1473,7 +1473,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() { float pos = cpos + step_off * anim->get_step(); bool valid = anim->has_loop() || (pos >= 0 && pos <= anim->get_length()); - onion.captures_valid[cidx] = valid; + onion.captures_valid.write[cidx] = valid; if (valid) { player->seek(pos, true); get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 04bd5f0cec..ee450333c8 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -679,7 +679,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { Ref<StyleBox> sb = name == selected_node ? style_selected : style; int strsize = font->get_string_size(name).width; - NodeRect &nr = node_rects[i]; + NodeRect &nr = node_rects.write[i]; Vector2 offset = nr.node.position; int h = nr.node.size.height; @@ -771,7 +771,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { if (idx == -1) return; - NodeRect &nr = node_rects[idx]; + const NodeRect &nr = node_rects[idx]; Vector2 from; from.x = nr.play.position.x; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 505dd4ab76..e98dfceb90 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -197,7 +197,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const for (int i = 0; i < preview_images.size(); i++) { if (preview_images[i].id == p_index) { - preview_images[i].image = p_image; + preview_images.write[i].image = p_image; if (preview_images[i].button->is_pressed()) { _preview_click(p_index); } diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp index ddb03d0250..454a5d72f2 100644 --- a/editor/plugins/audio_stream_editor_plugin.cpp +++ b/editor/plugins/audio_stream_editor_plugin.cpp @@ -81,8 +81,8 @@ void AudioStreamEditor::_draw_preview() { float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5; int idx = i; - lines[idx * 2 + 0] = Vector2(i + 1, rect.position.y + min * rect.size.y); - lines[idx * 2 + 1] = Vector2(i + 1, rect.position.y + max * rect.size.y); + lines.write[idx * 2 + 0] = Vector2(i + 1, rect.position.y + min * rect.size.y); + lines.write[idx * 2 + 1] = Vector2(i + 1, rect.position.y + max * rect.size.y); } Vector<Color> color; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1d20c63969..eed6b5a95c 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -533,7 +533,7 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel r_items.remove(i); i--; } else { - r_items[i].item = canvas_item; + r_items.write[i].item = canvas_item; } } } diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_editor_plugin.cpp index e837359d0c..5109379add 100644 --- a/editor/plugins/collision_polygon_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_editor_plugin.cpp @@ -276,7 +276,7 @@ bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<Inpu //apply ERR_FAIL_INDEX_V(edited_point, poly.size(), false); - poly[edited_point] = edited_point_pos; + poly.write[edited_point] = edited_point_pos; undo_redo->create_action(TTR("Edit Poly")); undo_redo->add_do_method(node, "set_polygon", poly); undo_redo->add_undo_method(node, "set_polygon", pre_move_edit); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index b003664dca..9e052bb027 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -446,8 +446,8 @@ void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { float radius = shape->get_radius(); float height = shape->get_height() / 2; - handles[0] = Point2(radius, -height); - handles[1] = Point2(0, -(height + radius)); + handles.write[0] = Point2(radius, -height); + handles.write[1] = Point2(0, -(height + radius)); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -458,7 +458,7 @@ void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { Ref<CircleShape2D> shape = node->get_shape(); handles.resize(1); - handles[0] = Point2(shape->get_radius(), 0); + handles.write[0] = Point2(shape->get_radius(), 0); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); @@ -476,8 +476,8 @@ void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { Ref<LineShape2D> shape = node->get_shape(); handles.resize(2); - handles[0] = shape->get_normal() * shape->get_d(); - handles[1] = shape->get_normal() * (shape->get_d() + 30.0); + handles.write[0] = shape->get_normal() * shape->get_d(); + handles.write[1] = shape->get_normal() * (shape->get_d() + 30.0); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -488,7 +488,7 @@ void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { Ref<RayShape2D> shape = node->get_shape(); handles.resize(1); - handles[0] = Point2(0, shape->get_length()); + handles.write[0] = Point2(0, shape->get_length()); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); @@ -499,8 +499,8 @@ void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { handles.resize(2); Vector2 ext = shape->get_extents(); - handles[0] = Point2(ext.x, 0); - handles[1] = Point2(0, -ext.y); + handles.write[0] = Point2(ext.x, 0); + handles.write[1] = Point2(0, -ext.y); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -511,8 +511,8 @@ void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { Ref<SegmentShape2D> shape = node->get_shape(); handles.resize(2); - handles[0] = shape->get_a(); - handles[1] = shape->get_b(); + handles.write[0] = shape->get_a(); + handles.write[1] = shape->get_b(); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp index a3be10dc33..3351e5918f 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.cpp +++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -255,7 +255,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { //apply ERR_FAIL_INDEX_V(edited_point, poly.size(), false); - poly[edited_point] = edited_point_pos; + poly.write[edited_point] = edited_point_pos; undo_redo->create_action(TTR("Edit Poly")); undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly); undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", pre_move_edit); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index 6d11079759..c2b17189ef 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -165,12 +165,12 @@ void Particles2DEditorPlugin::_generate_emission_mask() { if (emode == EMISSION_MODE_SOLID) { if (capture_colors) { - valid_colors[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; - valid_colors[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; - valid_colors[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; - valid_colors[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; + valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; + valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; + valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; + valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; } - valid_positions[vpc++] = Point2(i, j); + valid_positions.write[vpc++] = Point2(i, j); } else { @@ -189,7 +189,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { } if (on_border) { - valid_positions[vpc] = Point2(i, j); + valid_positions.write[vpc] = Point2(i, j); if (emode == EMISSION_MODE_BORDER_DIRECTED) { Vector2 normal; @@ -206,14 +206,14 @@ void Particles2DEditorPlugin::_generate_emission_mask() { } normal.normalize(); - valid_normals[vpc] = normal; + valid_normals.write[vpc] = normal; } if (capture_colors) { - valid_colors[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; - valid_colors[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; - valid_colors[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; - valid_colors[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; + valid_colors.write[vpc * 4 + 0] = r[(j * s.width + i) * 4 + 0]; + valid_colors.write[vpc * 4 + 1] = r[(j * s.width + i) * 4 + 1]; + valid_colors.write[vpc * 4 + 2] = r[(j * s.width + i) * 4 + 2]; + valid_colors.write[vpc * 4 + 3] = r[(j * s.width + i) * 4 + 3]; } vpc++; diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index e0325702a8..1f5a4a8a36 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -40,7 +40,6 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect float area_accum = 0; Map<float, int> triangle_area_map; - print_line("geometry size: " + itos(geometry.size())); for (int i = 0; i < geometry.size(); i++) { @@ -300,6 +299,10 @@ void ParticlesEditor::_menu_option(int p_option) { CPUParticles *cpu_particles = memnew(CPUParticles); cpu_particles->convert_from_particles(node); + cpu_particles->set_name(node->get_name()); + cpu_particles->set_transform(node->get_transform()); + cpu_particles->set_visible(node->is_visible()); + cpu_particles->set_pause_mode(node->get_pause_mode()); undo_redo->create_action("Replace Particles by CPUParticles"); undo_redo->add_do_method(node, "replace_by", cpu_particles); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 876da7f61a..3b82e6578b 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -31,7 +31,6 @@ #include "script_editor_plugin.h" #include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" #include "core/os/file_access.h" #include "core/os/input.h" #include "core/os/keyboard.h" @@ -283,7 +282,6 @@ void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) { - continue; } @@ -344,11 +342,11 @@ void ScriptEditor::_save_history() { if (Object::cast_to<ScriptEditorBase>(n)) { - history[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); + history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); } if (Object::cast_to<EditorHelp>(n)) { - history[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); + history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); } } @@ -375,11 +373,11 @@ void ScriptEditor::_go_to_tab(int p_idx) { if (Object::cast_to<ScriptEditorBase>(n)) { - history[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); + history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); } if (Object::cast_to<EditorHelp>(n)) { - history[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); + history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); } } @@ -402,7 +400,10 @@ void ScriptEditor::_go_to_tab(int p_idx) { if (is_visible_in_tree()) Object::cast_to<ScriptEditorBase>(c)->ensure_focus(); - notify_script_changed(Object::cast_to<ScriptEditorBase>(c)->get_edited_script()); + Ref<Script> script = Object::cast_to<ScriptEditorBase>(c)->get_edited_resource(); + if (script != NULL) { + notify_script_changed(script); + } } if (Object::cast_to<EditorHelp>(c)) { @@ -482,12 +483,23 @@ void ScriptEditor::_open_recent_script(int p_idx) { String path = rc[p_idx]; // if its not on disk its a help file or deleted if (FileAccess::exists(path)) { - Ref<Script> script = ResourceLoader::load(path); - if (script.is_valid()) { - edit(script, true); - return; + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + + if (extensions.find(path.get_extension())) { + Ref<Script> script = ResourceLoader::load(path); + if (script.is_valid()) { + edit(script, true); + return; + } } + Error err; + Ref<TextFile> text_file = _load_text_file(path, &err); + if (text_file.is_valid()) { + edit(text_file, true); + return; + } // if it's a path then its most likely a deleted file not help } else if (!path.is_resource_file()) { _help_class_open(path); @@ -513,12 +525,17 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { return; Node *tselected = tab_container->get_child(selected); + ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); if (current) { if (p_save) { apply_scripts(); } - notify_script_close(current->get_edited_script()); + + Ref<Script> script = current->get_edited_resource(); + if (script != NULL) { + notify_script_close(script); + } } // roll back to previous tab @@ -589,7 +606,7 @@ void ScriptEditor::_close_docs_tab() { void ScriptEditor::_copy_script_path() { ScriptEditorBase *se = _get_current_editor(); - Ref<Script> script = se->get_edited_script(); + RES script = se->get_edited_resource(); OS::get_singleton()->set_clipboard(script->get_path()); } @@ -655,7 +672,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) { if (!se) continue; - Ref<Script> script = se->get_edited_script(); + RES script = se->get_edited_resource(); if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) continue; //internal script, who cares @@ -672,7 +689,14 @@ void ScriptEditor::_resave_scripts(const String &p_str) { } } - editor->save_resource(script); + Ref<TextFile> text_file = script; + if (text_file != NULL) { + se->apply_code(); + _save_text_file(text_file, text_file->get_path()); + break; + } else { + editor->save_resource(script); + } se->tag_saved_version(); } @@ -689,25 +713,37 @@ void ScriptEditor::_reload_scripts() { continue; } - Ref<Script> script = se->get_edited_script(); + RES edited_res = se->get_edited_resource(); - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { + if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) { continue; //internal script, who cares } - uint64_t last_date = script->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(script->get_path()); + uint64_t last_date = edited_res->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); if (last_date == date) { continue; } - Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true); - ERR_CONTINUE(!rel_script.is_valid()); - script->set_source_code(rel_script->get_source_code()); - script->set_last_modified_time(rel_script->get_last_modified_time()); - script->reload(); + Ref<Script> script = edited_res; + if (script != NULL) { + Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true); + ERR_CONTINUE(!rel_script.is_valid()); + script->set_source_code(rel_script->get_source_code()); + script->set_last_modified_time(rel_script->get_last_modified_time()); + script->reload(); + } + + Ref<TextFile> text_file = edited_res; + if (text_file != NULL) { + Error err; + Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); + ERR_CONTINUE(!rel_text_file.is_valid()); + text_file->set_text(rel_text_file->get_text()); + text_file->set_last_modified_time(rel_text_file->get_last_modified_time()); + } se->reload_text(); } @@ -725,7 +761,7 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { continue; } - Ref<Script> script = se->get_edited_script(); + RES script = se->get_edited_resource(); if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { continue; //internal script, who cares @@ -750,7 +786,7 @@ void ScriptEditor::_live_auto_reload_running_scripts() { debugger->reload_scripts(); } -bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { +bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { disk_changed_list->clear(); TreeItem *r = disk_changed_list->create_item(); @@ -765,21 +801,20 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - Ref<Script> script = se->get_edited_script(); - - if (p_for_script.is_valid() && p_for_script != script) + RES edited_res = se->get_edited_resource(); + if (edited_res.is_valid() && p_for_script != edited_res) continue; - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) + if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) continue; //internal script, who cares - uint64_t last_date = script->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(script->get_path()); + uint64_t last_date = edited_res->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); if (last_date != date) { TreeItem *ti = disk_changed_list->create_item(r); - ti->set_text(0, script->get_path().get_file()); + ti->set_text(0, edited_res->get_path().get_file()); if (!use_autoreload || se->is_unsaved()) { need_ask = true; @@ -804,6 +839,49 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { void ScriptEditor::_file_dialog_action(String p_file) { switch (file_dialog_option) { + case FILE_OPEN: { + + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + if (extensions.find(p_file.get_extension())) { + Ref<Script> scr = ResourceLoader::load(p_file); + if (!scr.is_valid()) { + editor->show_warning(TTR("Error could not load file."), TTR("Error!")); + file_dialog_option = -1; + return; + } + + edit(scr); + file_dialog_option = -1; + return; + } + + Error error; + Ref<TextFile> text_file = _load_text_file(p_file, &error); + if (error != OK) { + editor->show_warning(TTR("Error could not load file."), TTR("Error!")); + } + + if (text_file.is_valid()) { + edit(text_file); + file_dialog_option = -1; + return; + } + } + case FILE_SAVE_AS: { + ScriptEditorBase *current = _get_current_editor(); + + String path = ProjectSettings::get_singleton()->localize_path(p_file); + Error err = _save_text_file(current->get_edited_resource(), path); + + if (err != OK) { + editor->show_accept(TTR("Error saving file!"), TTR("OK")); + return; + } + + ((Resource *)current->get_edited_resource().ptr())->set_path(path); + _update_script_names(); + } break; case THEME_SAVE_AS: { if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) { editor->show_warning(TTR("Error while saving theme"), TTR("Error saving")); @@ -823,7 +901,8 @@ Ref<Script> ScriptEditor::_get_current_script() { ScriptEditorBase *current = _get_current_editor(); if (current) { - return current->get_edited_script(); + Ref<Script> script = current->get_edited_resource(); + return script != NULL ? script : NULL; } else { return NULL; } @@ -848,8 +927,19 @@ void ScriptEditor::_menu_option(int p_option) { script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE); } break; case FILE_OPEN: { + file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = FILE_OPEN; - editor->open_resource("Script"); + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + file_dialog->clear_filters(); + for (int i = 0; i < extensions.size(); i++) { + file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + } + + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("Open File")); return; } break; case FILE_SAVE_ALL: { @@ -929,7 +1019,14 @@ void ScriptEditor::_menu_option(int p_option) { current->convert_indent_to_tabs(); } } - editor->save_resource(current->get_edited_script()); + + Ref<TextFile> text_file = current->get_edited_resource(); + if (text_file != NULL) { + current->apply_code(); + _save_text_file(text_file, text_file->get_path()); + break; + } + editor->save_resource(current->get_edited_resource()); } break; case FILE_SAVE_AS: { @@ -943,8 +1040,25 @@ void ScriptEditor::_menu_option(int p_option) { current->convert_indent_to_tabs(); } } - editor->push_item(Object::cast_to<Object>(current->get_edited_script().ptr())); - editor->save_resource_as(current->get_edited_script()); + + Ref<TextFile> text_file = current->get_edited_resource(); + if (text_file != NULL) { + file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = FILE_SAVE_AS; + + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + file_dialog->clear_filters(); + file_dialog->set_current_dir(text_file->get_path().get_base_dir()); + file_dialog->set_current_file(text_file->get_path().get_file()); + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("Save File As...")); + break; + } + + editor->push_item(Object::cast_to<Object>(current->get_edited_resource().ptr())); + editor->save_resource_as(current->get_edited_resource()); } break; @@ -956,8 +1070,8 @@ void ScriptEditor::_menu_option(int p_option) { } break; case FILE_RUN: { - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) { + Ref<Script> scr = current->get_edited_resource(); + if (scr == NULL || scr.is_null()) { EditorNode::get_singleton()->show_warning("Can't obtain the script for running"); break; } @@ -1000,8 +1114,7 @@ void ScriptEditor::_menu_option(int p_option) { _copy_script_path(); } break; case SHOW_IN_FILE_SYSTEM: { - ScriptEditorBase *se = _get_current_editor(); - Ref<Script> script = se->get_edited_script(); + RES script = current->get_edited_resource(); FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock(); file_system_dock->navigate_to_path(script->get_path()); // Ensure that the FileSystem dock is visible. @@ -1259,8 +1372,8 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) { if (se) { - Ref<Script> script = se->get_edited_script(); - if (!script.is_valid()) + Ref<Script> script = se->get_edited_resource(); + if (script == NULL || !script.is_valid()) continue; if (script->get_path().find("::") != -1 && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed @@ -1307,9 +1420,13 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { if (!se) continue; + Ref<Script> script = se->get_edited_resource(); + if (script == NULL) { + continue; + } + List<int> bpoints; se->get_breakpoints(&bpoints); - Ref<Script> script = se->get_edited_script(); String base = script->get_path(); ERR_CONTINUE(base.begins_with("local://") || base == ""); @@ -1452,7 +1569,7 @@ void ScriptEditor::_update_members_overview() { members_overview->set_item_metadata(i, functions[i].get_slice(":", 1).to_int() - 1); } - String path = se->get_edited_script()->get_path(); + String path = se->get_edited_resource()->get_path(); bool built_in = !path.is_resource_file(); String name = built_in ? path.get_file() : se->get_name(); filename->set_text(name); @@ -1570,7 +1687,7 @@ void ScriptEditor::_update_script_names() { if (se) { Ref<Texture> icon = se->get_icon(); - String path = se->get_edited_script()->get_path(); + String path = se->get_edited_resource()->get_path(); bool built_in = !path.is_resource_file(); String name = built_in ? path.get_file() : se->get_name(); @@ -1579,7 +1696,7 @@ void ScriptEditor::_update_script_names() { sd.name = name; sd.tooltip = path; sd.index = i; - sd.used = used.has(se->get_edited_script()); + sd.used = used.has(se->get_edited_resource()); sd.category = 0; sd.ref = se; @@ -1681,11 +1798,65 @@ void ScriptEditor::_update_script_names() { _update_script_colors(); } -bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool p_grab_focus) { +Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error) { + if (r_error) { + *r_error = ERR_FILE_CANT_OPEN; + } + + String local_path = ProjectSettings::get_singleton()->localize_path(p_path); + String path = ResourceLoader::path_remap(local_path); + + TextFile *text_file = memnew(TextFile); + Ref<TextFile> text_res(text_file); + Error err = text_file->load_text(path); + + if (err != OK) { + ERR_FAIL_COND_V(err != OK, RES()); + } + + text_file->set_file_path(local_path); + text_file->set_path(local_path, true); + + if (r_error) { + *r_error = OK; + } + + return text_res; +} + +Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_path) { + Ref<TextFile> sqscr = p_text_file; + ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); - if (p_script.is_null()) + String source = sqscr->get_text(); + + Error err; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + if (err) { + + ERR_FAIL_COND_V(err, err); + } + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } + file->close(); + memdelete(file); + + _res_saved_callback(sqscr); + return OK; +} + +bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus) { + + if (p_resource.is_null()) return false; + Ref<Script> script = p_resource; + // refuse to open built-in if scene is not loaded // see if already has it @@ -1694,17 +1865,18 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool const bool should_open = open_dominant || !EditorNode::get_singleton()->is_changing_scene(); - if (p_script->get_language()->overrides_external_editor()) { + if (script != NULL && script->get_language()->overrides_external_editor()) { if (should_open) { - Error err = p_script->get_language()->open_in_external_editor(p_script, p_line >= 0 ? p_line : 0, p_col); + Error err = script->get_language()->open_in_external_editor(script, p_line >= 0 ? p_line : 0, p_col); if (err != OK) ERR_PRINT("Couldn't open script in the overridden external text editor"); } return false; } - if ((debugger->get_dump_stack_script() != p_script || debugger->get_debug_with_external_editor()) && - p_script->get_path().is_resource_file() && + if ((debugger->get_dump_stack_script() != p_resource || debugger->get_debug_with_external_editor()) && + p_resource->get_path().is_resource_file() && + p_resource->get_class_name() != StringName("VisualScript") && bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path"); @@ -1714,7 +1886,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool if (flags.size()) { String project_path = ProjectSettings::get_singleton()->get_resource_path(); - String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); + String script_path = ProjectSettings::get_singleton()->globalize_path(p_resource->get_path()); flags = flags.replacen("{line}", itos(p_line > 0 ? p_line : 0)); flags = flags.replacen("{col}", itos(p_col)); @@ -1762,7 +1934,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool if (!se) continue; - if (se->get_edited_script() == p_script) { + if (se->get_edited_resource() == p_resource) { if (should_open) { if (tab_container->get_current_tab() != i) { @@ -1784,7 +1956,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool ScriptEditorBase *se; for (int i = script_editor_func_count - 1; i >= 0; i--) { - se = script_editor_funcs[i](p_script); + se = script_editor_funcs[i](p_resource); if (se) break; } @@ -1795,9 +1967,9 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool SyntaxHighlighter *highlighter = syntax_highlighters_funcs[i](); se->add_syntax_highlighter(highlighter); - if (!highlighter_set) { + if (script != NULL && !highlighter_set) { List<String> languages = highlighter->get_supported_languages(); - if (languages.find(p_script->get_language()->get_name())) { + if (languages.find(script->get_language()->get_name())) { se->set_syntax_highlighter(highlighter); highlighter_set = true; } @@ -1805,7 +1977,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool } tab_container->add_child(se); - se->set_edited_script(p_script); + se->set_edited_resource(p_resource); se->set_tooltip_request_func("_get_debug_tooltip", this); if (se->get_edit_menu()) { se->get_edit_menu()->hide(); @@ -1829,14 +2001,14 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool //test for modification, maybe the script was not edited but was loaded - _test_script_times_on_disk(p_script); - _update_modified_scripts_for_external_editor(p_script); + _test_script_times_on_disk(p_resource); + _update_modified_scripts_for_external_editor(p_resource); if (p_line >= 0) se->goto_line(p_line - 1); - notify_script_changed(p_script); - _add_recent_script(p_script->get_path()); + notify_script_changed(p_resource); + _add_recent_script(p_resource->get_path()); return true; } @@ -1863,12 +2035,19 @@ void ScriptEditor::save_all_scripts() { if (!se->is_unsaved()) continue; - Ref<Script> script = se->get_edited_script(); - if (script.is_valid()) + RES edited_res = se->get_edited_resource(); + if (edited_res.is_valid()) { se->apply_code(); + } - if (script->get_path() != "" && script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) - editor->save_resource(script); //external script, save it + if (edited_res->get_path() != "" && edited_res->get_path().find("local://") == -1 && edited_res->get_path().find("::") == -1) { + Ref<TextFile> text_file = edited_res; + if (text_file != NULL) { + _save_text_file(text_file, text_file->get_path()); + continue; + } + editor->save_resource(edited_res); //external script, save it + } } _update_script_names(); @@ -1938,7 +2117,7 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) continue; - if (se->get_edited_script() != script) + if (se->get_edited_resource() != script) continue; se->add_callback(p_function, p_args); @@ -2228,19 +2407,20 @@ void ScriptEditor::_make_script_list_context_menu() { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS); context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/show_in_file_system"), SHOW_IN_FILE_SYSTEM); - Ref<Script> scr = se->get_edited_script(); - if (!scr.is_null() && scr->is_tool()) { - context_menu->add_separator(); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN); + + Ref<Script> scr = se->get_edited_resource(); + if (scr != NULL) { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); + if (!scr.is_null() && scr->is_tool()) { + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN); + } } } else { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE); } - EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(selected)); - context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_down"), WINDOW_MOVE_DOWN); @@ -2268,14 +2448,28 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { restoring_layout = true; + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + for (int i = 0; i < scripts.size(); i++) { String path = scripts[i]; if (!FileAccess::exists(path)) continue; - Ref<Script> scr = ResourceLoader::load(path); - if (scr.is_valid()) { - edit(scr); + + if (extensions.find(path.get_extension())) { + Ref<Script> scr = ResourceLoader::load(path); + if (scr.is_valid()) { + edit(scr); + continue; + } + } + + Error error; + Ref<TextFile> text_file = _load_text_file(path, &error); + if (error == OK && text_file.is_valid()) { + edit(text_file); + continue; } } @@ -2311,7 +2505,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - String path = se->get_edited_script()->get_path(); + String path = se->get_edited_resource()->get_path(); if (!path.is_resource_file()) continue; @@ -2419,11 +2613,11 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { if (Object::cast_to<ScriptEditorBase>(n)) { - history[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); + history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state(); } if (Object::cast_to<EditorHelp>(n)) { - history[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); + history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll(); } history_pos = p_new_pos; @@ -2436,7 +2630,10 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { Object::cast_to<ScriptEditorBase>(n)->set_edit_state(history[history_pos].state); Object::cast_to<ScriptEditorBase>(n)->ensure_focus(); - notify_script_changed(Object::cast_to<ScriptEditorBase>(n)->get_edited_script()); + Ref<Script> script = Object::cast_to<ScriptEditorBase>(n)->get_edited_resource(); + if (script != NULL) { + notify_script_changed(script); + } } if (Object::cast_to<EditorHelp>(n)) { @@ -2473,7 +2670,11 @@ Vector<Ref<Script> > ScriptEditor::get_open_scripts() const { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) continue; - out_scripts.push_back(se->get_edited_script()); + + Ref<Script> script = se->get_edited_resource(); + if (script != NULL) { + out_scripts.push_back(script); + } } return out_scripts; @@ -2519,6 +2720,14 @@ void ScriptEditor::_open_script_request(const String &p_path) { Ref<Script> script = ResourceLoader::load(p_path); if (script.is_valid()) { script_editor->edit(script, false); + return; + } + + Error err; + Ref<TextFile> text_file = script_editor->_load_text_file(p_path, &err); + if (text_file.is_valid()) { + script_editor->edit(text_file, false); + return; } } @@ -2552,7 +2761,7 @@ void ScriptEditor::_on_find_in_files_requested(String text) { void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) { - Ref<Resource> res = ResourceLoader::load(fpath); + RES res = ResourceLoader::load(fpath); edit(res); ScriptEditorBase *seb = _get_current_editor(); @@ -2968,14 +3177,21 @@ ScriptEditor::~ScriptEditor() { void ScriptEditorPlugin::edit(Object *p_object) { - if (!Object::cast_to<Script>(p_object)) - return; + if (Object::cast_to<Script>(p_object)) { + script_editor->edit(Object::cast_to<Script>(p_object)); + } - script_editor->edit(Object::cast_to<Script>(p_object)); + if (Object::cast_to<TextFile>(p_object)) { + script_editor->edit(Object::cast_to<TextFile>(p_object)); + } } bool ScriptEditorPlugin::handles(Object *p_object) const { + if (Object::cast_to<TextFile>(p_object)) { + return true; + } + if (Object::cast_to<Script>(p_object)) { bool valid = _can_open_in_editor(Object::cast_to<Script>(p_object)); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index ad12add53f..186c80a5f9 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -43,6 +43,7 @@ #include "scene/gui/tool_button.h" #include "scene/gui/tree.h" #include "scene/main/timer.h" +#include "scene/resources/text_file.h" #include "script_language.h" class ScriptEditorQuickOpen : public ConfirmationDialog { @@ -74,7 +75,7 @@ class ScriptEditorDebugger; class ScriptEditorBase : public VBoxContainer { - GDCLASS(ScriptEditorBase, VBoxContainer); + GDCLASS(ScriptEditorBase, VBoxContainer) protected: static void _bind_methods(); @@ -84,9 +85,9 @@ public: virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter) = 0; virtual void apply_code() = 0; - virtual Ref<Script> get_edited_script() const = 0; + virtual RES get_edited_resource() const = 0; virtual Vector<String> get_functions() = 0; - virtual void set_edited_script(const Ref<Script> &p_script) = 0; + virtual void set_edited_resource(const RES &p_res) = 0; virtual void reload_text() = 0; virtual String get_name() = 0; virtual Ref<Texture> get_icon() = 0; @@ -99,7 +100,7 @@ public: virtual void convert_indent_to_tabs() = 0; virtual void ensure_focus() = 0; virtual void tag_saved_version() = 0; - virtual void reload(bool p_soft) = 0; + virtual void reload(bool p_soft) {} virtual void get_breakpoints(List<int> *p_breakpoints) = 0; virtual void add_callback(const String &p_function, PoolStringArray p_args) = 0; virtual void update_settings() = 0; @@ -116,7 +117,7 @@ public: }; typedef SyntaxHighlighter *(*CreateSyntaxHighlighterFunc)(); -typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const Ref<Script> &p_script); +typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const RES &p_resource); class EditorScriptCodeCompletionCache; class FindInFilesDialog; @@ -268,7 +269,7 @@ class ScriptEditor : public PanelContainer { void _resave_scripts(const String &p_str); void _reload_scripts(); - bool _test_script_times_on_disk(Ref<Script> p_for_script = Ref<Script>()); + bool _test_script_times_on_disk(RES p_for_script = Ref<Resource>()); void _add_recent_script(String p_path); void _update_recent_scripts(); @@ -378,6 +379,9 @@ class ScriptEditor : public PanelContainer { Ref<Script> _get_current_script(); Array _get_open_scripts() const; + Ref<TextFile> _load_text_file(const String &p_path, Error *r_error); + Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path); + void _on_find_in_files_requested(String text); void _on_find_in_files_result_selected(String fpath, int line_number, int begin, int end); void _start_find_in_files(bool with_replace); @@ -400,8 +404,8 @@ public: void ensure_select_current(); - _FORCE_INLINE_ bool edit(const Ref<Script> &p_script, bool p_grab_focus = true) { return edit(p_script, -1, 0, p_grab_focus); } - bool edit(const Ref<Script> &p_script, int p_line, int p_col, bool p_grab_focus = true); + _FORCE_INLINE_ bool edit(const RES &p_resource, bool p_grab_focus = true) { return edit(p_resource, -1, 0, p_grab_focus); } + bool edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus = true); void get_breakpoints(List<String> *p_breakpoints); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index ffc2203475..165d7e32b9 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -66,11 +66,24 @@ void ScriptTextEditor::apply_code() { _update_member_keywords(); } -Ref<Script> ScriptTextEditor::get_edited_script() const { - +RES ScriptTextEditor::get_edited_resource() const { return script; } +void ScriptTextEditor::set_edited_resource(const RES &p_res) { + ERR_FAIL_COND(!script.is_null()); + + script = p_res; + _set_theme_for_script(); + + code_editor->get_text_edit()->set_text(script->get_source_code()); + code_editor->get_text_edit()->clear_undo_history(); + code_editor->get_text_edit()->tag_saved_version(); + + emit_signal("name_changed"); + code_editor->update_line_and_column(); +} + void ScriptTextEditor::_update_member_keywords() { member_keywords.clear(); code_editor->get_text_edit()->clear_member_keywords(); @@ -116,6 +129,7 @@ void ScriptTextEditor::_load_theme_settings() { Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color"); Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color"); + Color safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color"); Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color"); Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color"); Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color"); @@ -147,6 +161,7 @@ void ScriptTextEditor::_load_theme_settings() { text_edit->add_color_override("completion_font_color", completion_font_color); text_edit->add_color_override("font_color", text_color); text_edit->add_color_override("line_number_color", line_number_color); + text_edit->add_color_override("safe_line_number_color", safe_line_number_color); text_edit->add_color_override("caret_color", caret_color); text_edit->add_color_override("caret_background_color", caret_background_color); text_edit->add_color_override("font_selected_color", text_selected_color); @@ -188,6 +203,7 @@ void ScriptTextEditor::_set_theme_for_script() { List<String> keywords; script->get_language()->get_reserved_words(&keywords); + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { text_edit->add_keyword_color(E->get(), colors_cache.keyword_color); @@ -249,7 +265,6 @@ void ScriptTextEditor::_set_theme_for_script() { //colorize strings List<String> strings; script->get_language()->get_string_delimiters(&strings); - for (List<String>::Element *E = strings.front(); E; E = E->next()) { String string = E->get(); @@ -324,197 +339,32 @@ bool ScriptTextEditor::is_unsaved() { Variant ScriptTextEditor::get_edit_state() { - Dictionary state; + return code_editor->get_edit_state(); +} - state["scroll_position"] = code_editor->get_text_edit()->get_v_scroll(); - state["column"] = code_editor->get_text_edit()->cursor_get_column(); - state["row"] = code_editor->get_text_edit()->cursor_get_line(); +void ScriptTextEditor::set_edit_state(const Variant &p_state) { - return state; + code_editor->set_edit_state(p_state); } -void ScriptTextEditor::_convert_case(CaseStyle p_case) { - TextEdit *te = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) { - return; - } - - if (te->is_selection_active()) { - te->begin_complex_operation(); - - int begin = te->get_selection_from_line(); - int end = te->get_selection_to_line(); - int begin_col = te->get_selection_from_column(); - int end_col = te->get_selection_to_column(); - - for (int i = begin; i <= end; i++) { - int len = te->get_line(i).length(); - if (i == end) - len -= len - end_col; - if (i == begin) - len -= begin_col; - String new_line = te->get_line(i).substr(i == begin ? begin_col : 0, len); - - switch (p_case) { - case UPPER: { - new_line = new_line.to_upper(); - } break; - case LOWER: { - new_line = new_line.to_lower(); - } break; - case CAPITALIZE: { - new_line = new_line.capitalize(); - } break; - } +void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { - if (i == begin) { - new_line = te->get_line(i).left(begin_col) + new_line; - } - if (i == end) { - new_line = new_line + te->get_line(i).right(end_col); - } - te->set_line(i, new_line); - } - te->end_complex_operation(); - } + code_editor->convert_case(p_case); } void ScriptTextEditor::trim_trailing_whitespace() { - TextEdit *tx = code_editor->get_text_edit(); - - bool trimed_whitespace = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - if (line.ends_with(" ") || line.ends_with("\t")) { - - if (!trimed_whitespace) { - tx->begin_complex_operation(); - trimed_whitespace = true; - } - - int end = 0; - for (int j = line.length() - 1; j > -1; j--) { - if (line[j] != ' ' && line[j] != '\t') { - end = j + 1; - break; - } - } - tx->set_line(i, line.substr(0, end)); - } - } - if (trimed_whitespace) { - tx->end_complex_operation(); - tx->update(); - } + code_editor->trim_trailing_whitespace(); } void ScriptTextEditor::convert_indent_to_spaces() { - TextEdit *tx = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); - - if (scr.is_null()) { - return; - } - - int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); - String indent = ""; - - for (int i = 0; i < indent_size; i++) { - indent += " "; - } - int cursor_line = tx->cursor_get_line(); - int cursor_column = tx->cursor_get_column(); - - bool changed_indentation = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - - if (line.length() <= 0) { - continue; - } - - int j = 0; - while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { - if (line[j] == '\t') { - if (!changed_indentation) { - tx->begin_complex_operation(); - changed_indentation = true; - } - if (cursor_line == i && cursor_column > j) { - cursor_column += indent_size - 1; - } - line = line.left(j) + indent + line.right(j + 1); - } - j++; - } - if (changed_indentation) { - tx->set_line(i, line); - } - } - if (changed_indentation) { - tx->cursor_set_column(cursor_column); - tx->end_complex_operation(); - tx->update(); - } + code_editor->convert_indent_to_spaces(); } void ScriptTextEditor::convert_indent_to_tabs() { - TextEdit *tx = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); - - if (scr.is_null()) { - return; - } - - int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); - indent_size -= 1; - - int cursor_line = tx->cursor_get_line(); - int cursor_column = tx->cursor_get_column(); - - bool changed_indentation = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - - if (line.length() <= 0) { - continue; - } - int j = 0; - int space_count = -1; - while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { - if (line[j] != '\t') { - space_count++; - - if (space_count == indent_size) { - if (!changed_indentation) { - tx->begin_complex_operation(); - changed_indentation = true; - } - if (cursor_line == i && cursor_column > j) { - cursor_column -= indent_size; - } - line = line.left(j - indent_size) + "\t" + line.right(j + 1); - j = 0; - space_count = -1; - } - } else { - space_count = -1; - } - j++; - } - if (changed_indentation) { - tx->set_line(i, line); - } - } - if (changed_indentation) { - tx->cursor_set_column(cursor_column); - tx->end_complex_operation(); - tx->update(); - } + code_editor->convert_indent_to_tabs(); } void ScriptTextEditor::tag_saved_version() { @@ -523,31 +373,17 @@ void ScriptTextEditor::tag_saved_version() { } void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - TextEdit *tx = code_editor->get_text_edit(); - tx->deselect(); - tx->unfold_line(p_line); - tx->call_deferred("cursor_set_line", p_line); -} -void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - TextEdit *tx = code_editor->get_text_edit(); - tx->unfold_line(p_line); - tx->call_deferred("cursor_set_line", p_line); - tx->call_deferred("cursor_set_column", p_begin); - tx->select(p_line, p_begin, p_line, p_end); + code_editor->goto_line(p_line); } -void ScriptTextEditor::ensure_focus() { +void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - code_editor->get_text_edit()->grab_focus(); + code_editor->goto_line_selection(p_line, p_begin, p_end); } -void ScriptTextEditor::set_edit_state(const Variant &p_state) { +void ScriptTextEditor::ensure_focus() { - Dictionary state = p_state; - code_editor->get_text_edit()->cursor_set_column(state["column"]); - code_editor->get_text_edit()->cursor_set_line(state["row"]); - code_editor->get_text_edit()->set_v_scroll(state["scroll_position"]); code_editor->get_text_edit()->grab_focus(); } @@ -576,21 +412,6 @@ Ref<Texture> ScriptTextEditor::get_icon() { return Ref<Texture>(); } -void ScriptTextEditor::set_edited_script(const Ref<Script> &p_script) { - - ERR_FAIL_COND(!script.is_null()); - - script = p_script; - _set_theme_for_script(); - - code_editor->get_text_edit()->set_text(script->get_source_code()); - code_editor->get_text_edit()->clear_undo_history(); - code_editor->get_text_edit()->tag_saved_version(); - - emit_signal("name_changed"); - code_editor->update_line_and_column(); -} - void ScriptTextEditor::_validate_script() { String errortxt; @@ -599,8 +420,9 @@ void ScriptTextEditor::_validate_script() { String text = te->get_text(); List<String> fnc; + Set<int> safe_lines; - if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc)) { + if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &safe_lines)) { String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt; code_editor->set_error(error_text); } else { @@ -621,8 +443,23 @@ void ScriptTextEditor::_validate_script() { } line--; + bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true); + bool last_is_safe = false; for (int i = 0; i < te->get_line_count(); i++) { te->set_line_as_marked(i, line == i); + if (highlight_safe) { + if (safe_lines.has(i + 1)) { + te->set_line_as_safe(i, true); + last_is_safe = true; + } else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().empty())) { + te->set_line_as_safe(i, true); + } else { + te->set_line_as_safe(i, false); + last_is_safe = false; + } + } else { + te->set_line_as_safe(i, false); + } } emit_signal("name_changed"); @@ -859,98 +696,15 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_MOVE_LINE_UP: { - Ref<Script> scr = script; - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = from_line; i <= to_line; i++) { - int line_id = i; - int next_id = i - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_up = from_line > 0 ? from_line - 1 : from_line; - int to_line_up = to_line > 0 ? to_line - 1 : to_line; - tx->select(from_line_up, from_col, to_line_up, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); + code_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = to_line; i >= from_line; i--) { - int line_id = i; - int next_id = i + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line; - int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line; - tx->select(from_line_down, from_col, to_line_down, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); - + code_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -958,7 +712,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_INDENT_RIGHT: { - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -966,72 +720,11 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_DELETE_LINE: { - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) - return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int to_line = tx->get_selection_to_line(); - int from_line = tx->get_selection_from_line(); - int count = Math::abs(to_line - from_line) + 1; - while (count) { - tx->set_line(tx->cursor_get_line(), ""); - tx->backspace_at_cursor(); - count--; - if (count) - tx->unfold_line(from_line); - } - tx->cursor_set_line(from_line - 1); - tx->deselect(); - } else { - int line = tx->cursor_get_line(); - tx->set_line(tx->cursor_get_line(), ""); - tx->backspace_at_cursor(); - tx->unfold_line(line); - tx->cursor_set_line(line); - } - tx->end_complex_operation(); + code_editor->delete_lines(); } break; case EDIT_CLONE_DOWN: { - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) - return; - - int from_line = tx->cursor_get_line(); - int to_line = tx->cursor_get_line(); - int column = tx->cursor_get_column(); - - if (tx->is_selection_active()) { - from_line = tx->get_selection_from_line(); - to_line = tx->get_selection_to_line(); - column = tx->cursor_get_column(); - } - int next_line = to_line + 1; - - if (to_line >= tx->get_line_count() - 1) { - tx->set_line(to_line, tx->get_line(to_line) + "\n"); - } - - tx->begin_complex_operation(); - for (int i = from_line; i <= to_line; i++) { - - tx->unfold_line(i); - if (i >= tx->get_line_count() - 1) { - tx->set_line(i, tx->get_line(i) + "\n"); - } - String line_clone = tx->get_line(i); - tx->insert_at(line_clone, next_line); - next_line++; - } - - tx->cursor_set_column(column); - if (tx->is_selection_active()) { - tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); - } - - tx->end_complex_operation(); - tx->update(); + code_editor->code_lines_down(); } break; case EDIT_TOGGLE_FOLD_LINE: { @@ -1050,7 +743,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_TOGGLE_COMMENT: { - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -1118,7 +811,7 @@ void ScriptTextEditor::_edit_option(int p_op) { case EDIT_AUTO_INDENT: { String text = tx->get_text(); - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -1161,15 +854,15 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_TO_UPPERCASE: { - _convert_case(UPPER); + _convert_case(CodeTextEditor::UPPER); } break; case EDIT_TO_LOWERCASE: { - _convert_case(LOWER); + _convert_case(CodeTextEditor::LOWER); } break; case EDIT_CAPITALIZE: { - _convert_case(CAPITALIZE); + _convert_case(CodeTextEditor::CAPITALIZE); } break; case SEARCH_FIND: { @@ -1209,7 +902,7 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = tx->cursor_get_line(); bool dobreak = !tx->is_line_set_as_breakpoint(line); tx->set_line_as_breakpoint(line, dobreak); - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { @@ -1220,7 +913,7 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = E->get(); bool dobreak = !tx->is_line_set_as_breakpoint(line); tx->set_line_as_breakpoint(line, dobreak); - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); } } case DEBUG_GOTO_NEXT_BREAKPOINT: { @@ -1340,7 +1033,7 @@ void ScriptTextEditor::clear_edit_menu() { void ScriptTextEditor::reload(bool p_soft) { TextEdit *te = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; scr->set_source_code(te->get_text()); @@ -1724,9 +1417,12 @@ ScriptTextEditor::ScriptTextEditor() { code_editor->get_text_edit()->set_drag_forwarding(this); } -static ScriptEditorBase *create_editor(const Ref<Script> &p_script) { +static ScriptEditorBase *create_editor(const RES &p_resource) { - return memnew(ScriptTextEditor); + if (Object::cast_to<Script>(*p_resource)) { + return memnew(ScriptTextEditor); + } + return NULL; } void ScriptTextEditor::register_editor() { diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index a415f478e8..f0b00a9117 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -138,12 +138,7 @@ protected: void _goto_line(int p_line) { goto_line(p_line); } void _lookup_symbol(const String &p_symbol, int p_row, int p_column); - enum CaseStyle { - UPPER, - LOWER, - CAPITALIZE, - }; - void _convert_case(CaseStyle p_case); + void _convert_case(CodeTextEditor::CaseStyle p_case); Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -154,14 +149,13 @@ public: virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); virtual void apply_code(); - virtual Ref<Script> get_edited_script() const; + virtual RES get_edited_resource() const; + virtual void set_edited_resource(const RES &p_res); virtual Vector<String> get_functions(); - virtual void set_edited_script(const Ref<Script> &p_script); virtual void reload_text(); virtual String get_name(); virtual Ref<Texture> get_icon(); virtual bool is_unsaved(); - virtual Variant get_edit_state(); virtual void set_edit_state(const Variant &p_state); virtual void ensure_focus(); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 4b7f27c0c1..7650cd6ae7 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -258,84 +258,10 @@ void ShaderEditor::_menu_option(int p_option) { shader_editor->get_text_edit()->select_all(); } break; case EDIT_MOVE_LINE_UP: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = from_line; i <= to_line; i++) { - int line_id = i; - int next_id = i - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_up = from_line > 0 ? from_line - 1 : from_line; - int to_line_up = to_line > 0 ? to_line - 1 : to_line; - tx->select(from_line_up, from_col, to_line_up, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); - + shader_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = to_line; i >= from_line; i--) { - int line_id = i; - int next_id = i + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line; - int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line; - tx->select(from_line_down, from_col, to_line_down, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); - + shader_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { @@ -356,55 +282,10 @@ void ShaderEditor::_menu_option(int p_option) { } break; case EDIT_DELETE_LINE: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - tx->begin_complex_operation(); - int line = tx->cursor_get_line(); - tx->set_line(tx->cursor_get_line(), ""); - tx->backspace_at_cursor(); - tx->cursor_set_line(line); - tx->end_complex_operation(); - + shader_editor->delete_lines(); } break; case EDIT_CLONE_DOWN: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - int from_line = tx->cursor_get_line(); - int to_line = tx->cursor_get_line(); - int column = tx->cursor_get_column(); - - if (tx->is_selection_active()) { - from_line = tx->get_selection_from_line(); - to_line = tx->get_selection_to_line(); - column = tx->cursor_get_column(); - } - int next_line = to_line + 1; - - tx->begin_complex_operation(); - for (int i = from_line; i <= to_line; i++) { - - if (i >= tx->get_line_count() - 1) { - tx->set_line(i, tx->get_line(i) + "\n"); - } - String line_clone = tx->get_line(i); - tx->insert_at(line_clone, next_line); - next_line++; - } - - tx->cursor_set_column(column); - if (tx->is_selection_active()) { - tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); - } - - tx->end_complex_operation(); - tx->update(); - + shader_editor->code_lines_down(); } break; case EDIT_TOGGLE_COMMENT: { diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp index 40a696119e..fe7d1df50c 100644 --- a/editor/plugins/skeleton_editor_plugin.cpp +++ b/editor/plugins/skeleton_editor_plugin.cpp @@ -68,16 +68,16 @@ void SkeletonEditor::create_physical_skeleton() { if (parent < 0) { - bones_infos[bone_id].relative_rest = skeleton->get_bone_rest(bone_id); + bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id); } else { - bones_infos[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id); + bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id); /// create physical bone on parent if (!bones_infos[parent].physical_bone) { - bones_infos[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); + bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos); ur->create_action(TTR("Create physical bones")); ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone); diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 37b8562e96..4b410b5ece 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -1928,6 +1928,11 @@ void SpatialEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, cons void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) { + if (lock_rotation) { + _nav_pan(p_event, p_relative); + return; + } + real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity"); real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel); bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis"); @@ -2563,6 +2568,19 @@ void SpatialEditorViewport::_menu_option(int p_option) { _update_name(); } break; + case VIEW_LOCK_ROTATION: { + + int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION); + bool current = view_menu->get_popup()->is_item_checked(idx); + lock_rotation = !current; + view_menu->get_popup()->set_item_checked(idx, !current); + if (lock_rotation) { + view_menu->set_icon(get_icon("Lock", "EditorIcons")); + } else { + view_menu->set_icon(Ref<Texture>()); + } + + } break; case VIEW_AUDIO_LISTENER: { int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER); @@ -2836,6 +2854,12 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { if (!view_menu->get_popup()->is_item_checked(idx)) _menu_option(display); } + if (p_state.has("lock_rotation")) { + lock_rotation = p_state["lock_rotation"]; + + int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION); + view_menu->get_popup()->set_item_checked(idx, lock_rotation); + } if (p_state.has("use_environment")) { bool env = p_state["use_environment"]; @@ -2923,6 +2947,8 @@ Dictionary SpatialEditorViewport::get_state() const { d["half_res"] = viewport_container->get_stretch_shrink() > 1; if (previewing) d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); + if (lock_rotation) + d["lock_rotation"] = lock_rotation; return d; } @@ -2951,6 +2977,7 @@ void SpatialEditorViewport::_bind_methods() { void SpatialEditorViewport::reset() { orthogonal = false; + lock_rotation = false; message_time = 0; message = ""; last_message = ""; @@ -3377,6 +3404,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true); view_menu->get_popup()->add_separator(); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_lock_rotation", TTR("Lock View Rotation")), VIEW_LOCK_ROTATION); + view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW); @@ -4641,9 +4670,7 @@ void SpatialEditor::_init_grid() { Vector3 p2_dest = p2 * (-axis_n1 + axis_n2); Color line_color = secondary_grid_color; - if (j == 0) { - continue; - } else if (j % primary_grid_steps == 0) { + if (j % primary_grid_steps == 0) { line_color = primary_grid_color; } @@ -5011,7 +5038,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_SELECT]->set_flat(true); tool_button[TOOL_MODE_SELECT]->set_pressed(true); - button_binds[0] = MENU_TOOL_SELECT; + button_binds.write[0] = MENU_TOOL_SELECT; tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_SELECT]->set_tooltip(TTR("Select Mode (Q)") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection")); @@ -5019,7 +5046,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]); tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true); tool_button[TOOL_MODE_MOVE]->set_flat(true); - button_binds[0] = MENU_TOOL_MOVE; + button_binds.write[0] = MENU_TOOL_MOVE; tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_MOVE]->set_tooltip(TTR("Move Mode (W)")); @@ -5027,7 +5054,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]); tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true); tool_button[TOOL_MODE_ROTATE]->set_flat(true); - button_binds[0] = MENU_TOOL_ROTATE; + button_binds.write[0] = MENU_TOOL_ROTATE; tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_ROTATE]->set_tooltip(TTR("Rotate Mode (E)")); @@ -5035,7 +5062,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]); tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true); tool_button[TOOL_MODE_SCALE]->set_flat(true); - button_binds[0] = MENU_TOOL_SCALE; + button_binds.write[0] = MENU_TOOL_SCALE; tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)")); @@ -5043,19 +5070,19 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]); tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true); tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true); - button_binds[0] = MENU_TOOL_LIST_SELECT; + button_binds.write[0] = MENU_TOOL_LIST_SELECT; tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode).")); tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton); hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]); - button_binds[0] = MENU_LOCK_SELECTED; + button_binds.write[0] = MENU_LOCK_SELECTED; tool_button[TOOL_LOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved).")); tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton); hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]); - button_binds[0] = MENU_UNLOCK_SELECTED; + button_binds.write[0] = MENU_UNLOCK_SELECTED; tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved).")); @@ -5066,7 +5093,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true); tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true); - button_binds[0] = MENU_TOOL_LOCAL_COORDS; + button_binds.write[0] = MENU_TOOL_LOCAL_COORDS; tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", this, "_menu_item_toggled", button_binds); ED_SHORTCUT("spatial_editor/local_coords", TTR("Local Coords"), KEY_T); sct = ED_GET_SHORTCUT("spatial_editor/local_coords").ptr()->get_as_text(); @@ -5076,7 +5103,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]); tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true); tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true); - button_binds[0] = MENU_TOOL_USE_SNAP; + button_binds.write[0] = MENU_TOOL_USE_SNAP; tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds); ED_SHORTCUT("spatial_editor/snap", TTR("Snap"), KEY_Y); sct = ED_GET_SHORTCUT("spatial_editor/snap").ptr()->get_as_text(); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 637926a913..c89db1867b 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -60,6 +60,7 @@ public: virtual Variant get_handle_value(int p_idx) const; virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + virtual bool is_gizmo_handle_highlighted(int idx) const { return false; } virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); @@ -93,7 +94,8 @@ class SpatialEditorViewport : public Control { VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, - VIEW_DISPLAY_SHADELESS + VIEW_DISPLAY_SHADELESS, + VIEW_LOCK_ROTATION }; public: @@ -131,6 +133,7 @@ private: Camera *camera; bool transforming; bool orthogonal; + bool lock_rotation; float gizmo_scale; bool freelook_active; diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 66673cca00..9bf1178b58 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -169,7 +169,7 @@ void SpriteEditor::_update_mesh_data() { Size2 img_size = Vector2(image->get_width(), image->get_height()); for (int j = 0; j < lines.size(); j++) { - lines[j] = expand(lines[j], rect, epsilon); + lines.write[j] = expand(lines[j], rect, epsilon); int index_ofs = computed_vertices.size(); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp new file mode 100644 index 0000000000..16c25f3074 --- /dev/null +++ b/editor/plugins/text_editor.cpp @@ -0,0 +1,607 @@ +/*************************************************************************/ +/* text_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "text_editor.h" + +void TextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) { + highlighters[p_highlighter->get_name()] = p_highlighter; + highlighter_menu->add_radio_check_item(p_highlighter->get_name()); +} + +void TextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) { + TextEdit *te = code_editor->get_text_edit(); + te->_set_syntax_highlighting(p_highlighter); + if (p_highlighter != NULL) { + highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true); + } else { + highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text("Standard"), true); + } + + // little work around. GDScript highlighter goes through text_edit for colours, + // so to remove all colours we need to set and unset them here. + if (p_highlighter == NULL) { // standard + TextEdit *text_edit = code_editor->get_text_edit(); + text_edit->add_color_override("number_color", colors_cache.font_color); + text_edit->add_color_override("function_color", colors_cache.font_color); + text_edit->add_color_override("number_color", colors_cache.font_color); + text_edit->add_color_override("member_variable_color", colors_cache.font_color); + } else { + _load_theme_settings(); + } +} + +void TextEditor::_change_syntax_highlighter(int p_idx) { + Map<String, SyntaxHighlighter *>::Element *el = highlighters.front(); + while (el != NULL) { + highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); + el = el->next(); + } + set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); +} + +void TextEditor::_load_theme_settings() { + + TextEdit *text_edit = code_editor->get_text_edit(); + text_edit->clear_colors(); + + Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); + Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color"); + Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color"); + Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color"); + Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color"); + Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color"); + Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); + Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color"); + Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color"); + Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color"); + Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color"); + Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color"); + Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color"); + Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color"); + Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color"); + Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color"); + Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); + Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); + Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); + Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); + Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); + Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); + Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); + Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); + Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); + + text_edit->add_color_override("background_color", background_color); + text_edit->add_color_override("completion_background_color", completion_background_color); + text_edit->add_color_override("completion_selected_color", completion_selected_color); + text_edit->add_color_override("completion_existing_color", completion_existing_color); + text_edit->add_color_override("completion_scroll_color", completion_scroll_color); + text_edit->add_color_override("completion_font_color", completion_font_color); + text_edit->add_color_override("font_color", text_color); + text_edit->add_color_override("line_number_color", line_number_color); + text_edit->add_color_override("caret_color", caret_color); + text_edit->add_color_override("caret_background_color", caret_background_color); + text_edit->add_color_override("font_selected_color", text_selected_color); + text_edit->add_color_override("selection_color", selection_color); + text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); + text_edit->add_color_override("current_line_color", current_line_color); + text_edit->add_color_override("line_length_guideline_color", line_length_guideline_color); + text_edit->add_color_override("word_highlighted_color", word_highlighted_color); + text_edit->add_color_override("number_color", number_color); + text_edit->add_color_override("function_color", function_color); + text_edit->add_color_override("member_variable_color", member_variable_color); + text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("mark_color", mark_color); + text_edit->add_color_override("code_folding_color", code_folding_color); + text_edit->add_color_override("search_result_color", search_result_color); + text_edit->add_color_override("search_result_border_color", search_result_border_color); + text_edit->add_color_override("symbol_color", symbol_color); + + text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 4)); + + colors_cache.font_color = text_color; + colors_cache.symbol_color = symbol_color; + colors_cache.keyword_color = keyword_color; + colors_cache.basetype_color = basetype_color; + colors_cache.type_color = type_color; + colors_cache.comment_color = comment_color; + colors_cache.string_color = string_color; +} + +String TextEditor::get_name() { + String name; + + if (text_file->get_path().find("local://") == -1 && text_file->get_path().find("::") == -1) { + name = text_file->get_path().get_file(); + if (is_unsaved()) { + name += "(*)"; + } + } else if (text_file->get_name() != "") { + name = text_file->get_name(); + } else { + name = text_file->get_class() + "(" + itos(text_file->get_instance_id()) + ")"; + } + + return name; +} + +Ref<Texture> TextEditor::get_icon() { + + if (get_parent_control() && get_parent_control()->has_icon(text_file->get_class(), "EditorIcons")) { + return get_parent_control()->get_icon(text_file->get_class(), "EditorIcons"); + } + return Ref<Texture>(); +} + +RES TextEditor::get_edited_resource() const { + return text_file; +} + +void TextEditor::set_edited_resource(const RES &p_res) { + ERR_FAIL_COND(!text_file.is_null()); + + text_file = p_res; + + code_editor->get_text_edit()->set_text(text_file->get_text()); + code_editor->get_text_edit()->clear_undo_history(); + code_editor->get_text_edit()->tag_saved_version(); + + emit_signal("name_changed"); + code_editor->update_line_and_column(); +} + +void TextEditor::add_callback(const String &p_function, PoolStringArray p_args) { +} + +void TextEditor::set_debugger_active(bool p_active) { +} + +void TextEditor::get_breakpoints(List<int> *p_breakpoints) { +} + +void TextEditor::reload_text() { + + ERR_FAIL_COND(text_file.is_null()); + + TextEdit *te = code_editor->get_text_edit(); + int column = te->cursor_get_column(); + int row = te->cursor_get_line(); + int h = te->get_h_scroll(); + int v = te->get_v_scroll(); + + te->set_text(text_file->get_text()); + te->clear_undo_history(); + te->cursor_set_line(row); + te->cursor_set_column(column); + te->set_h_scroll(h); + te->set_v_scroll(v); + + te->tag_saved_version(); + + code_editor->update_line_and_column(); +} + +void TextEditor::_validate_script() { + emit_signal("name_changed"); + emit_signal("edited_script_changed"); +} + +void TextEditor::apply_code() { + text_file->set_text(code_editor->get_text_edit()->get_text()); +} + +bool TextEditor::is_unsaved() { + + return code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version(); +} + +Variant TextEditor::get_edit_state() { + + return code_editor->get_edit_state(); +} + +void TextEditor::set_edit_state(const Variant &p_state) { + + code_editor->set_edit_state(p_state); +} + +void TextEditor::trim_trailing_whitespace() { + + code_editor->trim_trailing_whitespace(); +} + +void TextEditor::convert_indent_to_spaces() { + + code_editor->convert_indent_to_spaces(); +} + +void TextEditor::convert_indent_to_tabs() { + + code_editor->convert_indent_to_tabs(); +} + +void TextEditor::tag_saved_version() { + + code_editor->get_text_edit()->tag_saved_version(); +} + +void TextEditor::goto_line(int p_line, bool p_with_error) { + + code_editor->goto_line(p_line); +} + +void TextEditor::ensure_focus() { + + code_editor->get_text_edit()->grab_focus(); +} + +Vector<String> TextEditor::get_functions() { + + return Vector<String>(); +} + +bool TextEditor::show_members_overview() { + return true; +} + +void TextEditor::update_settings() { + + code_editor->update_editor_settings(); +} + +void TextEditor::set_tooltip_request_func(String p_method, Object *p_obj) { + + code_editor->get_text_edit()->set_tooltip_request_func(p_obj, p_method, this); +} + +Control *TextEditor::get_edit_menu() { + + return edit_hb; +} + +void TextEditor::clear_edit_menu() { + memdelete(edit_hb); +} + +void TextEditor::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_READY: + _load_theme_settings(); + set_syntax_highlighter(NULL); + break; + } +} + +void TextEditor::_edit_option(int p_op) { + TextEdit *tx = code_editor->get_text_edit(); + + switch (p_op) { + case EDIT_UNDO: { + + tx->undo(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_REDO: { + + tx->redo(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_CUT: { + + tx->cut(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_COPY: { + + tx->copy(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_PASTE: { + + tx->paste(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_SELECT_ALL: { + + tx->select_all(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_MOVE_LINE_UP: { + + code_editor->move_lines_up(); + } break; + case EDIT_MOVE_LINE_DOWN: { + + code_editor->move_lines_down(); + } break; + case EDIT_INDENT_LEFT: { + + tx->indent_left(); + } break; + case EDIT_INDENT_RIGHT: { + + tx->indent_right(); + } break; + case EDIT_DELETE_LINE: { + + code_editor->delete_lines(); + } break; + case EDIT_CLONE_DOWN: { + + code_editor->code_lines_down(); + } break; + case EDIT_TOGGLE_FOLD_LINE: { + + tx->toggle_fold_line(tx->cursor_get_line()); + tx->update(); + } break; + case EDIT_FOLD_ALL_LINES: { + + tx->fold_all_lines(); + tx->update(); + } break; + case EDIT_UNFOLD_ALL_LINES: { + + tx->unhide_all_lines(); + tx->update(); + } break; + case EDIT_TRIM_TRAILING_WHITESAPCE: { + + trim_trailing_whitespace(); + } break; + case EDIT_CONVERT_INDENT_TO_SPACES: { + + convert_indent_to_spaces(); + } break; + case EDIT_CONVERT_INDENT_TO_TABS: { + + convert_indent_to_tabs(); + } break; + case EDIT_TO_UPPERCASE: { + + _convert_case(CodeTextEditor::UPPER); + } break; + case EDIT_TO_LOWERCASE: { + + _convert_case(CodeTextEditor::LOWER); + } break; + case EDIT_CAPITALIZE: { + + _convert_case(CodeTextEditor::CAPITALIZE); + } break; + case SEARCH_FIND: { + + code_editor->get_find_replace_bar()->popup_search(); + } break; + case SEARCH_FIND_NEXT: { + + code_editor->get_find_replace_bar()->search_next(); + } break; + case SEARCH_FIND_PREV: { + + code_editor->get_find_replace_bar()->search_prev(); + } break; + case SEARCH_REPLACE: { + + code_editor->get_find_replace_bar()->popup_replace(); + } break; + case SEARCH_GOTO_LINE: { + + goto_line_dialog->popup_find_line(tx); + } break; + } +} + +void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { + + code_editor->convert_case(p_case); +} + +void TextEditor::_bind_methods() { + + ClassDB::bind_method("_validate_script", &TextEditor::_validate_script); + ClassDB::bind_method("_load_theme_settings", &TextEditor::_load_theme_settings); + ClassDB::bind_method("_edit_option", &TextEditor::_edit_option); + ClassDB::bind_method("_change_syntax_highlighter", &TextEditor::_change_syntax_highlighter); + ClassDB::bind_method("_text_edit_gui_input", &TextEditor::_text_edit_gui_input); +} + +static ScriptEditorBase *create_editor(const RES &p_resource) { + + if (Object::cast_to<TextFile>(*p_resource)) { + return memnew(TextEditor); + } + return NULL; +} + +void TextEditor::register_editor() { + + ScriptEditor::register_create_script_editor_function(create_editor); +} + +void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { + + Ref<InputEventMouseButton> mb = ev; + + if (mb.is_valid()) { + if (mb->get_button_index() == BUTTON_RIGHT) { + + int col, row; + TextEdit *tx = code_editor->get_text_edit(); + tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); + + tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); + bool can_fold = tx->can_fold(row); + bool is_folded = tx->is_folded(row); + + if (tx->is_right_click_moving_caret()) { + if (tx->is_selection_active()) { + + int from_line = tx->get_selection_from_line(); + int to_line = tx->get_selection_to_line(); + int from_column = tx->get_selection_from_column(); + int to_column = tx->get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + tx->deselect(); + } + } + if (!tx->is_selection_active()) { + tx->cursor_set_line(row, true, false); + tx->cursor_set_column(col); + } + } + + if (!mb->is_pressed()) { + _make_context_menu(tx->is_selection_active(), can_fold, is_folded); + } + } + } +} + +void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded) { + + context_menu->clear(); + if (p_selection) { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + } + + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + + if (p_selection) { + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); + } + if (p_can_fold || p_is_folded) + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + + context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); + context_menu->set_size(Vector2(1, 1)); + context_menu->popup(); +} + +TextEditor::TextEditor() { + code_editor = memnew(CodeTextEditor); + add_child(code_editor); + code_editor->add_constant_override("separation", 0); + code_editor->connect("load_theme_settings", this, "_load_theme_settings"); + code_editor->connect("validate_script", this, "_validate_script"); + code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + + update_settings(); + + code_editor->get_text_edit()->set_context_menu_enabled(false); + code_editor->get_text_edit()->connect("gui_input", this, "_text_edit_gui_input"); + + context_menu = memnew(PopupMenu); + add_child(context_menu); + context_menu->connect("id_pressed", this, "_edit_option"); + + edit_hb = memnew(HBoxContainer); + + search_menu = memnew(MenuButton); + edit_hb->add_child(search_menu); + search_menu->set_text(TTR("Search")); + search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); + + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); + + edit_menu = memnew(MenuButton); + edit_menu->set_text(TTR("Edit")); + edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + + edit_hb->add_child(edit_menu); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); + + edit_menu->get_popup()->add_separator(); + PopupMenu *convert_case = memnew(PopupMenu); + convert_case->set_name("convert_case"); + edit_menu->get_popup()->add_child(convert_case); + edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case"); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase")), EDIT_TO_UPPERCASE); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase")), EDIT_TO_LOWERCASE); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE); + convert_case->connect("id_pressed", this, "_edit_option"); + + highlighters["Standard"] = NULL; + highlighter_menu = memnew(PopupMenu); + highlighter_menu->set_name("highlighter_menu"); + edit_menu->get_popup()->add_child(highlighter_menu); + edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu"); + highlighter_menu->add_radio_check_item(TTR("Standard")); + highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter"); + + code_editor->get_text_edit()->set_drag_forwarding(this); +} diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h new file mode 100644 index 0000000000..8b1983d891 --- /dev/null +++ b/editor/plugins/text_editor.h @@ -0,0 +1,146 @@ +/*************************************************************************/ +/* text_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 TEXT_EDITOR_H +#define TEXT_EDITOR_H + +#include "script_editor_plugin.h" + +class TextEditor : public ScriptEditorBase { + + GDCLASS(TextEditor, ScriptEditorBase) + +private: + CodeTextEditor *code_editor; + + Ref<TextFile> text_file; + + HBoxContainer *edit_hb; + MenuButton *edit_menu; + PopupMenu *highlighter_menu; + MenuButton *search_menu; + PopupMenu *context_menu; + + GotoLineDialog *goto_line_dialog; + + struct ColorsCache { + Color font_color; + Color symbol_color; + Color keyword_color; + Color basetype_color; + Color type_color; + Color comment_color; + Color string_color; + } colors_cache; + + enum { + EDIT_UNDO, + EDIT_REDO, + EDIT_CUT, + EDIT_COPY, + EDIT_PASTE, + EDIT_SELECT_ALL, + EDIT_TRIM_TRAILING_WHITESAPCE, + EDIT_CONVERT_INDENT_TO_SPACES, + EDIT_CONVERT_INDENT_TO_TABS, + EDIT_MOVE_LINE_UP, + EDIT_MOVE_LINE_DOWN, + EDIT_INDENT_RIGHT, + EDIT_INDENT_LEFT, + EDIT_DELETE_LINE, + EDIT_CLONE_DOWN, + EDIT_TO_UPPERCASE, + EDIT_TO_LOWERCASE, + EDIT_CAPITALIZE, + EDIT_TOGGLE_FOLD_LINE, + EDIT_FOLD_ALL_LINES, + EDIT_UNFOLD_ALL_LINES, + SEARCH_FIND, + SEARCH_FIND_NEXT, + SEARCH_FIND_PREV, + SEARCH_REPLACE, + SEARCH_GOTO_LINE, + }; + +protected: + static void _bind_methods(); + + void _notification(int p_what); + + void _edit_option(int p_op); + void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded); + void _text_edit_gui_input(const Ref<InputEvent> &ev); + + Map<String, SyntaxHighlighter *> highlighters; + void _change_syntax_highlighter(int p_idx); + void _load_theme_settings(); + + void _convert_case(CodeTextEditor::CaseStyle p_case); + + void _validate_script(); + +public: + virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter); + virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); + + virtual String get_name(); + virtual Ref<Texture> get_icon(); + virtual RES get_edited_resource() const; + virtual void set_edited_resource(const RES &p_res); + void set_edited_file(const Ref<TextFile> &p_file); + virtual void reload_text(); + virtual void apply_code(); + virtual bool is_unsaved(); + virtual Variant get_edit_state(); + virtual void set_edit_state(const Variant &p_state); + virtual Vector<String> get_functions(); + virtual void get_breakpoints(List<int> *p_breakpoints); + virtual void goto_line(int p_line, bool p_with_error = false); + virtual void trim_trailing_whitespace(); + virtual void convert_indent_to_spaces(); + virtual void convert_indent_to_tabs(); + virtual void ensure_focus(); + virtual void tag_saved_version(); + virtual void update_settings(); + virtual bool show_members_overview(); + virtual bool can_lose_focus_on_node_selection() { return true; } + virtual void set_debugger_active(bool p_active); + virtual void set_tooltip_request_func(String p_method, Object *p_obj); + virtual void add_callback(const String &p_function, PoolStringArray p_args); + + virtual Control *get_edit_menu(); + virtual void clear_edit_menu(); + + static void register_editor(); + + TextEditor(); +}; + +#endif // TEXT_EDITOR_H diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 19646f37b5..435ef229c5 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -196,7 +196,7 @@ Vector<int> TileMapEditor::get_selected_tiles() const { } for (int i = items.size() - 1; i >= 0; i--) { - items[i] = palette->get_item_metadata(items[i]); + items.write[i] = palette->get_item_metadata(items[i]); } return items; } @@ -526,7 +526,7 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era if (!erase) { ids = get_selected_tiles(); - if (ids.size() == 0 && ids[0] == TileMap::INVALID_CELL) + if (ids.size() == 0 || ids[0] == TileMap::INVALID_CELL) return PoolVector<Vector2>(); } else if (prev_id == TileMap::INVALID_CELL) { return PoolVector<Vector2>(); @@ -538,9 +538,7 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era } } - Rect2i r = node->_edit_get_rect(); - r.position = r.position / node->get_cell_size(); - r.size = r.size / node->get_cell_size(); + Rect2i r = node->get_used_rect(); int area = r.get_area(); if (preview) { @@ -985,7 +983,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { ids.push_back(0); for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { - ids[0] = E->get().cell; + ids.write[0] = E->get().cell; _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose); } _finish_undo(); @@ -1008,7 +1006,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { - ids[0] = E->get().cell; + ids.write[0] = E->get().cell; _set_cell(E->get().pos + ofs, ids, E->get().flip_h, E->get().flip_v, E->get().transpose); } _finish_undo(); @@ -1029,7 +1027,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (points.size() == 0) return false; - undo_redo->create_action(TTR("Bucket Fill")); + _start_undo(TTR("Bucket Fill")); Dictionary op; op["id"] = get_selected_tiles(); @@ -1039,7 +1037,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _fill_points(points, op); - undo_redo->commit_action(); + _finish_undo(); // We want to keep the bucket-tool active return true; @@ -1230,7 +1228,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - tmp_cell[0] = E->get().idx; + tmp_cell.write[0] = E->get().idx; _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr); } } @@ -1267,7 +1265,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { - tmp_cell[0] = E->get().idx; + tmp_cell.write[0] = E->get().idx; _set_cell(E->key(), tmp_cell, E->get().xf, E->get().yf, E->get().tr); } } @@ -1752,7 +1750,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { bucket_cache_visited = 0; invalid_cell.resize(1); - invalid_cell[0] = TileMap::INVALID_CELL; + invalid_cell.write[0] = TileMap::INVALID_CELL; ED_SHORTCUT("tile_map_editor/erase_selection", TTR("Erase Selection"), KEY_DELETE); ED_SHORTCUT("tile_map_editor/find_tile", TTR("Find Tile"), KEY_MASK_CMD + KEY_F); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 682ca744ff..9218fed907 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -190,7 +190,7 @@ void VisualShaderEditor::_update_graph() { } for (int i = 0; i < plugins.size(); i++) { - custom_editor = plugins[i]->create_editor(vsnode); + custom_editor = plugins.write[i]->create_editor(vsnode); if (custom_editor) { break; } @@ -735,7 +735,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->connect("duplicate_nodes_request", this, "_duplicate_nodes"); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR); - //graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR); + graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 0d06b71420..95d39953cf 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -72,16 +72,26 @@ private: MESSAGE_SUCCESS }; + enum InputType { + PROJECT_PATH, + INSTALL_PATH + }; + Mode mode; Button *browse; + Button *install_browse; Button *create_dir; Container *name_container; Container *path_container; + Container *install_path_container; Label *msg; LineEdit *project_path; LineEdit *project_name; + LineEdit *install_path; TextureRect *status_rect; + TextureRect *install_status_rect; FileDialog *fdialog; + FileDialog *fdialog_install; String zip_path; String zip_title; AcceptDialog *dialog_error; @@ -89,10 +99,11 @@ private: String created_folder_path; - void set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS) { + void set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS, InputType input_type = PROJECT_PATH) { msg->set_text(p_msg); - Ref<Texture> current_icon = status_rect->get_texture(); + Ref<Texture> current_path_icon = status_rect->get_texture(); + Ref<Texture> current_install_icon = install_status_rect->get_texture(); Ref<Texture> new_icon; switch (p_type) { @@ -119,8 +130,11 @@ private: } break; } - if (current_icon != new_icon) + if (current_path_icon != new_icon && input_type == PROJECT_PATH) { status_rect->set_texture(new_icon); + } else if (current_install_icon != new_icon && input_type == INSTALL_PATH) { + install_status_rect->set_texture(new_icon); + } set_size(Size2(500, 0) * EDSCALE); } @@ -128,11 +142,19 @@ private: String _test_path() { DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - String valid_path; + String valid_path, valid_install_path; if (d->change_dir(project_path->get_text()) == OK) { valid_path = project_path->get_text(); } else if (d->change_dir(project_path->get_text().strip_edges()) == OK) { valid_path = project_path->get_text().strip_edges(); + } else if (project_path->get_text().ends_with(".zip")) { + if (d->file_exists(project_path->get_text())) { + valid_path = project_path->get_text(); + } + } else if (project_path->get_text().strip_edges().ends_with(".zip")) { + if (d->file_exists(project_path->get_text().strip_edges())) { + valid_path = project_path->get_text().strip_edges(); + } } if (valid_path == "") { @@ -142,11 +164,94 @@ private: return ""; } + if (mode == MODE_IMPORT && valid_path.ends_with(".zip")) { + if (d->change_dir(install_path->get_text()) == OK) { + valid_install_path = install_path->get_text(); + } else if (d->change_dir(install_path->get_text().strip_edges()) == OK) { + valid_install_path = install_path->get_text().strip_edges(); + } + + if (valid_install_path == "") { + set_message(TTR("The path does not exist."), MESSAGE_ERROR, INSTALL_PATH); + memdelete(d); + get_ok()->set_disabled(true); + return ""; + } + } + if (mode == MODE_IMPORT || mode == MODE_RENAME) { if (valid_path != "" && !d->file_exists("project.godot")) { - set_message(TTR("Please choose a 'project.godot' file."), MESSAGE_ERROR); + if (valid_path.ends_with(".zip")) { + FileAccess *src_f = NULL; + zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + + unzFile pkg = unzOpen2(valid_path.utf8().get_data(), &io); + if (!pkg) { + + set_message(TTR("Error opening package file, not in zip format."), MESSAGE_ERROR); + memdelete(d); + get_ok()->set_disabled(true); + unzClose(pkg); + return ""; + } + + int ret = unzGoToFirstFile(pkg); + while (ret == UNZ_OK) { + unz_file_info info; + char fname[16384]; + ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); + + if (String(fname).ends_with("project.godot")) { + break; + } + + ret = unzGoToNextFile(pkg); + } + + if (ret == UNZ_END_OF_LIST_OF_FILE) { + set_message(TTR("Invalid '.zip' project file, does not contain a 'project.godot' file."), MESSAGE_ERROR); + memdelete(d); + get_ok()->set_disabled(true); + unzClose(pkg); + return ""; + } + + unzClose(pkg); + + // check if the specified install folder is empty, even though this is not an error, it is good to check here + d->list_dir_begin(); + bool is_empty = true; + String n = d->get_next(); + while (n != String()) { + if (n != "." && n != "..") { + is_empty = false; + break; + } + n = d->get_next(); + } + d->list_dir_end(); + + if (!is_empty) { + + set_message(TTR("Please choose an empty folder."), MESSAGE_WARNING, INSTALL_PATH); + memdelete(d); + get_ok()->set_disabled(true); + return ""; + } + + } else { + set_message(TTR("Please choose a 'project.godot' or '.zip' file."), MESSAGE_ERROR); + memdelete(d); + install_path_container->hide(); + get_ok()->set_disabled(true); + return ""; + } + + } else if (valid_path.ends_with("zip")) { + + set_message(TTR("Directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH); memdelete(d); get_ok()->set_disabled(true); return ""; @@ -159,7 +264,7 @@ private: bool is_empty = true; String n = d->get_next(); while (n != String()) { - if (!n.begins_with(".")) { // i don't know if this is enough to guarantee an empty dir + if (n != "." && n != "..") { // i don't know if this is enough to guarantee an empty dir is_empty = false; break; } @@ -177,6 +282,7 @@ private: } set_message(""); + set_message("", MESSAGE_SUCCESS, INSTALL_PATH); memdelete(d); get_ok()->set_disabled(false); return valid_path; @@ -214,9 +320,14 @@ private: if (mode == MODE_IMPORT) { if (p.ends_with("project.godot")) { p = p.get_base_dir(); + install_path_container->hide(); + get_ok()->set_disabled(false); + } else if (p.ends_with(".zip")) { + install_path->set_text(p.get_base_dir()); + install_path_container->show(); get_ok()->set_disabled(false); } else { - set_message(TTR("Please choose a 'project.godot' file."), MESSAGE_ERROR); + set_message(TTR("Please choose a 'project.godot' or '.zip' file."), MESSAGE_ERROR); get_ok()->set_disabled(true); return; } @@ -224,7 +335,11 @@ private: String sp = p.simplify_path(); project_path->set_text(sp); _path_text_changed(sp); - get_ok()->call_deferred("grab_focus"); + if (p.ends_with(".zip")) { + install_path->call_deferred("grab_focus"); + } else { + get_ok()->call_deferred("grab_focus"); + } } void _path_selected(const String &p_path) { @@ -236,6 +351,14 @@ private: get_ok()->call_deferred("grab_focus"); } + void _install_path_selected(const String &p_path) { + String p = p_path; + String sp = p.simplify_path(); + install_path->set_text(sp); + _path_text_changed(sp); + get_ok()->call_deferred("grab_focus"); + } + void _browse_path() { fdialog->set_current_dir(project_path->get_text()); @@ -245,12 +368,19 @@ private: fdialog->set_mode(FileDialog::MODE_OPEN_FILE); fdialog->clear_filters(); fdialog->add_filter("project.godot ; " VERSION_NAME " Project"); + fdialog->add_filter("*.zip ; Zip File"); } else { fdialog->set_mode(FileDialog::MODE_OPEN_DIR); } fdialog->popup_centered_ratio(); } + void _browse_install_path() { + fdialog_install->set_current_dir(install_path->get_text()); + fdialog_install->set_mode(FileDialog::MODE_OPEN_DIR); + fdialog_install->popup_centered_ratio(); + } + void _create_folder() { if (project_name->get_text() == "" || created_folder_path != "" || project_name->get_text().ends_with(".") || project_name->get_text().ends_with(" ")) { @@ -328,7 +458,15 @@ private: } else { if (mode == MODE_IMPORT) { - // nothing to do + + if (project_path->get_text().ends_with(".zip")) { + + mode = MODE_INSTALL; + ok_pressed(); + + return; + } + } else { if (mode == MODE_NEW) { @@ -357,6 +495,11 @@ private: } else if (mode == MODE_INSTALL) { + if (project_path->get_text().ends_with(".zip")) { + dir = install_path->get_text(); + zip_path = project_path->get_text(); + } + FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); @@ -444,7 +587,7 @@ private: dialog_error->set_text(msg); dialog_error->popup_centered_minsize(); - } else { + } else if (!project_path->get_text().ends_with(".zip")) { dialog_error->set_text(TTR("Package Installed Successfully!")); dialog_error->popup_centered_minsize(); } @@ -486,6 +629,9 @@ private: if (status_rect->get_texture() == get_icon("StatusError", "EditorIcons")) msg->show(); + + if (install_status_rect->get_texture() == get_icon("StatusError", "EditorIcons")) + msg->show(); } void _notification(int p_what) { @@ -503,6 +649,8 @@ protected: ClassDB::bind_method("_path_text_changed", &ProjectDialog::_path_text_changed); ClassDB::bind_method("_path_selected", &ProjectDialog::_path_selected); ClassDB::bind_method("_file_selected", &ProjectDialog::_file_selected); + ClassDB::bind_method("_install_path_selected", &ProjectDialog::_install_path_selected); + ClassDB::bind_method("_browse_install_path", &ProjectDialog::_browse_install_path); ADD_SIGNAL(MethodInfo("project_created")); ADD_SIGNAL(MethodInfo("project_renamed")); } @@ -530,12 +678,15 @@ public: project_path->set_editable(false); browse->hide(); + install_browse->hide(); set_title(TTR("Rename Project")); get_ok()->set_text(TTR("Rename")); name_container->show(); status_rect->hide(); msg->hide(); + install_path_container->hide(); + install_status_rect->hide(); get_ok()->set_disabled(false); ProjectSettings *current = memnew(ProjectSettings); @@ -575,14 +726,18 @@ public: project_path->set_editable(true); browse->set_disabled(false); browse->show(); + install_browse->set_disabled(false); + install_browse->show(); create_dir->show(); status_rect->show(); + install_status_rect->show(); msg->show(); if (mode == MODE_IMPORT) { set_title(TTR("Import Existing Project")); get_ok()->set_text(TTR("Import & Edit")); name_container->hide(); + install_path_container->hide(); project_path->grab_focus(); } else if (mode == MODE_NEW) { @@ -590,6 +745,7 @@ public: set_title(TTR("Create New Project")); get_ok()->set_text(TTR("Create & Edit")); name_container->show(); + install_path_container->hide(); project_name->grab_focus(); } else if (mode == MODE_INSTALL) { @@ -597,6 +753,7 @@ public: set_title(TTR("Install Project:") + " " + zip_title); get_ok()->set_text(TTR("Install & Edit")); name_container->hide(); + install_path_container->hide(); project_path->grab_focus(); } @@ -644,6 +801,20 @@ public: project_path->set_h_size_flags(SIZE_EXPAND_FILL); pphb->add_child(project_path); + install_path_container = memnew(VBoxContainer); + vb->add_child(install_path_container); + + l = memnew(Label); + l->set_text(TTR("Project Installation Path:")); + install_path_container->add_child(l); + + HBoxContainer *iphb = memnew(HBoxContainer); + install_path_container->add_child(iphb); + + install_path = memnew(LineEdit); + install_path->set_h_size_flags(SIZE_EXPAND_FILL); + iphb->add_child(install_path); + // status icon status_rect = memnew(TextureRect); status_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); @@ -654,17 +825,33 @@ public: browse->connect("pressed", this, "_browse_path"); pphb->add_child(browse); + // install status icon + install_status_rect = memnew(TextureRect); + install_status_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + iphb->add_child(install_status_rect); + + install_browse = memnew(Button); + install_browse->set_text(TTR("Browse")); + install_browse->connect("pressed", this, "_browse_install_path"); + iphb->add_child(install_browse); + msg = memnew(Label); msg->set_align(Label::ALIGN_CENTER); vb->add_child(msg); fdialog = memnew(FileDialog); fdialog->set_access(FileDialog::ACCESS_FILESYSTEM); + fdialog_install = memnew(FileDialog); + fdialog_install->set_access(FileDialog::ACCESS_FILESYSTEM); add_child(fdialog); + add_child(fdialog_install); project_name->connect("text_changed", this, "_text_changed"); project_path->connect("text_changed", this, "_path_text_changed"); + install_path->connect("text_changed", this, "_path_text_changed"); fdialog->connect("dir_selected", this, "_path_selected"); fdialog->connect("file_selected", this, "_file_selected"); + fdialog_install->connect("dir_selected", this, "_install_path_selected"); + fdialog_install->connect("file_selected", this, "_install_path_selected"); set_hide_on_ok(false); mode = MODE_NEW; @@ -1594,8 +1781,8 @@ ProjectManager::ProjectManager() { vb->add_constant_override("separation", 15 * EDSCALE); String cp; - cp.push_back(0xA9); - cp.push_back(0); + cp += 0xA9; + cp += '0'; OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2018 Juan Linietsky, Ariel Manzur & Godot Contributors"); HBoxContainer *top_hb = memnew(HBoxContainer); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index e6ae2d64e7..2b2e03ce38 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1462,7 +1462,7 @@ void ProjectSettingsEditor::_update_translations() { t->set_editable(0, true); t->set_tooltip(0, l); t->set_checked(0, l_filter.has(l)); - translation_filter_treeitems[i] = t; + translation_filter_treeitems.write[i] = t; } } else { for (int i = 0; i < s; i++) { @@ -1502,7 +1502,7 @@ void ProjectSettingsEditor::_update_translations() { if (langnames.length() > 0) langnames += ","; langnames += names[i]; - translation_locales_idxs_remap[l_idx] = i; + translation_locales_idxs_remap.write[l_idx] = i; l_idx++; } } diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 7f46844f6c..b370a711e3 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -90,7 +90,7 @@ bool EditorResourceConversionPlugin::handles(const Ref<Resource> &p_resource) co return false; } -Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_resource) { +Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_resource) const { if (get_script_instance()) return get_script_instance()->call("_convert", p_resource); @@ -4394,7 +4394,7 @@ PropertyEditor::PropertyEditor() { use_filter = false; subsection_selectable = false; property_selectable = false; - show_type_icons = EDITOR_DEF("interface/editor/show_type_icons", false); + show_type_icons = false; // TODO: need to reimplement it to work with the new inspector } PropertyEditor::~PropertyEditor() { diff --git a/editor/property_editor.h b/editor/property_editor.h index 56743822d2..7d8fa22f3f 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -64,7 +64,7 @@ protected: public: virtual String converts_to() const; virtual bool handles(const Ref<Resource> &p_resource) const; - virtual Ref<Resource> convert(const Ref<Resource> &p_resource); + virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const; }; class CustomPropertyEditor : public Popup { diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp index 26dd931321..907bb50f7e 100644 --- a/editor/quick_open.cpp +++ b/editor/quick_open.cpp @@ -195,7 +195,7 @@ Vector<Pair<String, Ref<Texture> > > EditorQuickOpen::_sort_fs(Vector<Pair<Strin Vector<float> scores; scores.resize(list.size()); for (int i = 0; i < list.size(); i++) - scores[i] = _path_cmp(search_text, list[i].first); + scores.write[i] = _path_cmp(search_text, list[i].first); while (list.size() > 0) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 2ffaa0ca12..8d38bf39b5 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -724,7 +724,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } } break; - case TOOL_SCENE_CLEAR_INSTANCING: { + case TOOL_SCENE_MAKE_LOCAL: { List<Node *> selection = editor_selection->get_selected_node_list(); List<Node *>::Element *e = selection.front(); if (e) { @@ -736,7 +736,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; ERR_FAIL_COND(node->get_filename() == String()); - undo_redo->create_action(TTR("Discard Instancing")); + undo_redo->create_action(TTR("Make Local")); undo_redo->add_do_method(node, "set_filename", ""); undo_redo->add_undo_method(node, "set_filename", node->get_filename()); _node_replace_owner(node, node, root); @@ -2028,7 +2028,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { bool placeholder = selection[0]->get_scene_instance_load_placeholder(); menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN); menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER); - menu->add_item(TTR("Discard Instancing"), TOOL_SCENE_CLEAR_INSTANCING); + menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL); menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN); menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable); menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index fd74611bde..57f4759747 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -77,7 +77,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_BUTTON_MAX, TOOL_SCENE_EDITABLE_CHILDREN, TOOL_SCENE_USE_PLACEHOLDER, - TOOL_SCENE_CLEAR_INSTANCING, + TOOL_SCENE_MAKE_LOCAL, TOOL_SCENE_OPEN, TOOL_SCENE_CLEAR_INHERITANCE, TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM, diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 62848a6035..e483fde4bc 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -658,7 +658,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da Vector<float> p; p.resize(arr.size()); for (int i = 0; i < arr.size(); i++) { - p[i] = arr[i]; + p.write[i] = arr[i]; if (i < perf_items.size()) { float v = p[i]; @@ -693,7 +693,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da perf_items[i]->set_text(1, vs); perf_items[i]->set_tooltip(1, tt); if (p[i] > perf_max[i]) - perf_max[i] = p[i]; + perf_max.write[i] = p[i]; } } perf_history.push_front(p); @@ -807,7 +807,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da item.signature = "categ::" + name + "::" + item.name; item.name = item.name.capitalize(); c.total_time += item.total; - c.items[i / 2] = item; + c.items.write[i / 2] = item; } metric.categories.push_back(c); } @@ -844,7 +844,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da item.calls = calls; item.self = self; item.total = total; - funcs.items[i] = item; + funcs.items.write[i] = item; } metric.categories.push_back(funcs); @@ -1193,7 +1193,7 @@ void ScriptEditorDebugger::start() { perf_history.clear(); for (int i = 0; i < Performance::MONITOR_MAX; i++) { - perf_max[i] = 0; + perf_max.write[i] = 0; } int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); @@ -1249,6 +1249,9 @@ void ScriptEditorDebugger::stop() { EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree(); EditorNode::get_singleton()->get_scene_tree_dock()->hide_tab_buttons(); + Node *node = editor->get_scene_tree_dock()->get_tree_editor()->get_selected(); + editor->push_item(node); + if (hide_on_stop) { if (is_visible_in_tree()) EditorNode::get_singleton()->hide_bottom_panel(); @@ -2073,7 +2076,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { it->set_selectable(1, false); it->set_text(0, name.capitalize()); perf_items.push_back(it); - perf_max[i] = 0; + perf_max.write[i] = 0; } } diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index c45dea0df7..c450c0fd4c 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -33,6 +33,7 @@ #include "geometry.h" #include "quick_hull.h" #include "scene/3d/camera.h" +#include "scene/3d/soft_body.h" #include "scene/resources/box_shape.h" #include "scene/resources/capsule_shape.h" #include "scene/resources/convex_polygon_shape.h" @@ -228,7 +229,7 @@ void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) collision_segments.resize(from + p_lines.size()); for (int i = 0; i < p_lines.size(); i++) { - collision_segments[from + i] = p_lines[i]; + collision_segments.write[from + i] = p_lines[i]; } } @@ -256,8 +257,12 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi for (int i = 0; i < p_handles.size(); i++) { Color col(1, 1, 1, 1); + if (is_gizmo_handle_highlighted(i)) + col = Color(0, 0, 1, 0.9); + if (SpatialEditor::get_singleton()->get_over_gizmo_handle() != i) - col = Color(0.9, 0.9, 0.9, 0.9); + col.a = 0.8; + w[i] = col; } } @@ -291,14 +296,14 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi int chs = handles.size(); handles.resize(chs + p_handles.size()); for (int i = 0; i < p_handles.size(); i++) { - handles[i + chs] = p_handles[i]; + handles.write[i + chs] = p_handles[i]; } } else { int chs = secondary_handles.size(); secondary_handles.resize(chs + p_handles.size()); for (int i = 0; i < p_handles.size(); i++) { - secondary_handles[i + chs] = p_handles[i]; + secondary_handles.write[i + chs] = p_handles[i]; } } } @@ -592,7 +597,7 @@ void EditorSpatialGizmo::create() { for (int i = 0; i < instances.size(); i++) { - instances[i].create_instance(spatial_node); + instances.write[i].create_instance(spatial_node); } transform(); @@ -616,7 +621,7 @@ void EditorSpatialGizmo::free() { if (instances[i].instance.is_valid()) VS::get_singleton()->free(instances[i].instance); - instances[i].instance = RID(); + instances.write[i].instance = RID(); } valid = false; @@ -1119,8 +1124,8 @@ void AudioStreamPlayer3DSpatialGizmo::redraw() { Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs); Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs); - points[i * 2 + 0] = from; - points[i * 2 + 1] = to; + points.write[i * 2 + 0] = from; + points.write[i * 2 + 1] = to; } for (int i = 0; i < 4; i++) { @@ -1129,8 +1134,8 @@ void AudioStreamPlayer3DSpatialGizmo::redraw() { Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs); - points[200 + i * 2 + 0] = from; - points[200 + i * 2 + 1] = Vector3(); + points.write[200 + i * 2 + 0] = from; + points.write[200 + i * 2 + 1] = Vector3(); } add_lines(points, material); @@ -1436,11 +1441,11 @@ void SkeletonSpatialGizmo::redraw() { weights.resize(4); for (int i = 0; i < 4; i++) { - bones[i] = 0; - weights[i] = 0; + bones.write[i] = 0; + weights.write[i] = 0; } - weights[0] = 1; + weights.write[0] = 1; AABB aabb; @@ -1452,7 +1457,7 @@ void SkeletonSpatialGizmo::redraw() { int parent = skel->get_bone_parent(i); if (parent >= 0) { - grests[i] = grests[parent] * skel->get_bone_rest(i); + grests.write[i] = grests[parent] * skel->get_bone_rest(i); Vector3 v0 = grests[parent].origin; Vector3 v1 = grests[i].origin; @@ -1475,7 +1480,7 @@ void SkeletonSpatialGizmo::redraw() { int pointidx = 0; for (int j = 0; j < 3; j++) { - bones[0] = parent; + bones.write[0] = parent; surface_tool->add_bones(bones); surface_tool->add_weights(weights); surface_tool->add_color(rootcolor); @@ -1503,7 +1508,7 @@ void SkeletonSpatialGizmo::redraw() { Vector3 point = v0 + d * dist * 0.2; point += axis * dist * 0.1; - bones[0] = parent; + bones.write[0] = parent; surface_tool->add_bones(bones); surface_tool->add_weights(weights); surface_tool->add_color(bonecolor); @@ -1513,12 +1518,12 @@ void SkeletonSpatialGizmo::redraw() { surface_tool->add_color(bonecolor); surface_tool->add_vertex(point); - bones[0] = parent; + bones.write[0] = parent; surface_tool->add_bones(bones); surface_tool->add_weights(weights); surface_tool->add_color(bonecolor); surface_tool->add_vertex(point); - bones[0] = i; + bones.write[0] = i; surface_tool->add_bones(bones); surface_tool->add_weights(weights); surface_tool->add_color(bonecolor); @@ -1530,7 +1535,7 @@ void SkeletonSpatialGizmo::redraw() { SWAP(points[1], points[2]); for (int j = 0; j < 4; j++) { - bones[0] = parent; + bones.write[0] = parent; surface_tool->add_bones(bones); surface_tool->add_weights(weights); surface_tool->add_color(bonecolor); @@ -1555,8 +1560,8 @@ void SkeletonSpatialGizmo::redraw() { */ } else { - grests[i] = skel->get_bone_rest(i); - bones[0] = i; + grests.write[i] = skel->get_bone_rest(i); + bones.write[0] = i; } /* Transform t = grests[i]; @@ -1914,6 +1919,100 @@ VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) { /////////// +void SoftBodySpatialGizmo::redraw() { + clear(); + + if (!soft_body || soft_body->get_mesh().is_null()) { + return; + } + + // find mesh + + Vector<Vector3> lines; + + soft_body->get_mesh()->generate_debug_mesh_lines(lines); + + if (!lines.size()) { + return; + } + + Vector<Vector3> points; + soft_body->get_mesh()->generate_debug_mesh_indices(points); + + soft_body->get_mesh()->clear_cache(); + + Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); + Ref<Material> material = create_material("shape_material", gizmo_color); + + add_lines(lines, material); + add_collision_segments(lines); + add_handles(points); +} + +bool SoftBodySpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) { + return EditorSpatialGizmo::intersect_ray(p_camera, p_point, r_pos, r_normal, r_gizmo_handle, p_sec_first); + + /* Perform a shape cast but doesn't work with softbody + PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(SceneTree::get_singleton()->get_root()->get_world()->get_space()); + if (!physics_sphere_shape.is_valid()) { + physics_sphere_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_SPHERE); + real_t radius = 0.02; + PhysicsServer::get_singleton()->shape_set_data(physics_sphere_shape, radius); + } + + Vector3 sphere_motion(p_camera->project_ray_normal(p_point)); + real_t closest_safe; + real_t closest_unsafe; + PhysicsDirectSpaceState::ShapeRestInfo result; + bool collided = space_state->cast_motion( + physics_sphere_shape, + p_camera->get_transform(), + sphere_motion * Vector3(1000, 1000, 1000), + 0.f, + closest_safe, + closest_unsafe, + Set<RID>(), + 0xFFFFFFFF, + 0xFFFFFFFF, + &result); + + if (collided) { + + if (result.collider_id == soft_body->get_instance_id()) { + print_line("Collided"); + } else { + print_line("Collided but with wrong object: " + itos(result.collider_id)); + } + } else { + print_line("Not collided, motion: x: " + rtos(sphere_motion[0]) + " y: " + rtos(sphere_motion[1]) + " z: " + rtos(sphere_motion[2])); + } + return false; + */ +} + +void SoftBodySpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + soft_body->pin_point_toggle(p_idx); + redraw(); +} + +bool SoftBodySpatialGizmo::is_gizmo_handle_highlighted(int idx) const { + return soft_body->is_point_pinned(idx); +} + +SoftBodySpatialGizmo::SoftBodySpatialGizmo(SoftBody *p_soft_physics_body) : + EditorSpatialGizmo(), + soft_body(p_soft_physics_body) { + set_spatial_node(p_soft_physics_body); +} + +SoftBodySpatialGizmo::~SoftBodySpatialGizmo() { + //if (!physics_sphere_shape.is_valid()) { + // PhysicsServer::get_singleton()->free(physics_sphere_shape); + //} +} + +/////////// + String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { Ref<Shape> s = cs->get_shape(); @@ -2443,8 +2542,8 @@ void CollisionShapeSpatialGizmo::redraw() { Vector<Vector3> points; points.resize(md.edges.size() * 2); for (int i = 0; i < md.edges.size(); i++) { - points[i * 2 + 0] = md.vertices[md.edges[i].a]; - points[i * 2 + 1] = md.vertices[md.edges[i].b]; + points.write[i * 2 + 0] = md.vertices[md.edges[i].a]; + points.write[i * 2 + 1] = md.vertices[md.edges[i].b]; } add_lines(points, material); @@ -4051,6 +4150,12 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return lsg; } + if (Object::cast_to<SoftBody>(p_spatial)) { + + Ref<SoftBodySpatialGizmo> misg = memnew(SoftBodySpatialGizmo(Object::cast_to<SoftBody>(p_spatial))); + return misg; + } + if (Object::cast_to<MeshInstance>(p_spatial)) { Ref<MeshInstanceSpatialGizmo> misg = memnew(MeshInstanceSpatialGizmo(Object::cast_to<MeshInstance>(p_spatial))); @@ -4081,6 +4186,7 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg; } */ + if (Object::cast_to<CollisionShape>(p_spatial)) { Ref<CollisionShapeSpatialGizmo> misg = memnew(CollisionShapeSpatialGizmo(Object::cast_to<CollisionShape>(p_spatial))); diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 924f82dc16..198d028516 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -331,6 +331,23 @@ public: BakedIndirectLightGizmo(BakedLightmap *p_baker = NULL); }; +class SoftBodySpatialGizmo : public EditorSpatialGizmo { + GDCLASS(SoftBodySpatialGizmo, EditorSpatialGizmo); + + class SoftBody *soft_body; + //RID physics_sphere_shape; // Used for raycast that doesn't work, in this moment, with softbody + +public: + void redraw(); + virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); + virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel); + + virtual bool is_gizmo_handle_highlighted(int idx) const; + + SoftBodySpatialGizmo(SoftBody *p_soft_physics_body = NULL); + ~SoftBodySpatialGizmo(); +}; + class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo); diff --git a/editor/translations/af.po b/editor/translations/af.po index c5853bbb2f..d4c8bc26f4 100644 --- a/editor/translations/af.po +++ b/editor/translations/af.po @@ -7328,6 +7328,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ar.po b/editor/translations/ar.po index ccf2b97d9a..1535ccafb6 100644 --- a/editor/translations/ar.po +++ b/editor/translations/ar.po @@ -2,7 +2,6 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # Adel <dragonhunter250@gmail.com>, 2018. # athomield <athomield@hotmail.com>, 2017. # Basil Al-Khateeb <basil.y.alkhateeb@gmail.com>, 2017. @@ -15,13 +14,12 @@ # omar anwar aglan <omar.aglan91@yahoo.com>, 2017-2018. # OWs Tetra <owstetra@gmail.com>, 2017. # Rached Noureddine <rached.noureddine@gmail.com>, 2018. -# Rex_sa <asd1234567890m@gmail.com>, 2017. +# Rex_sa <asd1234567890m@gmail.com>, 2017, 2018. # Wajdi Feki <wajdi.feki@gmail.com>, 2017. -# msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-05-28 18:34+0000\n" +"PO-Revision-Date: 2018-07-15 19:34+0000\n" "Last-Translator: Rached Noureddine <rached.noureddine@gmail.com>\n" "Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/" "godot/ar/>\n" @@ -30,7 +28,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -4331,11 +4329,11 @@ msgstr "ولد رؤية AABB" #: editor/plugins/path_2d_editor_plugin.cpp msgid "Remove Point from Curve" -msgstr "" +msgstr "إزالة نقطة من المنحنى" #: editor/plugins/path_2d_editor_plugin.cpp msgid "Remove Out-Control from Curve" -msgstr "" +msgstr "أزل Out-Control من المنحنى" #: editor/plugins/path_2d_editor_plugin.cpp msgid "Remove In-Control from Curve" @@ -7392,6 +7390,11 @@ msgstr "بناء المشروع" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "إظهار الملفات" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" @@ -8076,7 +8079,7 @@ msgstr "" #: scene/resources/dynamic_font.cpp msgid "Invalid font size." -msgstr "" +msgstr "حجم الخط غير صالح" #~ msgid "Next" #~ msgstr "التالي" diff --git a/editor/translations/bg.po b/editor/translations/bg.po index 9f366b3d2f..71b9216b46 100644 --- a/editor/translations/bg.po +++ b/editor/translations/bg.po @@ -7383,6 +7383,11 @@ msgstr "Проект" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Преглед на файловете" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/bn.po b/editor/translations/bn.po index 3d00e3450c..aa36beefb6 100644 --- a/editor/translations/bn.po +++ b/editor/translations/bn.po @@ -7773,6 +7773,11 @@ msgstr "নতুন প্রকল্প" msgid "Warnings" msgstr "সতর্কতা" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "ফাইল" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ca.po b/editor/translations/ca.po index d2bffb0f84..085241296e 100644 --- a/editor/translations/ca.po +++ b/editor/translations/ca.po @@ -7438,6 +7438,11 @@ msgstr "Munta el Projecte" msgid "Warnings" msgstr "Avisos" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Visualitza Fitxers" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Final de la traça de la pila d'excepció interna" diff --git a/editor/translations/cs.po b/editor/translations/cs.po index 1066bbad94..b4cf176796 100644 --- a/editor/translations/cs.po +++ b/editor/translations/cs.po @@ -7372,6 +7372,11 @@ msgstr "Sestavit projekt" msgid "Warnings" msgstr "Varování" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Zobrazit soubory" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/da.po b/editor/translations/da.po index 3b5854334a..fcfdb6d249 100644 --- a/editor/translations/da.po +++ b/editor/translations/da.po @@ -7445,6 +7445,11 @@ msgstr "Projekt" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Vis filer" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/de.po b/editor/translations/de.po index d5d63f654b..c61d78e37e 100644 --- a/editor/translations/de.po +++ b/editor/translations/de.po @@ -27,12 +27,15 @@ # Tim Schellenberg <smwleod@gmail.com>, 2017. # Timo Schwarzer <account@timoschwarzer.com>, 2016-2018. # viernullvier <hannes.breul+github@gmail.com>, 2016. +# Arndt Heuvel <codeforpb@schatzkarten.net>, 2018. +# Gordon <gkone@gmx.net>, 2018. +# chillhelm <wilhelm@neubert.online>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-06-19 19:38+0000\n" -"Last-Translator: nimradium <nimra242001@gmail.com>\n" +"PO-Revision-Date: 2018-07-05 12:38+0000\n" +"Last-Translator: So Wieso <sowieso@dukun.de>\n" "Language-Team: German <https://hosted.weblate.org/projects/godot-engine/" "godot/de/>\n" "Language: de\n" @@ -40,7 +43,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0.1\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -331,8 +334,7 @@ msgstr "Optimieren" #: editor/animation_editor.cpp msgid "Select an AnimationPlayer from the Scene Tree to edit animations." msgstr "" -"Wählen Sie einen AnimationPlayer aus dem Szenenbaum aus, um Animationen zu " -"bearbeiten." +"AnimationPlayer aus dem Szenenbaum auswählen um Animationen zu bearbeiten." #: editor/animation_editor.cpp msgid "Key" @@ -1948,7 +1950,7 @@ msgstr "Umwandeln zu..." #: editor/editor_node.cpp msgid "MeshLibrary..." -msgstr "MeshLibrary..." +msgstr "Mesh-Bibliothek..." #: editor/editor_node.cpp msgid "TileSet..." @@ -2483,7 +2485,7 @@ msgstr "Mirrors werden geladen, bitte warten..." #: editor/export_template_manager.cpp msgid "Remove template version '%s'?" -msgstr "Template-Version '%s' entfernen?" +msgstr "Template-Version ‚%s‘ entfernen?" #: editor/export_template_manager.cpp msgid "Can't open export templates zip." @@ -6048,8 +6050,8 @@ msgid "" "Couldn't load project.godot in project path (error %d). It may be missing or " "corrupted." msgstr "" -"Konnte project.godot im Projektpfad nicht laden (Fehler %d). Sie könnte " -"fehlen oder beschädigt worden sein." +"Die Datei project.godot im Projektpfad konnte nicht geladen werden (Fehler " +"%d). Sie könnte fehlen oder beschädigt sein." #: editor/project_manager.cpp msgid "Couldn't edit project.godot in project path." @@ -7490,6 +7492,11 @@ msgstr "Projekt bauen" msgid "Warnings" msgstr "Warnungen" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Dateien anzeigen" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Ende des inneren Exception-Stack-Traces" diff --git a/editor/translations/de_CH.po b/editor/translations/de_CH.po index 26f824bc4b..7d11a9d09f 100644 --- a/editor/translations/de_CH.po +++ b/editor/translations/de_CH.po @@ -7424,6 +7424,11 @@ msgstr "Projektname:" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Datei(en) öffnen" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 1cb31e0ee9..d0f1d04a10 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -7265,6 +7265,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/el.po b/editor/translations/el.po index b3275b4647..4a9560e602 100644 --- a/editor/translations/el.po +++ b/editor/translations/el.po @@ -2,13 +2,11 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # George Tsiamasiotis <gtsiam@windowslive.com>, 2017-2018. -# msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-05-20 09:37+0000\n" +"PO-Revision-Date: 2018-07-21 22:38+0000\n" "Last-Translator: George Tsiamasiotis <gtsiam@windowslive.com>\n" "Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/" "el/>\n" @@ -16,7 +14,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -1135,7 +1133,7 @@ msgstr "Εμφάνιση στη διαχείριση αρχείων" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "New Folder..." -msgstr "Νέος φάκελος" +msgstr "Νέος φάκελος..." #: editor/editor_file_dialog.cpp msgid "Refresh" @@ -2698,7 +2696,7 @@ msgstr "Μετονομασία..." #: editor/filesystem_dock.cpp msgid "Move To..." -msgstr "Μετακίνηση σε" +msgstr "Μετακίνηση σε..." #: editor/filesystem_dock.cpp msgid "Open Scene(s)" @@ -2710,15 +2708,15 @@ msgstr "Στιγμιότυπο" #: editor/filesystem_dock.cpp msgid "Edit Dependencies..." -msgstr "Επεξεργασία εξαρτήσεων" +msgstr "Επεξεργασία εξαρτήσεων..." #: editor/filesystem_dock.cpp msgid "View Owners..." -msgstr "Προβολή ιδιοκτητών" +msgstr "Προβολή ιδιοκτητών..." #: editor/filesystem_dock.cpp msgid "Duplicate..." -msgstr "Αναπαραγωγή" +msgstr "Αναπαραγωγή..." #: editor/filesystem_dock.cpp msgid "Previous Directory" @@ -4031,7 +4029,7 @@ msgstr "Δημιουργία περιγράμματος" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh" -msgstr "Πλέγμα" +msgstr "Πλέγμα..." #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Trimesh Static Body" @@ -5712,9 +5710,8 @@ msgid "Options" msgstr "Επιλογές" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Has,Many,Options" -msgstr "Έχει,Πάρα,Πολλές,Επιλογές!" +msgstr "Έχει,Πολλές,Επιλογές" #: editor/plugins/theme_editor_plugin.cpp msgid "Tab 1" @@ -6001,9 +5998,8 @@ msgid "Imported Project" msgstr "Εισαγμένο έργο" #: editor/project_manager.cpp -#, fuzzy msgid "Invalid Project Name." -msgstr "Όνομα έργου:" +msgstr "Άκυρο όνομα έργου." #: editor/project_manager.cpp msgid "Couldn't create folder." @@ -6207,13 +6203,12 @@ msgid "Mouse Button" msgstr "Κουμπί ποντικιού" #: editor/project_settings_editor.cpp -#, fuzzy msgid "" "Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or " "'\"'." msgstr "" "Άκυρο όνομα ενέργειας. Δεν μπορεί να είναι άδειο ή να περιέχει '/', ':', " -"'=', '\\' ή '\"'" +"'=', '\\' ή '\"'." #: editor/project_settings_editor.cpp msgid "Action '%s' already exists!" @@ -7474,6 +7469,11 @@ msgstr "Δόμηση έργου" msgid "Warnings" msgstr "Προειδοποιήσεις" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Προβολή αρχείων" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Τέλος ιχνηλάτησης στοίβας εσωτερικής εξαίρεσης" diff --git a/editor/translations/es.po b/editor/translations/es.po index 89118d2501..8e1f0b13c9 100644 --- a/editor/translations/es.po +++ b/editor/translations/es.po @@ -29,12 +29,13 @@ # Swyter <swyterzone@gmail.com>, 2016-2017. # Vazquinhos <vazquinhos@gmail.com>, 2018. # Yovani Damián <blackblex@gmail.com>, 2018. +# Andrus Diaz German <andrusdiazaleman@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-06-22 08:31+0000\n" -"Last-Translator: R. Joshua Seville <rjoshua@protonmail.com>\n" +"PO-Revision-Date: 2018-07-20 16:43+0000\n" +"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/" "godot/es/>\n" "Language: es\n" @@ -54,19 +55,19 @@ msgstr "Toda la Selección" #: editor/animation_editor.cpp msgid "Anim Change Keyframe Time" -msgstr "Cambiar el tiempo del Fotograma Clave de Animación" +msgstr "Cambiar el Tiempo del Fotograma Clave de Animación" #: editor/animation_editor.cpp msgid "Anim Change Transition" -msgstr "Cambiar Transición de Animación" +msgstr "Cambiar la Transición de Animación" #: editor/animation_editor.cpp msgid "Anim Change Transform" -msgstr "Cambiar transformación de animación" +msgstr "Cambiar la Transformación de la Animación" #: editor/animation_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "Cambiar valor del Fotograma Clave de Animación" +msgstr "Cambiar valor de la Clave de Animación" #: editor/animation_editor.cpp msgid "Anim Change Call" @@ -114,7 +115,7 @@ msgstr "Cambiar Modo de Ciclo de Pista de Animación" #: editor/animation_editor.cpp msgid "Edit Node Curve" -msgstr "Editar Nodo de Curva" +msgstr "Editar Curva del Nodo" #: editor/animation_editor.cpp msgid "Edit Selection Curve" @@ -163,7 +164,7 @@ msgstr "Escalar Selección" #: editor/animation_editor.cpp msgid "Scale From Cursor" -msgstr "Escalar desde cursor" +msgstr "Escalar Desde Cursor" #: editor/animation_editor.cpp msgid "Goto Next Step" @@ -212,11 +213,11 @@ msgstr "Limpiar Animación" #: editor/animation_editor.cpp msgid "Create NEW track for %s and insert key?" -msgstr "¿Quieres crear una NUEVA pista para %s e insertar clave?" +msgstr "¿Crear NUEVA pista para %s e insertar clave?" #: editor/animation_editor.cpp msgid "Create %d NEW tracks and insert keys?" -msgstr "¿Quieres crear %d NUEVAS pistas e insertar claves?" +msgstr "¿Crear %d NUEVAS pistas e insertar claves?" #: editor/animation_editor.cpp editor/create_dialog.cpp #: editor/editor_audio_buses.cpp editor/plugins/abstract_polygon_2d_editor.cpp @@ -288,7 +289,7 @@ msgstr "Activar/Desactivar Bucle de Animación." #: editor/animation_editor.cpp msgid "Add new tracks." -msgstr "Añadir Nuevas Pistas." +msgstr "Añadir nuevas pistas." #: editor/animation_editor.cpp msgid "Move current track up." @@ -308,7 +309,7 @@ msgstr "Herramientas de pistas" #: editor/animation_editor.cpp msgid "Enable editing of individual keys by clicking them." -msgstr "Habilitar la edición de claves individuales al hacer clic." +msgstr "Habilitar la edición de claves individuales haciendo clic en ellas." #: editor/animation_editor.cpp msgid "Anim. Optimizer" @@ -366,7 +367,7 @@ msgstr "Limpiar todas las animaciones" #: editor/animation_editor.cpp msgid "Clean-Up Animation(s) (NO UNDO!)" -msgstr "Limpiar todas las animaciones (IRREVERSIBLE)" +msgstr "Limpiar las Animación(es) (¡IRREVERSIBLE!)" #: editor/animation_editor.cpp msgid "Clean-Up" @@ -374,39 +375,39 @@ msgstr "Limpiar" #: editor/array_property_edit.cpp msgid "Resize Array" -msgstr "Redimensionar «array»" +msgstr "Redimensionar Array" #: editor/array_property_edit.cpp msgid "Change Array Value Type" -msgstr "Cambiar tipo de valor del «array»" +msgstr "Cambiar Tipo de Valor del Array" #: editor/array_property_edit.cpp msgid "Change Array Value" -msgstr "Cambiar valor del «array»" +msgstr "Cambiar Valor del Array" #: editor/code_editor.cpp msgid "Go to Line" -msgstr "Ir a línea" +msgstr "Ir a Línea" #: editor/code_editor.cpp msgid "Line Number:" -msgstr "Número de línea:" +msgstr "Número de Línea:" #: editor/code_editor.cpp msgid "No Matches" -msgstr "Sin coincidencias" +msgstr "Sin Coincidencias" #: editor/code_editor.cpp msgid "Replaced %d occurrence(s)." -msgstr "%d ocurrencia/s reemplazadas." +msgstr "%d Ocurrencia(s) Reemplazada(s)." #: editor/code_editor.cpp msgid "Match Case" -msgstr "Coincidir mayús/minúsculas" +msgstr "Coincidir Mayús/Minúsculas" #: editor/code_editor.cpp msgid "Whole Words" -msgstr "Palabras completas" +msgstr "Palabras Completas" #: editor/code_editor.cpp msgid "Replace" @@ -414,11 +415,11 @@ msgstr "Reemplazar" #: editor/code_editor.cpp msgid "Replace All" -msgstr "Reemplazar todo" +msgstr "Reemplazar Todo" #: editor/code_editor.cpp msgid "Selection Only" -msgstr "Sólo selección" +msgstr "Sólo Selección" #: editor/code_editor.cpp msgid "Zoom In" @@ -430,7 +431,7 @@ msgstr "Alejar" #: editor/code_editor.cpp msgid "Reset Zoom" -msgstr "Restablecer zoom" +msgstr "Restablecer Zoom" #: editor/code_editor.cpp editor/script_editor_debugger.cpp msgid "Line:" @@ -449,8 +450,8 @@ msgid "" "Target method not found! Specify a valid method or attach a script to target " "Node." msgstr "" -"No se encontró el método del objetivo! Especifica un método válido o adjunta " -"un script al Nodo objetivo." +"¡Método objetivo no encontrado! Especifica un método válido o añade un " +"script al Nodo objetivo." #: editor/connections_dialog.cpp msgid "Connect To Node:" @@ -471,11 +472,11 @@ msgstr "Quitar" #: editor/connections_dialog.cpp msgid "Add Extra Call Argument:" -msgstr "Añadir argumento extra de llamada:" +msgstr "Añadir Argumento Extra de Llamada:" #: editor/connections_dialog.cpp msgid "Extra Call Arguments:" -msgstr "Argumentos extras de llamada:" +msgstr "Argumentos Extras de Llamada:" #: editor/connections_dialog.cpp msgid "Path to Node:" @@ -483,7 +484,7 @@ msgstr "Ruta al Nodo:" #: editor/connections_dialog.cpp msgid "Make Function" -msgstr "Crear función" +msgstr "Crear Función" #: editor/connections_dialog.cpp msgid "Deferred" @@ -538,7 +539,7 @@ msgstr "Señales" #: editor/create_dialog.cpp msgid "Change %s Type" -msgstr "Cambiar el tipo de %s" +msgstr "Cambiar el Tipo de %s" #: editor/create_dialog.cpp editor/project_settings_editor.cpp #: modules/visual_script/visual_script_editor.cpp @@ -579,11 +580,11 @@ msgstr "Descripción:" #: editor/dependency_editor.cpp msgid "Search Replacement For:" -msgstr "Buscar reemplazo para:" +msgstr "Buscar Reemplazo Para:" #: editor/dependency_editor.cpp msgid "Dependencies For:" -msgstr "Dependencias para:" +msgstr "Dependencias Para:" #: editor/dependency_editor.cpp msgid "" @@ -622,7 +623,7 @@ msgstr "Dependencias:" #: editor/dependency_editor.cpp msgid "Fix Broken" -msgstr "Arreglar rota(s)" +msgstr "Arreglar Rota(s)" #: editor/dependency_editor.cpp msgid "Dependency Editor" @@ -630,7 +631,7 @@ msgstr "Editor de Dependencias" #: editor/dependency_editor.cpp msgid "Search Replacement Resource:" -msgstr "Buscar recurso de reemplazo:" +msgstr "Buscar Recurso de Reemplazo:" #: editor/dependency_editor.cpp editor/editor_file_dialog.cpp #: editor/editor_help.cpp editor/editor_node.cpp editor/filesystem_dock.cpp @@ -641,13 +642,11 @@ msgstr "Abrir" #: editor/dependency_editor.cpp msgid "Owners Of:" -msgstr "Dueños de:" +msgstr "Dueños De:" #: editor/dependency_editor.cpp msgid "Remove selected files from the project? (no undo)" -msgstr "" -"¿Quieres quitar los archivos seleccionados del proyecto? (No puedes " -"deshacerlo)" +msgstr "¿Quitar los archivos seleccionados del proyecto? (irreversible)" #: editor/dependency_editor.cpp msgid "" @@ -657,7 +656,7 @@ msgid "" msgstr "" "Otros recursos necesitan los archivos que estás intentando quitar para " "funcionar.\n" -"¿Seguro que quieres quitarlos? (No puedes deshacerlo)" +"¿Quitarlos de todos modos? (irreversible)" #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -673,7 +672,7 @@ msgstr "La escena no se pudo cargar porque faltan las siguientes dependencias:" #: editor/dependency_editor.cpp editor/editor_node.cpp msgid "Open Anyway" -msgstr "Abrir de todos modos" +msgstr "Abrir de Todos Modos" #: editor/dependency_editor.cpp msgid "Which action should be taken?" @@ -689,23 +688,23 @@ msgstr "¡Hubo errores al cargar!" #: editor/dependency_editor.cpp msgid "Permanently delete %d item(s)? (No undo!)" -msgstr "¿Quieres eliminar permanentemente %d elementos? (Irreversible)" +msgstr "¿Eliminar permanentemente %d elemento(s)? (¡Irreversible!)" #: editor/dependency_editor.cpp msgid "Owns" -msgstr "Es dueño de" +msgstr "Dueño de" #: editor/dependency_editor.cpp msgid "Resources Without Explicit Ownership:" -msgstr "Recursos sin propietario explícito:" +msgstr "Recursos Sin Propietario Explícito:" #: editor/dependency_editor.cpp editor/editor_node.cpp msgid "Orphan Resource Explorer" -msgstr "Explorador de recursos huérfanos" +msgstr "Explorador de Recursos Huérfanos" #: editor/dependency_editor.cpp msgid "Delete selected files?" -msgstr "¿Quieres eliminar los archivos seleccionados?" +msgstr "¿Eliminar los archivos seleccionados?" #: editor/dependency_editor.cpp editor/editor_audio_buses.cpp #: editor/editor_file_dialog.cpp editor/editor_node.cpp @@ -745,7 +744,7 @@ msgstr "Desarrollador Principal" #: editor/editor_about.cpp msgid "Project Manager " -msgstr "Administrador de proyectos " +msgstr "Administrador de Proyectos " #: editor/editor_about.cpp msgid "Developers" @@ -757,11 +756,11 @@ msgstr "Autores" #: editor/editor_about.cpp msgid "Platinum Sponsors" -msgstr "Patrocinadores Platinum" +msgstr "Patrocinadores de Platino" #: editor/editor_about.cpp msgid "Gold Sponsors" -msgstr "Patrocinadores Gold" +msgstr "Patrocinadores de Oro" #: editor/editor_about.cpp msgid "Mini Sponsors" @@ -769,11 +768,11 @@ msgstr "Mini Patrocinadores" #: editor/editor_about.cpp msgid "Gold Donors" -msgstr "Donantes Gold" +msgstr "Donantes de Oro" #: editor/editor_about.cpp msgid "Silver Donors" -msgstr "Donantes Silver" +msgstr "Donantes de Plata" #: editor/editor_about.cpp msgid "Bronze Donors" @@ -825,7 +824,7 @@ msgstr "Descomprimiendo Assets" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Package Installed Successfully!" -msgstr "¡El paquete se ha instalado correctamente!" +msgstr "¡Paquete Instalado Exitosamente!" #: editor/editor_asset_installer.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -859,19 +858,19 @@ msgstr "Cambiar Volumen de Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Solo" -msgstr "Act./Desact. Solo de Bus de Audio" +msgstr "Alternar Solo de Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Mute" -msgstr "Alternar Mute del Bus de Audio" +msgstr "Alternar Silencio de Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Toggle Audio Bus Bypass Effects" -msgstr "Alternar puenteado de efectos en Bus de Audio" +msgstr "Alternar Puenteado de Efectos de Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Select Audio Bus Send" -msgstr "Seleccionar Envío de Audio Bus" +msgstr "Seleccionar Envío de Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus Effect" @@ -928,7 +927,7 @@ msgstr "Añadir Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Master bus can't be deleted!" -msgstr "¡No se puede borrar el Bus Maestro!" +msgstr "¡No se puede borrar el bus maestro!" #: editor/editor_audio_buses.cpp msgid "Delete Audio Bus" @@ -940,7 +939,7 @@ msgstr "Duplicar Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Reset Bus Volume" -msgstr "Restablecer Volumen del Bus" +msgstr "Restablecer Volumen de Bus" #: editor/editor_audio_buses.cpp msgid "Move Audio Bus" @@ -948,7 +947,7 @@ msgstr "Mover Bus de Audio" #: editor/editor_audio_buses.cpp msgid "Save Audio Bus Layout As..." -msgstr "Guardar configuración de los Buses de Audio como..." +msgstr "Guardar Configuración de Bus de Audio Como..." #: editor/editor_audio_buses.cpp msgid "Location for New Layout..." @@ -956,7 +955,7 @@ msgstr "Ubicación para Nueva Configuración..." #: editor/editor_audio_buses.cpp msgid "Open Audio Bus Layout" -msgstr "Abrir configuración de Bus de Audio" +msgstr "Abrir Configuración de Bus de Audio" #: editor/editor_audio_buses.cpp msgid "There is no 'res://default_bus_layout.tres' file." @@ -1002,7 +1001,7 @@ msgstr "Cargar configuración de Bus por defecto." #: editor/editor_autoload_settings.cpp msgid "Invalid name." -msgstr "El nombre no es correcto." +msgstr "Nombre inválido." #: editor/editor_autoload_settings.cpp msgid "Valid characters:" @@ -1011,24 +1010,24 @@ msgstr "Letras válidas:" #: editor/editor_autoload_settings.cpp msgid "Invalid name. Must not collide with an existing engine class name." msgstr "" -"El nombre no es correcto. No puede coincidir con el nombre de una clase que " -"ya exista en el motor gráfico." +"Nombre inválido. No debe coincidir con el nombre de una clase que ya exista " +"en el motor gráfico." #: editor/editor_autoload_settings.cpp msgid "Invalid name. Must not collide with an existing buit-in type name." msgstr "" -"El nombre no es correcto. No puede coincidir con un nombre de tipo que ya " -"esté integrado en el motor gráfico." +"Nombre inválido. No debe coincidir con un nombre de tipo que ya esté " +"integrado en el motor gráfico." #: editor/editor_autoload_settings.cpp msgid "Invalid name. Must not collide with an existing global constant name." msgstr "" -"El nombre no es correcto. No puede coincidir con un nombre de constante " -"global ya existente en el motor gráfico." +"Nombre inválido. No debe coincidir con un nombre de constante global ya " +"existente en el motor gráfico." #: editor/editor_autoload_settings.cpp msgid "Invalid Path." -msgstr "Ruta incorrecta." +msgstr "Ruta Inválida." #: editor/editor_autoload_settings.cpp msgid "File does not exist." @@ -1052,7 +1051,7 @@ msgstr "Renombrar Autoload" #: editor/editor_autoload_settings.cpp msgid "Toggle AutoLoad Globals" -msgstr "Des/Activar Globales de Autoload" +msgstr "Alternar Globales de Autoload" #: editor/editor_autoload_settings.cpp msgid "Move Autoload" @@ -1106,7 +1105,7 @@ msgstr "[vacío]" #: editor/editor_data.cpp msgid "[unsaved]" -msgstr "[no guardado]" +msgstr "[sin guardar]" #: editor/editor_dir_dialog.cpp msgid "Please select a base directory first" @@ -1114,12 +1113,12 @@ msgstr "Por favor, selecciona primero un directorio base" #: editor/editor_dir_dialog.cpp msgid "Choose a Directory" -msgstr "Elige una carpeta" +msgstr "Elige un Directorio" #: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp #: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp msgid "Create Folder" -msgstr "Crear carpeta" +msgstr "Crear Carpeta" #: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp #: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp @@ -1139,7 +1138,7 @@ msgstr "Elegir" #: editor/editor_export.cpp msgid "Storing File:" -msgstr "Archivo de almacenamiento:" +msgstr "Archivo de Almacenamiento:" #: editor/editor_export.cpp msgid "Packing" @@ -1147,11 +1146,11 @@ msgstr "Empaquetando" #: editor/editor_export.cpp platform/javascript/export/export.cpp msgid "Template file not found:" -msgstr "No se encontró archivo de plantilla:" +msgstr "Archivo de plantilla no encontrado:" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "File Exists, Overwrite?" -msgstr "El archivo ya existe, ¿quieres sobreescribirlo?" +msgstr "El Archivo ya Existe, ¿Quieres Sobreescribirlo?" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Select Current Folder" @@ -1159,15 +1158,15 @@ msgstr "Seleccionar Carpeta Actual" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Copy Path" -msgstr "Copiar ruta" +msgstr "Copiar Ruta" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Show In File Manager" -msgstr "Mostrar en el navegador de archivos" +msgstr "Mostrar en el Navegador de Archivos" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "New Folder..." -msgstr "Nueva carpeta..." +msgstr "Nueva Carpeta..." #: editor/editor_file_dialog.cpp msgid "Refresh" @@ -1183,19 +1182,19 @@ msgstr "Todos los archivos (*)" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Open a File" -msgstr "Abrir un archivo" +msgstr "Abrir un Archivo" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Open File(s)" -msgstr "Abrir archivo/s" +msgstr "Abrir Archivo(s)" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Open a Directory" -msgstr "Abrir una carpeta" +msgstr "Abrir un Directorio" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Open a File or Directory" -msgstr "Abrir un archivo o carpeta" +msgstr "Abrir un Archivo o Directorio" #: editor/editor_file_dialog.cpp editor/editor_node.cpp #: editor/plugins/animation_player_editor_plugin.cpp @@ -1205,7 +1204,7 @@ msgstr "Guardar" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Save a File" -msgstr "Guardar un archivo" +msgstr "Guardar un Archivo" #: editor/editor_file_dialog.cpp msgid "Go Back" @@ -1221,27 +1220,27 @@ msgstr "Subir" #: editor/editor_file_dialog.cpp msgid "Toggle Hidden Files" -msgstr "Ver/ocultar archivos ocultos" +msgstr "Ver/ocultar Archivos Ocultos" #: editor/editor_file_dialog.cpp msgid "Toggle Favorite" -msgstr "Añadir/quitar favorito" +msgstr "Añadir/quitar Favorito" #: editor/editor_file_dialog.cpp msgid "Toggle Mode" -msgstr "Cambiar modo" +msgstr "Cambiar Modo" #: editor/editor_file_dialog.cpp msgid "Focus Path" -msgstr "Seleccionar ruta" +msgstr "Seleccionar Ruta" #: editor/editor_file_dialog.cpp msgid "Move Favorite Up" -msgstr "Subir favorito" +msgstr "Subir Favorito" #: editor/editor_file_dialog.cpp msgid "Move Favorite Down" -msgstr "Bajar favorito" +msgstr "Bajar Favorito" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Go to parent folder" @@ -1249,7 +1248,7 @@ msgstr "Ir a la carpeta principal" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Directories & Files:" -msgstr "Carpetas y archivos:" +msgstr "Directorios y Archivos:" #: editor/editor_file_dialog.cpp msgid "Preview:" @@ -1266,7 +1265,7 @@ msgstr "Debe tener una extensión válida." #: editor/editor_file_system.cpp msgid "ScanSources" -msgstr "Analizando fuentes" +msgstr "Analizando Fuentes" #: editor/editor_file_system.cpp msgid "(Re)Importing Assets" @@ -1275,15 +1274,15 @@ msgstr "(Re)Importando Assets" #: editor/editor_help.cpp editor/editor_node.cpp #: editor/plugins/script_editor_plugin.cpp msgid "Search Help" -msgstr "Ayuda de búsqueda" +msgstr "Ayuda de Búsqueda" #: editor/editor_help.cpp msgid "Class List:" -msgstr "Lista de clases:" +msgstr "Lista de Clases:" #: editor/editor_help.cpp msgid "Search Classes" -msgstr "Buscar clases" +msgstr "Buscar Clases" #: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Top" @@ -1303,7 +1302,7 @@ msgstr "Heredada por:" #: editor/editor_help.cpp msgid "Brief Description:" -msgstr "Descripción breve:" +msgstr "Descripción Breve:" #: editor/editor_help.cpp msgid "Members" @@ -1323,11 +1322,11 @@ msgstr "Métodos públicos:" #: editor/editor_help.cpp msgid "GUI Theme Items" -msgstr "Elementos del Tema de GUI" +msgstr "Elementos del Tema de Interfaz" #: editor/editor_help.cpp msgid "GUI Theme Items:" -msgstr "Elementos de tema de interfaz:" +msgstr "Elementos del Tema de Interfaz:" #: editor/editor_help.cpp modules/visual_script/visual_script_editor.cpp msgid "Signals:" @@ -1359,7 +1358,7 @@ msgstr "Descripción" #: editor/editor_help.cpp msgid "Online Tutorials:" -msgstr "Tutoriales en línea:" +msgstr "Tutoriales en Línea:" #: editor/editor_help.cpp msgid "" @@ -1367,8 +1366,8 @@ msgid "" "$url]contribute one[/url][/color] or [color=$color][url=$url2]request one[/" "url][/color]." msgstr "" -"De momento no hay tutoriales para esta clase, puedes [color=$color][url=" -"$url]añadir uno[/url][/color] o [color=$color][url=$url2]pedir uno[color=" +"Actualmente no hay tutoriales para esta clase, puedes [color=$color][url=" +"$url]aportar uno[/url][/color] o [color=$color][url=$url2]pedir uno[color=" "$color][url=$url2]." #: editor/editor_help.cpp @@ -1393,7 +1392,7 @@ msgstr "Métodos" #: editor/editor_help.cpp msgid "Method Description:" -msgstr "Descripción de métodos:" +msgstr "Descripción del Método:" #: editor/editor_help.cpp msgid "" @@ -1405,11 +1404,11 @@ msgstr "" #: editor/editor_help.cpp msgid "Search Text" -msgstr "Texto de búsqueda" +msgstr "Texto de Búsqueda" #: editor/editor_help.cpp msgid "Find" -msgstr "Búsqueda" +msgstr "Buscar" #: editor/editor_log.cpp msgid "Output:" @@ -1420,11 +1419,11 @@ msgstr "Salida:" #: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp #: scene/gui/text_edit.cpp msgid "Clear" -msgstr "Borrar todo" +msgstr "Borrar Todo" #: editor/editor_log.cpp msgid "Clear Output" -msgstr "Borrar salida" +msgstr "Borrar Salida" #: editor/editor_node.cpp msgid "Project export failed with error code %d." @@ -1432,7 +1431,7 @@ msgstr "La exportación del proyecto falló con el código de error %d." #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Error saving resource!" -msgstr "¡Hubo un error al guardar el recurso!" +msgstr "¡Error al guardar el recurso!" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Save Resource As..." @@ -1485,7 +1484,7 @@ msgstr "Analizando" #: editor/editor_node.cpp msgid "Creating Thumbnail" -msgstr "Creando miniatura" +msgstr "Creando Miniatura" #: editor/editor_node.cpp msgid "This operation can't be done without a tree root." @@ -1501,7 +1500,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Failed to load resource." -msgstr "Hubo un problema al cargar el recurso." +msgstr "Error al cargar el recurso." #: editor/editor_node.cpp msgid "Can't load MeshLibrary for merging!" @@ -1529,7 +1528,7 @@ msgstr "Se han sobrescrito los ajustes predeterminados del editor." #: editor/editor_node.cpp msgid "Layout name not found!" -msgstr "¡No se encuentra el nombre del ajuste!" +msgstr "¡Nombre del ajuste no encontrado!" #: editor/editor_node.cpp msgid "Restored default layout to base settings." @@ -1594,23 +1593,23 @@ msgstr "Ocultar todas las propiedades" #: editor/editor_node.cpp msgid "Copy Params" -msgstr "Copiar parámetros" +msgstr "Copiar Parámetros" #: editor/editor_node.cpp msgid "Paste Params" -msgstr "Pegar parámetros" +msgstr "Pegar Parámetros" #: editor/editor_node.cpp editor/plugins/resource_preloader_editor_plugin.cpp msgid "Paste Resource" -msgstr "Pegar recurso" +msgstr "Pegar Recurso" #: editor/editor_node.cpp msgid "Copy Resource" -msgstr "Copiar recurso" +msgstr "Copiar Recurso" #: editor/editor_node.cpp msgid "Make Built-In" -msgstr "Convertirlo en integrado" +msgstr "Convertirlo en Integrado" #: editor/editor_node.cpp msgid "Make Sub-Resources Unique" @@ -1618,7 +1617,7 @@ msgstr "Creación de Subrecursos Únicos" #: editor/editor_node.cpp msgid "Open in Help" -msgstr "Abrir en la ayuda" +msgstr "Abrir en la Ayuda" #: editor/editor_node.cpp msgid "There is no defined scene to run." @@ -1711,11 +1710,11 @@ msgstr "Esta operación no puede realizarse sin una escena." #: editor/editor_node.cpp msgid "Export Mesh Library" -msgstr "Exportar biblioteca de mallas" +msgstr "Exportar Librería de Mallas" #: editor/editor_node.cpp msgid "This operation can't be done without a root node." -msgstr "Esta operación no puede realizarse sin un Nodo Raíz." +msgstr "Esta operación no puede realizarse sin un nodo raíz." #: editor/editor_node.cpp msgid "Export Tile Set" @@ -1727,7 +1726,7 @@ msgstr "Esta operación no puede realizarse sin un nodo seleccionado." #: editor/editor_node.cpp msgid "Current scene not saved. Open anyway?" -msgstr "La escena actual no se ha guardado. ¿Quieres abrirla de todos modos?" +msgstr "Escena actual no guardada ¿Abrir de todos modos?" #: editor/editor_node.cpp msgid "Can't reload a scene that was never saved." @@ -2320,7 +2319,7 @@ msgstr "Abrir Editor anterior" #: editor/editor_plugin.cpp msgid "Creating Mesh Previews" -msgstr "Creando vistas previas de las mallas" +msgstr "Creación de Vistas Previas de Malla" #: editor/editor_plugin.cpp msgid "Thumbnail..." @@ -2851,7 +2850,7 @@ msgstr "Generando \"Lightmaps\"" #: editor/import/resource_importer_scene.cpp msgid "Generating for Mesh: " -msgstr "Generando para modelo: " +msgstr "Generando para Malla: " #: editor/import/resource_importer_scene.cpp msgid "Running Custom Script..." @@ -3122,7 +3121,7 @@ msgstr "Posterior" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Depth" -msgstr "Profundidad" +msgstr "Depth" #: editor/plugins/animation_player_editor_plugin.cpp msgid "1 step" @@ -3996,7 +3995,7 @@ msgstr "Clic derecho: Borrar punto." #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh is empty!" -msgstr "¡La malla está vacía!" +msgstr "¡La Malla está vacía!" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Static Trimesh Body" @@ -4020,11 +4019,11 @@ msgstr "Crear forma convexa" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Navigation Mesh" -msgstr "Crear malla de navegación" +msgstr "Crear Malla de Navegación" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Contained Mesh is not of type ArrayMesh." -msgstr "La malla que contiene no es del tipo ArrayMesh." +msgstr "La Malla contenedora no es del tipo ArrayMesh." #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "UV Unwrap failed, mesh may not be manifold?" @@ -4042,7 +4041,7 @@ msgstr "El modelo no tiene UV en esta capa" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "MeshInstance lacks a Mesh!" -msgstr "¡MeshInstance no tiene malla!" +msgstr "¡MeshInstance no tiene Malla!" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh has not surface to create outlines from!" @@ -4050,7 +4049,7 @@ msgstr "¡La malla no tiene superficie de la que crear contornos!" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!" -msgstr "El tipo de la malla primitiva no es PRIMITIVE_TRIANGLES!" +msgstr "¡El tipo primitivo de malla no es PRIMITIVE_TRIANGLES!" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Could not create outline!" @@ -4098,7 +4097,7 @@ msgstr "Desenvuelva UV2 para Lightmap/AO" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Outline Mesh" -msgstr "Crear contorno de malla" +msgstr "Crear Contorno de Malla" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Outline Size:" @@ -4107,12 +4106,14 @@ msgstr "Tamaño del contorno:" #: editor/plugins/multimesh_editor_plugin.cpp msgid "No mesh source specified (and no MultiMesh set in node)." msgstr "" -"No se especificó malla de origen (y no hay MultiMesh establecido en el nodo)." +"No se ha especificado ninguna malla de origen (y no hay MultiMesh " +"establecido en el nodo)." #: editor/plugins/multimesh_editor_plugin.cpp msgid "No mesh source specified (and MultiMesh contains no Mesh)." msgstr "" -"No se especificó malla de origen (y MultiMesh no contiene ningún Mesh)." +"No se ha especificado ninguna malla de origen (y MultiMesh no contiene " +"ninguna Mesh)." #: editor/plugins/multimesh_editor_plugin.cpp msgid "Mesh source is invalid (invalid path)." @@ -4120,11 +4121,11 @@ msgstr "El origen de la malla es inválido (ruta inválida)." #: editor/plugins/multimesh_editor_plugin.cpp msgid "Mesh source is invalid (not a MeshInstance)." -msgstr "La malla elegida no es correcta (no es un MeshInstance)." +msgstr "El origen de la malla es inválido (no es un MeshInstance)." #: editor/plugins/multimesh_editor_plugin.cpp msgid "Mesh source is invalid (contains no Mesh resource)." -msgstr "La malla elegida no es correcta (no contiene ningún recurso Mesh)." +msgstr "El origen de la malla es inválido (no contiene ningún recurso Mesh)." #: editor/plugins/multimesh_editor_plugin.cpp msgid "No surface source specified." @@ -4152,7 +4153,7 @@ msgstr "No se pudo mapear el área." #: editor/plugins/multimesh_editor_plugin.cpp msgid "Select a Source Mesh:" -msgstr "Elige un origen de malla:" +msgstr "Elige un origen de Malla:" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Select a Target Surface:" @@ -4172,7 +4173,7 @@ msgstr "Superficie objetivo:" #: editor/plugins/multimesh_editor_plugin.cpp msgid "Source Mesh:" -msgstr "Modelo 3D elegido:" +msgstr "Malla de origen:" #: editor/plugins/multimesh_editor_plugin.cpp msgid "X-Axis" @@ -4212,11 +4213,11 @@ msgstr "¡Calcular!" #: editor/plugins/navigation_mesh_editor_plugin.cpp msgid "Bake the navigation mesh." -msgstr "Pre-calcular la malla de navegación 3D." +msgstr "Pre-calcular la malla de navegación." #: editor/plugins/navigation_mesh_editor_plugin.cpp msgid "Clear the navigation mesh." -msgstr "Vaciar malla de navegación 3D." +msgstr "Vaciar malla de navegación." #: editor/plugins/navigation_mesh_generator.cpp msgid "Setting up Configuration..." @@ -4501,7 +4502,7 @@ msgstr "Crear mapa UV" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Transform UV Map" -msgstr "Transformar mapa UV" +msgstr "Transformar Mapa UV" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Polygon 2D UV Editor" @@ -5416,11 +5417,11 @@ msgstr "Activar Vista Libre" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform" -msgstr "Transform" +msgstr "Transformar" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform Dialog..." -msgstr "Ventana de transformación..." +msgstr "Dialogo de Transformación..." #: editor/plugins/spatial_editor_plugin.cpp msgid "1 Viewport" @@ -5497,7 +5498,7 @@ msgstr "Profundidad máxima de vista:" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform Change" -msgstr "Transformar" +msgstr "Cambio de Transformación" #: editor/plugins/spatial_editor_plugin.cpp msgid "Translate:" @@ -6644,7 +6645,7 @@ msgstr "Reemparentar ubicación (selecciona un nuevo padre):" #: editor/reparent_dialog.cpp msgid "Keep Global Transform" -msgstr "Mantener transformación global" +msgstr "Mantener Transformación Global" #: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp msgid "Reparent" @@ -7498,6 +7499,11 @@ msgstr "Compilar Proyecto" msgid "Warnings" msgstr "Advertencias" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Ver Archivos" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Fin del reporte de la pila de excepciones" diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po index 64ee2404f1..bea184b813 100644 --- a/editor/translations/es_AR.po +++ b/editor/translations/es_AR.po @@ -7464,6 +7464,11 @@ msgstr "Construir Proyecto" msgid "Warnings" msgstr "Advertencias" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Ver Archivos" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Fin del stack trace de excepción interna" diff --git a/editor/translations/fa.po b/editor/translations/fa.po index f674ef99cc..eb192ececb 100644 --- a/editor/translations/fa.po +++ b/editor/translations/fa.po @@ -2,26 +2,25 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # alabd14313 <alabd14313@yahoo.com>, 2016. # Dante Marshal <Marshal.Devilhunter@gmail.com>, 2018. # hamed nasib <cghamed752@chmail.ir>, 2016. # Hasan Hejdari Nasab <hsn6@openmailbox.org>, 2017. # rezapouya <r.pouya@chmail.ir>, 2016. # sayyed hamed nasib <cghamed752@chmail.ir>, 2017. -# +# Behrooz Kashani <bkashani@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-04-29 05:39+0000\n" -"Last-Translator: Dante Marshal <Marshal.Devilhunter@gmail.com>\n" +"PO-Revision-Date: 2018-07-24 19:42+0000\n" +"Last-Translator: Behrooz Kashani <bkashani@gmail.com>\n" "Language-Team: Persian <https://hosted.weblate.org/projects/godot-engine/" "godot/fa/>\n" "Language: fa\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -636,9 +635,8 @@ msgstr "" "آیا در هر صورت حذف شوند؟(بدون برگشت)" #: editor/dependency_editor.cpp -#, fuzzy msgid "Cannot remove:" -msgstr "ناتوانی در حذف :" +msgstr "امکان حذف وجود ندارد :" #: editor/dependency_editor.cpp msgid "Error loading:" @@ -743,9 +741,8 @@ msgid "Gold Sponsors" msgstr "اسپانسرهای درجه ۲" #: editor/editor_about.cpp -#, fuzzy msgid "Mini Sponsors" -msgstr "اسپانسرهای دیگر" +msgstr "اسپانسرهای کوچک" #: editor/editor_about.cpp msgid "Gold Donors" @@ -789,7 +786,7 @@ msgstr "اجزا" #: editor/editor_about.cpp msgid "Licenses" -msgstr "" +msgstr "گواهینامه" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Error opening package file, not in zip format." @@ -7420,6 +7417,11 @@ msgstr "پروژه" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "نمایش پرونده ها" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/fi.po b/editor/translations/fi.po index f80efffd42..11f9bb51c7 100644 --- a/editor/translations/fi.po +++ b/editor/translations/fi.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-14 20:37+0000\n" +"PO-Revision-Date: 2018-07-19 10:36+0000\n" "Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n" "Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/" "godot/fi/>\n" @@ -20,7 +20,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0.1\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -2128,7 +2128,7 @@ msgstr "Käynnistä muokattavana oleva skene." #: editor/editor_node.cpp msgid "Play Scene" -msgstr "Toista skene" +msgstr "Pelaa skeneä" #: editor/editor_node.cpp msgid "Play custom scene" @@ -2414,7 +2414,7 @@ msgstr "Lataa uudelleen" #: editor/export_template_manager.cpp msgid "Uninstall" -msgstr "Poista" +msgstr "Poista asennus" #: editor/export_template_manager.cpp msgid "(Installed)" @@ -2475,7 +2475,7 @@ msgstr "" #: editor/export_template_manager.cpp #: editor/plugins/asset_library_editor_plugin.cpp msgid "Can't resolve." -msgstr "Yhdistäminen epäonnistui." +msgstr "Yhdeydenselvitys epäonnistui." #: editor/export_template_manager.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -2520,11 +2520,11 @@ msgstr "Yhteys katkaistu" #: editor/export_template_manager.cpp msgid "Resolving" -msgstr "Selvitetään" +msgstr "Selvitetään yhteyttä" #: editor/export_template_manager.cpp msgid "Can't Resolve" -msgstr "Yhdistäminen epäonnistui" +msgstr "Yhteyden selvittäminen epäonnistui" #: editor/export_template_manager.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -2809,7 +2809,7 @@ msgstr "Luodaan meshille: " #: editor/import/resource_importer_scene.cpp msgid "Running Custom Script..." -msgstr "Suorita valitsemasi skripti..." +msgstr "Suoritetaan mukautettua skriptiä..." #: editor/import/resource_importer_scene.cpp msgid "Couldn't load post-import script:" @@ -2940,7 +2940,7 @@ msgstr "VIRHE: Virheellinen animaation nimi!" #: editor/plugins/animation_player_editor_plugin.cpp msgid "ERROR: Animation name already exists!" -msgstr "VIrhe: Samanniminen animaatio on jo olemassa!" +msgstr "VIRHE: Samanniminen animaatio on jo olemassa!" #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp @@ -3316,7 +3316,8 @@ msgstr "Pyyntö epäonnistui, liikaa uudelleenohjauksia" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Bad download hash, assuming file has been tampered with." -msgstr "Latauksessa väärä hash, oletetaan että tiedostoa on näpelöity." +msgstr "" +"Latauksessa väärä hajautuskoodi, oletetaan että tiedostoa on näpelöity." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Expected:" @@ -3328,7 +3329,7 @@ msgstr "Saatiin:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Failed sha256 hash check" -msgstr "sha256 hash-tarkistus epäonnistui" +msgstr "sha256-hajautusarvon tarkistus epäonnistui" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Asset Download Error:" @@ -3442,7 +3443,7 @@ msgstr "" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Failed creating lightmap images, make sure path is writable." msgstr "" -"Lightmap-kuvien luonti epäonnistui, varmista, että polku on " +"Lightmap-kuvien luonti epäonnistui. Varmista, että polku on " "kirjoituskelpoinen." #: editor/plugins/baked_lightmap_editor_plugin.cpp @@ -5301,11 +5302,11 @@ msgstr "Tarttumisen tila (%s)" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" -msgstr "Pohjanäkymä" +msgstr "Alanäkymä" #: editor/plugins/spatial_editor_plugin.cpp msgid "Top View" -msgstr "Huippunäkymä" +msgstr "Ylänäkymä" #: editor/plugins/spatial_editor_plugin.cpp msgid "Rear View" @@ -7110,7 +7111,7 @@ msgstr "Aseta puusta" #: editor/settings_config_dialog.cpp msgid "Shortcuts" -msgstr "Pikakuvakkeet" +msgstr "Pikanäppäimet" #: editor/settings_config_dialog.cpp msgid "Binding" @@ -7435,6 +7436,11 @@ msgstr "Käännä projekti" msgid "Warnings" msgstr "Varoitukset" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Näytä tiedostot" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Sisemmän poikkeuksen kutsupinon loppu" diff --git a/editor/translations/fr.po b/editor/translations/fr.po index ee1d7b2cad..5c28d84a90 100644 --- a/editor/translations/fr.po +++ b/editor/translations/fr.po @@ -40,12 +40,14 @@ # Tommy Melançon-Roy <tommel1234@hotmail.com>, 2017-2018. # Willow <theotimefd@aol.com>, 2018. # Xananax <xananax@yelostudio.com>, 2017-2018. +# Perrier Mathis <mathis.perrier73@gmail.com>, 2018. +# Ewan Lehnebach <ewan.lehnebach@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-06-12 16:38+0000\n" -"Last-Translator: Philippe Gervaise <blah@malvese.org>\n" +"PO-Revision-Date: 2018-07-21 12:37+0000\n" +"Last-Translator: Perrier Mathis <mathis.perrier73@gmail.com>\n" "Language-Team: French <https://hosted.weblate.org/projects/godot-engine/" "godot/fr/>\n" "Language: fr\n" @@ -53,7 +55,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 3.0.1\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -65,11 +67,11 @@ msgstr "Toute la sélection" #: editor/animation_editor.cpp msgid "Anim Change Keyframe Time" -msgstr "Changer l'heure de l'animation des images clés" +msgstr "Animation Changer l'heure de l'image clé" #: editor/animation_editor.cpp msgid "Anim Change Transition" -msgstr "Transition du changement d'animation" +msgstr "Animation Changer la transition" #: editor/animation_editor.cpp msgid "Anim Change Transform" @@ -77,7 +79,7 @@ msgstr "Animation Changer la transformation" #: editor/animation_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "Changer la valeur de l'animation des images clés" +msgstr "Animation Changer la valeur de l'image clé" #: editor/animation_editor.cpp msgid "Anim Change Call" @@ -4076,7 +4078,7 @@ msgstr "Créer le contour" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh" -msgstr "Maillage" +msgstr "Maillages" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Trimesh Static Body" @@ -6512,7 +6514,7 @@ msgstr "Remaps par langue :" #: editor/project_settings_editor.cpp msgid "Locale" -msgstr "Langue" +msgstr "Localisation" #: editor/project_settings_editor.cpp msgid "Locales Filter" @@ -7513,6 +7515,11 @@ msgstr "Compiler le projet" msgid "Warnings" msgstr "Avertissements" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Voir Fichiers" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Fin de la trace d'appel (stack trace) intrinsèque" diff --git a/editor/translations/he.po b/editor/translations/he.po index 0f1881211f..6dfd0ab3a5 100644 --- a/editor/translations/he.po +++ b/editor/translations/he.po @@ -7294,6 +7294,10 @@ msgstr "" msgid "Warnings" msgstr "אזהרות" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/hi.po b/editor/translations/hi.po index 3340f13471..606da1d118 100644 --- a/editor/translations/hi.po +++ b/editor/translations/hi.po @@ -7327,6 +7327,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/hu.po b/editor/translations/hu.po index b04dd073df..84c64138dc 100644 --- a/editor/translations/hu.po +++ b/editor/translations/hu.po @@ -7405,6 +7405,11 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Fájlok Megtekintése" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/id.po b/editor/translations/id.po index 3956378ce7..a0356b8178 100644 --- a/editor/translations/id.po +++ b/editor/translations/id.po @@ -10,7 +10,7 @@ # Fajar Ru <kzofajar@gmail.com>, 2018. # Khairul Hidayat <khairulcyber4rt@gmail.com>, 2016. # Reza Hidayat Bayu Prabowo <rh.bayu.prabowo@gmail.com>, 2018. -# Romi Kusuma Bakti <romikusumab@gmail.com>, 2017. +# Romi Kusuma Bakti <romikusumab@gmail.com>, 2017, 2018. # Sofyan Sugianto <sofyanartem@gmail.com>, 2017-2018. # Tito <ijavadroid@gmail.com>, 2018. # Tom My <tom.asadinawan@gmail.com>, 2017. @@ -18,8 +18,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-22 08:30+0000\n" -"Last-Translator: Fajar Ru <kzofajar@gmail.com>\n" +"PO-Revision-Date: 2018-07-15 12:38+0000\n" +"Last-Translator: Romi Kusuma Bakti <romikusumab@gmail.com>\n" "Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/" "godot/id/>\n" "Language: id\n" @@ -917,9 +917,8 @@ msgid "Delete Audio Bus" msgstr "Hapus Bus Audio" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Duplicate Audio Bus" -msgstr "Duplikat Audio Bus" +msgstr "Duplikatkan Bus Audio" #: editor/editor_audio_buses.cpp msgid "Reset Bus Volume" @@ -976,9 +975,8 @@ msgid "Save this Bus Layout to a file." msgstr "Simpan Layout Bus ke berkas." #: editor/editor_audio_buses.cpp editor/import_dock.cpp -#, fuzzy msgid "Load Default" -msgstr "Muat Konfigurasi Bawaan" +msgstr "Muat Default" #: editor/editor_audio_buses.cpp msgid "Load the default Bus Layout." @@ -1294,18 +1292,16 @@ msgid "Members:" msgstr "Member-member:" #: editor/editor_help.cpp -#, fuzzy msgid "Public Methods" -msgstr "Fungsi Publik" +msgstr "Metode Publik" #: editor/editor_help.cpp msgid "Public Methods:" msgstr "Metode Publik:" #: editor/editor_help.cpp -#, fuzzy msgid "GUI Theme Items" -msgstr "Item-item Tema GUI:" +msgstr "Item Tema GUI" #: editor/editor_help.cpp msgid "GUI Theme Items:" @@ -1422,9 +1418,8 @@ msgstr "Simpan Resource Sebagai..." #: editor/editor_node.cpp editor/plugins/spatial_editor_plugin.cpp #: editor/scene_tree_dock.cpp -#, fuzzy msgid "I see..." -msgstr "Aku tahu..." +msgstr "Mengerti..." #: editor/editor_node.cpp msgid "Can't open file for writing:" @@ -1471,9 +1466,8 @@ msgid "Creating Thumbnail" msgstr "Membuat Thumbnail" #: editor/editor_node.cpp -#, fuzzy msgid "This operation can't be done without a tree root." -msgstr "Tindakan ini tidak bisa dilakukan tanpa \"tree root\"" +msgstr "Operasi ini tidak dapat diselesaikan tanpa root pohon." #: editor/editor_node.cpp msgid "" @@ -2712,7 +2706,7 @@ msgstr "Buka Scene" #: editor/filesystem_dock.cpp msgid "Instance" -msgstr "" +msgstr "Instance" #: editor/filesystem_dock.cpp msgid "Edit Dependencies..." @@ -2821,18 +2815,16 @@ msgid "Importing Scene..." msgstr "Mengimpor scene..." #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Generating Lightmaps" -msgstr "Sedang Membuat Pemetaan Cahaya" +msgstr "Membuat Pemetaan Cahaya" #: editor/import/resource_importer_scene.cpp msgid "Generating for Mesh: " msgstr "" #: editor/import/resource_importer_scene.cpp -#, fuzzy msgid "Running Custom Script..." -msgstr "Menjalankan Skrip Buatan..." +msgstr "Menjalankan Script Khusus..." #: editor/import/resource_importer_scene.cpp msgid "Couldn't load post-import script:" @@ -2868,7 +2860,7 @@ msgstr "Impor sebagai:" #: editor/import_dock.cpp editor/property_editor.cpp msgid "Preset..." -msgstr "" +msgstr "Prasetel..." #: editor/import_dock.cpp msgid "Reimport" @@ -7563,6 +7555,11 @@ msgstr "Proyek" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "File:" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/is.po b/editor/translations/is.po index 98a376edca..0d6200fba1 100644 --- a/editor/translations/is.po +++ b/editor/translations/is.po @@ -7301,6 +7301,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/it.po b/editor/translations/it.po index 2d566fe163..afb8c5cfb8 100644 --- a/editor/translations/it.po +++ b/editor/translations/it.po @@ -2,7 +2,6 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # Alessio Corridori <alessiocorridori@hotmail.com>, 2018. # Dario Bonfanti <bonfi.96@hotmail.it>, 2016-2017. # Dario D'Ambra <legione0@gmail.com>, 2017. @@ -15,13 +14,13 @@ # RealAquilus <JamesHeller@live.it>, 2017. # Samuele Zolfanelli <samdazel@gmail.com>, 2018. # Sean Bone <seanbone@zumguy.com>, 2017. -# +# Red Pill <redpill902@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-05-18 16:39+0000\n" -"Last-Translator: Alessio Corridori <alessiocorridori@hotmail.com>\n" +"PO-Revision-Date: 2018-06-25 18:40+0000\n" +"Last-Translator: Red Pill <redpill902@gmail.com>\n" "Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/" "godot/it/>\n" "Language: it\n" @@ -29,7 +28,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -40,9 +39,8 @@ msgid "All Selection" msgstr "Seleziona Tutto" #: editor/animation_editor.cpp -#, fuzzy msgid "Anim Change Keyframe Time" -msgstr "Anim Cambia Valore" +msgstr "Anim Cambia Tempo di Keyframe" #: editor/animation_editor.cpp msgid "Anim Change Transition" @@ -7640,6 +7638,11 @@ msgstr "Progetto" msgid "Warnings" msgstr "Avvertimento" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Vedi Files" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ja.po b/editor/translations/ja.po index 5ce73d0442..d7e2c07ac2 100644 --- a/editor/translations/ja.po +++ b/editor/translations/ja.po @@ -8251,6 +8251,11 @@ msgstr "プロジェクト" msgid "Warnings" msgstr "警告" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "ビューファイル:" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ko.po b/editor/translations/ko.po index be6b540a9a..197a11efa2 100644 --- a/editor/translations/ko.po +++ b/editor/translations/ko.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-06-07 16:40+0000\n" -"Last-Translator: pgyage3263 <pgyage3263@naver.com>\n" +"PO-Revision-Date: 2018-07-21 04:38+0000\n" +"Last-Translator: 송태섭 <xotjq237@gmail.com>\n" "Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/" "godot/ko/>\n" "Language: ko\n" @@ -23,7 +23,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.0\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -4003,7 +4003,7 @@ msgstr "외곽선 만들기" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh" -msgstr "메시" +msgstr "Mesh" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Trimesh Static Body" @@ -7412,6 +7412,11 @@ msgstr "프로젝트 빌드" msgid "Warnings" msgstr "경고" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "파일 보기" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "내부 예외 스택 추적의 끝" diff --git a/editor/translations/lt.po b/editor/translations/lt.po index bf4443627a..639e086d4c 100644 --- a/editor/translations/lt.po +++ b/editor/translations/lt.po @@ -7295,6 +7295,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ms.po b/editor/translations/ms.po index 19d8b6b7d8..09c7b39e08 100644 --- a/editor/translations/ms.po +++ b/editor/translations/ms.po @@ -2,22 +2,21 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # Sam Vanguard <syafz119@gmail.com>, 2018. # Shaqir Rafiq <moshamoradev@gmail.com>, 2018. -# +# Syaz Amirin <amirin123z@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-05 19:27+0000\n" -"Last-Translator: Shaqir Rafiq <moshamoradev@gmail.com>\n" +"PO-Revision-Date: 2018-06-30 09:40+0000\n" +"Last-Translator: Syaz Amirin <amirin123z@gmail.com>\n" "Language-Team: Malay <https://hosted.weblate.org/projects/godot-engine/godot/" "ms/>\n" "Language: ms\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.0\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -2014,11 +2013,11 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp msgid "Community" -msgstr "" +msgstr "Komuniti" #: editor/editor_node.cpp msgid "About" -msgstr "" +msgstr "Tentang" #: editor/editor_node.cpp msgid "Play the project." @@ -6244,7 +6243,7 @@ msgstr "" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp msgid "General" -msgstr "" +msgstr "Am" #: editor/project_settings_editor.cpp editor/property_editor.cpp msgid "Property:" @@ -7273,6 +7272,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/nb.po b/editor/translations/nb.po index e76053150c..abc026771d 100644 --- a/editor/translations/nb.po +++ b/editor/translations/nb.po @@ -14,8 +14,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-22 08:31+0000\n" -"Last-Translator: Frank T. Rambol <frank@d-fect.com>\n" +"PO-Revision-Date: 2018-06-28 14:40+0000\n" +"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n" "Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/godot-" "engine/godot/nb/>\n" "Language: nb\n" @@ -1756,7 +1756,9 @@ msgstr "Velg en HovedScene" #: editor/editor_node.cpp #, fuzzy msgid "Unable to enable addon plugin at: '%s' parsing of config failed." -msgstr "Kan ikke aktivere addon-plugin på: '%s' parsing av konfig feilet." +msgstr "" +"Kan ikke aktivere tilleggs-programtillegg på: \"%s\" tolking av oppsett " +"mislyktes." #: editor/editor_node.cpp msgid "Unable to find script field for addon plugin at: 'res://addons/%s'." @@ -1912,9 +1914,8 @@ msgid "MeshLibrary..." msgstr "MeshBibliotek..." #: editor/editor_node.cpp -#, fuzzy msgid "TileSet..." -msgstr "TileSet…" +msgstr "Flissett…" #: editor/editor_node.cpp editor/plugins/script_text_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp @@ -7495,6 +7496,11 @@ msgstr "Prosjekt" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Vis Filer" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/nl.po b/editor/translations/nl.po index bfedf322b3..240d99182f 100644 --- a/editor/translations/nl.po +++ b/editor/translations/nl.po @@ -2,7 +2,6 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # aelspire <aelspire@gmail.com>, 2017. # Aram Nap <xyphex.aram@gmail.com>, 2017. # Arjan219 <arjannugteren1@gmail.com>, 2017-2018. @@ -24,19 +23,19 @@ # Willem <studiebolmail@gmail.com>, 2018. # Wout Standaert <wout@blobkat.com>, 2017. # Zatherz <zatherz@linux.pl>, 2017. -# +# Tahar Meijs <tntmeijs@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-05-21 18:36+0000\n" -"Last-Translator: Johannes Smit <smitjohannes96@gmail.com>\n" +"PO-Revision-Date: 2018-06-30 15:36+0000\n" +"Last-Translator: Tahar Meijs <tntmeijs@gmail.com>\n" "Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/" "nl/>\n" "Language: nl\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -6427,7 +6426,7 @@ msgstr "" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp msgid "General" -msgstr "" +msgstr "Algemeen" #: editor/project_settings_editor.cpp editor/property_editor.cpp msgid "Property:" @@ -7492,6 +7491,11 @@ msgstr "Project" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Bekijk Bestanden" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/pl.po b/editor/translations/pl.po index 5ca2760249..a133a4d8d5 100644 --- a/editor/translations/pl.po +++ b/editor/translations/pl.po @@ -27,7 +27,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-22 08:31+0000\n" +"PO-Revision-Date: 2018-07-14 08:42+0000\n" "Last-Translator: RM <synaptykq@gmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/" "godot/pl/>\n" @@ -1975,7 +1975,7 @@ msgstr "Wyjdź do Listy Projektów" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Debug" -msgstr "Debuguj" +msgstr "Debugowanie" #: editor/editor_node.cpp msgid "Deploy with Remote Debug" @@ -3093,7 +3093,7 @@ msgstr "Poprzednie" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Future" -msgstr "Następne" +msgstr "Przyszłość" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Depth" @@ -3154,7 +3154,7 @@ msgstr "Czas Przejścia Między Animacjami" #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Animation" -msgstr "Animacja" +msgstr "Animacje" #: editor/plugins/animation_tree_editor_plugin.cpp msgid "New name:" @@ -6514,7 +6514,7 @@ msgstr "Mapowanie w zależności od lokalizacji:" #: editor/project_settings_editor.cpp msgid "Locale" -msgstr "Lokalizacja" +msgstr "Języki" #: editor/project_settings_editor.cpp msgid "Locales Filter" @@ -7137,7 +7137,7 @@ msgstr "Monitor" #: editor/script_editor_debugger.cpp msgid "Value" -msgstr "Wartość" +msgstr "Value" #: editor/script_editor_debugger.cpp msgid "Monitors" @@ -7525,6 +7525,11 @@ msgstr "Zbuduj projekt" msgid "Warnings" msgstr "Ostrzeżenia" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Pokaż pliki" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" @@ -7672,11 +7677,11 @@ msgstr "Dodaj węzeł(y) z drzewa" #: modules/visual_script/visual_script_editor.cpp msgid "Add Getter Property" -msgstr "" +msgstr "Dodaj właściwość Gettera" #: modules/visual_script/visual_script_editor.cpp msgid "Add Setter Property" -msgstr "" +msgstr "Dodaj właściwość Settera" #: modules/visual_script/visual_script_editor.cpp msgid "Change Base Type" @@ -7712,7 +7717,7 @@ msgstr "Iterator" #: modules/visual_script/visual_script_editor.cpp msgid "While" -msgstr "" +msgstr "While" #: modules/visual_script/visual_script_editor.cpp msgid "Return" @@ -8045,7 +8050,7 @@ msgstr "" #: scene/3d/arvr_nodes.cpp msgid "ARVRCamera must have an ARVROrigin node as its parent" -msgstr "ARVRCamera musi dziedziczyć po ARVROrigin node" +msgstr "ARVRCamera musi dziedziczyć po węźle ARVROrigin" #: scene/3d/arvr_nodes.cpp #, fuzzy @@ -8073,11 +8078,11 @@ msgstr "" #: scene/3d/arvr_nodes.cpp msgid "ARVROrigin requires an ARVRCamera child node" -msgstr "ARVROrigin wymaga by ARVRCamera dziedziczyła po node" +msgstr "ARVROrigin wymaga dziedziczącego po nim ARVRCamera" #: scene/3d/baked_lightmap.cpp msgid "%d%%" -msgstr "" +msgstr "%d%%" #: scene/3d/baked_lightmap.cpp msgid "(Time Left: %d:%02d s)" @@ -8106,6 +8111,10 @@ msgid "" "Consider adding CollisionShape or CollisionPolygon children nodes to define " "its shape." msgstr "" +"Ten węzeł nie posiada podwezła, który definiowałby jego kształt, więc nie " +"może wchodzić w interakcje z przestrzenią.\n" +"Powinieneś dodać węzeł \"CollisionShape2D\" lub \"CollisionPolygon2D\" jako " +"jego podwęzeł aby zdefiniować jego kształt." #: scene/3d/collision_polygon.cpp msgid "" diff --git a/editor/translations/pr.po b/editor/translations/pr.po index 0c085024e0..ee30748cee 100644 --- a/editor/translations/pr.po +++ b/editor/translations/pr.po @@ -7350,6 +7350,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po index 6d26cbc500..472fb1e7bc 100644 --- a/editor/translations/pt_BR.po +++ b/editor/translations/pt_BR.po @@ -23,12 +23,13 @@ # Renato Rotenberg <renato.rotenberg@gmail.com>, 2017. # Rodolfo R Gomes <rodolforg@gmail.com>, 2017-2018. # Tiago Almeida <thyagoeap@gmail.com>, 2017. +# Mauricio Luan Carneiro deSouza <newmailmlcs@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: 2016-05-30\n" -"PO-Revision-Date: 2018-06-16 18:43+0000\n" -"Last-Translator: Rodolfo R Gomes <rodolforg@gmail.com>\n" +"PO-Revision-Date: 2018-07-26 09:14+0000\n" +"Last-Translator: Mauricio Luan Carneiro deSouza <newmailmlcs@gmail.com>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "godot-engine/godot/pt_BR/>\n" "Language: pt_BR\n" @@ -36,7 +37,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 3.0.1\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -4036,7 +4037,7 @@ msgstr "Criar Contorno" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh" -msgstr "Mesh" +msgstr "Malha" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Trimesh Static Body" @@ -5100,7 +5101,7 @@ msgstr "Transformação do Eixo-Z." #: editor/plugins/spatial_editor_plugin.cpp msgid "View Plane Transform." -msgstr "Visualizar Transformação do Plano." +msgstr "Transformação do Plano de Visão." #: editor/plugins/spatial_editor_plugin.cpp msgid "Scaling: " @@ -5236,7 +5237,7 @@ msgstr "Visualizar Gizmos" #: editor/plugins/spatial_editor_plugin.cpp msgid "View Information" -msgstr "VIsualizar Informação" +msgstr "Visualizar Informações" #: editor/plugins/spatial_editor_plugin.cpp msgid "View FPS" @@ -7049,7 +7050,7 @@ msgstr "Processo Filho Conectado" #: editor/script_editor_debugger.cpp msgid "Copy Error" -msgstr "Erro ao Copiar" +msgstr "Copiar Erro" #: editor/script_editor_debugger.cpp msgid "Inspect Previous Instance" @@ -7463,6 +7464,11 @@ msgstr "Compilar Projeto" msgid "Warnings" msgstr "Avisos" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Ver Arquivos" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Fim da pilha de rastreamento de exceção interna" diff --git a/editor/translations/pt_PT.po b/editor/translations/pt_PT.po index 71275cd19a..d111d1dd4b 100644 --- a/editor/translations/pt_PT.po +++ b/editor/translations/pt_PT.po @@ -7442,6 +7442,11 @@ msgstr "Construir Projeto" msgid "Warnings" msgstr "Avisos" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Ver Ficheiros" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Fim do stack trace de exceção interna" diff --git a/editor/translations/ro.po b/editor/translations/ro.po index eaf931092a..c5a4e35903 100644 --- a/editor/translations/ro.po +++ b/editor/translations/ro.po @@ -7400,6 +7400,11 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Vizualizează Fișierele" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ru.po b/editor/translations/ru.po index 97c7284404..1c888d3330 100644 --- a/editor/translations/ru.po +++ b/editor/translations/ru.po @@ -17,12 +17,15 @@ # Sergey <maligin.serega2010@yandex.ru>, 2018. # Sergey Agarkov <zorgsoft@gmail.com>, 2017. # teriva <spirin.cos@yandex.ru>, 2018. +# Aleksey Terentyev <terentjew.alexey@ya.ru>, 2018. +# Игорь Д <protorian.di@gmail.com>, 2018. +# Егор Бураков <fend.q@mail.ru>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2018-06-18 19:42+0000\n" -"Last-Translator: ijet <my-ijet@mail.ru>\n" +"PO-Revision-Date: 2018-07-22 04:43+0000\n" +"Last-Translator: Егор Бураков <fend.q@mail.ru>\n" "Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/" "godot/ru/>\n" "Language: ru\n" @@ -31,7 +34,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 3.0.1\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -2347,7 +2350,7 @@ msgstr "Кадр %" #: editor/editor_profiler.cpp msgid "Physics Frame %" -msgstr "Физический шаг %" +msgstr "Кадр физики %" #: editor/editor_profiler.cpp editor/script_editor_debugger.cpp msgid "Time:" @@ -2359,7 +2362,7 @@ msgstr "Включительно" #: editor/editor_profiler.cpp msgid "Self" -msgstr "" +msgstr "Субъект" #: editor/editor_profiler.cpp msgid "Frame #:" @@ -4029,7 +4032,7 @@ msgstr "Создать контур" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Mesh" -msgstr "Полисетка" +msgstr "Массив" #: editor/plugins/mesh_instance_editor_plugin.cpp msgid "Create Trimesh Static Body" @@ -5561,7 +5564,7 @@ msgstr "Предпросмотр StyleBox:" #: editor/plugins/style_box_editor_plugin.cpp msgid "StyleBox" -msgstr "" +msgstr "StyleBox" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Set Region Rect" @@ -5684,14 +5687,12 @@ msgid "Checked Item" msgstr "Отмеченный элемент" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Radio Item" -msgstr "Добавить элемент" +msgstr "Переключатель" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Checked Radio Item" -msgstr "Отмеченный элемент" +msgstr "Отмеченный переключатель" #: editor/plugins/theme_editor_plugin.cpp msgid "Has" @@ -7233,7 +7234,7 @@ msgstr "Библиотеки: " #: modules/gdnative/register_types.cpp msgid "GDNative" -msgstr "" +msgstr "GDNative" #: modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -7450,6 +7451,11 @@ msgstr "Собрать проект" msgid "Warnings" msgstr "Предупреждения" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Просмотр Файлов" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Конец трассировки внутреннего стека исключений" diff --git a/editor/translations/sk.po b/editor/translations/sk.po index 9716dee696..94b6c137d0 100644 --- a/editor/translations/sk.po +++ b/editor/translations/sk.po @@ -7354,6 +7354,11 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Súbor:" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/sl.po b/editor/translations/sl.po index 0fe619654f..66e3c43bee 100644 --- a/editor/translations/sl.po +++ b/editor/translations/sl.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-10 08:44+0000\n" +"PO-Revision-Date: 2018-06-27 13:43+0000\n" "Last-Translator: matevž lapajne <sivar.lapajne@gmail.com>\n" "Language-Team: Slovenian <https://hosted.weblate.org/projects/godot-engine/" "godot/sl/>\n" @@ -19,7 +19,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" "%100==4 ? 2 : 3;\n" -"X-Generator: Weblate 3.0.1-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -3340,23 +3340,23 @@ msgstr "Razreševanje..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Error making request" -msgstr "" +msgstr "Napaka pri izdelavi zahteve" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Idle" -msgstr "" +msgstr "Nedejaven" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Retry" -msgstr "" +msgstr "Ponovi" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Download Error" -msgstr "" +msgstr "Napaka Pri Prenosu" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Download for this asset is already in progress!" -msgstr "" +msgstr "Prenos za ta dodatek je že v teku!" #: editor/plugins/asset_library_editor_plugin.cpp msgid "first" @@ -3382,7 +3382,7 @@ msgstr "Vse" #: editor/plugins/asset_library_editor_plugin.cpp #: editor/project_settings_editor.cpp msgid "Plugins" -msgstr "" +msgstr "Vtičniki" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Sort:" @@ -3390,7 +3390,7 @@ msgstr "Razvrsti:" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Reverse" -msgstr "" +msgstr "Obrni" #: editor/plugins/asset_library_editor_plugin.cpp #: editor/project_settings_editor.cpp @@ -3407,15 +3407,15 @@ msgstr "Podpora..." #: editor/plugins/asset_library_editor_plugin.cpp msgid "Official" -msgstr "" +msgstr "Uradno" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Testing" -msgstr "" +msgstr "Preskušanje" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Assets ZIP File" -msgstr "" +msgstr "Dodatki v ZIP Datoteki" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "" @@ -3423,6 +3423,9 @@ msgid "" "Save your scene (for images to be saved in the same dir), or pick a save " "path from the BakedLightmap properties." msgstr "" +"Ni mogoče določiti poti shranjevanja slik svetlobnih kart.\n" +"Shrani prizor (za slike, da bodo shranjene v isti mapi), ali izberi pot za " +"shranitev iz lastnosti Zapečene Svetlobne karte." #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "" @@ -3435,53 +3438,54 @@ msgstr "" #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Failed creating lightmap images, make sure path is writable." msgstr "" +"Napaka pri izdelavi slik, svetlobnih kart. Poskrbite, da je pot zapisljiva." #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Bake Lightmaps" -msgstr "" +msgstr "Zapeči Svetlobne karte" #: editor/plugins/camera_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Preview" -msgstr "" +msgstr "Predogled" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Configure Snap" -msgstr "" +msgstr "Nastavi Zaskok" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Grid Offset:" -msgstr "" +msgstr "Mrežni Zamik:" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Grid Step:" -msgstr "" +msgstr "Mrežni Korak:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotation Offset:" -msgstr "" +msgstr "Rotacijski Odmik:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotation Step:" -msgstr "" +msgstr "Rotacijski Korak:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move Pivot" -msgstr "" +msgstr "Premakni Točko" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move Action" -msgstr "" +msgstr "Premakni Dejanje" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move vertical guide" -msgstr "" +msgstr "Premakni navpični vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Create new vertical guide" -msgstr "" +msgstr "Ustvari nov navpični vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Remove vertical guide" @@ -3489,59 +3493,61 @@ msgstr "Odstranite navpični vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move horizontal guide" -msgstr "" +msgstr "Premakni vodoravni vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Create new horizontal guide" -msgstr "" +msgstr "Ustvari nov vodoravni vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Remove horizontal guide" -msgstr "Odstrani vodoravno vodilo" +msgstr "Odstrani vodoravni vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Create new horizontal and vertical guides" -msgstr "" +msgstr "Ustvari nov vodoravni in navpični vodnik" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Edit IK Chain" -msgstr "" +msgstr "Uredi Verigo IK" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Edit CanvasItem" -msgstr "" +msgstr "Uredi Platno Stvari" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Anchors only" -msgstr "" +msgstr "Samo Sidrišča" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Change Anchors and Margins" -msgstr "" +msgstr "Spremeni Sidrišča in Robove" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Change Anchors" -msgstr "" +msgstr "Spremeni Sidrišča" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Paste Pose" -msgstr "" +msgstr "Prilepi Pozicijo" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Select Mode" -msgstr "Izberite Način" +msgstr "Izberi Način" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Drag: Rotate" -msgstr "Povlecite: Zavrti" +msgstr "Povleci: Vrtenje" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Alt+Drag: Move" -msgstr "" +msgstr "Alt+Drag: Premakni" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)." msgstr "" +"Pritisni 'v' za Spremembo Točke in 'Shift+v' za Vleko Točke (med " +"premikanjem)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Alt+RMB: Depth list selection" @@ -3561,16 +3567,16 @@ msgid "" "Show a list of all objects at the position clicked\n" "(same as Alt+RMB in select mode)." msgstr "" -"Ob kliku prikaži seznam vseh objektov na tem mestu.\n" +"Ob kliku prikaži seznam vseh objektov na tem mestu\n" "(isto kot Alt+RMB v načinu izbire)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Click to change object's rotation pivot." -msgstr "" +msgstr "Klikni, če želiš spremeniti rotacijsko točko objekta." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Pan Mode" -msgstr "" +msgstr "Način Plošče" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Toggles snapping" @@ -3578,66 +3584,66 @@ msgstr "Preklopi pripenjanje" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Use Snap" -msgstr "" +msgstr "Uporabi Pripenjanje" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snapping options" -msgstr "" +msgstr "Možnosti pripenjanja" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap to grid" -msgstr "" +msgstr "Pripni na mrežo" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Use Rotation Snap" -msgstr "" +msgstr "Uporabi Rotacijsko Pripenjanje" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Configure Snap..." -msgstr "Preoblikuj Zaskok..." +msgstr "Nastavi Pripenjanje..." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap Relative" -msgstr "" +msgstr "Pripni Relativno" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Use Pixel Snap" -msgstr "" +msgstr "Uporabi Pripenjanje Pikslov" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Smart snapping" -msgstr "" +msgstr "Pametno pripenjanje" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap to parent" -msgstr "" +msgstr "Pripni na Predhodnika" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap to node anchor" -msgstr "" +msgstr "Pripni na gradnik vodilo" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap to node sides" -msgstr "" +msgstr "Pripni na gradnik strani" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap to other nodes" -msgstr "" +msgstr "Pripni na druge gradnike" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Snap to guides" -msgstr "" +msgstr "Pripni na vodnike" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Lock the selected object in place (can't be moved)." -msgstr "Izbrani predmet zaklenite na svoje mesto (ga ni mogoče premakniti)." +msgstr "Izbrani predmet zakleni na svoje mesto (ni ga mogoče premakniti)." #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp msgid "Unlock the selected object (can be moved)." -msgstr "Odklenite izbrani predmet (ga lahko premaknete)." +msgstr "Odkleni izbrani predmet (lahko ga premaknete)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Makes sure the object's children are not selectable." @@ -5945,9 +5951,8 @@ msgid "Imported Project" msgstr "" #: editor/project_manager.cpp -#, fuzzy msgid "Invalid Project Name." -msgstr "Ime Projekta:" +msgstr "Neveljavno Ime Projekta." #: editor/project_manager.cpp msgid "Couldn't create folder." @@ -7374,6 +7379,11 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Ogled datotek" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po index c838174131..9998a16e3a 100644 --- a/editor/translations/sr_Cyrl.po +++ b/editor/translations/sr_Cyrl.po @@ -7461,6 +7461,11 @@ msgstr "Пројекат" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Погледај датотеке" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po index 975418d4fb..4d293a592d 100644 --- a/editor/translations/sr_Latn.po +++ b/editor/translations/sr_Latn.po @@ -7272,6 +7272,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/sv.po b/editor/translations/sv.po index 9ec654128a..f9e65bb600 100644 --- a/editor/translations/sv.po +++ b/editor/translations/sv.po @@ -2,24 +2,24 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # bergmarklund <davemcgroin@gmail.com>, 2017, 2018. # Christoffer Sundbom <christoffer_karlsson@live.se>, 2017. # Jakob Sinclair <sinclair.jakob@mailbox.org>, 2018. # . <grenoscar@gmail.com>, 2018. -# +# Kristoffer Grundström <kristoffer.grundstrom1983@gmail.com>, 2018. +# Magnus Helander <helander@fastmail.net>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-05-07 11:42+0000\n" -"Last-Translator: anonymous <>\n" +"PO-Revision-Date: 2018-07-24 12:44+0000\n" +"Last-Translator: Magnus Helander <helander@fastmail.net>\n" "Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/" "godot/sv/>\n" "Language: sv\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -30,9 +30,8 @@ msgid "All Selection" msgstr "Alla urval" #: editor/animation_editor.cpp -#, fuzzy msgid "Anim Change Keyframe Time" -msgstr "Anim Ändra Värde" +msgstr "Anim Ändra Nyckelram Tid" #: editor/animation_editor.cpp msgid "Anim Change Transition" @@ -88,16 +87,15 @@ msgstr "Ändra Anim Spårets Värde Läge" #: editor/animation_editor.cpp msgid "Anim Track Change Wrap Mode" -msgstr "" +msgstr "Anim Spåra Ändra Linda om Läge" #: editor/animation_editor.cpp msgid "Edit Node Curve" msgstr "Redigera Nodkurva" #: editor/animation_editor.cpp -#, fuzzy msgid "Edit Selection Curve" -msgstr "Redigera Urval Kurva" +msgstr "Redigera Urvalsurva" #: editor/animation_editor.cpp msgid "Anim Delete Keys" @@ -7903,6 +7901,11 @@ msgstr "Projekt" msgid "Warnings" msgstr "Varning" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Visa Filer" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/ta.po b/editor/translations/ta.po index d7910c2c87..d3d80facc3 100644 --- a/editor/translations/ta.po +++ b/editor/translations/ta.po @@ -7274,6 +7274,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/th.po b/editor/translations/th.po index 4db8459f1b..2393ca98a9 100644 --- a/editor/translations/th.po +++ b/editor/translations/th.po @@ -7359,6 +7359,11 @@ msgstr "Build โปรเจกต์" msgid "Warnings" msgstr "คำเตือน" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "ดูไฟล์" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "สิ้นสุดสแตคข้อผิดพลาดภายใน" diff --git a/editor/translations/tr.po b/editor/translations/tr.po index 292cec4063..abe7d485fa 100644 --- a/editor/translations/tr.po +++ b/editor/translations/tr.po @@ -17,18 +17,19 @@ # razah <icnikerazah@gmail.com>, 2017-2018. # stnmycri <satenmeycri@gmail.com>, 2017-2018. # Yavuz Günay <yavuzgunay@gmail.com>, 2017. +# Onur Sanır <onursanir@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-06-10 09:46+0000\n" -"Last-Translator: Aykut YILDIRIM <aykutyildirim@windowslive.com>\n" +"PO-Revision-Date: 2018-07-07 20:42+0000\n" +"Last-Translator: Onur Sanır <onursanir@gmail.com>\n" "Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/" "godot/tr/>\n" "Language: tr\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.0.1-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -5696,9 +5697,8 @@ msgid "Options" msgstr "Seçenekler" #: editor/plugins/theme_editor_plugin.cpp -#, fuzzy msgid "Has,Many,Options" -msgstr "Bir Çok,Seçenek,Var!" +msgstr "Birçok,Seçenek,Var" #: editor/plugins/theme_editor_plugin.cpp msgid "Tab 1" @@ -7438,6 +7438,11 @@ msgstr "Projeyi İnşa et" msgid "Warnings" msgstr "Uyarılar" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Dosyaları Görüntüle" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "İç özel durum yığını izlemesinin sonu" diff --git a/editor/translations/uk.po b/editor/translations/uk.po index 067c7be724..d940561131 100644 --- a/editor/translations/uk.po +++ b/editor/translations/uk.po @@ -7447,6 +7447,11 @@ msgstr "Зібрати проект" msgid "Warnings" msgstr "Попередження" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "Перегляд файлів" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "Кінець трасування стека для внутрішнього виключення" diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po index 0162eb0788..3857bff9b0 100644 --- a/editor/translations/ur_PK.po +++ b/editor/translations/ur_PK.po @@ -7331,6 +7331,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/vi.po b/editor/translations/vi.po index 6651bd170c..faf77300b8 100644 --- a/editor/translations/vi.po +++ b/editor/translations/vi.po @@ -2,25 +2,24 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # 01lifeleft <01lifeleft@gmail.com>, 2018. # Dlean Jeans <dleanjeans@gmail.com>, 2018. # Hai Le <dark.hades.1102@gmail.com>, 2017. # Nguyễn Tuấn Anh <anhnt.fami@gmail.com>, 2017. # Tung Le <tungkradle@gmail.com>, 2017. -# +# 38569459 <xxx38569459@gmail.com>, 2018. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-04-18 15:44+0000\n" -"Last-Translator: 01lifeleft <01lifeleft@gmail.com>\n" +"PO-Revision-Date: 2018-07-22 06:42+0000\n" +"Last-Translator: 38569459 <xxx38569459@gmail.com>\n" "Language-Team: Vietnamese <https://hosted.weblate.org/projects/godot-engine/" "godot/vi/>\n" "Language: vi\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -141,24 +140,24 @@ msgstr "Chọn Scale" #: editor/animation_editor.cpp msgid "Scale From Cursor" -msgstr "" +msgstr "Scale từ trỏ chuột" #: editor/animation_editor.cpp msgid "Goto Next Step" -msgstr "" +msgstr "Đến Step tiếp theo" #: editor/animation_editor.cpp msgid "Goto Prev Step" -msgstr "" +msgstr "Đến Step trước đó" #: editor/animation_editor.cpp editor/plugins/curve_editor_plugin.cpp #: editor/property_editor.cpp msgid "Linear" -msgstr "" +msgstr "Tuyến" #: editor/animation_editor.cpp editor/plugins/theme_editor_plugin.cpp msgid "Constant" -msgstr "" +msgstr "Cố định" #: editor/animation_editor.cpp msgid "In" @@ -178,11 +177,11 @@ msgstr "Ngoài-Trong" #: editor/animation_editor.cpp msgid "Transitions" -msgstr "" +msgstr "Chuyển tiếp" #: editor/animation_editor.cpp msgid "Optimize Animation" -msgstr "" +msgstr "Tối ưu Animation" #: editor/animation_editor.cpp msgid "Clean-Up Animation" @@ -190,11 +189,11 @@ msgstr "Dọn dẹp Animation" #: editor/animation_editor.cpp msgid "Create NEW track for %s and insert key?" -msgstr "" +msgstr "Tạo track mới cho %s và chèn key?" #: editor/animation_editor.cpp msgid "Create %d NEW tracks and insert keys?" -msgstr "" +msgstr "Tạo %d track mới và chèn key?" #: editor/animation_editor.cpp editor/create_dialog.cpp #: editor/editor_audio_buses.cpp editor/plugins/abstract_polygon_2d_editor.cpp @@ -210,15 +209,15 @@ msgstr "Tạo & Chèn Anim" #: editor/animation_editor.cpp msgid "Anim Insert Track & Key" -msgstr "" +msgstr "Chèn Track & Key Anim" #: editor/animation_editor.cpp msgid "Anim Insert Key" -msgstr "" +msgstr "Chèn Key Anim" #: editor/animation_editor.cpp msgid "Change Anim Len" -msgstr "" +msgstr "Đổi độ dài Anim" #: editor/animation_editor.cpp msgid "Change Anim Loop" @@ -226,23 +225,25 @@ msgstr "Đổi vòng lặp Anim" #: editor/animation_editor.cpp msgid "Anim Create Typed Value Key" -msgstr "" +msgstr "Tạo Key để nhập giá trị Anim" #: editor/animation_editor.cpp msgid "Anim Insert" msgstr "Chèn Anim" #: editor/animation_editor.cpp +#, fuzzy msgid "Anim Scale Keys" -msgstr "" +msgstr "Anim Scale Keys" #: editor/animation_editor.cpp msgid "Anim Add Call Track" msgstr "Thêm Track Gọi Function" #: editor/animation_editor.cpp +#, fuzzy msgid "Animation zoom." -msgstr "" +msgstr "Phóng Animation." #: editor/animation_editor.cpp msgid "Length (s):" @@ -266,27 +267,27 @@ msgstr "Mở/Tắt lặp animation." #: editor/animation_editor.cpp msgid "Add new tracks." -msgstr "" +msgstr "Thêm track mới." #: editor/animation_editor.cpp msgid "Move current track up." -msgstr "" +msgstr "Di chuyển track lên." #: editor/animation_editor.cpp msgid "Move current track down." -msgstr "" +msgstr "Di chuyển track xuống." #: editor/animation_editor.cpp msgid "Remove selected track." -msgstr "" +msgstr "Bỏ track đang chọn." #: editor/animation_editor.cpp msgid "Track tools" -msgstr "" +msgstr "Công cụ Track" #: editor/animation_editor.cpp msgid "Enable editing of individual keys by clicking them." -msgstr "" +msgstr "Cho phép chỉnh sửa từng key riêng bằng cách chọn chúng." #: editor/animation_editor.cpp msgid "Anim. Optimizer" @@ -306,162 +307,171 @@ msgstr "" #: editor/animation_editor.cpp msgid "Optimize" -msgstr "" +msgstr "Tối ưu" #: editor/animation_editor.cpp msgid "Select an AnimationPlayer from the Scene Tree to edit animations." msgstr "Chọn một AnimationPlayer từ Scene Tree để chỉnh sửa animation." #: editor/animation_editor.cpp +#, fuzzy msgid "Key" -msgstr "" +msgstr "Mã" #: editor/animation_editor.cpp msgid "Transition" -msgstr "" +msgstr "Chuyển tiếp" #: editor/animation_editor.cpp msgid "Scale Ratio:" -msgstr "" +msgstr "Tỉ lệ Scale:" #: editor/animation_editor.cpp msgid "Call Functions in Which Node?" -msgstr "" +msgstr "Gọi Function từ Node nào?" #: editor/animation_editor.cpp msgid "Remove invalid keys" -msgstr "" +msgstr "Hủy key không đúng chuẩn" #: editor/animation_editor.cpp +#, fuzzy msgid "Remove unresolved and empty tracks" -msgstr "" +msgstr "Gỡ bỏ track trống và không tìm thấy" #: editor/animation_editor.cpp msgid "Clean-up all animations" -msgstr "" +msgstr "Dọn dẹp tất cả animations" #: editor/animation_editor.cpp msgid "Clean-Up Animation(s) (NO UNDO!)" -msgstr "" +msgstr "Dọn dẹp tất cả Animation (KHÔNG THỂ HỒI LẠI)" #: editor/animation_editor.cpp msgid "Clean-Up" -msgstr "" +msgstr "Dọn dẹp" #: editor/array_property_edit.cpp msgid "Resize Array" -msgstr "" +msgstr "Đổi lại size Array" #: editor/array_property_edit.cpp msgid "Change Array Value Type" -msgstr "" +msgstr "Đổi loại giá trị Array" #: editor/array_property_edit.cpp msgid "Change Array Value" -msgstr "" +msgstr "Đổi giá trị Array" #: editor/code_editor.cpp msgid "Go to Line" -msgstr "" +msgstr "Đến Dòng" #: editor/code_editor.cpp msgid "Line Number:" -msgstr "" +msgstr "Dòng số:" #: editor/code_editor.cpp msgid "No Matches" -msgstr "" +msgstr "Không tìm thấy" #: editor/code_editor.cpp msgid "Replaced %d occurrence(s)." msgstr "" #: editor/code_editor.cpp +#, fuzzy msgid "Match Case" -msgstr "" +msgstr "Trùng khớp" #: editor/code_editor.cpp msgid "Whole Words" -msgstr "" +msgstr "Cả từ" #: editor/code_editor.cpp msgid "Replace" -msgstr "" +msgstr "Thay thế" #: editor/code_editor.cpp msgid "Replace All" -msgstr "" +msgstr "Thay thế tất cả" #: editor/code_editor.cpp msgid "Selection Only" -msgstr "" +msgstr "Chỉ lựa chọn" #: editor/code_editor.cpp msgid "Zoom In" -msgstr "" +msgstr "Phóng to" #: editor/code_editor.cpp msgid "Zoom Out" -msgstr "" +msgstr "Thu nhỏ" #: editor/code_editor.cpp msgid "Reset Zoom" -msgstr "" +msgstr "Đặt lại phóng" #: editor/code_editor.cpp editor/script_editor_debugger.cpp msgid "Line:" -msgstr "" +msgstr "Dòng:" #: editor/code_editor.cpp +#, fuzzy msgid "Col:" -msgstr "" +msgstr "Col:" #: editor/connections_dialog.cpp msgid "Method in target Node must be specified!" -msgstr "" +msgstr "Cách thức trong Node được chọn phải được ghi rõ!" #: editor/connections_dialog.cpp msgid "" "Target method not found! Specify a valid method or attach a script to target " "Node." msgstr "" +"Cách thức của đối tượng không tìm thấy! ghi rõ một cách thức hợp lệ hoặc " +"đính kèm một script cho đối tượng Node." #: editor/connections_dialog.cpp msgid "Connect To Node:" -msgstr "" +msgstr "Kết nối đến Node:" #: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp #: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp msgid "Add" -msgstr "" +msgstr "Thêm" #: editor/connections_dialog.cpp editor/dependency_editor.cpp #: editor/plugins/animation_tree_editor_plugin.cpp #: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp #: editor/project_settings_editor.cpp msgid "Remove" -msgstr "" +msgstr "Xóa" #: editor/connections_dialog.cpp +#, fuzzy msgid "Add Extra Call Argument:" -msgstr "" +msgstr "Thêm đối số:" #: editor/connections_dialog.cpp msgid "Extra Call Arguments:" msgstr "" #: editor/connections_dialog.cpp +#, fuzzy msgid "Path to Node:" -msgstr "" +msgstr "Đường đến Node:" #: editor/connections_dialog.cpp msgid "Make Function" -msgstr "" +msgstr "Tạo Function" #: editor/connections_dialog.cpp +#, fuzzy msgid "Deferred" -msgstr "" +msgstr "Hoãn lại" #: editor/connections_dialog.cpp msgid "Oneshot" @@ -479,45 +489,45 @@ msgstr "" #: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Close" -msgstr "" +msgstr "Tắt" #: editor/connections_dialog.cpp msgid "Connect" -msgstr "" +msgstr "Kết nối" #: editor/connections_dialog.cpp msgid "Connect '%s' to '%s'" -msgstr "" +msgstr "Kết nối '%s' đến '%s'" #: editor/connections_dialog.cpp msgid "Connecting Signal:" -msgstr "" +msgstr "Đang kết nối Signal:" #: editor/connections_dialog.cpp msgid "Disconnect '%s' from '%s'" -msgstr "" +msgstr "Hủy kết nối '%s' từ '%s'" #: editor/connections_dialog.cpp msgid "Connect..." -msgstr "" +msgstr "Kết nối..." #: editor/connections_dialog.cpp #: editor/plugins/animation_tree_editor_plugin.cpp msgid "Disconnect" -msgstr "" +msgstr "Hủy kết nối" #: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp msgid "Signals" -msgstr "" +msgstr "Tín hiệu" #: editor/create_dialog.cpp msgid "Change %s Type" -msgstr "" +msgstr "Đổi %s Type" #: editor/create_dialog.cpp editor/project_settings_editor.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Change" -msgstr "" +msgstr "Đổi" #: editor/create_dialog.cpp msgid "Create New %s" @@ -526,38 +536,39 @@ msgstr "Tạo %s Mới" #: editor/create_dialog.cpp editor/editor_file_dialog.cpp #: editor/filesystem_dock.cpp msgid "Favorites:" -msgstr "" +msgstr "Ưa thích:" #: editor/create_dialog.cpp editor/editor_file_dialog.cpp msgid "Recent:" -msgstr "" +msgstr "Gần đây:" #: editor/create_dialog.cpp editor/editor_node.cpp #: editor/plugins/asset_library_editor_plugin.cpp #: editor/plugins/script_editor_plugin.cpp editor/property_selector.cpp #: editor/quick_open.cpp msgid "Search:" -msgstr "" +msgstr "Tìm kiếm:" #: editor/create_dialog.cpp editor/editor_help.cpp #: editor/plugins/script_editor_plugin.cpp editor/property_selector.cpp #: editor/quick_open.cpp msgid "Matches:" -msgstr "" +msgstr "Phù hợp:" #: editor/create_dialog.cpp editor/editor_help.cpp #: editor/plugins/asset_library_editor_plugin.cpp editor/property_selector.cpp #: editor/script_editor_debugger.cpp msgid "Description:" -msgstr "" +msgstr "Mô tả:" #: editor/dependency_editor.cpp msgid "Search Replacement For:" -msgstr "" +msgstr "Tìm kiếm thay thế cho:" #: editor/dependency_editor.cpp +#, fuzzy msgid "Dependencies For:" -msgstr "" +msgstr "Phần phụ thuộc cho:" #: editor/dependency_editor.cpp msgid "" @@ -2017,12 +2028,14 @@ msgid "Issue Tracker" msgstr "" #: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp +#, fuzzy msgid "Community" -msgstr "" +msgstr "Cộng đồng" #: editor/editor_node.cpp +#, fuzzy msgid "About" -msgstr "" +msgstr "Thông tin" #: editor/editor_node.cpp msgid "Play the project." @@ -4223,7 +4236,7 @@ msgstr "" #: editor/plugins/particles_editor_plugin.cpp msgid "Volume" -msgstr "" +msgstr "Âm lượng" #: editor/plugins/particles_editor_plugin.cpp msgid "Emission Source: " @@ -4265,7 +4278,7 @@ msgstr "" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp msgid "Select Points" -msgstr "" +msgstr "Chọn Points" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp @@ -4275,12 +4288,12 @@ msgstr "" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp msgid "Click: Add Point" -msgstr "" +msgstr "Nhấp: Tạo Point" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp msgid "Right Click: Delete Point" -msgstr "" +msgstr "Nhấp chuột phải: Xóa Point" #: editor/plugins/path_2d_editor_plugin.cpp msgid "Select Control Points (Shift+Drag)" @@ -4299,7 +4312,7 @@ msgstr "" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp msgid "Delete Point" -msgstr "" +msgstr "Xóa Point" #: editor/plugins/path_2d_editor_plugin.cpp #: editor/plugins/path_editor_plugin.cpp @@ -4562,27 +4575,27 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp msgid "Save Theme" -msgstr "" +msgstr "Lưu Theme" #: editor/plugins/script_editor_plugin.cpp msgid "Save Theme As" -msgstr "" +msgstr "Lưu Theme thành" #: editor/plugins/script_editor_plugin.cpp msgid "Close Docs" -msgstr "" +msgstr "Đóng Docs" #: editor/plugins/script_editor_plugin.cpp msgid "Close All" -msgstr "" +msgstr "Đóng tất cả" #: editor/plugins/script_editor_plugin.cpp msgid "Close Other Tabs" -msgstr "" +msgstr "Đóng tất cả Tab" #: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp msgid "Run" -msgstr "" +msgstr "Chạy" #: editor/plugins/script_editor_plugin.cpp msgid "Toggle Scripts Panel" @@ -4591,12 +4604,12 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp #: editor/plugins/script_text_editor.cpp msgid "Find..." -msgstr "" +msgstr "Tìm..." #: editor/plugins/script_editor_plugin.cpp #: editor/plugins/script_text_editor.cpp msgid "Find Next" -msgstr "" +msgstr "Tìm tiếp theo" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Step Over" @@ -4613,7 +4626,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp #: editor/script_editor_debugger.cpp msgid "Continue" -msgstr "" +msgstr "Tiếp tục" #: editor/plugins/script_editor_plugin.cpp msgid "Keep Debugger Open" @@ -4645,11 +4658,11 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp msgid "Discard" -msgstr "" +msgstr "Hủy" #: editor/plugins/script_editor_plugin.cpp msgid "Create Script" -msgstr "" +msgstr "Tạo Script" #: editor/plugins/script_editor_plugin.cpp msgid "" @@ -4680,7 +4693,7 @@ msgstr "" #: editor/plugins/script_text_editor.cpp msgid "Pick Color" -msgstr "" +msgstr "Chọn màu" #: editor/plugins/script_text_editor.cpp msgid "Convert Case" @@ -4701,13 +4714,13 @@ msgstr "" #: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp #: scene/gui/text_edit.cpp msgid "Cut" -msgstr "" +msgstr "Cắt" #: editor/plugins/script_text_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp #: scene/gui/line_edit.cpp scene/gui/text_edit.cpp msgid "Copy" -msgstr "" +msgstr "Copy" #: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp #: scene/gui/text_edit.cpp @@ -6252,8 +6265,9 @@ msgid "Project Settings (project.godot)" msgstr "" #: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp +#, fuzzy msgid "General" -msgstr "" +msgstr "Tổng quan" #: editor/project_settings_editor.cpp editor/property_editor.cpp msgid "Property:" @@ -7283,6 +7297,10 @@ msgstr "" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +msgid "View log" +msgstr "" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po index 48e30ceab3..51e0181fc8 100644 --- a/editor/translations/zh_CN.po +++ b/editor/translations/zh_CN.po @@ -7372,6 +7372,11 @@ msgstr "构建项目" msgid "Warnings" msgstr "警告" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "查看文件" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "内部异常堆栈追朔结束" diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po index 568390a7a8..de03512af1 100644 --- a/editor/translations/zh_HK.po +++ b/editor/translations/zh_HK.po @@ -7589,6 +7589,11 @@ msgstr "專案" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "檔案" + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po index 38b565a37f..df0c474322 100644 --- a/editor/translations/zh_TW.po +++ b/editor/translations/zh_TW.po @@ -2,7 +2,6 @@ # Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. # Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. -# # Allen H <w84miracle@gmail.com>, 2017. # Billy SU <g4691821@gmail.com>, 2018. # Chao Yu <casd82@gmail.com>, 2017. @@ -12,19 +11,18 @@ # popcade <popcade@gmail.com>, 2016. # Qing <icinriiq@gmail.com>, 2018. # Sam Pan <sampan66@gmail.com>, 2016. -# msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2018-04-24 09:35+0000\n" -"Last-Translator: Qing <icinriiq@gmail.com>\n" +"PO-Revision-Date: 2018-07-15 16:35+0000\n" +"Last-Translator: Kisaragi Hiu <mail@kisaragi-hiu.com>\n" "Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hant/>\n" "Language: zh_TW\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.0-dev\n" +"X-Generator: Weblate 3.1-dev\n" #: editor/animation_editor.cpp msgid "Disabled" @@ -35,9 +33,8 @@ msgid "All Selection" msgstr "所有的選擇" #: editor/animation_editor.cpp -#, fuzzy msgid "Anim Change Keyframe Time" -msgstr "動畫更改座標" +msgstr "動畫更改關鍵幀時間" #: editor/animation_editor.cpp msgid "Anim Change Transition" @@ -52,9 +49,8 @@ msgid "Anim Change Keyframe Value" msgstr "動畫更改關鍵幀數值" #: editor/animation_editor.cpp -#, fuzzy msgid "Anim Change Call" -msgstr "動畫改變呼叫" +msgstr "動畫更改呼叫" #: editor/animation_editor.cpp msgid "Anim Add Track" @@ -345,7 +341,7 @@ msgstr "移除無效按鍵" #: editor/animation_editor.cpp msgid "Remove unresolved and empty tracks" -msgstr "" +msgstr "刪除未解決或是空的軌道" #: editor/animation_editor.cpp msgid "Clean-up all animations" @@ -523,9 +519,8 @@ msgid "Signals" msgstr "信號" #: editor/create_dialog.cpp -#, fuzzy msgid "Change %s Type" -msgstr "變更鏡頭尺寸" +msgstr "變更 %s 尺寸" #: editor/create_dialog.cpp editor/project_settings_editor.cpp #: modules/visual_script/visual_script_editor.cpp @@ -533,9 +528,8 @@ msgid "Change" msgstr "更換" #: editor/create_dialog.cpp -#, fuzzy msgid "Create New %s" -msgstr "新增" +msgstr "新增 %s" #: editor/create_dialog.cpp editor/editor_file_dialog.cpp #: editor/filesystem_dock.cpp @@ -618,7 +612,7 @@ msgstr "相依性編輯器" #: editor/dependency_editor.cpp msgid "Search Replacement Resource:" -msgstr "" +msgstr "搜尋替代資源:" #: editor/dependency_editor.cpp editor/editor_file_dialog.cpp #: editor/editor_help.cpp editor/editor_node.cpp editor/filesystem_dock.cpp @@ -670,7 +664,7 @@ msgstr "修復相依性" #: editor/dependency_editor.cpp msgid "Errors loading!" -msgstr "" +msgstr "載入錯誤!" #: editor/dependency_editor.cpp msgid "Permanently delete %d item(s)? (No undo!)" @@ -682,7 +676,7 @@ msgstr "擁有" #: editor/dependency_editor.cpp msgid "Resources Without Explicit Ownership:" -msgstr "" +msgstr "沒有明定擁有者的資源:" #: editor/dependency_editor.cpp editor/editor_node.cpp msgid "Orphan Resource Explorer" @@ -701,16 +695,19 @@ msgid "Delete" msgstr "刪除" #: editor/dictionary_property_edit.cpp +#, fuzzy msgid "Change Dictionary Key" -msgstr "" +msgstr "改變字典 key" #: editor/dictionary_property_edit.cpp +#, fuzzy msgid "Change Dictionary Value" -msgstr "" +msgstr "改變字典 value" #: editor/editor_about.cpp +#, fuzzy msgid "Thanks from the Godot community!" -msgstr "" +msgstr "Godot 社群感謝你!" #: editor/editor_about.cpp msgid "Thanks!" @@ -718,7 +715,7 @@ msgstr "謝謝!" #: editor/editor_about.cpp msgid "Godot Engine contributors" -msgstr "" +msgstr "Godot Engine 貢獻者" #: editor/editor_about.cpp msgid "Project Founders" @@ -726,12 +723,11 @@ msgstr "專案創始人" #: editor/editor_about.cpp msgid "Lead Developer" -msgstr "" +msgstr "主開發者" #: editor/editor_about.cpp -#, fuzzy msgid "Project Manager " -msgstr "專案創始人" +msgstr "專案管理人 " #: editor/editor_about.cpp msgid "Developers" @@ -739,35 +735,38 @@ msgstr "開發者" #: editor/editor_about.cpp msgid "Authors" -msgstr "" +msgstr "作者" #: editor/editor_about.cpp msgid "Platinum Sponsors" -msgstr "" +msgstr "白金贊助" #: editor/editor_about.cpp msgid "Gold Sponsors" -msgstr "" +msgstr "黃金贊助" #: editor/editor_about.cpp +#, fuzzy msgid "Mini Sponsors" -msgstr "" +msgstr "迷你贊助" #: editor/editor_about.cpp msgid "Gold Donors" -msgstr "" +msgstr "黃金捐贈者" #: editor/editor_about.cpp +#, fuzzy msgid "Silver Donors" -msgstr "" +msgstr "白銀捐贈者" #: editor/editor_about.cpp +#, fuzzy msgid "Bronze Donors" -msgstr "" +msgstr "紅銅捐贈者" #: editor/editor_about.cpp msgid "Donors" -msgstr "" +msgstr "捐贈者" #: editor/editor_about.cpp msgid "License" @@ -775,7 +774,7 @@ msgstr "授權" #: editor/editor_about.cpp msgid "Thirdparty License" -msgstr "" +msgstr "第三方授權條款" #: editor/editor_about.cpp msgid "" @@ -784,14 +783,16 @@ msgid "" "is an exhaustive list of all such thirdparty components with their " "respective copyright statements and license terms." msgstr "" +"Godot Engine 依賴著許多與 MIT 授權條款相容、自由開源的第三方函式庫。以下是這" +"些第三方元件的完整列表,附有它們各自的著作權宣示與授權條款。" #: editor/editor_about.cpp msgid "All Components" -msgstr "" +msgstr "所有元件" #: editor/editor_about.cpp msgid "Components" -msgstr "" +msgstr "元件" #: editor/editor_about.cpp msgid "Licenses" @@ -799,21 +800,20 @@ msgstr "授權" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Error opening package file, not in zip format." -msgstr "" +msgstr "開啟套件檔案出錯,非 zip 格式。" #: editor/editor_asset_installer.cpp -#, fuzzy msgid "Uncompressing Assets" -msgstr "(重新)載入素材" +msgstr "正在解壓縮素材" #: editor/editor_asset_installer.cpp editor/project_manager.cpp msgid "Package Installed Successfully!" -msgstr "" +msgstr "套件安裝成功!" #: editor/editor_asset_installer.cpp #: editor/plugins/asset_library_editor_plugin.cpp msgid "Success!" -msgstr "" +msgstr "成功!" #: editor/editor_asset_installer.cpp #: editor/plugins/asset_library_editor_plugin.cpp @@ -821,147 +821,148 @@ msgid "Install" msgstr "安裝" #: editor/editor_asset_installer.cpp +#, fuzzy msgid "Package Installer" -msgstr "" +msgstr "套件安裝" #: editor/editor_audio_buses.cpp msgid "Speakers" -msgstr "" +msgstr "喇叭" #: editor/editor_audio_buses.cpp msgid "Add Effect" -msgstr "" +msgstr "新增效果" #: editor/editor_audio_buses.cpp msgid "Rename Audio Bus" -msgstr "" +msgstr "重新命名 Audio Bus" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Change Audio Bus Volume" -msgstr "重設縮放大小" +msgstr "變更 Audio Bus 音量" #: editor/editor_audio_buses.cpp +#, fuzzy msgid "Toggle Audio Bus Solo" -msgstr "" +msgstr "切換 Audio Bus 的 Solo" #: editor/editor_audio_buses.cpp +#, fuzzy msgid "Toggle Audio Bus Mute" -msgstr "" +msgstr "切換 Audio Bus 的 Mute" #: editor/editor_audio_buses.cpp +#, fuzzy msgid "Toggle Audio Bus Bypass Effects" -msgstr "" +msgstr "切換 Audio Bus 忽略效果" #: editor/editor_audio_buses.cpp msgid "Select Audio Bus Send" -msgstr "" +msgstr "選擇 Audio Bus 輸出地點" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus Effect" -msgstr "" +msgstr "新增 Audio Bus 效果" #: editor/editor_audio_buses.cpp msgid "Move Bus Effect" -msgstr "" +msgstr "移動 Bus 效果" #: editor/editor_audio_buses.cpp msgid "Delete Bus Effect" -msgstr "" +msgstr "刪除 Bus 效果" #: editor/editor_audio_buses.cpp msgid "Audio Bus, Drag and Drop to rearrange." -msgstr "" +msgstr "Audio Bus。拖放以重新排列。" #: editor/editor_audio_buses.cpp +#, fuzzy msgid "Solo" -msgstr "" +msgstr "Solo" #: editor/editor_audio_buses.cpp msgid "Mute" msgstr "靜音" #: editor/editor_audio_buses.cpp +#, fuzzy msgid "Bypass" -msgstr "" +msgstr "忽略效果 (Bypass)" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Bus options" -msgstr "除錯選項" +msgstr "Bus 選項" #: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp #: editor/plugins/tile_map_editor_plugin.cpp editor/scene_tree_dock.cpp msgid "Duplicate" -msgstr "" +msgstr "製作複本" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Reset Volume" -msgstr "重設縮放大小" +msgstr "重設音量" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Delete Effect" -msgstr "刪除" +msgstr "刪除效果" #: editor/editor_audio_buses.cpp msgid "Audio" -msgstr "" +msgstr "聲音" #: editor/editor_audio_buses.cpp msgid "Add Audio Bus" -msgstr "" +msgstr "新增 Audio Bus" #: editor/editor_audio_buses.cpp msgid "Master bus can't be deleted!" -msgstr "" +msgstr "Master Bus 不能被刪除!" #: editor/editor_audio_buses.cpp msgid "Delete Audio Bus" -msgstr "" +msgstr "刪除 Audio Bus" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Duplicate Audio Bus" -msgstr "複製所選" +msgstr "製作 Audio Bus 的複本" #: editor/editor_audio_buses.cpp -#, fuzzy msgid "Reset Bus Volume" -msgstr "重設縮放大小" +msgstr "重設 Bus 音量" #: editor/editor_audio_buses.cpp msgid "Move Audio Bus" -msgstr "" +msgstr "移動 Audio Bus" #: editor/editor_audio_buses.cpp msgid "Save Audio Bus Layout As..." -msgstr "" +msgstr "另存 Audio Bus 配置為..." #: editor/editor_audio_buses.cpp +#, fuzzy msgid "Location for New Layout..." -msgstr "" +msgstr "新配置的位置..." #: editor/editor_audio_buses.cpp msgid "Open Audio Bus Layout" -msgstr "" +msgstr "開啟 Audio Bus 配置" #: editor/editor_audio_buses.cpp msgid "There is no 'res://default_bus_layout.tres' file." -msgstr "" +msgstr "「res://default_bus_layout.tres」檔案不存在。" #: editor/editor_audio_buses.cpp msgid "Invalid file, not an audio bus layout." -msgstr "" +msgstr "檔案格式不正確,不是 Audio Bus 配置檔。" #: editor/editor_audio_buses.cpp msgid "Add Bus" -msgstr "" +msgstr "新增 Bus" #: editor/editor_audio_buses.cpp msgid "Create a new Bus Layout." -msgstr "" +msgstr "建立新的 Bus 配置。" #: editor/editor_audio_buses.cpp editor/property_editor.cpp #: editor/script_create_dialog.cpp @@ -970,7 +971,7 @@ msgstr "載入" #: editor/editor_audio_buses.cpp msgid "Load an existing Bus Layout." -msgstr "" +msgstr "讀取現存的 Bus 配置。" #: editor/editor_audio_buses.cpp #: editor/plugins/animation_player_editor_plugin.cpp @@ -979,7 +980,7 @@ msgstr "另存新檔" #: editor/editor_audio_buses.cpp msgid "Save this Bus Layout to a file." -msgstr "" +msgstr "儲存目前的 Bus 配置到檔案裡。" #: editor/editor_audio_buses.cpp editor/import_dock.cpp msgid "Load Default" @@ -987,7 +988,7 @@ msgstr "載入預設值" #: editor/editor_audio_buses.cpp msgid "Load the default Bus Layout." -msgstr "" +msgstr "載入預設的 Bus 配置。" #: editor/editor_autoload_settings.cpp msgid "Invalid name." @@ -999,7 +1000,7 @@ msgstr "合法字元:" #: editor/editor_autoload_settings.cpp msgid "Invalid name. Must not collide with an existing engine class name." -msgstr "" +msgstr "不正確的名字。名字不能與現有的 engine class 名衝突。" #: editor/editor_autoload_settings.cpp msgid "Invalid name. Must not collide with an existing buit-in type name." @@ -1022,16 +1023,19 @@ msgid "Not in resource path." msgstr "在資源路徑中找不到" #: editor/editor_autoload_settings.cpp +#, fuzzy msgid "Add AutoLoad" -msgstr "" +msgstr "新增 AutoLoad" #: editor/editor_autoload_settings.cpp +#, fuzzy msgid "Autoload '%s' already exists!" -msgstr "" +msgstr "Autoload「%s」已經存在!" #: editor/editor_autoload_settings.cpp +#, fuzzy msgid "Rename Autoload" -msgstr "" +msgstr "重新命名 Autoload" #: editor/editor_autoload_settings.cpp msgid "Toggle AutoLoad Globals" @@ -1039,19 +1043,21 @@ msgstr "" #: editor/editor_autoload_settings.cpp msgid "Move Autoload" -msgstr "" +msgstr "移動 Autoload" #: editor/editor_autoload_settings.cpp +#, fuzzy msgid "Remove Autoload" -msgstr "" +msgstr "刪除 Autoload" #: editor/editor_autoload_settings.cpp msgid "Enable" msgstr "啟用" #: editor/editor_autoload_settings.cpp +#, fuzzy msgid "Rearrange Autoloads" -msgstr "" +msgstr "重新排列 Autoload" #: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp #: scene/gui/file_dialog.cpp @@ -1084,16 +1090,18 @@ msgid "Updating scene..." msgstr "更新場景中..." #: editor/editor_data.cpp +#, fuzzy msgid "[empty]" -msgstr "" +msgstr "(空)" #: editor/editor_data.cpp msgid "[unsaved]" -msgstr "" +msgstr "(未儲存)" #: editor/editor_dir_dialog.cpp +#, fuzzy msgid "Please select a base directory first" -msgstr "" +msgstr "請先選擇一個基底的資料夾" #: editor/editor_dir_dialog.cpp msgid "Choose a Directory" @@ -1122,7 +1130,7 @@ msgstr "選擇" #: editor/editor_export.cpp msgid "Storing File:" -msgstr "" +msgstr "儲存檔案:" #: editor/editor_export.cpp msgid "Packing" @@ -1137,22 +1145,20 @@ msgid "File Exists, Overwrite?" msgstr "檔案已經存在, 要覆寫嗎?" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp -#, fuzzy msgid "Select Current Folder" -msgstr "新增資料夾" +msgstr "選擇目前的資料夾" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Copy Path" -msgstr "" +msgstr "複製路徑" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp msgid "Show In File Manager" -msgstr "" +msgstr "在檔案管理員內顯示" #: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp -#, fuzzy msgid "New Folder..." -msgstr "新增資料夾" +msgstr "新增資料夾..." #: editor/editor_file_dialog.cpp msgid "Refresh" @@ -1160,7 +1166,7 @@ msgstr "重新整理" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "All Recognized" -msgstr "" +msgstr "可認得全部" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "All Files (*)" @@ -1168,7 +1174,7 @@ msgstr "所有類型檔案" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Open a File" -msgstr "" +msgstr "開啟檔案" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Open File(s)" @@ -1190,7 +1196,7 @@ msgstr "儲存" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Save a File" -msgstr "" +msgstr "儲存檔案" #: editor/editor_file_dialog.cpp msgid "Go Back" @@ -1209,12 +1215,13 @@ msgid "Toggle Hidden Files" msgstr "切換顯示隱藏檔案" #: editor/editor_file_dialog.cpp +#, fuzzy msgid "Toggle Favorite" -msgstr "" +msgstr "切換最愛" #: editor/editor_file_dialog.cpp msgid "Toggle Mode" -msgstr "" +msgstr "切換模式" #: editor/editor_file_dialog.cpp msgid "Focus Path" @@ -1247,8 +1254,9 @@ msgid "File:" msgstr "檔案:" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +#, fuzzy msgid "Must use a valid extension." -msgstr "" +msgstr "必須使用有效的副檔名。" #: editor/editor_file_system.cpp msgid "ScanSources" @@ -1261,27 +1269,28 @@ msgstr "(重新)載入素材" #: editor/editor_help.cpp editor/editor_node.cpp #: editor/plugins/script_editor_plugin.cpp msgid "Search Help" -msgstr "" +msgstr "搜尋幫助" #: editor/editor_help.cpp msgid "Class List:" -msgstr "" +msgstr "Class 列表:" #: editor/editor_help.cpp msgid "Search Classes" -msgstr "" +msgstr "搜尋 Class" #: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Top" -msgstr "" +msgstr "上面" #: editor/editor_help.cpp editor/property_editor.cpp msgid "Class:" -msgstr "" +msgstr "Class:" #: editor/editor_help.cpp editor/scene_tree_editor.cpp msgid "Inherits:" -msgstr "" +msgstr "繼承:" #: editor/editor_help.cpp msgid "Inherited by:" @@ -1305,19 +1314,19 @@ msgstr "" #: editor/editor_help.cpp msgid "Public Methods:" -msgstr "" +msgstr "公開 method:" #: editor/editor_help.cpp msgid "GUI Theme Items" -msgstr "" +msgstr "介面主題項目" #: editor/editor_help.cpp msgid "GUI Theme Items:" -msgstr "" +msgstr "介面主題項目:" #: editor/editor_help.cpp modules/visual_script/visual_script_editor.cpp msgid "Signals:" -msgstr "" +msgstr "訊號:" #: editor/editor_help.cpp msgid "Enumerations" @@ -1333,11 +1342,11 @@ msgstr "" #: editor/editor_help.cpp msgid "Constants" -msgstr "" +msgstr "定數" #: editor/editor_help.cpp msgid "Constants:" -msgstr "" +msgstr "定數:" #: editor/editor_help.cpp msgid "Description" @@ -1345,7 +1354,7 @@ msgstr "描述:" #: editor/editor_help.cpp msgid "Online Tutorials:" -msgstr "" +msgstr "線上教學:" #: editor/editor_help.cpp msgid "" @@ -1353,20 +1362,25 @@ msgid "" "$url]contribute one[/url][/color] or [color=$color][url=$url2]request one[/" "url][/color]." msgstr "" +"目前沒有這個 class 的教學,你可以[color=$color][url=$url]貢獻一個[/url][/" +"color]或[color=$color][url=$url2]要求一個[/url][/color]。" #: editor/editor_help.cpp msgid "Properties" msgstr "" #: editor/editor_help.cpp +#, fuzzy msgid "Property Description:" -msgstr "" +msgstr "Property 說明:" #: editor/editor_help.cpp msgid "" "There is currently no description for this property. Please help us by " "[color=$color][url=$url]contributing one[/url][/color]!" msgstr "" +"目前沒有這個 property 的說明。請幫我們[color=$color][url=$url]貢獻[/url][/" +"color]一個!" #: editor/editor_help.cpp msgid "Methods" @@ -1374,13 +1388,15 @@ msgstr "方法" #: editor/editor_help.cpp msgid "Method Description:" -msgstr "" +msgstr "Method 說明:" #: editor/editor_help.cpp msgid "" "There is currently no description for this method. Please help us by [color=" "$color][url=$url]contributing one[/url][/color]!" msgstr "" +"目前沒有這個 method 的說明。請幫我們[color=$color][url=$url]貢獻[/url][/" +"color]一個!" #: editor/editor_help.cpp msgid "Search Text" @@ -1408,15 +1424,15 @@ msgstr "輸出:" #: editor/editor_node.cpp msgid "Project export failed with error code %d." -msgstr "" +msgstr "專案輸出失敗,錯誤代碼是 %d。" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Error saving resource!" -msgstr "" +msgstr "儲存資源錯誤!" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Save Resource As..." -msgstr "" +msgstr "另存資源為..." #: editor/editor_node.cpp editor/plugins/spatial_editor_plugin.cpp #: editor/scene_tree_dock.cpp @@ -1424,16 +1440,17 @@ msgid "I see..." msgstr "我知道了" #: editor/editor_node.cpp +#, fuzzy msgid "Can't open file for writing:" -msgstr "" +msgstr "無法以寫入模式開啟檔案:" #: editor/editor_node.cpp msgid "Requested file format unknown:" -msgstr "" +msgstr "要求了不明的檔案格式:" #: editor/editor_node.cpp msgid "Error while saving." -msgstr "" +msgstr "儲存中發生了錯誤。" #: editor/editor_node.cpp msgid "Can't open '%s'." @@ -1445,11 +1462,12 @@ msgstr "分析 \"%s\" 時發生錯誤。" #: editor/editor_node.cpp msgid "Unexpected end of file '%s'." -msgstr "" +msgstr "意料外的檔案結尾 (EOF) '%s'。" #: editor/editor_node.cpp +#, fuzzy msgid "Missing '%s' or its dependencies." -msgstr "" +msgstr "缺失 '%s' 或它的依存。" #: editor/editor_node.cpp msgid "Error while loading '%s'." @@ -1457,7 +1475,7 @@ msgstr "載入 \"%s\" 時發生錯誤。" #: editor/editor_node.cpp msgid "Saving Scene" -msgstr "" +msgstr "正在儲存場景" #: editor/editor_node.cpp msgid "Analyzing" @@ -7424,6 +7442,11 @@ msgstr "專案設定" msgid "Warnings" msgstr "" +#: modules/mono/editor/mono_bottom_panel.cpp +#, fuzzy +msgid "View log" +msgstr "過濾檔案..." + #: modules/mono/mono_gd/gd_mono_utils.cpp msgid "End of inner exception stack trace" msgstr "" diff --git a/main/input_default.cpp b/main/input_default.cpp index 29d30110e3..4363fc1c88 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -684,7 +684,7 @@ void InputDefault::joy_button(int p_device, int p_button, bool p_pressed) { return; }; - Map<int, JoyEvent>::Element *el = map_db[joy.mapping].buttons.find(p_button); + const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].buttons.find(p_button); if (!el) { //don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis //return _button_event(p_last_id, p_device, p_button, p_pressed); @@ -755,7 +755,7 @@ void InputDefault::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { return; }; - Map<int, JoyEvent>::Element *el = map_db[joy.mapping].axis.find(p_axis); + const Map<int, JoyEvent>::Element *el = map_db[joy.mapping].axis.find(p_axis); if (!el) { //return _axis_event(p_last_id, p_device, p_axis, p_value); return; @@ -831,7 +831,7 @@ void InputDefault::joy_hat(int p_device, int p_val) { _THREAD_SAFE_METHOD_; const Joypad &joy = joy_names[p_device]; - JoyEvent *map; + const JoyEvent *map; if (joy.mapping == -1) { map = hat_map_default; diff --git a/main/main.cpp b/main/main.cpp index 56dd5f73e7..5beeb95a11 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1734,8 +1734,11 @@ bool Main::iteration() { int physics_fps = Engine::get_singleton()->get_iterations_per_second(); float frame_slice = 1.0 / physics_fps; + float time_scale = Engine::get_singleton()->get_time_scale(); + MainFrameTime advance = main_timer_sync.advance(frame_slice, physics_fps); double step = advance.idle_step; + double scaled_step = step * time_scale; Engine::get_singleton()->_frame_step = step; @@ -1757,8 +1760,6 @@ bool Main::iteration() { advance.physics_steps = max_physics_steps; } - float time_scale = Engine::get_singleton()->get_time_scale(); - bool exit = false; Engine::get_singleton()->_in_physics = true; @@ -1805,11 +1806,11 @@ bool Main::iteration() { if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) { if (VisualServer::get_singleton()->has_changed()) { - VisualServer::get_singleton()->draw(); // flush visual commands + VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands Engine::get_singleton()->frames_drawn++; } } else { - VisualServer::get_singleton()->draw(); // flush visual commands + VisualServer::get_singleton()->draw(true, scaled_step); // flush visual commands Engine::get_singleton()->frames_drawn++; force_redraw_requested = false; } diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp index 5c7633a0cf..0a9d03c1b7 100644 --- a/main/tests/test_gdscript.cpp +++ b/main/tests/test_gdscript.cpp @@ -193,14 +193,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { case GDScriptParser::OperatorNode::OP_BIT_INVERT: { txt = "~" + _parser_expr(c_node->arguments[0]); } break; - case GDScriptParser::OperatorNode::OP_PREINC: { - } break; - case GDScriptParser::OperatorNode::OP_PREDEC: { - } break; - case GDScriptParser::OperatorNode::OP_INC: { - } break; - case GDScriptParser::OperatorNode::OP_DEC: { - } break; case GDScriptParser::OperatorNode::OP_IN: { txt = _parser_expr(c_node->arguments[0]) + " in " + _parser_expr(c_node->arguments[1]); } break; @@ -455,10 +447,9 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i print_line("\n"); } - for (int i = 0; i < p_class->constant_expressions.size(); i++) { - - const GDScriptParser::ClassNode::Constant &constant = p_class->constant_expressions[i]; - _print_indent(p_indent, "const " + String(constant.identifier) + "=" + _parser_expr(constant.expression)); + for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { + const GDScriptParser::ClassNode::Constant &constant = E->get(); + _print_indent(p_indent, "const " + String(E->key()) + "=" + _parser_expr(constant.expression)); } for (int i = 0; i < p_class->variables.size(); i++) { @@ -933,8 +924,8 @@ MainLoop *test(TestType p_type) { Vector<uint8_t> buf; int flen = fa->get_len(); buf.resize(fa->get_len() + 1); - fa->get_buffer(&buf[0], flen); - buf[flen] = 0; + fa->get_buffer(buf.ptrw(), flen); + buf.write[flen] = 0; String code; code.parse_utf8((const char *)&buf[0]); diff --git a/main/tests/test_io.cpp b/main/tests/test_io.cpp index 08dc374ed1..4f98955995 100644 --- a/main/tests/test_io.cpp +++ b/main/tests/test_io.cpp @@ -103,7 +103,7 @@ MainLoop *test() { int len = z->get_len(); Vector<uint8_t> zip; zip.resize(len); - z->get_buffer(&zip[0], len); + z->get_buffer(zip.ptrw(), len); z->close(); memdelete(z); diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp index 8b71c5dc70..1a72416d6a 100644 --- a/main/tests/test_math.cpp +++ b/main/tests/test_math.cpp @@ -503,8 +503,8 @@ MainLoop *test() { Vector<uint8_t> buf; int flen = fa->get_len(); buf.resize(fa->get_len() + 1); - fa->get_buffer(&buf[0], flen); - buf[flen] = 0; + fa->get_buffer(buf.ptrw(), flen); + buf.write[flen] = 0; String code; code.parse_utf8((const char *)&buf[0]); diff --git a/main/tests/test_physics.cpp b/main/tests/test_physics.cpp index 475663dabe..99c8fce70e 100644 --- a/main/tests/test_physics.cpp +++ b/main/tests/test_physics.cpp @@ -228,11 +228,11 @@ protected: for (int i = 0; i < p_width; i++) { - grid[i].resize(p_height); + grid.write[i].resize(p_height); for (int j = 0; j < p_height; j++) { - grid[i][j] = 1.0 + Math::random(-p_cellheight, p_cellheight); + grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight); } } diff --git a/misc/dist/linux/godot.appdata.xml b/misc/dist/linux/org.godotengine.Godot.appdata.xml index a381556025..8278f1f6f5 100644 --- a/misc/dist/linux/godot.appdata.xml +++ b/misc/dist/linux/org.godotengine.Godot.appdata.xml @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- Copyright 2017-2018 Rémi Verschelde <akien@godotengine.org> --> <component type="desktop"> - <id>godot.desktop</id> + <id>org.godotengine.Godot.desktop</id> <metadata_license>CC0-1.0</metadata_license> <project_license>MIT</project_license> <name>Godot Engine</name> <summary>Multi-platform 2D and 3D game engine with a feature-rich editor</summary> + <icon type="remote">https://raw.githubusercontent.com/godotengine/godot/master/icon.png</icon> + <launchable type="desktop-id">org.godotengine.Godot.desktop</launchable> <description> <p> Godot is an advanced, feature-packed, multi-platform 2D and 3D game @@ -24,8 +26,12 @@ <image>https://download.tuxfamily.org/godotengine/media/screenshots/editor_3d_fracteed-720p.jpg</image> </screenshot> </screenshots> + <categories> + <category>Development</category> + </categories> <url type="homepage">https://godotengine.org</url> <url type="bugtracker">https://github.com/godotengine/godot/issues</url> + <url type="faq">http://docs.godotengine.org/en/latest/about/faq.html</url> <url type="help">http://docs.godotengine.org</url> <url type="donation">https://godotengine.org/donate</url> <url type="translate">https://hosted.weblate.org/projects/godot-engine/godot</url> diff --git a/misc/dist/linux/godot.desktop b/misc/dist/linux/org.godotengine.Godot.desktop index 974352b117..439b1d87b8 100644 --- a/misc/dist/linux/godot.desktop +++ b/misc/dist/linux/org.godotengine.Godot.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Name=Godot Engine GenericName=Libre game engine -Comment=Multi-platform 2D and 3D game engine with a feature rich editor +Comment=Multi-platform 2D and 3D game engine with a feature-rich editor Exec=godot -p Icon=godot Terminal=false diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index bfb452d109..b004641838 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -80,7 +80,7 @@ void AreaBullet::dispatch_callbacks() { // Reverse order because I've to remove EXIT objects for (int i = overlappingObjects.size() - 1; 0 <= i; --i) { - OverlappingObjectData &otherObj = overlappingObjects[i]; + OverlappingObjectData &otherObj = overlappingObjects.write[i]; switch (otherObj.state) { case OVERLAP_STATE_ENTER: @@ -199,13 +199,13 @@ void AreaBullet::add_overlap(CollisionObjectBullet *p_otherObject) { void AreaBullet::put_overlap_as_exit(int p_index) { scratch(); - overlappingObjects[p_index].state = OVERLAP_STATE_EXIT; + overlappingObjects.write[p_index].state = OVERLAP_STATE_EXIT; } void AreaBullet::put_overlap_as_inside(int p_index) { // This check is required to be sure this body was inside if (OVERLAP_STATE_DIRTY == overlappingObjects[p_index].state) { - overlappingObjects[p_index].state = OVERLAP_STATE_INSIDE; + overlappingObjects.write[p_index].state = OVERLAP_STATE_INSIDE; } } diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 54431f93f1..9263a9ba6d 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -169,7 +169,7 @@ real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const { } RID BulletPhysicsServer::space_create() { - SpaceBullet *space = bulletnew(SpaceBullet(false)); + SpaceBullet *space = bulletnew(SpaceBullet); CreateThenReturnRID(space_owner, space); } @@ -567,9 +567,6 @@ void BulletPhysicsServer::body_clear_shapes(RID p_body) { void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, uint32_t p_ID) { CollisionObjectBullet *body = get_collisin_object(p_body); - if (!body) { - body = soft_body_owner.get(p_body); - } ERR_FAIL_COND(!body); body->set_instance_id(p_ID); @@ -647,6 +644,20 @@ float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) con return body->get_param(p_param); } +void BulletPhysicsServer::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_combine_mode(p_param, p_mode); +} + +PhysicsServer::CombineMode BulletPhysicsServer::body_get_combine_mode(RID p_body, BodyParameter p_param) const { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); + + return body->get_combine_mode(p_param); +} + void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -710,6 +721,34 @@ Vector3 BulletPhysicsServer::body_get_applied_torque(RID p_body) const { return body->get_applied_torque(); } +void BulletPhysicsServer::body_add_central_force(RID p_body, const Vector3 &p_force) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_force(p_force); +} + +void BulletPhysicsServer::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_force(p_force, p_pos); +} + +void BulletPhysicsServer::body_add_torque(RID p_body, const Vector3 &p_torque) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_torque(p_torque); +} + +void BulletPhysicsServer::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { + RigidBodyBullet *body = rigid_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_impulse(p_impulse); +} + void BulletPhysicsServer::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -853,6 +892,13 @@ RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) { CreateThenReturnRID(soft_body_owner, body); } +void BulletPhysicsServer::soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->update_visual_server(p_visual_server_handler); +} + void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) { SoftBodyBullet *body = soft_body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -879,11 +925,11 @@ RID BulletPhysicsServer::soft_body_get_space(RID p_body) const { return space->get_self(); } -void BulletPhysicsServer::soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) { +void BulletPhysicsServer::soft_body_set_mesh(RID p_body, const REF &p_mesh) { SoftBodyBullet *body = soft_body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_trimesh_body_shape(p_indices, p_vertices, p_triangles_num); + body->set_soft_mesh(p_mesh); } void BulletPhysicsServer::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) { @@ -961,14 +1007,16 @@ void BulletPhysicsServer::soft_body_set_transform(RID p_body, const Transform &p SoftBodyBullet *body = soft_body_owner.get(p_body); ERR_FAIL_COND(!body); - body->set_transform(p_transform); + body->set_soft_transform(p_transform); } -Transform BulletPhysicsServer::soft_body_get_transform(RID p_body) const { +Vector3 BulletPhysicsServer::soft_body_get_vertex_position(RID p_body, int vertex_index) const { const SoftBodyBullet *body = soft_body_owner.get(p_body); - ERR_FAIL_COND_V(!body, Transform()); + Vector3 pos; + ERR_FAIL_COND_V(!body, pos); - return body->get_transform(); + body->get_node_position(vertex_index, pos); + return pos; } void BulletPhysicsServer::soft_body_set_ray_pickable(RID p_body, bool p_enable) { @@ -983,6 +1031,154 @@ bool BulletPhysicsServer::soft_body_is_ray_pickable(RID p_body) const { return body->is_ray_pickable(); } +void BulletPhysicsServer::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_simulation_precision(p_simulation_precision); +} + +int BulletPhysicsServer::soft_body_get_simulation_precision(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_simulation_precision(); +} + +void BulletPhysicsServer::soft_body_set_total_mass(RID p_body, real_t p_total_mass) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_total_mass(p_total_mass); +} + +real_t BulletPhysicsServer::soft_body_get_total_mass(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_total_mass(); +} + +void BulletPhysicsServer::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_linear_stiffness(p_stiffness); +} + +real_t BulletPhysicsServer::soft_body_get_linear_stiffness(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_linear_stiffness(); +} + +void BulletPhysicsServer::soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_areaAngular_stiffness(p_stiffness); +} + +real_t BulletPhysicsServer::soft_body_get_areaAngular_stiffness(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_areaAngular_stiffness(); +} + +void BulletPhysicsServer::soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_volume_stiffness(p_stiffness); +} + +real_t BulletPhysicsServer::soft_body_get_volume_stiffness(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_volume_stiffness(); +} + +void BulletPhysicsServer::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_pressure_coefficient(p_pressure_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_pressure_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_pressure_coefficient(); +} + +void BulletPhysicsServer::soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + return body->set_pose_matching_coefficient(p_pose_matching_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_pose_matching_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_pose_matching_coefficient(); +} + +void BulletPhysicsServer::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_damping_coefficient(p_damping_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_damping_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_damping_coefficient(); +} + +void BulletPhysicsServer::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_drag_coefficient(p_drag_coefficient); +} + +real_t BulletPhysicsServer::soft_body_get_drag_coefficient(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_drag_coefficient(); +} + +void BulletPhysicsServer::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_node_position(p_point_index, p_global_position); +} + +Vector3 BulletPhysicsServer::soft_body_get_point_global_position(RID p_body, int p_point_index) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.)); + Vector3 pos; + body->get_node_position(p_point_index, pos); + return pos; +} + +Vector3 BulletPhysicsServer::soft_body_get_point_offset(RID p_body, int p_point_index) const { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, Vector3()); + Vector3 res; + body->get_node_offset(p_point_index, res); + return res; +} + +void BulletPhysicsServer::soft_body_remove_all_pinned_points(RID p_body) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->reset_all_node_mass(); +} + +void BulletPhysicsServer::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND(!body); + body->set_node_mass(p_point_index, p_pin ? 0 : 1); +} + +bool BulletPhysicsServer::soft_body_is_point_pinned(RID p_body, int p_point_index) { + SoftBodyBullet *body = soft_body_owner.get(p_body); + ERR_FAIL_COND_V(!body, 0.f); + return body->get_node_mass(p_point_index); +} + PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const { JointBullet *joint = joint_owner.get(p_joint); ERR_FAIL_COND_V(!joint, JOINT_PIN); diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index e931915bba..2c5b7e51cf 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -213,6 +213,9 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value); virtual float body_get_param(RID p_body, BodyParameter p_param) const; + virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); + virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; + virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin); virtual real_t body_get_kinematic_safe_margin(RID p_body) const; @@ -225,6 +228,11 @@ public: virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque); virtual Vector3 body_get_applied_torque(RID p_body) const; + virtual void body_add_central_force(RID p_body, const Vector3 &p_force); + virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos); + virtual void body_add_torque(RID p_body, const Vector3 &p_torque); + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse); virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); @@ -259,10 +267,12 @@ public: virtual RID soft_body_create(bool p_init_sleeping = false); + virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler); + virtual void soft_body_set_space(RID p_body, RID p_space); virtual RID soft_body_get_space(RID p_body) const; - virtual void soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num); + virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh); virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer); virtual uint32_t soft_body_get_collision_layer(RID p_body) const; @@ -277,12 +287,49 @@ public: virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant); virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const; + /// Special function. This function has bad performance virtual void soft_body_set_transform(RID p_body, const Transform &p_transform); - virtual Transform soft_body_get_transform(RID p_body) const; + virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable); virtual bool soft_body_is_ray_pickable(RID p_body) const; + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision); + virtual int soft_body_get_simulation_precision(RID p_body); + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass); + virtual real_t soft_body_get_total_mass(RID p_body); + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness); + virtual real_t soft_body_get_linear_stiffness(RID p_body); + + virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness); + virtual real_t soft_body_get_areaAngular_stiffness(RID p_body); + + virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness); + virtual real_t soft_body_get_volume_stiffness(RID p_body); + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient); + virtual real_t soft_body_get_pressure_coefficient(RID p_body); + + virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient); + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body); + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient); + virtual real_t soft_body_get_damping_coefficient(RID p_body); + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient); + virtual real_t soft_body_get_drag_coefficient(RID p_body); + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position); + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index); + + virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const; + + virtual void soft_body_remove_all_pinned_points(RID p_body); + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin); + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index); + /* JOINT API */ virtual JointType joint_get_type(RID p_joint) const; diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index 57e4db708e..271cdb0223 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -111,6 +111,8 @@ void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_coll void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) { exceptions.insert(p_ignoreCollisionObject->get_self()); + if (!bt_collision_object) + return; bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true); if (space) space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher()); @@ -221,7 +223,7 @@ void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform } void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { - ShapeWrapper &shp = shapes[p_index]; + ShapeWrapper &shp = shapes.write[p_index]; shp.shape->remove_owner(this); p_shape->add_owner(this); shp.shape = p_shape; @@ -231,8 +233,8 @@ void RigidCollisionObjectBullet::set_shape(int p_index, ShapeBullet *p_shape) { void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { ERR_FAIL_INDEX(p_index, get_shape_count()); - shapes[p_index].set_transform(p_transform); - on_shape_changed(shapes[p_index].shape); + shapes.write[p_index].set_transform(p_transform); + on_shape_changed(shapes.write[p_index].shape); } void RigidCollisionObjectBullet::remove_shape(ShapeBullet *p_shape) { @@ -285,7 +287,7 @@ void RigidCollisionObjectBullet::on_shape_changed(const ShapeBullet *const p_sha const int size = shapes.size(); for (int i = 0; i < size; ++i) { if (shapes[i].shape == p_shape) { - bulletdelete(shapes[i].bt_shape); + bulletdelete(shapes.write[i].bt_shape); } } on_shapes_changed(); @@ -305,7 +307,7 @@ void RigidCollisionObjectBullet::on_shapes_changed() { // Reset shape if required if (force_shape_reset) { for (i = 0; i < shapes_size; ++i) { - shpWrapper = &shapes[i]; + shpWrapper = &shapes.write[i]; bulletdelete(shpWrapper->bt_shape); } force_shape_reset = false; @@ -314,7 +316,7 @@ void RigidCollisionObjectBullet::on_shapes_changed() { // Insert all shapes btVector3 body_scale(get_bt_body_scale()); for (i = 0; i < shapes_size; ++i) { - shpWrapper = &shapes[i]; + shpWrapper = &shapes.write[i]; if (shpWrapper->active) { if (!shpWrapper->bt_shape) { shpWrapper->bt_shape = shpWrapper->shape->create_bt_shape(shpWrapper->scale * body_scale); @@ -332,7 +334,7 @@ void RigidCollisionObjectBullet::on_shapes_changed() { } void RigidCollisionObjectBullet::set_shape_disabled(int p_index, bool p_disabled) { - shapes[p_index].active = !p_disabled; + shapes.write[p_index].active = !p_disabled; on_shapes_changed(); } @@ -346,7 +348,7 @@ void RigidCollisionObjectBullet::on_body_scale_changed() { } void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_permanentlyFromThisBody) { - ShapeWrapper &shp = shapes[p_index]; + ShapeWrapper &shp = shapes.write[p_index]; shp.shape->remove_owner(this, p_permanentlyFromThisBody); bulletdelete(shp.bt_shape); } diff --git a/modules/bullet/register_types.cpp b/modules/bullet/register_types.cpp index b119b7720f..a76b0438b4 100644 --- a/modules/bullet/register_types.cpp +++ b/modules/bullet/register_types.cpp @@ -32,19 +32,26 @@ #include "bullet_physics_server.h" #include "class_db.h" +#include "project_settings.h" /** @author AndreaCatania */ +#ifndef _3D_DISABLED PhysicsServer *_createBulletPhysicsCallback() { return memnew(BulletPhysicsServer); } +#endif void register_bullet_types() { - +#ifndef _3D_DISABLED PhysicsServerManager::register_server("Bullet", &_createBulletPhysicsCallback); PhysicsServerManager::set_default_server("Bullet", 1); + + GLOBAL_DEF("physics/3d/active_soft_world", true); + ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/active_soft_world", PropertyInfo(Variant::BOOL, "physics/3d/active_soft_world")); +#endif } void unregister_bullet_types() { diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 2fc96a77b5..81a62edba6 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -126,6 +126,10 @@ void BulletPhysicsDirectBodyState::add_torque(const Vector3 &p_torque) { body->apply_torque(p_torque); } +void BulletPhysicsDirectBodyState::apply_central_impulse(const Vector3 &p_j) { + body->apply_central_impulse(p_j); +} + void BulletPhysicsDirectBodyState::apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { body->apply_impulse(p_pos, p_j); } @@ -154,6 +158,10 @@ Vector3 BulletPhysicsDirectBodyState::get_contact_local_normal(int p_contact_idx return body->collisions[p_contact_idx].hitNormal; } +float BulletPhysicsDirectBodyState::get_contact_impulse(int p_contact_idx) const { + return body->collisions[p_contact_idx].appliedImpulse; +} + int BulletPhysicsDirectBodyState::get_contact_local_shape(int p_contact_idx) const { return body->collisions[p_contact_idx].local_shape; } @@ -175,7 +183,7 @@ int BulletPhysicsDirectBodyState::get_contact_collider_shape(int p_contact_idx) } Vector3 BulletPhysicsDirectBodyState::get_contact_collider_velocity_at_position(int p_contact_idx) const { - RigidBodyBullet::CollisionData &colDat = body->collisions[p_contact_idx]; + RigidBodyBullet::CollisionData &colDat = body->collisions.write[p_contact_idx]; btVector3 hitLocation; G_TO_B(colDat.hitLocalLocation, hitLocation); @@ -220,8 +228,8 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { continue; } - shapes[i].transform = shape_wrapper->transform; - shapes[i].transform.getOrigin() *= owner_scale; + shapes.write[i].transform = shape_wrapper->transform; + shapes.write[i].transform.getOrigin() *= owner_scale; switch (shape_wrapper->shape->get_type()) { case PhysicsServer::SHAPE_SPHERE: case PhysicsServer::SHAPE_BOX: @@ -229,11 +237,11 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { case PhysicsServer::SHAPE_CYLINDER: case PhysicsServer::SHAPE_CONVEX_POLYGON: case PhysicsServer::SHAPE_RAY: { - shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); + shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); } break; default: WARN_PRINT("This shape is not supported to be kinematic!"); - shapes[i].shape = NULL; + shapes.write[i].shape = NULL; } } } @@ -241,7 +249,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { void RigidBodyBullet::KinematicUtilities::just_delete_shapes(int new_size) { for (int i = shapes.size() - 1; 0 <= i; --i) { if (shapes[i].shape) { - bulletdelete(shapes[i].shape); + bulletdelete(shapes.write[i].shape); } } shapes.resize(new_size); @@ -257,6 +265,8 @@ RigidBodyBullet::RigidBodyBullet() : angularDamp(0), can_sleep(true), omit_forces_integration(false), + restitution_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT), + friction_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT), force_integration_callback(NULL), isTransformChanged(false), previousActiveState(true), @@ -281,7 +291,7 @@ RigidBodyBullet::RigidBodyBullet() : areasWhereIam.resize(maxAreasWhereIam); for (int i = areasWhereIam.size() - 1; 0 <= i; --i) { - areasWhereIam[i] = NULL; + areasWhereIam.write[i] = NULL; } btBody->setSleepingThresholds(0.2, 0.2); } @@ -401,17 +411,18 @@ void RigidBodyBullet::on_collision_checker_start() { collisionsCount = 0; } -bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, int p_other_shape_index, int p_local_shape_index) { +bool RigidBodyBullet::add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index) { if (collisionsCount >= maxCollisionsDetection) { return false; } - CollisionData &cd = collisions[collisionsCount]; + CollisionData &cd = collisions.write[collisionsCount]; cd.hitLocalLocation = p_hitLocalLocation; cd.otherObject = p_otherObject; cd.hitWorldLocation = p_hitWorldLocation; cd.hitNormal = p_hitNormal; + cd.appliedImpulse = p_appliedImpulse; cd.other_object_shape = p_other_shape_index; cd.local_shape = p_local_shape_index; @@ -750,6 +761,22 @@ Vector3 RigidBodyBullet::get_angular_velocity() const { return gVec; } +void RigidBodyBullet::set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode) { + if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { + restitution_combine_mode = p_mode; + } else { + friction_combine_mode = p_mode; + } +} + +PhysicsServer::CombineMode RigidBodyBullet::get_combine_mode(PhysicsServer::BodyParameter p_param) const { + if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { + return restitution_combine_mode; + } else { + return friction_combine_mode; + } +} + void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) { if (mode == PhysicsServer::BODY_MODE_KINEMATIC) { // The kinematic use MotionState class @@ -795,15 +822,15 @@ void RigidBodyBullet::on_enter_area(AreaBullet *p_area) { if (NULL == areasWhereIam[i]) { // This area has the highest priority - areasWhereIam[i] = p_area; + areasWhereIam.write[i] = p_area; break; } else { if (areasWhereIam[i]->get_spOv_priority() > p_area->get_spOv_priority()) { // The position was found, just shift all elements for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam[j + 1] = areasWhereIam[j]; + areasWhereIam.write[j + 1] = areasWhereIam[j]; } - areasWhereIam[i] = p_area; + areasWhereIam.write[i] = p_area; break; } } @@ -827,7 +854,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { if (p_area == areasWhereIam[i]) { // The area was fount, just shift down all elements for (int j = i; j < areaWhereIamCount; ++j) { - areasWhereIam[j] = areasWhereIam[j + 1]; + areasWhereIam.write[j] = areasWhereIam[j + 1]; } wasTheAreaFound = true; break; @@ -840,7 +867,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { } --areaWhereIamCount; - areasWhereIam[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe + areasWhereIam.write[areaWhereIamCount] = NULL; // Even if this is not required, I clear the last element to be safe if (PhysicsServer::AREA_SPACE_OVERRIDE_DISABLED != p_area->get_spOv_mode()) { scratch_space_override_modificator(); } diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index b9511243c7..35af3b90d8 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -113,6 +113,7 @@ public: virtual void add_central_force(const Vector3 &p_force); virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos); virtual void add_torque(const Vector3 &p_torque); + virtual void apply_central_impulse(const Vector3 &p_impulse); virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j); virtual void apply_torque_impulse(const Vector3 &p_j); @@ -123,6 +124,7 @@ public: virtual Vector3 get_contact_local_position(int p_contact_idx) const; virtual Vector3 get_contact_local_normal(int p_contact_idx) const; + virtual float get_contact_impulse(int p_contact_idx) const; virtual int get_contact_local_shape(int p_contact_idx) const; virtual RID get_contact_collider(int p_contact_idx) const; @@ -149,6 +151,7 @@ public: Vector3 hitLocalLocation; Vector3 hitWorldLocation; Vector3 hitNormal; + float appliedImpulse; }; struct ForceIntegrationCallback { @@ -200,6 +203,9 @@ private: bool can_sleep; bool omit_forces_integration; + PhysicsServer::CombineMode restitution_combine_mode; + PhysicsServer::CombineMode friction_combine_mode; + Vector<CollisionData> collisions; // these parameters are used to avoid vector resize int maxCollisionsDetection; @@ -248,7 +254,7 @@ public: } bool can_add_collision() { return collisionsCount < maxCollisionsDetection; } - bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, int p_other_shape_index, int p_local_shape_index); + bool add_collision_object(RigidBodyBullet *p_otherObject, const Vector3 &p_hitWorldLocation, const Vector3 &p_hitLocalLocation, const Vector3 &p_hitNormal, const float &p_appliedImpulse, int p_other_shape_index, int p_local_shape_index); void assert_no_constraints(); @@ -295,6 +301,12 @@ public: void set_angular_velocity(const Vector3 &p_velocity); Vector3 get_angular_velocity() const; + void set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode); + PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const; + + _FORCE_INLINE_ PhysicsServer::CombineMode get_restitution_combine_mode() const { return restitution_combine_mode; } + _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } + virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index 92e7c2df98..e4c1a5f9b5 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -304,7 +304,7 @@ void ConvexPolygonShapeBullet::get_vertices(Vector<Vector3> &out_vertices) { const int n_of_vertices = vertices.size(); out_vertices.resize(n_of_vertices); for (int i = n_of_vertices - 1; 0 <= i; --i) { - B_TO_G(vertices[i], out_vertices[i]); + B_TO_G(vertices[i], out_vertices.write[i]); } } diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 5c20eb73f1..1686a6e87e 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -32,42 +32,24 @@ #include "bullet_types_converter.h" #include "bullet_utilities.h" -#include "scene/3d/immediate_geometry.h" +#include "scene/3d/soft_body.h" #include "space_bullet.h" -/** - @author AndreaCatania -*/ - SoftBodyBullet::SoftBodyBullet() : CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY), - mass(1), + total_mass(1), simulation_precision(5), - stiffness(0.5f), - pressure_coefficient(50), - damping_coefficient(0.005), - drag_coefficient(0.005), + linear_stiffness(0.5), + areaAngular_stiffness(0.5), + volume_stiffness(0.5), + pressure_coefficient(0.), + pose_matching_coefficient(0.), + damping_coefficient(0.01), + drag_coefficient(0.), bt_soft_body(NULL), - soft_shape_type(SOFT_SHAPETYPE_NONE), - isScratched(false), - soft_body_shape_data(NULL) { - - test_geometry = memnew(ImmediateGeometry); - - red_mat = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - red_mat->set_line_width(20.0); - red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - red_mat->set_albedo(Color(1, 0, 0, 1)); - test_geometry->set_material_override(red_mat); - - test_is_in_scene = false; -} + isScratched(false) {} SoftBodyBullet::~SoftBodyBullet() { - bulletdelete(soft_body_shape_data); } void SoftBodyBullet::reload_body() { @@ -80,8 +62,6 @@ void SoftBodyBullet::reload_body() { void SoftBodyBullet::set_space(SpaceBullet *p_space) { if (space) { isScratched = false; - - // Remove this object from the physics world space->remove_soft_body(this); } @@ -90,86 +70,181 @@ void SoftBodyBullet::set_space(SpaceBullet *p_space) { if (space) { space->add_soft_body(this); } - - reload_soft_body(); } -void SoftBodyBullet::dispatch_callbacks() { - if (!bt_soft_body) { +void SoftBodyBullet::dispatch_callbacks() {} + +void SoftBodyBullet::on_collision_filters_change() {} + +void SoftBodyBullet::on_collision_checker_start() {} + +void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {} + +void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {} + +void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_server_handler) { + if (!bt_soft_body) return; + + /// Update visual server vertices + const btSoftBody::tNodeArray &nodes(bt_soft_body->m_nodes); + const int nodes_count = nodes.size(); + + const Vector<int> *vs_indices; + const void *vertex_position; + const void *vertex_normal; + + for (int vertex_index = 0; vertex_index < nodes_count; ++vertex_index) { + vertex_position = reinterpret_cast<const void *>(&nodes[vertex_index].m_x); + vertex_normal = reinterpret_cast<const void *>(&nodes[vertex_index].m_n); + + vs_indices = &indices_table[vertex_index]; + + const int vs_indices_size(vs_indices->size()); + for (int x = 0; x < vs_indices_size; ++x) { + p_visual_server_handler->set_vertex((*vs_indices)[x], vertex_position); + p_visual_server_handler->set_normal((*vs_indices)[x], vertex_normal); + } } - if (!test_is_in_scene) { - test_is_in_scene = true; - SceneTree::get_singleton()->get_current_scene()->add_child(test_geometry); + /// Generate AABB + btVector3 aabb_min; + btVector3 aabb_max; + bt_soft_body->getAabb(aabb_min, aabb_max); + + btVector3 size(aabb_max - aabb_min); + + AABB aabb; + B_TO_G(aabb_min, aabb.position); + B_TO_G(size, aabb.size); + + p_visual_server_handler->set_aabb(aabb); +} + +void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) { + + if (p_mesh.is_null() || !p_mesh->surface_is_softbody_friendly(0)) + soft_mesh.unref(); + else + soft_mesh = p_mesh; + + if (soft_mesh.is_null()) { + + destroy_soft_body(); + return; } - test_geometry->clear(); - test_geometry->begin(Mesh::PRIMITIVE_LINES, NULL); - bool first = true; - Vector3 pos; - for (int i = 0; i < bt_soft_body->m_nodes.size(); ++i) { - const btSoftBody::Node &n = bt_soft_body->m_nodes[i]; - B_TO_G(n.m_x, pos); - test_geometry->add_vertex(pos); - if (!first) { - test_geometry->add_vertex(pos); - } else { - first = false; - } + Array arrays = soft_mesh->surface_get_arrays(0); + ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & VS::ARRAY_FORMAT_INDEX)); + set_trimesh_body_shape(arrays[VS::ARRAY_INDEX], arrays[VS::ARRAY_VERTEX]); +} + +void SoftBodyBullet::destroy_soft_body() { + + if (!bt_soft_body) + return; + + if (space) { + /// Remove from world before deletion + space->remove_soft_body(this); } - test_geometry->end(); + + destroyBulletCollisionObject(); + bt_soft_body = NULL; +} + +void SoftBodyBullet::set_soft_transform(const Transform &p_transform) { + reset_all_node_positions(); + move_all_nodes(p_transform); } -void SoftBodyBullet::on_collision_filters_change() { +void SoftBodyBullet::move_all_nodes(const Transform &p_transform) { + if (!bt_soft_body) + return; + btTransform bt_transf; + G_TO_B(p_transform, bt_transf); + bt_soft_body->transform(bt_transf); } -void SoftBodyBullet::on_collision_checker_start() { +void SoftBodyBullet::set_node_position(int p_node_index, const Vector3 &p_global_position) { + btVector3 bt_pos; + G_TO_B(p_global_position, bt_pos); + set_node_position(p_node_index, bt_pos); } -void SoftBodyBullet::on_enter_area(AreaBullet *p_area) { +void SoftBodyBullet::set_node_position(int p_node_index, const btVector3 &p_global_position) { + if (bt_soft_body) { + bt_soft_body->m_nodes[p_node_index].m_x = p_global_position; + } } -void SoftBodyBullet::on_exit_area(AreaBullet *p_area) { +void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) const { + if (bt_soft_body) { + B_TO_G(bt_soft_body->m_nodes[p_node_index].m_x, r_position); + } } -void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) { +void SoftBodyBullet::get_node_offset(int p_node_index, Vector3 &r_offset) const { + if (soft_mesh.is_null()) + return; + + Array arrays = soft_mesh->surface_get_arrays(0); + PoolVector<Vector3> vertices(arrays[VS::ARRAY_VERTEX]); - TrimeshSoftShapeData *shape_data = bulletnew(TrimeshSoftShapeData); - shape_data->m_triangles_indices = p_indices; - shape_data->m_vertices = p_vertices; - shape_data->m_triangles_num = p_triangles_num; + if (0 <= p_node_index && vertices.size() > p_node_index) { + r_offset = vertices[p_node_index]; + } +} - set_body_shape_data(shape_data, SOFT_SHAPE_TYPE_TRIMESH); - reload_soft_body(); +void SoftBodyBullet::get_node_offset(int p_node_index, btVector3 &r_offset) const { + Vector3 off; + get_node_offset(p_node_index, off); + G_TO_B(off, r_offset); } -void SoftBodyBullet::set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type) { - bulletdelete(soft_body_shape_data); - soft_body_shape_data = p_soft_shape_data; - soft_shape_type = p_type; +void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) { + if (0 >= p_mass) { + pin_node(node_index); + } else { + unpin_node(node_index); + } + if (bt_soft_body) { + bt_soft_body->setMass(node_index, p_mass); + } } -void SoftBodyBullet::set_transform(const Transform &p_transform) { - transform = p_transform; +btScalar SoftBodyBullet::get_node_mass(int node_index) const { if (bt_soft_body) { - // TODO the softbody set new transform considering the current transform as center of world - // like if it's local transform, so I must fix this by setting nwe transform considering the old - btTransform bt_trans; - G_TO_B(transform, bt_trans); - //bt_soft_body->transform(bt_trans); + return bt_soft_body->getMass(node_index); + } else { + return -1 == search_node_pinned(node_index) ? 1 : 0; } } -const Transform &SoftBodyBullet::get_transform() const { - return transform; +void SoftBodyBullet::reset_all_node_mass() { + if (bt_soft_body) { + for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { + bt_soft_body->setMass(pinned_nodes[i], 1); + } + } + pinned_nodes.resize(0); } -void SoftBodyBullet::get_first_node_origin(btVector3 &p_out_origin) const { - if (bt_soft_body && bt_soft_body->m_nodes.size()) { - p_out_origin = bt_soft_body->m_nodes[0].m_x; - } else { - p_out_origin.setZero(); +void SoftBodyBullet::reset_all_node_positions() { + if (soft_mesh.is_null()) + return; + + Array arrays = soft_mesh->surface_get_arrays(0); + PoolVector<Vector3> vs_vertices(arrays[VS::ARRAY_VERTEX]); + PoolVector<Vector3>::Read vs_vertices_read = vs_vertices.read(); + + for (int vertex_index = bt_soft_body->m_nodes.size() - 1; 0 <= vertex_index; --vertex_index) { + + G_TO_B(vs_vertices_read[indices_table[vertex_index][0]], bt_soft_body->m_nodes[vertex_index].m_x); + + bt_soft_body->m_nodes[vertex_index].m_q = bt_soft_body->m_nodes[vertex_index].m_x; + bt_soft_body->m_nodes[vertex_index].m_v = btVector3(0, 0, 0); + bt_soft_body->m_nodes[vertex_index].m_f = btVector3(0, 0, 0); } } @@ -181,22 +256,34 @@ void SoftBodyBullet::set_activation_state(bool p_active) { } } -void SoftBodyBullet::set_mass(real_t p_val) { +void SoftBodyBullet::set_total_mass(real_t p_val) { if (0 >= p_val) { p_val = 1; } - mass = p_val; + total_mass = p_val; if (bt_soft_body) { - bt_soft_body->setTotalMass(mass); + bt_soft_body->setTotalMass(total_mass); } } -void SoftBodyBullet::set_stiffness(real_t p_val) { - stiffness = p_val; +void SoftBodyBullet::set_linear_stiffness(real_t p_val) { + linear_stiffness = p_val; if (bt_soft_body) { - mat0->m_kAST = stiffness; - mat0->m_kLST = stiffness; - mat0->m_kVST = stiffness; + mat0->m_kLST = linear_stiffness; + } +} + +void SoftBodyBullet::set_areaAngular_stiffness(real_t p_val) { + areaAngular_stiffness = p_val; + if (bt_soft_body) { + mat0->m_kAST = areaAngular_stiffness; + } +} + +void SoftBodyBullet::set_volume_stiffness(real_t p_val) { + volume_stiffness = p_val; + if (bt_soft_body) { + mat0->m_kVST = volume_stiffness; } } @@ -204,6 +291,9 @@ void SoftBodyBullet::set_simulation_precision(int p_val) { simulation_precision = p_val; if (bt_soft_body) { bt_soft_body->m_cfg.piterations = simulation_precision; + bt_soft_body->m_cfg.viterations = simulation_precision; + bt_soft_body->m_cfg.diterations = simulation_precision; + bt_soft_body->m_cfg.citerations = simulation_precision; } } @@ -214,6 +304,13 @@ void SoftBodyBullet::set_pressure_coefficient(real_t p_val) { } } +void SoftBodyBullet::set_pose_matching_coefficient(real_t p_val) { + pose_matching_coefficient = p_val; + if (bt_soft_body) { + bt_soft_body->m_cfg.kMT = pose_matching_coefficient; + } +} + void SoftBodyBullet::set_damping_coefficient(real_t p_val) { damping_coefficient = p_val; if (bt_soft_body) { @@ -228,89 +325,156 @@ void SoftBodyBullet::set_drag_coefficient(real_t p_val) { } } -void SoftBodyBullet::reload_soft_body() { - +void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices) { + /// Assert the current soft body is destroyed destroy_soft_body(); - create_soft_body(); - if (bt_soft_body) { + /// Parse visual server indices to physical indices. + /// Merge all overlapping vertices and create a map of physical vertices to visual server - // TODO the softbody set new transform considering the current transform as center of world - // like if it's local transform, so I must fix this by setting nwe transform considering the old - btTransform bt_trans; - G_TO_B(transform, bt_trans); - bt_soft_body->transform(bt_trans); + { + /// This is the map of visual server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map + Vector<int> vs_indices_to_physics_table; - bt_soft_body->generateBendingConstraints(2, mat0); - mat0->m_kAST = stiffness; - mat0->m_kLST = stiffness; - mat0->m_kVST = stiffness; + { // Map vertices + indices_table.resize(0); - bt_soft_body->m_cfg.piterations = simulation_precision; - bt_soft_body->m_cfg.kDP = damping_coefficient; - bt_soft_body->m_cfg.kDG = drag_coefficient; - bt_soft_body->m_cfg.kPR = pressure_coefficient; - bt_soft_body->setTotalMass(mass); - } - if (space) { - // TODO remove this please - space->add_soft_body(this); - } -} + int index = 0; + Map<Vector3, int> unique_vertices; -void SoftBodyBullet::create_soft_body() { - if (!space || !soft_body_shape_data) { - return; - } - ERR_FAIL_COND(!space->is_using_soft_world()); - switch (soft_shape_type) { - case SOFT_SHAPE_TYPE_TRIMESH: { - TrimeshSoftShapeData *trimesh_data = static_cast<TrimeshSoftShapeData *>(soft_body_shape_data); - - Vector<int> indices; - Vector<btScalar> vertices; - - int i; - const int indices_size = trimesh_data->m_triangles_indices.size(); - const int vertices_size = trimesh_data->m_vertices.size(); - indices.resize(indices_size); - vertices.resize(vertices_size * 3); - - PoolVector<int>::Read i_r = trimesh_data->m_triangles_indices.read(); - for (i = 0; i < indices_size; ++i) { - indices[i] = i_r[i]; + const int vs_vertices_size(p_vertices.size()); + + PoolVector<Vector3>::Read p_vertices_read = p_vertices.read(); + + for (int vs_vertex_index = 0; vs_vertex_index < vs_vertices_size; ++vs_vertex_index) { + + Map<Vector3, int>::Element *e = unique_vertices.find(p_vertices_read[vs_vertex_index]); + int vertex_id; + if (e) { + // Already rxisting + vertex_id = e->value(); + } else { + // Create new one + unique_vertices[p_vertices_read[vs_vertex_index]] = vertex_id = index++; + indices_table.push_back(Vector<int>()); + } + + indices_table.write[vertex_id].push_back(vs_vertex_index); + vs_indices_to_physics_table.push_back(vertex_id); + } + } + + const int indices_map_size(indices_table.size()); + + Vector<btScalar> bt_vertices; + + { // Parse vertices to bullet + + bt_vertices.resize(indices_map_size * 3); + PoolVector<Vector3>::Read p_vertices_read = p_vertices.read(); + + for (int i = 0; i < indices_map_size; ++i) { + bt_vertices.write[3 * i + 0] = p_vertices_read[indices_table[i][0]].x; + bt_vertices.write[3 * i + 1] = p_vertices_read[indices_table[i][0]].y; + bt_vertices.write[3 * i + 2] = p_vertices_read[indices_table[i][0]].z; } - i_r = PoolVector<int>::Read(); + } + + Vector<int> bt_triangles; + const int triangles_size(p_indices.size() / 3); + + { // Parse indices + + bt_triangles.resize(triangles_size * 3); + + PoolVector<int>::Read p_indices_read = p_indices.read(); - PoolVector<Vector3>::Read f_r = trimesh_data->m_vertices.read(); - for (int j = i = 0; i < vertices_size; ++i, j += 3) { - vertices[j + 0] = f_r[i][0]; - vertices[j + 1] = f_r[i][1]; - vertices[j + 2] = f_r[i][2]; + for (int i = 0; i < triangles_size; ++i) { + bt_triangles.write[3 * i + 0] = vs_indices_to_physics_table[p_indices_read[3 * i + 2]]; + bt_triangles.write[3 * i + 1] = vs_indices_to_physics_table[p_indices_read[3 * i + 1]]; + bt_triangles.write[3 * i + 2] = vs_indices_to_physics_table[p_indices_read[3 * i + 0]]; } - f_r = PoolVector<Vector3>::Read(); + } - bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(*space->get_soft_body_world_info(), vertices.ptr(), indices.ptr(), trimesh_data->m_triangles_num); - } break; - default: - ERR_PRINT("Shape type not supported"); - return; + btSoftBodyWorldInfo fake_world_info; + bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(fake_world_info, &bt_vertices[0], &bt_triangles[0], triangles_size, false); + setup_soft_body(); } +} + +void SoftBodyBullet::setup_soft_body() { + + if (!bt_soft_body) + return; + // Soft body setup setupBulletCollisionObject(bt_soft_body); - bt_soft_body->getCollisionShape()->setMargin(0.001f); + bt_soft_body->m_worldInfo = NULL; // Remove fake world info + bt_soft_body->getCollisionShape()->setMargin(0.01); bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT))); + + // Space setup + if (space) { + space->add_soft_body(this); + } + mat0 = bt_soft_body->appendMaterial(); + + // Assign soft body data + bt_soft_body->generateBendingConstraints(2, mat0); + + mat0->m_kLST = linear_stiffness; + mat0->m_kAST = areaAngular_stiffness; + mat0->m_kVST = volume_stiffness; + + // Clusters allow to have Soft vs Soft collision but doesn't work well right now + + //bt_soft_body->m_cfg.kSRHR_CL = 1;// Soft vs rigid hardness [0,1] (cluster only) + //bt_soft_body->m_cfg.kSKHR_CL = 1;// Soft vs kinematic hardness [0,1] (cluster only) + //bt_soft_body->m_cfg.kSSHR_CL = 1;// Soft vs soft hardness [0,1] (cluster only) + //bt_soft_body->m_cfg.kSR_SPLT_CL = 1; // Soft vs rigid impulse split [0,1] (cluster only) + //bt_soft_body->m_cfg.kSK_SPLT_CL = 1; // Soft vs kinematic impulse split [0,1] (cluster only) + //bt_soft_body->m_cfg.kSS_SPLT_CL = 1; // Soft vs Soft impulse split [0,1] (cluster only) + //bt_soft_body->m_cfg.collisions = btSoftBody::fCollision::CL_SS + btSoftBody::fCollision::CL_RS + btSoftBody::fCollision::VF_SS; + //bt_soft_body->generateClusters(64); + + bt_soft_body->m_cfg.piterations = simulation_precision; + bt_soft_body->m_cfg.viterations = simulation_precision; + bt_soft_body->m_cfg.diterations = simulation_precision; + bt_soft_body->m_cfg.citerations = simulation_precision; + bt_soft_body->m_cfg.kDP = damping_coefficient; + bt_soft_body->m_cfg.kDG = drag_coefficient; + bt_soft_body->m_cfg.kPR = pressure_coefficient; + bt_soft_body->m_cfg.kMT = pose_matching_coefficient; + bt_soft_body->setTotalMass(total_mass); + + btSoftBodyHelpers::ReoptimizeLinkOrder(bt_soft_body); + bt_soft_body->updateBounds(); + + // Set pinned nodes + for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { + bt_soft_body->setMass(pinned_nodes[i], 0); + } } -void SoftBodyBullet::destroy_soft_body() { - if (space) { - /// This step is required to assert that the body is not into the world during deletion - /// This step is required since to change the body shape the body must be re-created. - /// Here is handled the case when the body is assigned into a world and the body - /// shape is changed. - space->remove_soft_body(this); +void SoftBodyBullet::pin_node(int p_node_index) { + if (-1 == search_node_pinned(p_node_index)) { + pinned_nodes.push_back(p_node_index); } - destroyBulletCollisionObject(); - bt_soft_body = NULL; +} + +void SoftBodyBullet::unpin_node(int p_node_index) { + const int id = search_node_pinned(p_node_index); + if (-1 != id) { + pinned_nodes.remove(id); + } +} + +int SoftBodyBullet::search_node_pinned(int p_node_index) const { + for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { + if (p_node_index == pinned_nodes[i]) { + return i; + } + } + return -1; } diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index 9895643b84..c775193584 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -40,7 +40,10 @@ #define x11_None 0L #endif -#include <BulletSoftBody/btSoftBodyHelpers.h> +#include "BulletSoftBody/btSoftBodyHelpers.h" +#include "collision_object_bullet.h" +#include "scene/resources/mesh.h" +#include "servers/physics_server.h" #ifdef x11_None /// This is required to re add the macro None defined by x11 compiler @@ -52,39 +55,34 @@ @author AndreaCatania */ -struct SoftShapeData {}; -struct TrimeshSoftShapeData : public SoftShapeData { - PoolVector<int> m_triangles_indices; - PoolVector<Vector3> m_vertices; - int m_triangles_num; -}; - class SoftBodyBullet : public CollisionObjectBullet { -public: - enum SoftShapeType { - SOFT_SHAPETYPE_NONE = 0, - SOFT_SHAPE_TYPE_TRIMESH - }; private: btSoftBody *bt_soft_body; + Vector<Vector<int> > indices_table; btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody - SoftShapeType soft_shape_type; bool isScratched; - SoftShapeData *soft_body_shape_data; + Ref<Mesh> soft_mesh; - Transform transform; int simulation_precision; - real_t mass; - real_t stiffness; // [0,1] + real_t total_mass; + real_t linear_stiffness; // [0,1] + real_t areaAngular_stiffness; // [0,1] + real_t volume_stiffness; // [0,1] real_t pressure_coefficient; // [-inf,+inf] + real_t pose_matching_coefficient; // [0,1] real_t damping_coefficient; // [0,1] real_t drag_coefficient; // [0,1] + Vector<int> pinned_nodes; - class ImmediateGeometry *test_geometry; // TODO remove this please - Ref<SpatialMaterial> red_mat; // TODO remove this please - bool test_is_in_scene; // TODO remove this please + // Other property to add + //btScalar kVC; // Volume conversation coefficient [0,+inf] + //btScalar kDF; // Dynamic friction coefficient [0,1] + //btScalar kMT; // Pose matching coefficient [0,1] + //btScalar kCHR; // Rigid contacts hardness [0,1] + //btScalar kKHR; // Kinetic contacts hardness [0,1] + //btScalar kSHR; // Soft contacts hardness [0,1] public: SoftBodyBullet(); @@ -101,39 +99,64 @@ public: _FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; } - void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num); - void set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type); + void update_visual_server(class SoftBodyVisualServerHandler *p_visual_server_handler); - void set_transform(const Transform &p_transform); - /// This function doesn't return the exact COM transform. - /// It returns the origin only of first node (vertice) of current soft body - /// --- - /// The soft body doesn't have a fixed center of mass, but is a group of nodes (vertices) - /// that each has its own position in the world. - /// For this reason return the correct COM is not so simple and must be calculate - /// Check this to improve this function http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=8803 - const Transform &get_transform() const; - void get_first_node_origin(btVector3 &p_out_origin) const; + void set_soft_mesh(const Ref<Mesh> &p_mesh); + void destroy_soft_body(); + + // Special function. This function has bad performance + void set_soft_transform(const Transform &p_transform); + + void move_all_nodes(const Transform &p_transform); + void set_node_position(int node_index, const Vector3 &p_global_position); + void set_node_position(int node_index, const btVector3 &p_global_position); + void get_node_position(int node_index, Vector3 &r_position) const; + // Heavy function, Please cache this info + void get_node_offset(int node_index, Vector3 &r_offset) const; + // Heavy function, Please cache this info + void get_node_offset(int node_index, btVector3 &r_offset) const; + + void set_node_mass(int node_index, btScalar p_mass); + btScalar get_node_mass(int node_index) const; + void reset_all_node_mass(); + void reset_all_node_positions(); void set_activation_state(bool p_active); - void set_mass(real_t p_val); - _FORCE_INLINE_ real_t get_mass() const { return mass; } - void set_stiffness(real_t p_val); - _FORCE_INLINE_ real_t get_stiffness() const { return stiffness; } + void set_total_mass(real_t p_val); + _FORCE_INLINE_ real_t get_total_mass() const { return total_mass; } + + void set_linear_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; } + + void set_areaAngular_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_areaAngular_stiffness() const { return areaAngular_stiffness; } + + void set_volume_stiffness(real_t p_val); + _FORCE_INLINE_ real_t get_volume_stiffness() const { return volume_stiffness; } + void set_simulation_precision(int p_val); _FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; } + void set_pressure_coefficient(real_t p_val); _FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; } + + void set_pose_matching_coefficient(real_t p_val); + _FORCE_INLINE_ real_t get_pose_matching_coefficient() const { return pose_matching_coefficient; } + void set_damping_coefficient(real_t p_val); _FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; } + void set_drag_coefficient(real_t p_val); _FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; } private: - void reload_soft_body(); - void create_soft_body(); - void destroy_soft_body(); + void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices); + void setup_soft_body(); + + void pin_node(int p_node_index); + void unpin_node(int p_node_index); + int search_node_pinned(int p_node_index) const; }; #endif // SOFT_BODY_BULLET_H diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 971fd39509..8454bea4eb 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -36,6 +36,7 @@ #include "constraint_bullet.h" #include "godot_collision_configuration.h" #include "godot_collision_dispatcher.h" +#include "project_settings.h" #include "rigid_body_bullet.h" #include "servers/physics_server.h" #include "soft_body_bullet.h" @@ -325,7 +326,7 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_ } } -SpaceBullet::SpaceBullet(bool p_create_soft_world) : +SpaceBullet::SpaceBullet() : broadphase(NULL), dispatcher(NULL), solver(NULL), @@ -338,7 +339,7 @@ SpaceBullet::SpaceBullet(bool p_create_soft_world) : gravityMagnitude(10), contactDebugCount(0) { - create_empty_world(p_create_soft_world); + create_empty_world(GLOBAL_DEF("physics/3d/active_soft_world", true)); direct_access = memnew(BulletPhysicsDirectSpaceState(this)); } @@ -355,6 +356,7 @@ void SpaceBullet::flush_queries() { } void SpaceBullet::step(real_t p_delta_time) { + delta_time = p_delta_time; dynamicsWorld->stepSimulation(p_delta_time, 0, 0); } @@ -483,6 +485,7 @@ void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) { void SpaceBullet::add_soft_body(SoftBodyBullet *p_body) { if (is_using_soft_world()) { if (p_body->get_bt_soft_body()) { + p_body->get_bt_soft_body()->m_worldInfo = get_soft_body_world_info(); static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->addSoftBody(p_body->get_bt_soft_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); } } else { @@ -494,6 +497,7 @@ void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) { if (is_using_soft_world()) { if (p_body->get_bt_soft_body()) { static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body()); + p_body->get_bt_soft_body()->m_worldInfo = NULL; } } } @@ -549,7 +553,43 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { } btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) { - return MAX(body0->getRestitution(), body1->getRestitution()); + + const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_restitution_combine_mode(); + + switch (cm) { + case PhysicsServer::COMBINE_MODE_INHERIT: + if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_restitution_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) + return calculateGodotCombinedRestitution(body1, body0); + // else use MAX [This is used when the two bodies doesn't use physical material] + case PhysicsServer::COMBINE_MODE_MAX: + return MAX(body0->getRestitution(), body1->getRestitution()); + case PhysicsServer::COMBINE_MODE_MIN: + return MIN(body0->getRestitution(), body1->getRestitution()); + case PhysicsServer::COMBINE_MODE_MULTIPLY: + return body0->getRestitution() * body1->getRestitution(); + default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: + return (body0->getRestitution() + body1->getRestitution()) / 2; + } +} + +btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) { + + const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_friction_combine_mode(); + + switch (cm) { + case PhysicsServer::COMBINE_MODE_INHERIT: + if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) + return calculateGodotCombinedFriction(body1, body0); + // else use MULTIPLY [This is used when the two bodies doesn't use physical material] + case PhysicsServer::COMBINE_MODE_MULTIPLY: + return body0->getFriction() * body1->getFriction(); + case PhysicsServer::COMBINE_MODE_MAX: + return MAX(body0->getFriction(), body1->getFriction()); + case PhysicsServer::COMBINE_MODE_MIN: + return MIN(body0->getFriction(), body1->getFriction()); + default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: + return (body0->getFriction() * body1->getFriction()) / 2; + } } void SpaceBullet::create_empty_world(bool p_create_soft_world) { @@ -585,6 +625,7 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) { ghostPairCallback = bulletnew(btGhostPairCallback); godotFilterCallback = bulletnew(GodotFilterCallback); gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution; + gCalculateCombinedFrictionCallback = &calculateGodotCombinedFriction; dynamicsWorld->setWorldUserInfo(this); @@ -645,7 +686,7 @@ void SpaceBullet::check_ghost_overlaps() { /// 1. Reset all states for (i = area->overlappingObjects.size() - 1; 0 <= i; --i) { - AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects[i]; + AreaBullet::OverlappingObjectData &otherObj = area->overlappingObjects.write[i]; // This check prevent the overwrite of ENTER state // if this function is called more times before dispatchCallbacks if (otherObj.state != AreaBullet::OVERLAP_STATE_ENTER) { @@ -754,19 +795,20 @@ void SpaceBullet::check_body_collision() { Vector3 collisionWorldPosition; Vector3 collisionLocalPosition; Vector3 normalOnB; + float appliedImpulse = pt.m_appliedImpulse; B_TO_G(pt.m_normalWorldOnB, normalOnB); if (bodyA->can_add_collision()) { B_TO_G(pt.getPositionWorldOnB(), collisionWorldPosition); /// pt.m_localPointB Doesn't report the exact point in local space B_TO_G(pt.getPositionWorldOnB() - contactManifold->getBody1()->getWorldTransform().getOrigin(), collisionLocalPosition); - bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, pt.m_index1, pt.m_index0); + bodyA->add_collision_object(bodyB, collisionWorldPosition, collisionLocalPosition, normalOnB, appliedImpulse, pt.m_index1, pt.m_index0); } if (bodyB->can_add_collision()) { B_TO_G(pt.getPositionWorldOnA(), collisionWorldPosition); /// pt.m_localPointA Doesn't report the exact point in local space B_TO_G(pt.getPositionWorldOnA() - contactManifold->getBody0()->getWorldTransform().getOrigin(), collisionLocalPosition); - bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, pt.m_index0, pt.m_index1); + bodyB->add_collision_object(bodyA, collisionWorldPosition, collisionLocalPosition, normalOnB * -1, appliedImpulse * -1, pt.m_index0, pt.m_index1); } #ifdef DEBUG_ENABLED diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index a6c2786878..6b86fc2f03 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -84,7 +84,7 @@ public: }; class SpaceBullet : public RIDBullet { -private: + friend class AreaBullet; friend void onBulletTickCallback(btDynamicsWorld *world, btScalar timeStep); friend class BulletPhysicsDirectSpaceState; @@ -109,12 +109,14 @@ private: Vector<Vector3> contactDebug; int contactDebugCount; + real_t delta_time; public: - SpaceBullet(bool p_create_soft_world); + SpaceBullet(); virtual ~SpaceBullet(); void flush_queries(); + real_t get_delta_time() { return delta_time; } void step(real_t p_delta_time); _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() { return broadphase; } @@ -162,7 +164,7 @@ public: contactDebugCount = 0; } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { - if (contactDebugCount < contactDebug.size()) contactDebug[contactDebugCount++] = p_contact; + if (contactDebugCount < contactDebug.size()) contactDebug.write[contactDebugCount++] = p_contact; } _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contactDebug; } _FORCE_INLINE_ int get_debug_contact_count() { return contactDebugCount; } diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 4e6e701bfd..87c2caec0d 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -62,7 +62,7 @@ void CSGBrush::build_from_faces(const PoolVector<Vector3> &p_vertices, const Poo faces.resize(p_vertices.size() / 3); for (int i = 0; i < faces.size(); i++) { - Face &f = faces[i]; + Face &f = faces.write[i]; f.vertices[0] = rv[i * 3 + 0]; f.vertices[1] = rv[i * 3 + 1]; f.vertices[2] = rv[i * 3 + 2]; @@ -101,7 +101,7 @@ void CSGBrush::build_from_faces(const PoolVector<Vector3> &p_vertices, const Poo materials.resize(material_map.size()); for (Map<Ref<Material>, int>::Element *E = material_map.front(); E; E = E->next()) { - materials[E->get()] = E->key(); + materials.write[E->get()] = E->key(); } _regen_face_aabbs(); @@ -111,10 +111,10 @@ void CSGBrush::_regen_face_aabbs() { for (int i = 0; i < faces.size(); i++) { - faces[i].aabb.position = faces[i].vertices[0]; - faces[i].aabb.expand_to(faces[i].vertices[1]); - faces[i].aabb.expand_to(faces[i].vertices[2]); - faces[i].aabb.grow_by(faces[i].aabb.get_longest_axis_size() * 0.001); //make it a tad bigger to avoid num precision erros + faces.write[i].aabb.position = faces[i].vertices[0]; + faces.write[i].aabb.expand_to(faces[i].vertices[1]); + faces.write[i].aabb.expand_to(faces[i].vertices[2]); + faces.write[i].aabb.grow_by(faces[i].aabb.get_longest_axis_size() * 0.001); //make it a tad bigger to avoid num precision erros } } @@ -125,7 +125,7 @@ void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) { for (int i = 0; i < faces.size(); i++) { for (int j = 0; j < 3; j++) { - faces[i].vertices[j] = p_xform.xform(p_brush.faces[i].vertices[j]); + faces.write[i].vertices[j] = p_xform.xform(p_brush.faces[i].vertices[j]); } } @@ -341,7 +341,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_ new_edge.points[0] = edges[i].points[0]; new_edge.points[1] = point_idx; new_edge.outer = edges[i].outer; - edges[i].points[0] = point_idx; + edges.write[i].points[0] = point_idx; edges.insert(i, new_edge); i++; //skip newly inserted edge base_edges++; //will need an extra one in the base triangle @@ -637,7 +637,7 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in int to_point = e.edge_point; int current_edge = e.edge; - edge_process[e.edge] = true; //mark as processed + edge_process.write[e.edge] = true; //mark as processed int limit = p_poly.points.size() * 4; //avoid infinite recursion @@ -708,7 +708,7 @@ void CSGBrushOperation::_add_poly_points(const BuildPoly &p_poly, int p_edge, in prev_point = to_point; to_point = next_point; - edge_process[next_edge] = true; //mark this edge as processed + edge_process.write[next_edge] = true; //mark this edge as processed current_edge = next_edge; limit--; @@ -792,13 +792,13 @@ void CSGBrushOperation::_merge_poly(MeshMerge &mesh, int p_face_idx, const Build //none processed by default for (int i = 0; i < edge_process.size(); i++) { - edge_process[i] = false; + edge_process.write[i] = false; } //put edges in points, so points can go through them for (int i = 0; i < p_poly.edges.size(); i++) { - vertex_process[p_poly.edges[i].points[0]].push_back(i); - vertex_process[p_poly.edges[i].points[1]].push_back(i); + vertex_process.write[p_poly.edges[i].points[0]].push_back(i); + vertex_process.write[p_poly.edges[i].points[1]].push_back(i); } Vector<PolyPoints> polys; @@ -854,7 +854,7 @@ void CSGBrushOperation::_merge_poly(MeshMerge &mesh, int p_face_idx, const Build _add_poly_outline(p_poly, p_poly.edges[i].points[0], p_poly.edges[i].points[1], vertex_process, outline); if (outline.size() > 1) { - polys[intersect_poly].holes.push_back(outline); + polys.write[intersect_poly].holes.push_back(outline); } } _add_poly_points(p_poly, i, p_poly.edges[i].points[0], p_poly.edges[i].points[1], vertex_process, edge_process, polys); @@ -953,18 +953,18 @@ void CSGBrushOperation::_merge_poly(MeshMerge &mesh, int p_face_idx, const Build //duplicate point int insert_at = with_outline_vertex; - polys[i].points.insert(insert_at, polys[i].points[insert_at]); + polys.write[i].points.insert(insert_at, polys[i].points[insert_at]); insert_at++; //insert all others, outline should be backwards (must check) int holesize = polys[i].holes[j].size(); for (int k = 0; k <= holesize; k++) { int idx = (from_hole_vertex + k) % holesize; - polys[i].points.insert(insert_at, polys[i].holes[j][idx]); + polys.write[i].points.insert(insert_at, polys[i].holes[j][idx]); insert_at++; } added_hole = true; - polys[i].holes.remove(j); + polys.write[i].holes.remove(j); break; //got rid of hole, break and continue } } @@ -980,7 +980,7 @@ void CSGBrushOperation::_merge_poly(MeshMerge &mesh, int p_face_idx, const Build Vector<Vector2> vertices; vertices.resize(polys[i].points.size()); for (int j = 0; j < vertices.size(); j++) { - vertices[j] = p_poly.points[polys[i].points[j]].point; + vertices.write[j] = p_poly.points[polys[i].points[j]].point; } Vector<int> indices = Geometry::triangulate_polygon(vertices); @@ -1267,7 +1267,7 @@ void CSGBrushOperation::MeshMerge::mark_inside_faces() { int intersections = _bvh_count_intersections(bvh, max_depth, max_alloc - 1, center, target, i); if (intersections & 1) { - faces[i].inside = true; + faces.write[i].inside = true; } } } @@ -1419,13 +1419,13 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_A if (mesh_merge.faces[i].inside) continue; for (int j = 0; j < 3; j++) { - result.faces[outside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; - result.faces[outside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; + result.faces.write[outside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; + result.faces.write[outside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; } - result.faces[outside_count].smooth = mesh_merge.faces[i].smooth; - result.faces[outside_count].invert = mesh_merge.faces[i].invert; - result.faces[outside_count].material = mesh_merge.faces[i].material_idx; + result.faces.write[outside_count].smooth = mesh_merge.faces[i].smooth; + result.faces.write[outside_count].invert = mesh_merge.faces[i].invert; + result.faces.write[outside_count].material = mesh_merge.faces[i].material_idx; outside_count++; } @@ -1451,13 +1451,13 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_A if (!mesh_merge.faces[i].inside) continue; for (int j = 0; j < 3; j++) { - result.faces[inside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; - result.faces[inside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; + result.faces.write[inside_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; + result.faces.write[inside_count].uvs[j] = mesh_merge.faces[i].uvs[j]; } - result.faces[inside_count].smooth = mesh_merge.faces[i].smooth; - result.faces[inside_count].invert = mesh_merge.faces[i].invert; - result.faces[inside_count].material = mesh_merge.faces[i].material_idx; + result.faces.write[inside_count].smooth = mesh_merge.faces[i].smooth; + result.faces.write[inside_count].invert = mesh_merge.faces[i].invert; + result.faces.write[inside_count].material = mesh_merge.faces[i].material_idx; inside_count++; } @@ -1489,19 +1489,19 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_A continue; for (int j = 0; j < 3; j++) { - result.faces[face_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; - result.faces[face_count].uvs[j] = mesh_merge.faces[i].uvs[j]; + result.faces.write[face_count].vertices[j] = mesh_merge.points[mesh_merge.faces[i].points[j]]; + result.faces.write[face_count].uvs[j] = mesh_merge.faces[i].uvs[j]; } if (mesh_merge.faces[i].from_b) { //invert facing of insides of B - SWAP(result.faces[face_count].vertices[1], result.faces[face_count].vertices[2]); - SWAP(result.faces[face_count].uvs[1], result.faces[face_count].uvs[2]); + SWAP(result.faces.write[face_count].vertices[1], result.faces.write[face_count].vertices[2]); + SWAP(result.faces.write[face_count].uvs[1], result.faces.write[face_count].uvs[2]); } - result.faces[face_count].smooth = mesh_merge.faces[i].smooth; - result.faces[face_count].invert = mesh_merge.faces[i].invert; - result.faces[face_count].material = mesh_merge.faces[i].material_idx; + result.faces.write[face_count].smooth = mesh_merge.faces[i].smooth; + result.faces.write[face_count].invert = mesh_merge.faces[i].invert; + result.faces.write[face_count].material = mesh_merge.faces[i].material_idx; face_count++; } @@ -1513,6 +1513,6 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_A //updatelist of materials result.materials.resize(mesh_merge.materials.size()); for (const Map<Ref<Material>, int>::Element *E = mesh_merge.materials.front(); E; E = E->next()) { - result.materials[E->get()] = E->key(); + result.materials.write[E->get()] = E->key(); } } diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 2150320c4a..3b1ddfe4c0 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -278,8 +278,8 @@ void CSGShapeSpatialGizmo::redraw() { int f = i / 6; for (int j = 0; j < 3; j++) { int j_n = (j + 1) % 3; - lines[i + j * 2 + 0] = r[f * 3 + j]; - lines[i + j * 2 + 1] = r[f * 3 + j_n]; + lines.write[i + j * 2 + 0] = r[f * 3 + j]; + lines.write[i + j * 2 + 1] = r[f * 3 + j_n]; } } } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 67cc7e1ba2..9f2171a82a 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -177,7 +177,7 @@ void CSGShape::_update_shape() { Vector<int> face_count; face_count.resize(n->materials.size() + 1); for (int i = 0; i < face_count.size(); i++) { - face_count[i] = 0; + face_count.write[i] = 0; } for (int i = 0; i < n->faces.size(); i++) { @@ -200,7 +200,7 @@ void CSGShape::_update_shape() { } } - face_count[idx]++; + face_count.write[idx]++; } Vector<ShapeUpdateSurface> surfaces; @@ -210,18 +210,18 @@ void CSGShape::_update_shape() { //create arrays for (int i = 0; i < surfaces.size(); i++) { - surfaces[i].vertices.resize(face_count[i] * 3); - surfaces[i].normals.resize(face_count[i] * 3); - surfaces[i].uvs.resize(face_count[i] * 3); - surfaces[i].last_added = 0; + surfaces.write[i].vertices.resize(face_count[i] * 3); + surfaces.write[i].normals.resize(face_count[i] * 3); + surfaces.write[i].uvs.resize(face_count[i] * 3); + surfaces.write[i].last_added = 0; if (i != surfaces.size() - 1) { - surfaces[i].material = n->materials[i]; + surfaces.write[i].material = n->materials[i]; } - surfaces[i].verticesw = surfaces[i].vertices.write(); - surfaces[i].normalsw = surfaces[i].normals.write(); - surfaces[i].uvsw = surfaces[i].uvs.write(); + surfaces.write[i].verticesw = surfaces.write[i].vertices.write(); + surfaces.write[i].normalsw = surfaces.write[i].normals.write(); + surfaces.write[i].uvsw = surfaces.write[i].uvs.write(); } //fill arrays @@ -281,7 +281,7 @@ void CSGShape::_update_shape() { surfaces[idx].normalsw[last + order[j]] = normal; } - surfaces[idx].last_added += 3; + surfaces.write[idx].last_added += 3; } } @@ -290,9 +290,9 @@ void CSGShape::_update_shape() { for (int i = 0; i < surfaces.size(); i++) { - surfaces[i].verticesw = PoolVector<Vector3>::Write(); - surfaces[i].normalsw = PoolVector<Vector3>::Write(); - surfaces[i].uvsw = PoolVector<Vector2>::Write(); + surfaces.write[i].verticesw = PoolVector<Vector3>::Write(); + surfaces.write[i].normalsw = PoolVector<Vector3>::Write(); + surfaces.write[i].uvsw = PoolVector<Vector2>::Write(); if (surfaces[i].last_added == 0) continue; diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp index 88768829d7..25b7f2472d 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/networked_multiplayer_enet.cpp @@ -666,7 +666,7 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * while (total) { for (size_t i = 0; i < inBufferCount; i++) { int to_copy = MIN(total, int(inBuffers[i].dataLength)); - copymem(&enet->src_compressor_mem[ofs], inBuffers[i].data, to_copy); + copymem(&enet->src_compressor_mem.write[ofs], inBuffers[i].data, to_copy); ofs += to_copy; total -= to_copy; } diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp index 385c020a78..b525725107 100644 --- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp +++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp @@ -125,7 +125,7 @@ bool ARVRInterfaceGDNative::is_stereo() { return stereo; } -bool ARVRInterfaceGDNative::is_initialized() { +bool ARVRInterfaceGDNative::is_initialized() const { bool initialized; ERR_FAIL_COND_V(interface == NULL, false); diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h index e50be6e196..26d0cdf9f4 100644 --- a/modules/gdnative/arvr/arvr_interface_gdnative.h +++ b/modules/gdnative/arvr/arvr_interface_gdnative.h @@ -59,7 +59,7 @@ public: virtual StringName get_name() const; virtual int get_capabilities() const; - virtual bool is_initialized(); + virtual bool is_initialized() const; virtual bool initialize(); virtual void uninitialize(); diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py index c5b37d35b4..701a13d32f 100644 --- a/modules/gdnative/config.py +++ b/modules/gdnative/config.py @@ -9,9 +9,11 @@ def get_doc_classes(): "ARVRInterfaceGDNative", "GDNative", "GDNativeLibrary", + "MultiplayerPeerGDNative", "NativeScript", "PacketPeerGDNative", "PluginScript", + "StreamPeerGDNative", ] def get_doc_path(): diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml new file mode 100644 index 0000000000..4433179726 --- /dev/null +++ b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/modules/gdnative/doc_classes/PacketPeerGDNative.xml b/modules/gdnative/doc_classes/PacketPeerGDNative.xml new file mode 100644 index 0000000000..0ae54bc9c7 --- /dev/null +++ b/modules/gdnative/doc_classes/PacketPeerGDNative.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PacketPeerGDNative" inherits="PacketPeer" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/modules/gdnative/doc_classes/StreamPeerGDNative.xml b/modules/gdnative/doc_classes/StreamPeerGDNative.xml new file mode 100644 index 0000000000..d86cd2c25a --- /dev/null +++ b/modules/gdnative/doc_classes/StreamPeerGDNative.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="StreamPeerGDNative" inherits="StreamPeer" category="Core" version="3.1"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <demos> + </demos> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index e7ebcc73af..0acd6c27d8 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -277,7 +277,7 @@ void GDNative::set_library(Ref<GDNativeLibrary> p_library) { library = p_library; } -Ref<GDNativeLibrary> GDNative::get_library() { +Ref<GDNativeLibrary> GDNative::get_library() const { return library; } @@ -373,7 +373,7 @@ bool GDNative::initialize() { if (library->should_load_once() && !GDNativeLibrary::loaded_libraries->has(lib_path)) { Vector<Ref<GDNative> > gdnatives; gdnatives.resize(1); - gdnatives[0] = Ref<GDNative>(this); + gdnatives.write[0] = Ref<GDNative>(this); GDNativeLibrary::loaded_libraries->insert(lib_path, gdnatives); } @@ -428,7 +428,7 @@ bool GDNative::terminate() { return true; } -bool GDNative::is_initialized() { +bool GDNative::is_initialized() const { return initialized; } @@ -442,7 +442,7 @@ Vector<StringName> GDNativeCallRegistry::get_native_call_types() { size_t idx = 0; for (Map<StringName, native_call_cb>::Element *E = native_calls.front(); E; E = E->next(), idx++) { - call_types[idx] = E->key(); + call_types.write[idx] = E->key(); } return call_types; @@ -474,7 +474,7 @@ Variant GDNative::call_native(StringName p_native_call_type, StringName p_proced return res; } -Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_optional) { +Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_optional) const { if (!initialized) { ERR_PRINT("No valid library handle, can't get symbol from GDNative object"); diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index b17bb94f1c..148f85723e 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -148,16 +148,16 @@ public: static void _bind_methods(); void set_library(Ref<GDNativeLibrary> p_library); - Ref<GDNativeLibrary> get_library(); + Ref<GDNativeLibrary> get_library() const; - bool is_initialized(); + bool is_initialized() const; bool initialize(); bool terminate(); Variant call_native(StringName p_native_call_type, StringName p_procedure_name, Array p_arguments = Array()); - Error get_symbol(StringName p_procedure_name, void *&r_handle, bool p_optional = true); + Error get_symbol(StringName p_procedure_name, void *&r_handle, bool p_optional = true) const; }; class GDNativeLibraryResourceLoader : public ResourceFormatLoader { diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp index 7f5dbc12be..8ca57392a3 100644 --- a/modules/gdnative/gdnative/string.cpp +++ b/modules/gdnative/gdnative/string.cpp @@ -207,7 +207,7 @@ godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_arra Array *keys_proxy = (Array *)p_keys; keys.resize(keys_proxy->size()); for (int i = 0; i < keys_proxy->size(); i++) { - keys[i] = (*keys_proxy)[i]; + keys.write[i] = (*keys_proxy)[i]; } return self->findmk(keys); @@ -220,7 +220,7 @@ godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot Array *keys_proxy = (Array *)p_keys; keys.resize(keys_proxy->size()); for (int i = 0; i < keys_proxy->size(); i++) { - keys[i] = (*keys_proxy)[i]; + keys.write[i] = (*keys_proxy)[i]; } return self->findmk(keys, p_from); @@ -233,7 +233,7 @@ godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, co Array *keys_proxy = (Array *)p_keys; keys.resize(keys_proxy->size()); for (int i = 0; i < keys_proxy->size(); i++) { - keys[i] = (*keys_proxy)[i]; + keys.write[i] = (*keys_proxy)[i]; } return self->findmk(keys, p_from, r_key); @@ -696,7 +696,7 @@ godot_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const Array *splitter_proxy = (Array *)p_splitters; splitters.resize(splitter_proxy->size()); for (int i = 0; i < splitter_proxy->size(); i++) { - splitters[i] = (*splitter_proxy)[i]; + splitters.write[i] = (*splitter_proxy)[i]; } godot_array result; @@ -719,7 +719,7 @@ godot_array GDAPI godot_string_split_floats_mk_allows_empty(const godot_string * Array *splitter_proxy = (Array *)p_splitters; splitters.resize(splitter_proxy->size()); for (int i = 0; i < splitter_proxy->size(); i++) { - splitters[i] = (*splitter_proxy)[i]; + splitters.write[i] = (*splitter_proxy)[i]; } godot_array result; @@ -774,7 +774,7 @@ godot_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const g Array *splitter_proxy = (Array *)p_splitters; splitters.resize(splitter_proxy->size()); for (int i = 0; i < splitter_proxy->size(); i++) { - splitters[i] = (*splitter_proxy)[i]; + splitters.write[i] = (*splitter_proxy)[i]; } godot_array result; @@ -797,7 +797,7 @@ godot_array GDAPI godot_string_split_ints_mk_allows_empty(const godot_string *p_ Array *splitter_proxy = (Array *)p_splitters; splitters.resize(splitter_proxy->size()); for (int i = 0; i < splitter_proxy->size(); i++) { - splitters[i] = (*splitter_proxy)[i]; + splitters.write[i] = (*splitter_proxy)[i]; } godot_array result; diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index 4012e821bb..70ca8d68b8 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -110,7 +110,6 @@ struct ClassAPI { bool is_singleton; bool is_instanciable; // @Unclear - bool is_creatable; bool is_reference; List<MethodAPI> methods; @@ -385,7 +384,6 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back(String("\t\t\"instanciable\": ") + (api.is_instanciable ? "true" : "false") + ",\n"); source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n"); // @Unclear - // source.push_back(String("\t\t\"createable\": ") + (api.is_creatable ? "true" : "false") + ",\n"); source.push_back("\t\t\"constants\": {\n"); for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) { diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 7bab718b81..3a49b3fe71 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -149,7 +149,10 @@ Ref<Script> NativeScript::get_base_script() const { if (!script_data) return Ref<Script>(); - Ref<NativeScript> ns = Ref<NativeScript>(NSL->create_script()); + NativeScript *script = (NativeScript *)NSL->create_script(); + Ref<NativeScript> ns = Ref<NativeScript>(script); + ERR_FAIL_COND_V(!ns.is_valid(), Ref<Script>()); + ns->set_class_name(script_data->base); ns->set_library(get_library()); return ns; @@ -1053,7 +1056,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const s->set_class_name(p_class_name); return Ref<NativeScript>(s); } -bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { +bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { return true; } @@ -1154,8 +1157,8 @@ int NativeScriptLanguage::register_binding_functions(godot_instance_binding_func } // set the functions - binding_functions[idx].first = true; - binding_functions[idx].second = p_binding_functions; + binding_functions.write[idx].first = true; + binding_functions.write[idx].second = p_binding_functions; return idx; } @@ -1170,7 +1173,7 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) { binding_functions[p_idx].second.free_instance_binding_data(binding_functions[p_idx].second.data, binding_data[p_idx]); } - binding_functions[p_idx].first = false; + binding_functions.write[p_idx].first = false; if (binding_functions[p_idx].second.free_func) binding_functions[p_idx].second.free_func(binding_functions[p_idx].second.data); @@ -1196,7 +1199,7 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec binding_data->resize(p_idx + 1); for (int i = old_size; i <= p_idx; i++) { - (*binding_data)[i] = NULL; + (*binding_data).write[i] = NULL; } } @@ -1205,7 +1208,7 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec const void *global_type_tag = global_type_tags[p_idx].get(p_object->get_class_name()); // no binding data yet, soooooo alloc new one \o/ - (*binding_data)[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, global_type_tag, (godot_object *)p_object); + (*binding_data).write[p_idx] = binding_functions[p_idx].second.alloc_instance_binding_data(binding_functions[p_idx].second.data, global_type_tag, (godot_object *)p_object); } return (*binding_data)[p_idx]; @@ -1218,7 +1221,7 @@ void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { binding_data->resize(binding_functions.size()); for (int i = 0; i < binding_functions.size(); i++) { - (*binding_data)[i] = NULL; + (*binding_data).write[i] = NULL; } binding_instances.insert(binding_data); diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index be093dde4b..1b39b63ad9 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -295,7 +295,7 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 8018178bd5..816b0f0cab 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -108,7 +108,7 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const return script; } -bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { +bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { PoolStringArray functions; if (_desc.validate) { bool ret = _desc.validate( diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index 709345885b..2443e31361 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -74,7 +74,7 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index d18297f2f8..ae1a218392 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -341,10 +341,10 @@ void register_gdnative_types() { Ref<GDNativeLibrary> lib = ResourceLoader::load(path); - singleton_gdnatives[i].instance(); - singleton_gdnatives[i]->set_library(lib); + singleton_gdnatives.write[i].instance(); + singleton_gdnatives.write[i]->set_library(lib); - if (!singleton_gdnatives[i]->initialize()) { + if (!singleton_gdnatives.write[i]->initialize()) { // Can't initialize. Don't make a native_call then continue; } @@ -374,7 +374,7 @@ void unregister_gdnative_types() { continue; } - singleton_gdnatives[i]->terminate(); + singleton_gdnatives.write[i]->terminate(); } singleton_gdnatives.clear(); diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index fedc510f01..f2a1a5b50c 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -75,9 +75,11 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ bool in_keyword = false; bool in_word = false; bool in_function_name = false; + bool in_variable_declaration = false; bool in_member_variable = false; bool in_node_path = false; bool is_hex_notation = false; + bool expect_type = false; Color keyword_color; Color color; @@ -205,6 +207,8 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ if (str[k] == '(') { in_function_name = true; + } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::TK_PR_VAR)) { + in_variable_declaration = true; } } @@ -222,6 +226,28 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ if (is_symbol) { in_function_name = false; in_member_variable = false; + + if (expect_type && str[j] != ' ' && str[j] != '\t' && str[j] != ':') { + expect_type = false; + } + if (j > 0 && str[j] == '>' && str[j - 1] == '-') { + expect_type = true; + } + + if (in_variable_declaration || previous_text == "(" || previous_text == ",") { + int k = j; + // Skip space + while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { + k++; + } + + if (str[k] == ':') { + // has type hint + expect_type = true; + } + } + + in_variable_declaration = false; } if (!in_node_path && in_region == -1 && str[j] == '$') { @@ -256,6 +282,9 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_ } else if (is_number) { next_type = NUMBER; color = number_color; + } else if (expect_type) { + next_type = TYPE; + color = type_color; } else { next_type = IDENTIFIER; } @@ -330,6 +359,7 @@ void GDScriptSyntaxHighlighter::_update_cache() { function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color"); node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color"); + type_color = EDITOR_GET("text_editor/highlighting/base_type_color"); } SyntaxHighlighter *GDScriptSyntaxHighlighter::create() { diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 0296ab7652..b8cb4a65e9 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -44,7 +44,8 @@ private: FUNCTION, KEYWORD, MEMBER, - IDENTIFIER + IDENTIFIER, + TYPE, }; // colours @@ -56,6 +57,7 @@ private: Color number_color; Color member_color; Color node_path_color; + Color type_color; public: static SyntaxHighlighter *create(); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index b3ebd4fe4b..cff3be76ae 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -220,16 +220,14 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { void GDScript::get_script_method_list(List<MethodInfo> *p_list) const { for (const Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) { + GDScriptFunction *func = E->get(); MethodInfo mi; mi.name = E->key(); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - PropertyInfo arg; - arg.type = Variant::NIL; //variant - arg.name = E->get()->get_argument_name(i); - mi.arguments.push_back(arg); + for (int i = 0; i < func->get_argument_count(); i++) { + mi.arguments.push_back(func->get_argument_type(i)); } - mi.return_val.name = "Variant"; + mi.return_val = func->get_return_type(); p_list->push_back(mi); } } @@ -277,16 +275,14 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const { if (!E) return MethodInfo(); + GDScriptFunction *func = E->get(); MethodInfo mi; mi.name = E->key(); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - PropertyInfo arg; - arg.type = Variant::NIL; //variant - arg.name = E->get()->get_argument_name(i); - mi.arguments.push_back(arg); + for (int i = 0; i < func->get_argument_count(); i++) { + mi.arguments.push_back(func->get_argument_type(i)); } - mi.return_val.name = "Variant"; + mi.return_val = func->get_return_type(); return mi; } @@ -734,7 +730,7 @@ Error GDScript::load_byte_code(const String &p_path) { Vector<uint8_t> key; key.resize(32); for (int i = 0; i < key.size(); i++) { - key[i] = script_encryption_key[i]; + key.write[i] = script_encryption_key[i]; } Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_READ); ERR_FAIL_COND_V(err, err); @@ -941,8 +937,12 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { if (err.error == Variant::CallError::CALL_OK) { return true; //function exists, call was successful } - } else - members[E->get().index] = p_value; + } else { + if (!E->get().data_type.is_type(p_value)) { + return false; // Type mismatch + } + members.write[E->get().index] = p_value; + } return true; } } @@ -1270,7 +1270,7 @@ void GDScriptInstance::reload_members() { if (member_indices_cache.has(E->key())) { Variant value = members[member_indices_cache[E->key()]]; - new_members[E->get().index] = value; + new_members.write[E->get().index] = value; } } @@ -1320,7 +1320,7 @@ void GDScriptLanguage::_add_global(const StringName &p_name, const Variant &p_va if (globals.has(p_name)) { //overwrite existing - global_array[globals[p_name]] = p_value; + global_array.write[globals[p_name]] = p_value; return; } globals[p_name] = global_array.size(); @@ -1735,7 +1735,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "NAN", "self", "true", + "void", // functions + "as", "assert", "breakpoint", "class", @@ -1824,8 +1826,40 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) { const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree()); - if (r_base_type && c->extends_used && c->extends_class.size() == 1) { - *r_base_type = c->extends_class[0]; //todo, should work much better + if (r_base_type) { + GDScriptParser::DataType base_type; + if (c->base_type.has_type) { + base_type = c->base_type; + while (base_type.has_type && base_type.kind != GDScriptParser::DataType::NATIVE) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> gds = base_type.script_type; + if (gds.is_valid()) { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); + } else { + base_type = GDScriptParser::DataType(); + } + } break; + default: { + base_type = GDScriptParser::DataType(); + } break; + } + } + } + if (base_type.has_type) { + *r_base_type = base_type.native_type; + } else { + // Fallback + if (c->extends_used && c->extends_class.size() == 1) { + *r_base_type = c->extends_class[0]; + } else if (!c->extends_used) { + *r_base_type = "Reference"; + } + } } return c->name; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index d1c57a0330..79ac9ed413 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -64,6 +64,7 @@ class GDScript : public Script { StringName setter; StringName getter; MultiplayerAPI::RPCMode rpc_mode; + GDScriptDataType data_type; }; friend class GDScriptInstance; @@ -145,8 +146,13 @@ public: const Map<StringName, Ref<GDScript> > &get_subclasses() const { return subclasses; } const Map<StringName, Variant> &get_constants() const { return constants; } const Set<StringName> &get_members() const { return members; } + const GDScriptDataType &get_member_type(const StringName &p_member) const { + ERR_FAIL_COND_V(!member_indices.has(p_member), GDScriptDataType()); + return member_indices[p_member].data_type; + } const Map<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; } const Ref<GDScriptNativeClass> &get_native() const { return native; } + const String &get_script_class_name() const { return name; } virtual bool has_script_signal(const StringName &p_signal) const; virtual void get_script_signal_list(List<MethodInfo> *r_signals) const; @@ -349,10 +355,10 @@ public: Vector<StackInfo> csi; csi.resize(_debug_call_stack_pos); for (int i = 0; i < _debug_call_stack_pos; i++) { - csi[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0; + csi.write[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0; if (_call_stack[i].function) - csi[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name(); - csi[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path(); + csi.write[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name(); + csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path(); } return csi; } @@ -391,7 +397,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 70f3d704ae..fe393957db 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -111,23 +111,50 @@ bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptP return true; } -/* -int GDScriptCompiler::_parse_subexpression(CodeGen& codegen,const GDScriptParser::Node *p_expression) { - +GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const { + if (!p_datatype.has_type) { + return GDScriptDataType(); + } - int ret = _parse_expression(codegen,p_expression); - if (ret<0) - return ret; + GDScriptDataType result; + result.has_type = true; - if (ret&(GDScriptFunction::ADDR_TYPE_STACK<<GDScriptFunction::ADDR_BITS)) { - codegen.stack_level++; - codegen.check_max_stack_level(); - //stack was used, keep value + switch (p_datatype.kind) { + case GDScriptParser::DataType::BUILTIN: { + result.kind = GDScriptDataType::BUILTIN; + result.builtin_type = p_datatype.builtin_type; + } break; + case GDScriptParser::DataType::NATIVE: { + result.kind = GDScriptDataType::NATIVE; + result.native_type = p_datatype.native_type; + } break; + case GDScriptParser::DataType::SCRIPT: { + result.kind = GDScriptDataType::SCRIPT; + result.script_type = p_datatype.script_type; + result.native_type = result.script_type->get_instance_base_type(); + } + case GDScriptParser::DataType::GDSCRIPT: { + result.kind = GDScriptDataType::GDSCRIPT; + result.script_type = p_datatype.script_type; + result.native_type = result.script_type->get_instance_base_type(); + } break; + case GDScriptParser::DataType::CLASS: { + result.kind = GDScriptDataType::GDSCRIPT; + if (!p_datatype.class_type->owner) { + result.script_type = Ref<GDScript>(main_script); + } else { + result.script_type = class_map[p_datatype.class_type->name]; + } + result.native_type = result.script_type->get_instance_base_type(); + } break; + default: { + ERR_PRINT("Parser bug: converting unresolved type."); + result.has_type = false; + } } - return ret; + return result; } -*/ int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level) { @@ -263,15 +290,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: owner = owner->_owner; } - /* - handled in constants now - if (codegen.script->subclasses.has(identifier)) { - //same with a subclass, make it a local constant. - int idx = codegen.get_constant_pos(codegen.script->subclasses[identifier]); - return idx|(GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDScriptFunction::ADDR_BITS); //make it a local constant (faster access) - - }*/ - if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; @@ -430,6 +448,83 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return dst_addr; } break; + case GDScriptParser::Node::TYPE_CAST: { + const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression); + + int slevel = p_stack_level; + int src_addr = _parse_expression(codegen, cn->source_node, slevel); + if (src_addr < 0) + return src_addr; + if (src_addr & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) { + slevel++; + codegen.alloc_stack(slevel); + } + + switch (cn->cast_type.kind) { + case GDScriptParser::DataType::BUILTIN: { + codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN); + codegen.opcodes.push_back(cn->cast_type.builtin_type); + } break; + case GDScriptParser::DataType::NATIVE: { + int class_idx; + if (GDScriptLanguage::get_singleton()->get_global_map().has(cn->cast_type.native_type)) { + + class_idx = GDScriptLanguage::get_singleton()->get_global_map()[cn->cast_type.native_type]; + class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) + } else { + _set_error("Invalid native class type '" + String(cn->cast_type.native_type) + "'.", cn); + return -1; + } + codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator + codegen.opcodes.push_back(class_idx); // variable type + } break; + case GDScriptParser::DataType::CLASS: { + + Variant script; + int idx = -1; + if (!cn->cast_type.class_type->owner) { + script = codegen.script; + } else { + StringName name = cn->cast_type.class_type->name; + if (class_map[name] == codegen.script->subclasses[name]) { + idx = codegen.get_name_map_pos(name); + idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS; + } else { + script = class_map[name]; + } + } + + if (idx < 0) { + idx = codegen.get_constant_pos(script); + idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) + } + + codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator + codegen.opcodes.push_back(idx); // variable type + } break; + case GDScriptParser::DataType::SCRIPT: + case GDScriptParser::DataType::GDSCRIPT: { + + Variant script = cn->cast_type.script_type; + int idx = codegen.get_constant_pos(script); + idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) + + codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator + codegen.opcodes.push_back(idx); // variable type + } break; + default: { + _set_error("Parser bug: unresolved data type.", cn); + return -1; + } + } + + codegen.opcodes.push_back(src_addr); // source adddress + int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode + codegen.alloc_stack(p_stack_level); + return dst_addr; + + } break; case GDScriptParser::Node::TYPE_OPERATOR: { //hell breaks loose @@ -690,8 +785,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size() + 3); - codegen.opcodes[jump_fail_pos] = codegen.opcodes.size(); - codegen.opcodes[jump_fail_pos2] = codegen.opcodes.size(); + codegen.opcodes.write[jump_fail_pos] = codegen.opcodes.size(); + codegen.opcodes.write[jump_fail_pos2] = codegen.opcodes.size(); codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_FALSE); codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); return p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS; @@ -723,8 +818,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(codegen.opcodes.size() + 3); - codegen.opcodes[jump_success_pos] = codegen.opcodes.size(); - codegen.opcodes[jump_success_pos2] = codegen.opcodes.size(); + codegen.opcodes.write[jump_success_pos] = codegen.opcodes.size(); + codegen.opcodes.write[jump_success_pos2] = codegen.opcodes.size(); codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TRUE); codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); return p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS; @@ -755,7 +850,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: int jump_past_pos = codegen.opcodes.size(); codegen.opcodes.push_back(0); - codegen.opcodes[jump_fail_pos] = codegen.opcodes.size(); + codegen.opcodes.write[jump_fail_pos] = codegen.opcodes.size(); res = _parse_expression(codegen, on->arguments[2], p_stack_level); if (res < 0) return res; @@ -764,7 +859,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); codegen.opcodes.push_back(res); - codegen.opcodes[jump_past_pos] = codegen.opcodes.size(); + codegen.opcodes.write[jump_past_pos] = codegen.opcodes.size(); return p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS; @@ -782,14 +877,6 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: case GDScriptParser::OperatorNode::OP_BIT_INVERT: { if (!_create_unary_operator(codegen, on, Variant::OP_BIT_NEGATE, p_stack_level)) return -1; } break; - case GDScriptParser::OperatorNode::OP_PREINC: { - } break; //? - case GDScriptParser::OperatorNode::OP_PREDEC: { - } break; - case GDScriptParser::OperatorNode::OP_INC: { - } break; - case GDScriptParser::OperatorNode::OP_DEC: { - } break; //binary operators (in precedence order) case GDScriptParser::OperatorNode::OP_IN: { if (!_create_binary_operator(codegen, on, Variant::OP_IN, p_stack_level)) return -1; @@ -1064,12 +1151,87 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: if (src_address_b < 0) return -1; - codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator - codegen.opcodes.push_back(dst_address_a); // argument 1 - codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) + GDScriptParser::DataType assign_type = on->arguments[0]->get_datatype(); + + if (assign_type.has_type && !on->arguments[1]->get_datatype().has_type) { + // Typed assignment + switch (assign_type.kind) { + case GDScriptParser::DataType::BUILTIN: { + codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator + codegen.opcodes.push_back(assign_type.builtin_type); // variable type + codegen.opcodes.push_back(dst_address_a); // argument 1 + codegen.opcodes.push_back(src_address_b); // argument 2 + } break; + case GDScriptParser::DataType::NATIVE: { + int class_idx; + if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) { + + class_idx = GDScriptLanguage::get_singleton()->get_global_map()[assign_type.native_type]; + class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) + } else { + _set_error("Invalid native class type '" + String(assign_type.native_type) + "'.", on->arguments[0]); + return -1; + } + codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE); // perform operator + codegen.opcodes.push_back(class_idx); // variable type + codegen.opcodes.push_back(dst_address_a); // argument 1 + codegen.opcodes.push_back(src_address_b); // argument 2 + } break; + case GDScriptParser::DataType::CLASS: { + + Variant script; + int idx = -1; + if (!assign_type.class_type->owner) { + script = codegen.script; + } else { + StringName name = assign_type.class_type->name; + if (class_map[name] == codegen.script->subclasses[name]) { + idx = codegen.get_name_map_pos(name); + idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS; + } else { + script = class_map[name]; + } + } + + if (idx < 0) { + idx = codegen.get_constant_pos(script); + idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) + } + + codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator + codegen.opcodes.push_back(idx); // variable type + codegen.opcodes.push_back(dst_address_a); // argument 1 + codegen.opcodes.push_back(src_address_b); // argument 2 + } break; + case GDScriptParser::DataType::SCRIPT: + case GDScriptParser::DataType::GDSCRIPT: { + + Variant script = assign_type.script_type; + int idx = codegen.get_constant_pos(script); + idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access) + + codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator + codegen.opcodes.push_back(idx); // variable type + codegen.opcodes.push_back(dst_address_a); // argument 1 + codegen.opcodes.push_back(src_address_b); // argument 2 + } break; + default: { + ERR_PRINT("Compiler bug: unresolved assign."); + + // Shouldn't get here, but fail-safe to a regular assignment + codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator + codegen.opcodes.push_back(dst_address_a); // argument 1 + codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) + } + } + } else { + // Either untyped assignment or already type-checked by the parser + codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator + codegen.opcodes.push_back(dst_address_a); // argument 1 + codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) + } return dst_address_a; //if anything, returns wathever was assigned or correct stack position } - } break; case GDScriptParser::OperatorNode::OP_IS: { @@ -1199,10 +1361,10 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(break_addr); - codegen.opcodes[continue_addr + 1] = codegen.opcodes.size(); + codegen.opcodes.write[continue_addr + 1] = codegen.opcodes.size(); } - codegen.opcodes[break_addr + 1] = codegen.opcodes.size(); + codegen.opcodes.write[break_addr + 1] = codegen.opcodes.size(); } break; @@ -1231,16 +1393,16 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); int end_addr = codegen.opcodes.size(); codegen.opcodes.push_back(0); - codegen.opcodes[else_addr] = codegen.opcodes.size(); + codegen.opcodes.write[else_addr] = codegen.opcodes.size(); Error err = _parse_block(codegen, cf->body_else, p_stack_level, p_break_addr, p_continue_addr); if (err) return err; - codegen.opcodes[end_addr] = codegen.opcodes.size(); + codegen.opcodes.write[end_addr] = codegen.opcodes.size(); } else { //end without else - codegen.opcodes[else_addr] = codegen.opcodes.size(); + codegen.opcodes.write[else_addr] = codegen.opcodes.size(); } } break; @@ -1291,7 +1453,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(continue_pos); - codegen.opcodes[break_pos + 1] = codegen.opcodes.size(); + codegen.opcodes.write[break_pos + 1] = codegen.opcodes.size(); codegen.pop_stack_identifiers(); @@ -1317,7 +1479,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); codegen.opcodes.push_back(continue_addr); - codegen.opcodes[break_addr + 1] = codegen.opcodes.size(); + codegen.opcodes.write[break_addr + 1] = codegen.opcodes.size(); } break; case GDScriptParser::ControlFlowNode::CF_SWITCH: { @@ -1525,6 +1687,18 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser if (p_func) { gdfunc->_static = p_func->_static; gdfunc->rpc_mode = p_func->rpc_mode; + gdfunc->argument_types.resize(p_func->argument_types.size()); + for (int i = 0; i < p_func->argument_types.size(); i++) { + gdfunc->argument_types.write[i] = _gdtype_from_datatype(p_func->argument_types[i]); + } + gdfunc->return_type = _gdtype_from_datatype(p_func->return_type); + } else { + gdfunc->_static = false; + gdfunc->rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + gdfunc->return_type = GDScriptDataType(); + gdfunc->return_type.has_type = true; + gdfunc->return_type.kind = GDScriptDataType::BUILTIN; + gdfunc->return_type.builtin_type = Variant::NIL; } #ifdef TOOLS_ENABLED @@ -1534,11 +1708,11 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser if (codegen.constant_map.size()) { gdfunc->_constant_count = codegen.constant_map.size(); gdfunc->constants.resize(codegen.constant_map.size()); - gdfunc->_constants_ptr = &gdfunc->constants[0]; + gdfunc->_constants_ptr = gdfunc->constants.ptrw(); const Variant *K = NULL; while ((K = codegen.constant_map.next(K))) { int idx = codegen.constant_map[*K]; - gdfunc->constants[idx] = *K; + gdfunc->constants.write[idx] = *K; } } else { @@ -1552,7 +1726,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->_global_names_ptr = &gdfunc->global_names[0]; for (Map<StringName, int>::Element *E = codegen.name_map.front(); E; E = E->next()) { - gdfunc->global_names[E->get()] = E->key(); + gdfunc->global_names.write[E->get()] = E->key(); } gdfunc->_global_names_count = gdfunc->global_names.size(); @@ -1567,7 +1741,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->named_globals.resize(codegen.named_globals.size()); gdfunc->_named_globals_ptr = gdfunc->named_globals.ptr(); for (int i = 0; i < codegen.named_globals.size(); i++) { - gdfunc->named_globals[i] = codegen.named_globals[i]; + gdfunc->named_globals.write[i] = codegen.named_globals[i]; } gdfunc->_named_globals_count = gdfunc->named_globals.size(); } @@ -1653,12 +1827,23 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser return OK; } -Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { - - Map<StringName, Ref<GDScript> > old_subclasses; +Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { - if (p_keep_state) { - old_subclasses = p_script->subclasses; + if (p_class->owner && p_class->owner->owner) { + // Owner is not root + StringName owner_name = p_class->owner->name; + if (!parsed_classes.has(owner_name)) { + if (parsing_classes.has(owner_name)) { + _set_error("Cyclic class reference for '" + String(owner_name) + "'.", p_class); + return ERR_PARSE_ERROR; + } + parsing_classes.insert(owner_name); + Error err = _parse_class_level(class_map[owner_name].ptr(), class_map[owner_name]->_owner, p_class->owner, p_keep_state); + if (err) { + return err; + } + parsing_classes.erase(owner_name); + } } p_script->native = Ref<GDScriptNativeClass>(); @@ -1682,236 +1867,100 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons Ref<GDScriptNativeClass> native; - if (p_class->extends_used) { - //do inheritance - String path = p_class->extends_file; - - Ref<GDScript> script; - - if (path != "") { - //path (and optionally subclasses) - - if (path.is_rel_path()) { - - String base; - - if (p_owner) { - GDScript *current_class = p_owner; - while (current_class != NULL) { - base = current_class->get_path(); - if (base == "") - current_class = current_class->_owner; - else - break; - } - } else { - base = p_script->get_path(); - } - - if (base == "" || base.is_rel_path()) { - _set_error("Could not resolve relative path for parent class: " + path, p_class); - return ERR_FILE_NOT_FOUND; - } - path = base.get_base_dir().plus_file(path).simplify_path(); - } - script = ResourceLoader::load(path); - if (script.is_null()) { - _set_error("Could not load base class: " + path, p_class); - return ERR_FILE_NOT_FOUND; - } - if (!script->valid) { - - _set_error("Script not fully loaded (cyclic preload?): " + path, p_class); - return ERR_BUSY; - } - //print_line("EXTENDS PATH: "+path+" script is "+itos(script.is_valid())+" indices is "+itos(script->member_indices.size())+" valid? "+itos(script->valid)); - - if (p_class->extends_class.size()) { - - for (int i = 0; i < p_class->extends_class.size(); i++) { - - String sub = p_class->extends_class[i]; - if (script->subclasses.has(sub)) { - - Ref<Script> subclass = script->subclasses[sub]; //avoid reference from disappearing - script = subclass; - } else { - - _set_error("Could not find subclass: " + sub, p_class); - return ERR_FILE_NOT_FOUND; - } - } - } - - } else { - - ERR_FAIL_COND_V(p_class->extends_class.size() == 0, ERR_BUG); - //look around for the subclasses - - String base = p_class->extends_class[0]; - GDScript *p = p_owner; - Ref<GDScript> base_class; - - while (p) { - - if (p->subclasses.has(base)) { - - base_class = p->subclasses[base]; - break; - } - - if (p->constants.has(base)) { - - base_class = p->constants[base]; - if (base_class.is_null()) { - _set_error("Constant is not a class: " + base, p_class); - return ERR_SCRIPT_FAILED; - } - break; - } - - p = p->_owner; - } - - if (base_class.is_valid()) { - - String ident = base; - - for (int i = 1; i < p_class->extends_class.size(); i++) { - - String subclass = p_class->extends_class[i]; - - ident += ("." + subclass); - - if (base_class->subclasses.has(subclass)) { - - base_class = base_class->subclasses[subclass]; - } else if (base_class->constants.has(subclass)) { - - Ref<GDScript> new_base_class = base_class->constants[subclass]; - if (new_base_class.is_null()) { - _set_error("Constant is not a class: " + ident, p_class); - return ERR_SCRIPT_FAILED; - } - base_class = new_base_class; - } else { - - _set_error("Could not find subclass: " + ident, p_class); - return ERR_FILE_NOT_FOUND; - } - } - - script = base_class; - - } else { - - if (p_class->extends_class.size() > 1) { - - _set_error("Invalid inheritance (unknown class+subclasses)", p_class); - return ERR_FILE_NOT_FOUND; + // Inheritance + switch (p_class->base_type.kind) { + case GDScriptParser::DataType::CLASS: { + StringName base_name = p_class->base_type.class_type->name; + // Make sure dependency is parsed first + if (!parsed_classes.has(base_name)) { + if (parsing_classes.has(base_name)) { + _set_error("Cyclic class reference for '" + String(base_name) + "'.", p_class); + return ERR_PARSE_ERROR; } - //if not found, try engine classes - if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) { - - _set_error("Unknown class: '" + base + "'", p_class); - return ERR_FILE_NOT_FOUND; - } - - int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base]; - native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx]; - if (!native.is_valid()) { - - _set_error("Global not a class: '" + base + "'", p_class); - - return ERR_FILE_NOT_FOUND; + parsing_classes.insert(base_name); + Error err = _parse_class_level(class_map[base_name].ptr(), class_map[base_name]->_owner, p_class->base_type.class_type, p_keep_state); + if (err) { + return err; } + parsing_classes.erase(base_name); } - } - - if (script.is_valid()) { - - p_script->base = script; + Ref<GDScript> base = class_map[base_name]; + p_script->base = base; p_script->_base = p_script->base.ptr(); - p_script->member_indices = script->member_indices; - - } else if (native.is_valid()) { - + p_script->member_indices = base->member_indices; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> base = p_class->base_type.script_type; + p_script->base = base; + p_script->_base = p_script->base.ptr(); + p_script->member_indices = base->member_indices; + } break; + case GDScriptParser::DataType::NATIVE: { + int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_class->base_type.native_type]; + native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; + ERR_FAIL_COND_V(native.is_null(), ERR_BUG); p_script->native = native; - } else { - - _set_error("Could not determine inheritance", p_class); - return ERR_FILE_NOT_FOUND; - } - - } else { - // without extends, implicitly extend Reference - int native_idx = GDScriptLanguage::get_singleton()->get_global_map()["Reference"]; - native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx]; - ERR_FAIL_COND_V(native.is_null(), ERR_BUG); - p_script->native = native; + } break; + default: { + _set_error("Parser bug: invalid inheritance.", p_class); + return ERR_BUG; + } break; } - //print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size())); - for (int i = 0; i < p_class->variables.size(); i++) { StringName name = p_class->variables[i].identifier; - if (p_script->member_indices.has(name)) { - _set_error("Member '" + name + "' already exists (in current or parent class)", p_class); - return ERR_ALREADY_EXISTS; - } - if (_is_class_member_property(p_script, name)) { - _set_error("Member '" + name + "' already exists as a class property.", p_class); - return ERR_ALREADY_EXISTS; - } - if (p_class->variables[i]._export.type != Variant::NIL) { + GDScript::MemberInfo minfo; + minfo.index = p_script->member_indices.size(); + minfo.setter = p_class->variables[i].setter; + minfo.getter = p_class->variables[i].getter; + minfo.rpc_mode = p_class->variables[i].rpc_mode; + minfo.data_type = _gdtype_from_datatype(p_class->variables[i].data_type); - p_script->member_info[name] = p_class->variables[i]._export; + PropertyInfo prop_info = minfo.data_type; + prop_info.name = name; + PropertyInfo export_info = p_class->variables[i]._export; + + if (export_info.type != Variant::NIL) { + + if (!minfo.data_type.has_type) { + prop_info.type = export_info.type; + prop_info.class_name = export_info.class_name; + } + prop_info.hint = export_info.hint; + prop_info.hint_string = export_info.hint_string; + prop_info.usage = export_info.usage; #ifdef TOOLS_ENABLED if (p_class->variables[i].default_value.get_type() != Variant::NIL) { - p_script->member_default_values[name] = p_class->variables[i].default_value; } #endif } else { - - p_script->member_info[name] = PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE); + prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE; } - //int new_idx = p_script->member_indices.size(); - GDScript::MemberInfo minfo; - minfo.index = p_script->member_indices.size(); - minfo.setter = p_class->variables[i].setter; - minfo.getter = p_class->variables[i].getter; - minfo.rpc_mode = p_class->variables[i].rpc_mode; - + p_script->member_info[name] = prop_info; p_script->member_indices[name] = minfo; p_script->members.insert(name); #ifdef TOOLS_ENABLED - p_script->member_lines[name] = p_class->variables[i].line; #endif } - for (int i = 0; i < p_class->constant_expressions.size(); i++) { + for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { - StringName name = p_class->constant_expressions[i].identifier; - ERR_CONTINUE(p_class->constant_expressions[i].expression->type != GDScriptParser::Node::TYPE_CONSTANT); + StringName name = E->key(); - if (_is_class_member_property(p_script, name)) { - _set_error("Member '" + name + "' already exists as a class property.", p_class); - return ERR_ALREADY_EXISTS; - } + ERR_CONTINUE(E->get().expression->type != GDScriptParser::Node::TYPE_CONSTANT); - GDScriptParser::ConstantNode *constant = static_cast<GDScriptParser::ConstantNode *>(p_class->constant_expressions[i].expression); + GDScriptParser::ConstantNode *constant = static_cast<GDScriptParser::ConstantNode *>(E->get().expression); p_script->constants.insert(name, constant->value); -//p_script->constants[constant->value].make_const(); #ifdef TOOLS_ENABLED - p_script->member_lines[name] = p_class->constant_expressions[i].expression->line; + p_script->member_lines[name] = E->get().expression->line; #endif } @@ -1944,23 +1993,27 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons p_script->_signals[name] = p_class->_signals[i].arguments; } + + if (!p_class->owner) { + parsed_classes.insert(p_class->name); + } + //parse sub-classes for (int i = 0; i < p_class->subclasses.size(); i++) { StringName name = p_class->subclasses[i]->name; - Ref<GDScript> subclass; + Ref<GDScript> subclass = class_map[name]; - if (old_subclasses.has(name)) { - subclass = old_subclasses[name]; - } else { - subclass.instance(); + // Subclass might still be parsing, just skip it + if (!parsed_classes.has(name) && !parsing_classes.has(name)) { + parsing_classes.insert(name); + Error err = _parse_class_level(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state); + if (err) + return err; + parsing_classes.erase(name); } - Error err = _parse_class(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state); - if (err) - return err; - #ifdef TOOLS_ENABLED p_script->member_lines[name] = p_class->subclasses[i]->line; @@ -1970,6 +2023,10 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons p_script->subclasses.insert(name, subclass); } + return OK; +} + +Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { //parse methods bool has_initializer = false; @@ -2010,44 +2067,6 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons } #ifdef DEBUG_ENABLED - //validate setters/getters if debug is enabled - for (int i = 0; i < p_class->variables.size(); i++) { - - if (p_class->variables[i].setter) { - const Map<StringName, GDScriptFunction *>::Element *E = p_script->get_member_functions().find(p_class->variables[i].setter); - if (!E) { - _set_error("Setter function '" + String(p_class->variables[i].setter) + "' not found in class.", NULL); - err_line = p_class->variables[i].line; - err_column = 0; - return ERR_PARSE_ERROR; - } - - if (E->get()->is_static()) { - - _set_error("Setter function '" + String(p_class->variables[i].setter) + "' is static.", NULL); - err_line = p_class->variables[i].line; - err_column = 0; - return ERR_PARSE_ERROR; - } - } - if (p_class->variables[i].getter) { - const Map<StringName, GDScriptFunction *>::Element *E = p_script->get_member_functions().find(p_class->variables[i].getter); - if (!E) { - _set_error("Getter function '" + String(p_class->variables[i].getter) + "' not found in class.", NULL); - err_line = p_class->variables[i].line; - err_column = 0; - return ERR_PARSE_ERROR; - } - - if (E->get()->is_static()) { - - _set_error("Getter function '" + String(p_class->variables[i].getter) + "' is static.", NULL); - err_line = p_class->variables[i].line; - err_column = 0; - return ERR_PARSE_ERROR; - } - } - } //validate instances if keeping state @@ -2100,22 +2119,67 @@ Error GDScriptCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, cons } #endif + for (int i = 0; i < p_class->subclasses.size(); i++) { + StringName name = p_class->subclasses[i]->name; + Ref<GDScript> subclass = class_map[name]; + + Error err = _parse_class_blocks(subclass.ptr(), p_class->subclasses[i], p_keep_state); + if (err) { + return err; + } + } + p_script->valid = true; return OK; } +void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { + + Map<StringName, Ref<GDScript> > old_subclasses; + + if (p_keep_state) { + old_subclasses = p_script->subclasses; + } + + for (int i = 0; i < p_class->subclasses.size(); i++) { + StringName name = p_class->subclasses[i]->name; + + Ref<GDScript> subclass; + + if (old_subclasses.has(name)) { + subclass = old_subclasses[name]; + } else { + subclass.instance(); + } + + subclass->_owner = const_cast<GDScript *>(p_script); + class_map.insert(name, subclass); + + _make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state); + } +} + Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state) { err_line = -1; err_column = -1; error = ""; parser = p_parser; + main_script = p_script; const GDScriptParser::Node *root = parser->get_parse_tree(); ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, ERR_INVALID_DATA); source = p_script->get_path(); - Error err = _parse_class(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); + // Create scripts for subclasses beforehand so they can be referenced + _make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); + + Error err = _parse_class_level(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); + + if (err) + return err; + + err = _parse_class_blocks(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state); if (err) return err; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 237b0de9e7..55f5e2b48e 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -31,12 +31,17 @@ #ifndef GDSCRIPT_COMPILER_H #define GDSCRIPT_COMPILER_H +#include "core/set.h" #include "gdscript.h" #include "gdscript_parser.h" class GDScriptCompiler { const GDScriptParser *parser; + Map<StringName, Ref<GDScript> > class_map; + Set<StringName> parsed_classes; + Set<StringName> parsing_classes; + GDScript *main_script; struct CodeGen { GDScript *script; @@ -138,11 +143,15 @@ class GDScriptCompiler { bool _create_unary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level); bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer = false); + GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const; + int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level); int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false); Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1); Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false); - Error _parse_class(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); + void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state); int err_line; int err_column; StringName source; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index c8d2d2e3e8..2a42524ba7 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -37,6 +37,7 @@ #include "os/file_access.h" #ifdef TOOLS_ENABLED +#include "core/reference.h" #include "editor/editor_file_system.h" #include "editor/editor_settings.h" #include "engine.h" @@ -53,21 +54,45 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const { p_delimiters->push_back("' '"); } Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { +#ifdef TOOLS_ENABLED + bool th = EDITOR_DEF("text_editor/completion/add_type_hints", false); +#else + bool th = false; +#endif String _template = "extends %BASE%\n" "\n" "# Declare member variables here. Examples:\n" - "# var a = 2\n" - "# var b = \"text\"\n" + "# var a %INT_TYPE%= 2\n" + "# var b %STRING_TYPE%= \"text\"\n" "\n" "# Called when the node enters the scene tree for the first time.\n" - "func _ready():\n" + "func _ready()%VOID_RETURN%:\n" "%TS%pass # Replace with function body.\n" "\n" "# Called every frame. 'delta' is the elapsed time since the previous frame.\n" - "#func _process(delta):\n" + "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n" "#%TS%pass\n"; +#ifdef TOOLS_ENABLED + if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) { + _template = _template.replace("%INT_TYPE%", ": int "); + _template = _template.replace("%STRING_TYPE%", ": String "); + _template = _template.replace("%FLOAT_TYPE%", " : float"); + _template = _template.replace("%VOID_RETURN%", " -> void"); + } else { + _template = _template.replace("%INT_TYPE%", ""); + _template = _template.replace("%STRING_TYPE%", ""); + _template = _template.replace("%FLOAT_TYPE%", ""); + _template = _template.replace("%VOID_RETURN%", ""); + } +#else + _template = _template.replace("%INT_TYPE%", ""); + _template = _template.replace("%STRING_TYPE%", ""); + _template = _template.replace("%FLOAT_TYPE%", ""); + _template = _template.replace("%VOID_RETURN%", ""); +#endif + _template = _template.replace("%BASE%", p_base_class_name); _template = _template.replace("%TS%", _get_indentation()); @@ -91,11 +116,11 @@ void GDScriptLanguage::make_template(const String &p_class_name, const String &p p_script->set_source_code(src); } -bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { +bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { GDScriptParser parser; - Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path); + Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path, false, r_safe_lines); if (err) { r_line_error = parser.get_error_line(); r_col_error = parser.get_error_column(); @@ -415,63 +440,34 @@ void GDScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_cons String GDScriptLanguage::make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const { +#ifdef TOOLS_ENABLED + bool th = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints"); +#else + bool th = false; +#endif + String s = "func " + p_name + "("; if (p_args.size()) { for (int i = 0; i < p_args.size(); i++) { if (i > 0) s += ", "; s += p_args[i].get_slice(":", 0); + if (th) { + String type = p_args[i].get_slice(":", 1); + if (!type.empty() && type != "var") { + s += " : " + type; + } + } } } - s += "):\n" + _get_indentation() + "pass # Replace with function body.\n"; + s += String(")") + (th ? " -> void" : "") + ":\n" + _get_indentation() + "pass # Replace with function body.\n"; return s; } -#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) - -struct GDScriptCompletionIdentifier { - - String enumeration; - StringName obj_type; - Ref<GDScript> script; - Variant::Type type; - Variant value; //im case there is a value, also return it +//////// COMPLETION ////////// - GDScriptCompletionIdentifier() : - type(Variant::NIL) {} -}; - -static GDScriptCompletionIdentifier _get_type_from_variant(const Variant &p_variant, bool p_allow_gdnative_class = false) { - - GDScriptCompletionIdentifier t; - t.type = p_variant.get_type(); - t.value = p_variant; - if (p_variant.get_type() == Variant::OBJECT) { - Object *obj = p_variant; - if (obj) { - - if (p_allow_gdnative_class && Object::cast_to<GDScriptNativeClass>(obj)) { - t.obj_type = Object::cast_to<GDScriptNativeClass>(obj)->get_name(); - t.value = Variant(); - } else { - - t.obj_type = obj->get_class(); - } - } - } - return t; -} - -static GDScriptCompletionIdentifier _get_type_from_pinfo(const PropertyInfo &p_info) { - - GDScriptCompletionIdentifier t; - t.type = p_info.type; - if (p_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { - t.obj_type = p_info.hint_string; - } - return t; -} +#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) struct GDScriptCompletionContext { @@ -480,1043 +476,1612 @@ struct GDScriptCompletionContext { const GDScriptParser::BlockNode *block; Object *base; String base_path; -}; - -static Ref<Reference> _get_parent_class(GDScriptCompletionContext &context) { - - if (context._class->extends_used) { - //do inheritance - String path = context._class->extends_file; - - Ref<GDScript> script; - Ref<GDScriptNativeClass> native; + int line; - if (path != "") { - //path (and optionally subclasses) - - if (path.is_rel_path()) { - - path = context.base_path.plus_file(path); - } - - if (ScriptCodeCompletionCache::get_singleton()) - script = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(path); - else - script = ResourceLoader::load(path); + GDScriptCompletionContext() : + _class(NULL), + function(NULL), + block(NULL), + base(NULL) {} +}; - if (script.is_null()) { - return REF(); - } - if (!script->is_valid()) { +struct GDScriptCompletionIdentifier { + GDScriptParser::DataType type; + String enumeration; + Variant value; + const GDScriptParser::Node *assigned_expression; - return REF(); - } - //print_line("EXTENDS PATH: "+path+" script is "+itos(script.is_valid())+" indices is "+itos(script->member_indices.size())+" valid? "+itos(script->valid)); + GDScriptCompletionIdentifier() : + assigned_expression(NULL) {} +}; - if (context._class->extends_class.size()) { +static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) { - for (int i = 0; i < context._class->extends_class.size(); i++) { + for (int i = 0; i < p_dir->get_file_count(); i++) { + r_list.insert("\"" + p_dir->get_file_path(i) + "\""); + } - String sub = context._class->extends_class[i]; - if (script->get_subclasses().has(sub)) { + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + _get_directory_contents(p_dir->get_subdir(i), r_list); + } +} - script = script->get_subclasses()[sub]; - } else { +static String _get_visual_datatype(const PropertyInfo &p_info, bool p_isarg = true) { - return REF(); - } - } - } + if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + String enum_name = p_info.class_name; + if (enum_name.find(".") == -1) { + return enum_name; + } + return enum_name.get_slice(".", 1); + } - if (script.is_valid()) - return script; + String n = p_info.name; + int idx = n.find(":"); + if (idx != -1) { + return n.substr(idx + 1, n.length()); + } + if (p_info.type == Variant::OBJECT) { + if (p_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + return p_info.hint_string; } else { + return p_info.class_name.operator String(); + } + } + if (p_info.type == Variant::NIL) { + if (p_isarg || (p_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) { + return "var"; + } else { + return "void"; + } + } - if (context._class->extends_class.size() == 0) { - ERR_PRINT("BUG"); - return REF(); - } - - String base = context._class->extends_class[0]; - - if (context._class->extends_class.size() > 1) { - - return REF(); - } - //if not found, try engine classes - if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) { + return Variant::get_type_name(p_info.type); +} - return REF(); +static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value) { + GDScriptCompletionIdentifier ci; + ci.value = p_value; + ci.type.is_constant = true; + ci.type.has_type = true; + ci.type.kind = GDScriptParser::DataType::BUILTIN; + ci.type.builtin_type = p_value.get_type(); + + if (ci.type.builtin_type == Variant::OBJECT) { + Object *obj = p_value.operator Object *(); + if (!obj) { + return ci; + } + ci.type.native_type = obj->get_class_name(); + Ref<Script> scr = p_value; + if (scr.is_valid()) { + ci.type.is_meta_type = true; + } else { + ci.type.is_meta_type = false; + scr = obj->get_script(); + } + if (scr.is_valid()) { + ci.type.script_type = scr; + Ref<GDScript> gds = scr; + if (gds.is_valid()) { + ci.type.kind = GDScriptParser::DataType::GDSCRIPT; + } else { + ci.type.kind = GDScriptParser::DataType::SCRIPT; } - - int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base]; - native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx]; - return native; + ci.type.native_type = scr->get_instance_base_type(); + } else { + ci.type.kind = GDScriptParser::DataType::NATIVE; } } - return Ref<Reference>(); + return ci; } -static GDScriptCompletionIdentifier _get_native_class(GDScriptCompletionContext &context) { +static GDScriptCompletionIdentifier _type_from_property(const PropertyInfo &p_property) { + GDScriptCompletionIdentifier ci; - GDScriptCompletionIdentifier id; - - REF pc = _get_parent_class(context); - if (!pc.is_valid()) { - return id; + if (p_property.type == Variant::NIL) { + // Variant + return ci; } - Ref<GDScriptNativeClass> nc = pc; - Ref<GDScript> s = pc; - if (s.is_null() && nc.is_null()) { - return id; - } - while (!s.is_null()) { - nc = s->get_native(); - s = s->get_base(); - } - if (nc.is_null()) { - return id; + if (p_property.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + ci.enumeration = p_property.class_name; } - id.type = Variant::OBJECT; - if (context.base) - id.value = context.base; - id.obj_type = nc->get_name(); - return id; + ci.type.has_type = true; + ci.type.builtin_type = p_property.type; + if (p_property.type == Variant::OBJECT) { + ci.type.kind = GDScriptParser::DataType::NATIVE; + ci.type.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name; + } else { + ci.type.kind = GDScriptParser::DataType::BUILTIN; + } + return ci; } -static bool _guess_identifier_type(GDScriptCompletionContext &context, int p_line, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type, bool p_for_indexing); - -static bool _guess_expression_type(GDScriptCompletionContext &context, const GDScriptParser::Node *p_node, int p_line, GDScriptCompletionIdentifier &r_type, bool p_for_indexing = false) { - - if (p_node->type == GDScriptParser::Node::TYPE_CONSTANT) { - - const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(p_node); +static GDScriptCompletionIdentifier _type_from_gdtype(const GDScriptDataType &p_gdtype) { + GDScriptCompletionIdentifier ci; + if (!p_gdtype.has_type) { + return ci; + } - r_type = _get_type_from_variant(cn->value); + ci.type.has_type = true; + ci.type.builtin_type = p_gdtype.builtin_type; + ci.type.native_type = p_gdtype.native_type; + ci.type.script_type = p_gdtype.script_type; - return true; - } else if (p_node->type == GDScriptParser::Node::TYPE_DICTIONARY) { - - r_type.type = Variant::DICTIONARY; + switch (p_gdtype.kind) { + case GDScriptDataType::BUILTIN: { + ci.type.kind = GDScriptParser::DataType::BUILTIN; + } break; + case GDScriptDataType::NATIVE: { + ci.type.kind = GDScriptParser::DataType::NATIVE; + } break; + case GDScriptDataType::GDSCRIPT: { + ci.type.kind = GDScriptParser::DataType::GDSCRIPT; + } break; + case GDScriptDataType::SCRIPT: { + ci.type.kind = GDScriptParser::DataType::SCRIPT; + } break; + } + return ci; +} - //what the heck, fill it anyway - const GDScriptParser::DictionaryNode *an = static_cast<const GDScriptParser::DictionaryNode *>(p_node); - Dictionary d; - for (int i = 0; i < an->elements.size(); i++) { - GDScriptCompletionIdentifier k; - if (_guess_expression_type(context, an->elements[i].key, p_line, k) && k.value.get_type() != Variant::NIL) { - GDScriptCompletionIdentifier v; - if (_guess_expression_type(context, an->elements[i].value, p_line, v)) { - d[k.value] = v.value; +static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_identifier_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_method_return_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); + +static bool _guess_expression_type(const GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_expression, GDScriptCompletionIdentifier &r_type) { + bool found = false; + switch (p_expression->type) { + case GDScriptParser::Node::TYPE_CONSTANT: { + const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(p_expression); + r_type = _type_from_variant(cn->value); + found = true; + } break; + case GDScriptParser::Node::TYPE_SELF: { + if (p_context._class) { + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::CLASS; + r_type.type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class); + r_type.type.is_constant = true; + r_type.value = p_context.base; + found = true; + } + } break; + case GDScriptParser::Node::TYPE_IDENTIFIER: { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression); + found = _guess_identifier_type(p_context, id->name, r_type); + } break; + case GDScriptParser::Node::TYPE_DICTIONARY: { + // Try to recreate the dictionary + const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(p_expression); + Dictionary d; + bool full = true; + for (int i = 0; i < dn->elements.size(); i++) { + GDScriptCompletionIdentifier key; + if (_guess_expression_type(p_context, dn->elements[i].key, key)) { + GDScriptCompletionIdentifier value; + if (_guess_expression_type(p_context, dn->elements[i].value, value)) { + if (!value.type.is_constant) { + full = false; + break; + } + d[key.value] = value.value; + } else { + full = false; + break; + } + } else { + full = false; + break; } } - } - r_type.value = d; - return true; - } else if (p_node->type == GDScriptParser::Node::TYPE_ARRAY) { - - r_type.type = Variant::ARRAY; - //what the heck, fill it anyway - const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_node); - Array arr; - arr.resize(an->elements.size()); - for (int i = 0; i < an->elements.size(); i++) { - GDScriptCompletionIdentifier ci; - if (_guess_expression_type(context, an->elements[i], p_line, ci)) { - arr[i] = ci.value; + if (full) { + // If not fully constant, setting this value is detrimental to the inference + r_type.value = d; + r_type.type.is_constant = true; } - } - r_type.value = arr; - return true; - - } else if (p_node->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { - - MethodInfo mi = GDScriptFunctions::get_info(static_cast<const GDScriptParser::BuiltInFunctionNode *>(p_node)->function); - r_type = _get_type_from_pinfo(mi.return_val); - - return true; - } else if (p_node->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - - return _guess_identifier_type(context, p_line - 1, static_cast<const GDScriptParser::IdentifierNode *>(p_node)->name, r_type, p_for_indexing); - } else if (p_node->type == GDScriptParser::Node::TYPE_SELF) { - //eeh... - - r_type = _get_native_class(context); - return r_type.type != Variant::NIL; - - } else if (p_node->type == GDScriptParser::Node::TYPE_OPERATOR) { - - const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_node); - if (op->op == GDScriptParser::OperatorNode::OP_CALL) { - - if (op->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) { - - const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(op->arguments[0]); - r_type.type = tn->vtype; - return true; - } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { - - const GDScriptParser::BuiltInFunctionNode *bin = static_cast<const GDScriptParser::BuiltInFunctionNode *>(op->arguments[0]); - return _guess_expression_type(context, bin, p_line, r_type); - - } else if (op->arguments.size() > 1 && op->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - - StringName id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1])->name; - - if (op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER && String(id) == "new") { - - //shortcut - StringName identifier = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name; - - if (ClassDB::class_exists(identifier)) { - r_type.type = Variant::OBJECT; - r_type.value = Variant(); - r_type.obj_type = identifier; - return true; - } + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::BUILTIN; + r_type.type.builtin_type = Variant::DICTIONARY; + } break; + case GDScriptParser::Node::TYPE_ARRAY: { + // Try to recreate the array + const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_expression); + Array a; + bool full = true; + a.resize(an->elements.size()); + for (int i = 0; i < an->elements.size(); i++) { + GDScriptCompletionIdentifier value; + if (_guess_expression_type(p_context, an->elements[i], value)) { + a[i] = value.value; + } else { + full = false; + break; } - - GDScriptCompletionIdentifier base; - if (!_guess_expression_type(context, op->arguments[0], p_line, base)) - return false; - - if (base.type == Variant::OBJECT) { - - if (id.operator String() == "new" && base.value.get_type() == Variant::OBJECT) { - - Object *obj = base.value; - if (obj && Object::cast_to<GDScriptNativeClass>(obj)) { - GDScriptNativeClass *gdnc = Object::cast_to<GDScriptNativeClass>(obj); - r_type.type = Variant::OBJECT; - r_type.value = Variant(); - r_type.obj_type = gdnc->get_name(); - return true; - } else { - - if (base.obj_type != StringName()) { - - r_type.type = Variant::OBJECT; - r_type.value = Variant(); - r_type.obj_type = base.obj_type; - return true; - } + } + if (full) { + // If not fully constant, setting this value is detrimental to the inference + r_type.value = a; + } + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::BUILTIN; + r_type.type.builtin_type = Variant::ARRAY; + } break; + case GDScriptParser::Node::TYPE_OPERATOR: { + const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_expression); + switch (op->op) { + case GDScriptParser::OperatorNode::OP_CALL: { + if (op->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) { + const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(op->arguments[0]); + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::BUILTIN; + r_type.type.builtin_type = tn->vtype; + found = true; + break; + } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { + const GDScriptParser::BuiltInFunctionNode *bin = static_cast<const GDScriptParser::BuiltInFunctionNode *>(op->arguments[0]); + MethodInfo mi = GDScriptFunctions::get_info(bin->function); + r_type = _type_from_property(mi.return_val); + found = true; + break; + } else if (op->arguments.size() >= 2 && op->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { + StringName id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1])->name; + + GDScriptCompletionContext c = p_context; + c.line = op->line; + + GDScriptCompletionIdentifier base; + if (!_guess_expression_type(c, op->arguments[0], base)) { + found = false; + break; } - } - if (ClassDB::has_method(base.obj_type, id)) { - -#ifdef TOOLS_ENABLED - MethodBind *mb = ClassDB::get_method(base.obj_type, id); - PropertyInfo pi = mb->get_return_info(); + // Try call if constant methods with constant arguments + if (base.type.is_constant && base.value.get_type() == Variant::OBJECT) { + GDScriptParser::DataType native_type = base.type; - //try calling the function if constant and all args are constant, should not crash.. - Object *baseptr = base.value; - - if (mb->is_const() && pi.type == Variant::OBJECT) { - - bool all_valid = true; - Vector<Variant> args; - for (int i = 2; i < op->arguments.size(); i++) { - GDScriptCompletionIdentifier arg; + while (native_type.kind == GDScriptParser::DataType::CLASS) { + native_type = native_type.class_type->base_type; + } - if (_guess_expression_type(context, op->arguments[i], p_line, arg)) { - if (arg.value.get_type() != Variant::NIL && arg.value.get_type() != Variant::OBJECT) { // calling with object seems dangerous, i don' t know - args.push_back(arg.value); + while (native_type.kind == GDScriptParser::DataType::GDSCRIPT || native_type.kind == GDScriptParser::DataType::SCRIPT) { + if (native_type.script_type.is_valid()) { + Ref<Script> parent = native_type.script_type->get_base_script(); + if (parent.is_valid()) { + native_type.script_type = parent; } else { - all_valid = false; - break; + native_type.kind = GDScriptParser::DataType::NATIVE; + native_type.native_type = native_type.script_type->get_instance_base_type(); + if (!ClassDB::class_exists(native_type.native_type)) { + native_type.native_type = String("_") + native_type.native_type; + if (!ClassDB::class_exists(native_type.native_type)) { + native_type.has_type = false; + } + } } - } else { - all_valid = false; } } - if (all_valid && String(id) == "get_node" && ClassDB::is_parent_class(base.obj_type, "Node") && args.size()) { - - String arg1 = args[0]; - if (arg1.begins_with("/root/")) { - String which = arg1.get_slice("/", 2); - if (which != "") { - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); - //print_line("find singleton"); - - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - - String s = E->get().name; - if (!s.begins_with("autoload/")) - continue; - //print_line("found "+s); - String name = s.get_slice("/", 1); - //print_line("name: "+name+", which: "+which); - if (name == which) { - String script = ProjectSettings::get_singleton()->get(s); - - if (!script.begins_with("res://")) { - script = "res://" + script; - } - - if (!script.ends_with(".gd")) { - //not a script, try find the script anyway, - //may have some success - script = script.get_basename() + ".gd"; - } - - if (FileAccess::exists(script)) { - - //print_line("is a script"); - - Ref<Script> scr; - if (ScriptCodeCompletionCache::get_singleton()) - scr = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(script); - else - scr = ResourceLoader::load(script); - - r_type.obj_type = "Node"; - r_type.type = Variant::OBJECT; - r_type.script = scr; - r_type.value = Variant(); - - return true; - } + if (native_type.has_type && native_type.kind == GDScriptParser::DataType::NATIVE) { + MethodBind *mb = ClassDB::get_method(native_type.native_type, id); + if (mb && mb->is_const()) { + bool all_is_const = true; + Vector<Variant> args; + GDScriptCompletionContext c = p_context; + c.line = op->line; + for (int i = 2; all_is_const && i < op->arguments.size(); i++) { + GDScriptCompletionIdentifier arg; + + if (_guess_expression_type(c, op->arguments[i], arg)) { + if (arg.type.has_type && arg.type.is_constant && arg.value.get_type() != Variant::OBJECT) { + args.push_back(arg.value); + } else { + all_is_const = false; } + } else { + all_is_const = false; } } - } - } - if (baseptr) { - - if (all_valid) { - Vector<const Variant *> argptr; - for (int i = 0; i < args.size(); i++) { - argptr.push_back(&args[i]); + Object *baseptr = base.value; + + if (all_is_const && String(id) == "get_node" && ClassDB::is_parent_class(native_type.native_type, "Node") && args.size()) { + + String arg1 = args[0]; + if (arg1.begins_with("/root/")) { + String which = arg1.get_slice("/", 2); + if (which != "") { + // Try singletons first + if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(which)) { + r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]); + found = true; + } else { + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + String s = E->get().name; + if (!s.begins_with("autoload/")) { + continue; + } + String name = s.get_slice("/", 1); + if (name == which) { + String script = ProjectSettings::get_singleton()->get(s); + + if (script.begins_with("*")) { + script = script.right(1); + } + + if (!script.begins_with("res://")) { + script = "res://" + script; + } + + if (!script.ends_with(".gd")) { + //not a script, try find the script anyway, + //may have some success + script = script.get_basename() + ".gd"; + } + + if (FileAccess::exists(script)) { + Ref<Script> scr; + if (ScriptCodeCompletionCache::get_singleton()) { + scr = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(script); + } else { + scr = ResourceLoader::load(script); + } + if (scr.is_valid()) { + r_type.type.has_type = true; + r_type.type.script_type = scr; + r_type.type.is_constant = false; + Ref<GDScript> gds = scr; + if (gds.is_valid()) { + r_type.type.kind = GDScriptParser::DataType::GDSCRIPT; + } else { + r_type.type.kind = GDScriptParser::DataType::SCRIPT; + } + r_type.value = Variant(); + found = true; + } + } + break; + } + } + } + } + } } - Variant::CallError ce; - Variant ret = mb->call(baseptr, (const Variant **)argptr.ptr(), argptr.size(), ce); - - if (ce.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) { + if (!found && all_is_const && baseptr) { + Vector<const Variant *> argptr; + for (int i = 0; i < args.size(); i++) { + argptr.push_back(&args[i]); + } - if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != NULL) { + Variant::CallError ce; + Variant ret = mb->call(baseptr, (const Variant **)argptr.ptr(), argptr.size(), ce); - r_type = _get_type_from_variant(ret); - return true; + if (ce.error == Variant::CallError::CALL_OK && ret.get_type() != Variant::NIL) { + if (ret.get_type() != Variant::OBJECT || ret.operator Object *() != NULL) { + r_type = _type_from_variant(ret); + found = true; + } } } } } } - r_type.type = pi.type; - if (pi.hint == PROPERTY_HINT_RESOURCE_TYPE) { - r_type.obj_type = pi.hint_string; + if (!found) { + found = _guess_method_return_type_from_base(c, base, id, r_type); } - - return true; -#else - return false; -#endif - } else { - return false; } - } else { - //method for some variant.. - Variant::CallError ce; - Variant v = Variant::construct(base.type, NULL, 0, ce); - List<MethodInfo> mi; - v.get_method_list(&mi); - for (List<MethodInfo>::Element *E = mi.front(); E; E = E->next()) { - - if (!E->get().name.begins_with("_") && E->get().name == id.operator String()) { - - MethodInfo mi = E->get(); - r_type.type = mi.return_val.type; - if (mi.return_val.hint == PROPERTY_HINT_RESOURCE_TYPE) { - r_type.obj_type = mi.return_val.hint_string; - } - return true; - } + } break; + case GDScriptParser::OperatorNode::OP_PARENT_CALL: { + if (!p_context._class || !op->arguments.size() || op->arguments[0]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { + break; } - } - } - } else if (op->op == GDScriptParser::OperatorNode::OP_INDEX || op->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED) { - GDScriptCompletionIdentifier p1; - GDScriptCompletionIdentifier p2; + StringName id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name; - if (op->op == GDScriptParser::OperatorNode::OP_INDEX_NAMED) { + GDScriptCompletionIdentifier base; + base.value = p_context.base; + base.type = p_context._class->base_type; - if (op->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - String id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1])->name; - p2.type = Variant::STRING; - p2.value = id; - } + GDScriptCompletionContext c = p_context; + c.line = op->line; - } else { - if (op->arguments[1]) { - if (!_guess_expression_type(context, op->arguments[1], p_line, p2)) { - - return false; + found = _guess_method_return_type_from_base(c, base, id, r_type); + } break; + case GDScriptParser::OperatorNode::OP_INDEX_NAMED: { + if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { + found = false; + break; } - } - } - - if (op->arguments[0]->type == GDScriptParser::Node::TYPE_ARRAY) { - - const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(op->arguments[0]); - if (p2.value.is_num()) { - int index = p2.value; - if (index < 0 || index >= an->elements.size()) - return false; - return _guess_expression_type(context, an->elements[index], p_line, r_type); - } - - } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) { - - const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]); + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]); - if (p2.value.get_type() == Variant::NIL) - return false; - - for (int i = 0; i < dn->elements.size(); i++) { - - GDScriptCompletionIdentifier k; + GDScriptCompletionContext c = p_context; + c.line = op->line; - if (!_guess_expression_type(context, dn->elements[i].key, p_line, k)) { - - return false; + GDScriptCompletionIdentifier base; + if (!_guess_expression_type(c, op->arguments[0], base)) { + found = false; + break; } - if (k.value.get_type() == Variant::NIL) - return false; + if (base.value.get_type() == Variant::DICTIONARY && base.value.operator Dictionary().has(String(id->name))) { + Variant value = base.value.operator Dictionary()[String(id->name)]; + r_type = _type_from_variant(value); + found = true; + break; + } - if (k.value == p2.value) { + const GDScriptParser::DictionaryNode *dn = NULL; + if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) { + dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]); + } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) { + dn = static_cast<const GDScriptParser::DictionaryNode *>(base.assigned_expression); + } - return _guess_expression_type(context, dn->elements[i].value, p_line, r_type); + if (dn) { + for (int i = 0; i < dn->elements.size(); i++) { + GDScriptCompletionIdentifier key; + if (!_guess_expression_type(c, dn->elements[i].key, key)) { + continue; + } + if (key.value == String(id->name)) { + r_type.assigned_expression = dn->elements[i].value; + found = _guess_expression_type(c, dn->elements[i].value, r_type); + break; + } + } } - } - } else { + if (!found) { + found = _guess_identifier_type_from_base(c, base, id->name, r_type); + } + } break; + case GDScriptParser::OperatorNode::OP_INDEX: { + if (op->arguments.size() < 2) { + found = false; + break; + } - if (op->arguments[0]) { - if (!_guess_expression_type(context, op->arguments[0], p_line, p1)) { + GDScriptCompletionContext c = p_context; + c.line = op->line; - return false; + GDScriptCompletionIdentifier base; + if (!_guess_expression_type(c, op->arguments[0], base)) { + found = false; + break; } - } - if (p1.value.get_type() == Variant::OBJECT) { - //?? - - if (p1.obj_type != StringName() && p2.type == Variant::STRING) { + GDScriptCompletionIdentifier index; + if (!_guess_expression_type(c, op->arguments[1], index)) { + found = false; + break; + } - StringName base_type = p1.obj_type; + if (base.value.in(index.value)) { + Variant value = base.value.get(index.value); + r_type = _type_from_variant(value); + found = true; + break; + } - if (p1.obj_type == "GDScriptNativeClass") { - //native enum - Ref<GDScriptNativeClass> gdn = p1.value; - if (gdn.is_valid()) { + // Look if it is a dictionary node + const GDScriptParser::DictionaryNode *dn = NULL; + if (op->arguments[0]->type == GDScriptParser::Node::TYPE_DICTIONARY) { + dn = static_cast<const GDScriptParser::DictionaryNode *>(op->arguments[0]); + } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_DICTIONARY) { + dn = static_cast<const GDScriptParser::DictionaryNode *>(base.assigned_expression); + } - base_type = gdn->get_name(); + if (dn) { + for (int i = 0; i < dn->elements.size(); i++) { + GDScriptCompletionIdentifier key; + if (!_guess_expression_type(c, dn->elements[i].key, key)) { + continue; } - } - StringName index = p2.value; - bool valid; - Variant::Type t = ClassDB::get_property_type(base_type, index, &valid); - if (t != Variant::NIL && valid) { - r_type.type = t; - if (t == Variant::INT || t == Variant::OBJECT) { -//check for enum! -#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) - - StringName getter = ClassDB::get_property_getter(base_type, index); - if (getter != StringName()) { - MethodBind *mb = ClassDB::get_method(base_type, getter); - if (mb) { - PropertyInfo rt = mb->get_return_info(); - if ((rt.usage & PROPERTY_USAGE_CLASS_IS_ENUM) && t == Variant::INT) { - r_type.enumeration = rt.class_name; - } else if (t == Variant::OBJECT) { - - r_type.obj_type = rt.class_name; - } - } - } -#endif + if (key.value == index.value) { + r_type.assigned_expression = dn->elements[i].value; + found = _guess_expression_type(p_context, dn->elements[i].value, r_type); + break; } - - return true; } } - } else if (p1.value.get_type() != Variant::NIL) { - bool valid; - Variant ret = p1.value.get(p2.value, &valid); - if (valid) { - r_type = _get_type_from_variant(ret); - return true; + // Look if it is an array node + if (!found && index.value.is_num()) { + int idx = index.value; + const GDScriptParser::ArrayNode *an = NULL; + if (op->arguments[0]->type == GDScriptParser::Node::TYPE_ARRAY) { + an = static_cast<const GDScriptParser::ArrayNode *>(op->arguments[0]); + } else if (base.assigned_expression && base.assigned_expression->type == GDScriptParser::Node::TYPE_ARRAY) { + an = static_cast<const GDScriptParser::ArrayNode *>(base.assigned_expression); + } + + if (an && idx >= 0 && an->elements.size() > idx) { + r_type.assigned_expression = an->elements[idx]; + found = _guess_expression_type(c, an->elements[idx], r_type); + break; + } } - } else { - if (p1.type != Variant::NIL) { - Variant::CallError ce; - Variant base = Variant::construct(p1.type, NULL, 0, ce); - bool valid; - Variant ret = base.get(p2.value, &valid); + // Look for valid indexing in other types + if (!found && (index.value.get_type() == Variant::STRING || index.value.get_type() == Variant::NODE_PATH)) { + StringName id = index.value; + found = _guess_identifier_type_from_base(c, base, id, r_type); + } else if (!found && index.type.kind == GDScriptParser::DataType::BUILTIN) { + Variant::CallError err; + Variant base_val = Variant::construct(base.type.builtin_type, NULL, 0, err); + bool valid = false; + Variant res = base_val.get(index.value, &valid); if (valid) { - r_type = _get_type_from_variant(ret); - return true; + r_type = _type_from_variant(res); + r_type.value = Variant(); + r_type.type.is_constant = false; + found = true; } } - } - } + } break; + default: { + if (op->arguments.size() < 2) { + found = false; + break; + } - } else { + Variant::Operator vop = Variant::OP_MAX; + switch (op->op) { + case GDScriptParser::OperatorNode::OP_ADD: vop = Variant::OP_ADD; break; + case GDScriptParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBTRACT; break; + case GDScriptParser::OperatorNode::OP_MUL: vop = Variant::OP_MULTIPLY; break; + case GDScriptParser::OperatorNode::OP_DIV: vop = Variant::OP_DIVIDE; break; + case GDScriptParser::OperatorNode::OP_MOD: vop = Variant::OP_MODULE; break; + case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: vop = Variant::OP_SHIFT_LEFT; break; + case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: vop = Variant::OP_SHIFT_RIGHT; break; + case GDScriptParser::OperatorNode::OP_BIT_AND: vop = Variant::OP_BIT_AND; break; + case GDScriptParser::OperatorNode::OP_BIT_OR: vop = Variant::OP_BIT_OR; break; + case GDScriptParser::OperatorNode::OP_BIT_XOR: vop = Variant::OP_BIT_XOR; break; + default: {} + } - Variant::Operator vop = Variant::OP_MAX; - switch (op->op) { - case GDScriptParser::OperatorNode::OP_ADD: vop = Variant::OP_ADD; break; - case GDScriptParser::OperatorNode::OP_SUB: vop = Variant::OP_SUBTRACT; break; - case GDScriptParser::OperatorNode::OP_MUL: vop = Variant::OP_MULTIPLY; break; - case GDScriptParser::OperatorNode::OP_DIV: vop = Variant::OP_DIVIDE; break; - case GDScriptParser::OperatorNode::OP_MOD: vop = Variant::OP_MODULE; break; - case GDScriptParser::OperatorNode::OP_SHIFT_LEFT: vop = Variant::OP_SHIFT_LEFT; break; - case GDScriptParser::OperatorNode::OP_SHIFT_RIGHT: vop = Variant::OP_SHIFT_RIGHT; break; - case GDScriptParser::OperatorNode::OP_BIT_AND: vop = Variant::OP_BIT_AND; break; - case GDScriptParser::OperatorNode::OP_BIT_OR: vop = Variant::OP_BIT_OR; break; - case GDScriptParser::OperatorNode::OP_BIT_XOR: vop = Variant::OP_BIT_XOR; break; - default: {} - } - - if (vop == Variant::OP_MAX) - return false; + if (vop == Variant::OP_MAX) { + break; + } - GDScriptCompletionIdentifier p1; - GDScriptCompletionIdentifier p2; + GDScriptCompletionContext context = p_context; + context.line = op->line; - if (op->arguments[0]) { - if (!_guess_expression_type(context, op->arguments[0], p_line, p1)) { + GDScriptCompletionIdentifier p1; + GDScriptCompletionIdentifier p2; - return false; - } - } + if (!_guess_expression_type(context, op->arguments[0], p1)) { + found = false; + break; + } - if (op->arguments.size() > 1) { - if (!_guess_expression_type(context, op->arguments[1], p_line, p2)) { + if (!_guess_expression_type(context, op->arguments[1], p2)) { + found = false; + break; + } - return false; - } - } + Variant::CallError ce; + bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT; + Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type.builtin_type, NULL, 0, ce); + bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT; + Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type.builtin_type, NULL, 0, ce); + // avoid potential invalid ops + if ((vop == Variant::OP_DIVIDE || vop == Variant::OP_MODULE) && v2.get_type() == Variant::INT) { + v2 = 1; + v2_use_value = false; + } + if (vop == Variant::OP_DIVIDE && v2.get_type() == Variant::REAL) { + v2 = 1.0; + v2_use_value = false; + } - Variant::CallError ce; - bool v1_use_value = p1.value.get_type() != Variant::NIL && p1.value.get_type() != Variant::OBJECT; - Variant v1 = (v1_use_value) ? p1.value : Variant::construct(p1.type, NULL, 0, ce); - bool v2_use_value = p2.value.get_type() != Variant::NIL && p2.value.get_type() != Variant::OBJECT; - Variant v2 = (v2_use_value) ? p2.value : Variant::construct(p2.type, NULL, 0, ce); - // avoid potential invalid ops - if ((vop == Variant::OP_DIVIDE || vop == Variant::OP_MODULE) && v2.get_type() == Variant::INT) { - v2 = 1; - v2_use_value = false; - } - if (vop == Variant::OP_DIVIDE && v2.get_type() == Variant::REAL) { - v2 = 1.0; - v2_use_value = false; + Variant res; + bool valid; + Variant::evaluate(vop, v1, v2, res, valid); + if (!valid) { + found = false; + break; + } + r_type = _type_from_variant(res); + if (!v1_use_value || !v2_use_value) { + r_type.value = Variant(); + r_type.type.is_constant = false; + } + + found = true; + } break; } + } break; + } - Variant r; - bool valid; - Variant::evaluate(vop, v1, v2, r, valid); - if (!valid) - return false; - r_type.type = r.get_type(); - if (v1_use_value && v2_use_value) - r_type.value = r; + // It may have found a null, but that's never useful + if (found && r_type.type.has_type && r_type.type.kind == GDScriptParser::DataType::BUILTIN && r_type.type.builtin_type == Variant::NIL) { + found = false; + } - return true; + // Check type hint last. For collections we want chance to get the actual value first + // This way we can detect types from the content of dictionaries and arrays + if (!found && p_expression->get_datatype().has_type) { + r_type.type = p_expression->get_datatype(); + if (!r_type.assigned_expression) { + r_type.assigned_expression = p_expression; } + found = true; } - return false; + return found; } -static bool _guess_identifier_type_in_block(GDScriptCompletionContext &context, int p_line, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { +static bool _guess_identifier_type(const GDScriptCompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { - if (context.block->if_condition && context.block->if_condition->type == GDScriptParser::Node::TYPE_OPERATOR && static_cast<const GDScriptParser::OperatorNode *>(context.block->if_condition)->op == GDScriptParser::OperatorNode::OP_IS) { - //is used, check if identifier is in there! this helps resolve in blocks that are (if (identifier is value)): which are very common.. - //super dirty hack, but very useful - //credit: Zylann - //TODO: this could be hacked to detect ANDed conditions too.. - const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(context.block->if_condition); - if (op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name == p_identifier) { - //bingo - if (_guess_expression_type(context, op->arguments[1], op->line, r_type)) { - return true; + // Look in blocks first + const GDScriptParser::BlockNode *blk = p_context.block; + int last_assign_line = -1; + const GDScriptParser::Node *last_assigned_expression = NULL; + GDScriptParser::DataType var_type; + while (blk) { + if (blk->variables.has(p_identifier)) { + if (blk->variables[p_identifier]->line > p_context.line) { + return false; } - } - } - GDScriptCompletionIdentifier gdi = _get_native_class(context); - if (gdi.obj_type != StringName()) { - bool valid; - Variant::Type t = ClassDB::get_property_type(gdi.obj_type, p_identifier, &valid); - if (t != Variant::NIL && valid) { - r_type.type = t; - if (t == Variant::INT) { -//check for enum! -#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) + var_type = blk->variables[p_identifier]->datatype; - StringName getter = ClassDB::get_property_getter(gdi.obj_type, p_identifier); - if (getter != StringName()) { - MethodBind *mb = ClassDB::get_method(gdi.obj_type, getter); - if (mb) { - PropertyInfo rt = mb->get_return_info(); - if (rt.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { - r_type.enumeration = rt.class_name; - } - } + if (!last_assigned_expression && blk->variables[p_identifier]->assign && blk->variables[p_identifier]->assign->type == GDScriptParser::Node::TYPE_OPERATOR) { + const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(blk->variables[p_identifier]->assign); + if (op->op == GDScriptParser::OperatorNode::OP_ASSIGN && op->arguments.size() >= 2) { + last_assign_line = op->line; + last_assigned_expression = op->arguments[1]; } -#endif } - return true; } - } - - const GDScriptParser::Node *last_assign = NULL; - int last_assign_line = -1; - - for (int i = 0; i < context.block->statements.size(); i++) { - - if (context.block->statements[i]->line > p_line) - continue; - - if (context.block->statements[i]->type == GDScriptParser::BlockNode::TYPE_LOCAL_VAR) { - const GDScriptParser::LocalVarNode *lv = static_cast<const GDScriptParser::LocalVarNode *>(context.block->statements[i]); + for (const List<GDScriptParser::Node *>::Element *E = blk->statements.front(); E; E = E->next()) { + const GDScriptParser::Node *expr = E->get(); + if (expr->line > p_context.line || expr->type != GDScriptParser::Node::TYPE_OPERATOR) { + continue; + } - if (lv->assign && lv->name == p_identifier) { + const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(expr); + if (op->op != GDScriptParser::OperatorNode::OP_ASSIGN || op->line < last_assign_line) { + continue; + } - last_assign = lv->assign; - last_assign_line = context.block->statements[i]->line; + if (op->arguments.size() >= 2 && op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0]); + if (id->name == p_identifier) { + last_assign_line = op->line; + last_assigned_expression = op->arguments[1]; + } } } - if (context.block->statements[i]->type == GDScriptParser::BlockNode::TYPE_OPERATOR) { - const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(context.block->statements[i]); - if (op->op == GDScriptParser::OperatorNode::OP_ASSIGN) { - - if (op->arguments.size() && op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - - const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0]); - - if (id->name == p_identifier) { - - last_assign = op->arguments[1]; - last_assign_line = context.block->statements[i]->line; - } + if (blk->if_condition && blk->if_condition->type == GDScriptParser::Node::TYPE_OPERATOR && static_cast<const GDScriptParser::OperatorNode *>(blk->if_condition)->op == GDScriptParser::OperatorNode::OP_IS) { + //is used, check if identifier is in there! this helps resolve in blocks that are (if (identifier is value)): which are very common.. + //super dirty hack, but very useful + //credit: Zylann + //TODO: this could be hacked to detect ANDed conditions too.. + const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(blk->if_condition); + if (op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name == p_identifier) { + //bingo + GDScriptCompletionContext c = p_context; + c.line = op->line; + c.block = blk; + if (_guess_expression_type(p_context, op->arguments[1], r_type)) { + return true; } } } - } - - //use the last assignment, (then backwards?) - if (last_assign && last_assign_line != p_line) { - return _guess_expression_type(context, last_assign, last_assign_line, r_type); + blk = blk->parent_block; } - return false; -} - -static bool _guess_identifier_from_assignment_in_function(GDScriptCompletionContext &context, int p_src_line, const StringName &p_identifier, const StringName &p_function, GDScriptCompletionIdentifier &r_type) { - - const GDScriptParser::FunctionNode *func = NULL; - for (int i = 0; i < context._class->functions.size(); i++) { - if (context._class->functions[i]->name == p_function) { - func = context._class->functions[i]; - break; + if (last_assigned_expression && last_assign_line != p_context.line) { + GDScriptCompletionContext c = p_context; + c.line = last_assign_line; + r_type.assigned_expression = last_assigned_expression; + if (_guess_expression_type(c, last_assigned_expression, r_type)) { + return true; } } - if (!func) - return false; + if (var_type.has_type) { + r_type.type = var_type; + return true; + } - for (int i = 0; i < func->body->statements.size(); i++) { + if (p_context.function) { + for (int i = 0; i < p_context.function->arguments.size(); i++) { + if (p_context.function->arguments[i] == p_identifier) { + if (p_context.function->argument_types[i].has_type) { + r_type.type = p_context.function->argument_types[i]; + return true; + } - if (func->body->statements[i]->line == p_src_line) { - break; + int def_from = p_context.function->arguments.size() - p_context.function->default_values.size(); + if (i >= def_from) { + int def_idx = def_from - i; + if (p_context.function->default_values[def_idx]->type == GDScriptParser::Node::TYPE_OPERATOR) { + const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_context.function->default_values[def_idx]); + if (op->arguments.size() < 2) { + return false; + } + GDScriptCompletionContext c = p_context; + c.function = NULL; + c.block = NULL; + return _guess_expression_type(c, op->arguments[1], r_type); + } + } + break; + } } - if (func->body->statements[i]->type == GDScriptParser::BlockNode::TYPE_OPERATOR) { - const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(func->body->statements[i]); - if (op->op == GDScriptParser::OperatorNode::OP_ASSIGN) { - - if (op->arguments.size() && op->arguments[0]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - - const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0]); - - if (id->name == p_identifier) { - - return _guess_expression_type(context, op->arguments[1], func->body->statements[i]->line, r_type); + GDScriptParser::DataType base_type = p_context._class->base_type; + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> gds = base_type.script_type; + if (gds.is_valid() && gds->has_method(p_context.function->name)) { + GDScriptFunction *func = gds->get_member_functions()[p_context.function->name]; + if (func) { + for (int i = 0; i < func->get_argument_count(); i++) { + if (func->get_argument_name(i) == p_identifier) { + r_type = _type_from_gdtype(func->get_argument_type(i)); + return true; + } + } + } + Ref<GDScript> base_gds = gds->get_base_script(); + if (base_gds.is_valid()) { + base_type.kind = GDScriptParser::DataType::GDSCRIPT; + base_type.script_type = base_gds; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); + } + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); } - } + } break; + case GDScriptParser::DataType::NATIVE: { + List<MethodInfo> methods; + ClassDB::get_method_list(base_type.native_type, &methods); + ClassDB::get_virtual_methods(base_type.native_type, &methods); + + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name == p_context.function->name) { + MethodInfo &mi = E->get(); + for (List<PropertyInfo>::Element *E = mi.arguments.front(); E; E = E->next()) { + if (E->get().name == p_identifier) { + r_type = _type_from_property(E->get()); + return true; + } + } + } + } + base_type.has_type = false; + } break; + default: { + base_type.has_type = false; + } break; } } } - return false; -} - -static bool _guess_identifier_type(GDScriptCompletionContext &context, int p_line, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type, bool p_for_indexing) { - - //go to block first + // Check current class (including inheritance) + if (p_context._class) { + GDScriptCompletionIdentifier context_base; + context_base.value = p_context.base; + context_base.type.has_type = true; + context_base.type.kind = GDScriptParser::DataType::CLASS; + context_base.type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class); + context_base.type.is_meta_type = p_context.function && p_context.function->_static; - const GDScriptParser::BlockNode *block = context.block; - - while (block) { - - GDScriptCompletionContext c = context; - c.block = block; - - if (_guess_identifier_type_in_block(c, p_line, p_identifier, r_type)) { + if (_guess_identifier_type_from_base(p_context, context_base, p_identifier, r_type)) { return true; } - - block = block->parent_block; } - //guess from argument if virtual - if (context.function && context.function->name != StringName()) { - - int argindex = -1; + // Check named scripts + if (ScriptServer::is_global_class(p_identifier)) { + Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_identifier)); + if (scr.is_valid()) { + r_type = _type_from_variant(scr); + r_type.type.is_meta_type = true; + return true; + } + return false; + } - for (int i = 0; i < context.function->arguments.size(); i++) { + // Check ClassDB + if (ClassDB::class_exists(p_identifier)) { + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::NATIVE; + r_type.type.native_type = p_identifier; + if (Engine::get_singleton()->has_singleton(p_identifier)) { + r_type.type.is_meta_type = false; + r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier); + } else { + r_type.type.is_meta_type = true; + int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier]; + r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx]; + } + return true; + } - if (context.function->arguments[i] == p_identifier) { - argindex = i; - break; - } + // ClassDB again for underscore-prefixed classes + StringName under_id = String("_") + p_identifier; + if (ClassDB::class_exists(under_id)) { + r_type.type.has_type = true; + r_type.type.kind = GDScriptParser::DataType::NATIVE; + r_type.type.native_type = p_identifier; + if (Engine::get_singleton()->has_singleton(p_identifier)) { + r_type.type.is_meta_type = false; + r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier); + } else { + r_type.type.is_meta_type = true; + int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier]; + r_type.value = GDScriptLanguage::get_singleton()->get_global_array()[idx]; } + return true; + } - if (argindex != -1) { - GDScriptCompletionIdentifier id = _get_native_class(context); - if (id.type == Variant::OBJECT && id.obj_type != StringName()) { - //this kinda sucks but meh + // Check autoload singletons + if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(p_identifier)) { + r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[p_identifier]); + return true; + } - List<MethodInfo> vmethods; - ClassDB::get_virtual_methods(id.obj_type, &vmethods); - for (List<MethodInfo>::Element *E = vmethods.front(); E; E = E->next()) { + return false; +} - if (E->get().name == context.function->name && argindex < E->get().arguments.size()) { +static bool _guess_identifier_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { + GDScriptParser::DataType base_type = p_base.type; + bool _static = base_type.is_meta_type; + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + if (base_type.class_type->constant_expressions.has(p_identifier)) { + GDScriptParser::ClassNode::Constant c = base_type.class_type->constant_expressions[p_identifier]; + r_type.type = c.type; + if (c.expression->type == GDScriptParser::Node::TYPE_CONSTANT) { + r_type.value = static_cast<const GDScriptParser::ConstantNode *>(c.expression)->value; + } + return true; + } - PropertyInfo arg = E->get().arguments[argindex]; + if (!_static) { + for (int i = 0; i < base_type.class_type->variables.size(); i++) { + GDScriptParser::ClassNode::Member m = base_type.class_type->variables[i]; + if (m.identifier == p_identifier) { + if (m.data_type.has_type) { + r_type.type = m.data_type; + return true; + } + if (m.expression) { + if (_guess_expression_type(p_context, m.expression, r_type)) { + return true; + } + if (m.expression->get_datatype().has_type) { + r_type.type = m.expression->get_datatype(); + return true; + } + } + return false; + } + } + } + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> gds = base_type.script_type; + if (gds.is_valid()) { + if (gds->get_constants().has(p_identifier)) { + r_type = _type_from_variant(gds->get_constants()[p_identifier]); + return true; + } + if (!_static) { + const Set<StringName>::Element *m = gds->get_members().find(p_identifier); + if (m) { + r_type = _type_from_gdtype(gds->get_member_type(p_identifier)); + return true; + } + } + Ref<GDScript> parent = gds->get_base_script(); + if (parent.is_valid()) { + base_type.script_type = parent; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); + } + } else { + return false; + } + } break; + case GDScriptParser::DataType::SCRIPT: { + Ref<Script> scr = base_type.script_type; + if (scr.is_valid()) { + Map<StringName, Variant> constants; + scr->get_constants(&constants); + if (constants.has(p_identifier)) { + r_type = _type_from_variant(constants[p_identifier]); + return true; + } - int scp = String(arg.name).find(":"); - if (scp != -1) { + if (!_static) { + List<PropertyInfo> members; + scr->get_script_property_list(&members); + for (const List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { + const PropertyInfo &prop = E->get(); + if (prop.name == p_identifier) { + r_type = _type_from_property(prop); + return true; + } + } + } + Ref<Script> parent = scr->get_base_script(); + if (parent.is_valid()) { + base_type.script_type = parent; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = scr->get_instance_base_type(); + } + } else { + return false; + } + } break; + case GDScriptParser::DataType::NATIVE: { + StringName class_name = base_type.native_type; + if (!ClassDB::class_exists(class_name)) { + class_name = String("_") + class_name; + if (!ClassDB::class_exists(class_name)) { + return false; + } + } - r_type.type = Variant::OBJECT; - r_type.obj_type = String(arg.name).substr(scp + 1, String(arg.name).length()); - return true; + // Skip constants since they're all integers. Type does not matter because int has no members + List<PropertyInfo> props; + ClassDB::get_property_list(class_name, &props); + for (const List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + const PropertyInfo &prop = E->get(); + if (prop.name == p_identifier) { + StringName getter = ClassDB::get_property_getter(class_name, p_identifier); + if (getter != StringName()) { + MethodBind *g = ClassDB::get_method(class_name, getter); + if (g) { + r_type = _type_from_property(g->get_return_info()); + return true; + } } else { - - r_type.type = arg.type; - if (arg.hint == PROPERTY_HINT_RESOURCE_TYPE) - r_type.obj_type = arg.hint_string; + r_type = _type_from_property(prop); return true; } + break; } } - } + return false; + } break; + case GDScriptParser::DataType::BUILTIN: { + Variant::CallError err; + Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + + if (err.error != Variant::CallError::CALL_OK) { + return false; + } + bool valid = false; + Variant res = tmp.get(p_identifier, &valid); + if (valid) { + r_type = _type_from_variant(res); + r_type.value = Variant(); + r_type.type.is_constant = false; + return true; + } + return false; + } break; + default: { + return false; + } break; } } - //guess type in constant + return false; +} - for (int i = 0; i < context._class->constant_expressions.size(); i++) { +static bool _find_last_return_in_block(const GDScriptCompletionContext &p_context, int &r_last_return_line, const GDScriptParser::Node **r_last_returned_value) { + if (!p_context.block) { + return false; + } - if (context._class->constant_expressions[i].identifier == p_identifier) { + for (int i = 0; i < p_context.block->statements.size(); i++) { + if (p_context.block->statements[i]->line < r_last_return_line) { + continue; + } + if (p_context.block->statements[i]->type != GDScriptParser::Node::TYPE_CONTROL_FLOW) { + continue; + } - ERR_FAIL_COND_V(context._class->constant_expressions[i].expression->type != GDScriptParser::Node::TYPE_CONSTANT, false); - r_type = _get_type_from_variant(static_cast<const GDScriptParser::ConstantNode *>(context._class->constant_expressions[i].expression)->value); - return true; + const GDScriptParser::ControlFlowNode *cf = static_cast<const GDScriptParser::ControlFlowNode *>(p_context.block->statements[i]); + if (cf->cf_type == GDScriptParser::ControlFlowNode::CF_RETURN && cf->arguments.size() > 0) { + if (cf->line > r_last_return_line) { + r_last_return_line = cf->line; + *r_last_returned_value = cf->arguments[0]; + } } } - if (!(context.function && context.function->_static)) { + // Recurse into subblocks + for (int i = 0; i < p_context.block->sub_blocks.size(); i++) { + GDScriptCompletionContext c = p_context; + c.block = p_context.block->sub_blocks[i]; + _find_last_return_in_block(c, r_last_return_line, r_last_returned_value); + } - for (int i = 0; i < context._class->variables.size(); i++) { + return false; +} - if (context._class->variables[i].identifier == p_identifier) { +static bool _guess_method_return_type_from_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type) { + GDScriptParser::DataType base_type = p_base.type; + bool _static = base_type.is_meta_type; - if (context._class->variables[i]._export.type != Variant::NIL) { + if (_static && p_method == "new") { + r_type.type = base_type; + r_type.type.is_meta_type = false; + r_type.type.is_constant = false; + return true; + } - r_type = _get_type_from_pinfo(context._class->variables[i]._export); - return true; - } else if (context._class->variables[i].expression) { - if (p_line <= context._class->variables[i].line) - return false; + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + if (!base_type.class_type) { + base_type.has_type = false; + break; + } - bool rtype = _guess_expression_type(context, context._class->variables[i].expression, context._class->variables[i].line, r_type); - if (rtype && r_type.type != Variant::NIL) - return true; - //return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type); + for (int i = 0; i < base_type.class_type->static_functions.size(); i++) { + if (base_type.class_type->static_functions[i]->name == p_method) { + int last_return_line = -1; + const GDScriptParser::Node *last_returned_value = NULL; + GDScriptCompletionContext c = p_context; + c._class = base_type.class_type; + c.function = base_type.class_type->static_functions[i]; + c.block = c.function->body; + + _find_last_return_in_block(c, last_return_line, &last_returned_value); + if (last_returned_value) { + c.line = c.block->end_line; + return _guess_expression_type(c, last_returned_value, r_type); + } + } + } + if (!_static) { + for (int i = 0; i < base_type.class_type->functions.size(); i++) { + if (base_type.class_type->functions[i]->name == p_method) { + int last_return_line = -1; + const GDScriptParser::Node *last_returned_value = NULL; + GDScriptCompletionContext c = p_context; + c._class = base_type.class_type; + c.function = base_type.class_type->functions[i]; + c.block = c.function->body; + + _find_last_return_in_block(c, last_return_line, &last_returned_value); + if (last_returned_value) { + c.line = c.block->end_line; + return _guess_expression_type(c, last_returned_value, r_type); + } + } + } } - //try to guess from assignment in constructor or _ready - if (_guess_identifier_from_assignment_in_function(context, p_line + 1, p_identifier, "_ready", r_type)) - return true; - if (_guess_identifier_from_assignment_in_function(context, p_line + 1, p_identifier, "_enter_tree", r_type)) - return true; - if (_guess_identifier_from_assignment_in_function(context, p_line + 1, p_identifier, "_init", r_type)) + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> gds = base_type.script_type; + if (gds.is_valid()) { + if (gds->get_member_functions().has(p_method)) { + r_type = _type_from_gdtype(gds->get_member_functions()[p_method]->get_return_type()); + return true; + } + Ref<GDScript> base_script = gds->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); + } + } else { + return false; + } + } break; + case GDScriptParser::DataType::SCRIPT: { + Ref<Script> scr = base_type.script_type; + if (scr.is_valid()) { + List<MethodInfo> methods; + scr->get_script_method_list(&methods); + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + MethodInfo &mi = E->get(); + if (mi.name == p_method) { + r_type = _type_from_property(mi.return_val); + return true; + } + } + Ref<Script> base_script = scr->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = scr->get_instance_base_type(); + } + } else { + return false; + } + } break; + case GDScriptParser::DataType::NATIVE: { + StringName native = base_type.native_type; + if (!ClassDB::class_exists(native)) { + native = String("_") + native; + if (!ClassDB::class_exists(native)) { + return false; + } + } + MethodBind *mb = ClassDB::get_method(native, p_method); + if (mb) { + r_type = _type_from_property(mb->get_return_info()); return true; + } + return false; + } break; + case GDScriptParser::DataType::BUILTIN: { + Variant::CallError err; + Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK) { + return false; + } + + List<MethodInfo> methods; + tmp.get_method_list(&methods); + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + MethodInfo &mi = E->get(); + if (mi.name == p_method) { + r_type = _type_from_property(mi.return_val); + return true; + } + } + return false; + } break; + default: { return false; } } } + return false; +} - //autoloads as singletons - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); - - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - - String s = E->get().name; - if (!s.begins_with("autoload/")) - continue; - String name = s.get_slice("/", 1); - if (name == String(p_identifier)) { +static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx) { - String path = ProjectSettings::get_singleton()->get(s); - if (path.begins_with("*")) { - String script = path.substr(1, path.length()); + String arghint = _get_visual_datatype(p_info.return_val, false) + " " + p_info.name + "("; - if (!script.ends_with(".gd")) { - //not a script, try find the script anyway, - //may have some success - script = script.get_basename() + ".gd"; - } + int def_args = p_info.arguments.size() - p_info.default_arguments.size(); + int i = 0; + for (const List<PropertyInfo>::Element *E = p_info.arguments.front(); E; E = E->next()) { + if (i > 0) { + arghint += ", "; + } else { + arghint += " "; + } - if (FileAccess::exists(script)) { + if (i == p_arg_idx) { + arghint += String::chr(0xFFFF); + } + arghint += _get_visual_datatype(E->get(), true) + " " + E->get().name; - //print_line("is a script"); + if (i - def_args >= 0) { + arghint += String(" = ") + p_info.default_arguments[i - def_args].get_construct_string(); + } - Ref<Script> scr; - if (ScriptCodeCompletionCache::get_singleton()) - scr = ScriptCodeCompletionCache::get_singleton()->get_cached_resource(script); - else - scr = ResourceLoader::load(script); + if (i == p_arg_idx) { + arghint += String::chr(0xFFFF); + } - r_type.obj_type = "Node"; - r_type.type = Variant::OBJECT; - r_type.script = scr; - r_type.value = Variant(); + i++; + } - return true; - } - } + if (p_info.flags & METHOD_FLAG_VARARG) { + if (p_info.arguments.size() > 0) { + arghint += ", "; + } else { + arghint += " "; } + if (p_arg_idx >= p_info.arguments.size()) { + arghint += String::chr(0xFFFF); + } + arghint += "..."; + if (p_arg_idx >= p_info.arguments.size()) { + arghint += String::chr(0xFFFF); + } + } + if (p_info.arguments.size() > 0 || (p_info.flags & METHOD_FLAG_VARARG)) { + arghint += " "; } - //global - for (Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) { - if (E->key() == p_identifier) { + arghint += ")"; - r_type = _get_type_from_variant(GDScriptLanguage::get_singleton()->get_global_array()[E->get()], !p_for_indexing); - return true; - } - } - return false; + return arghint; } -static void _find_identifiers_in_block(GDScriptCompletionContext &context, int p_line, bool p_only_functions, Set<String> &result) { +static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx) { - if (p_only_functions) - return; + String arghint = p_function->return_type.to_string() + " " + p_function->name.operator String() + "("; - for (int i = 0; i < context.block->statements.size(); i++) { + int def_args = p_function->arguments.size() - p_function->default_values.size(); + for (int i = 0; i < p_function->arguments.size(); i++) { + if (i > 0) { + arghint += ", "; + } else { + arghint += " "; + } - GDScriptParser::Node *statement = context.block->statements[i]; - if (statement->line > p_line) - continue; + if (i == p_arg_idx) { + arghint += String::chr(0xFFFF); + } + arghint += p_function->argument_types[i].to_string() + " " + p_function->arguments[i].operator String(); + + if (i - def_args >= 0) { + String def_val = "<unknown>"; + if (p_function->default_values[i - def_args] && p_function->default_values[i - def_args]->type == GDScriptParser::Node::TYPE_OPERATOR) { + const GDScriptParser::OperatorNode *assign = static_cast<const GDScriptParser::OperatorNode *>(p_function->default_values[i - def_args]); + + if (assign->arguments.size() >= 2) { + if (assign->arguments[1]->type == GDScriptParser::Node::TYPE_CONSTANT) { + const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(assign->arguments[1]); + def_val = cn->value.get_construct_string(); + } else if (assign->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(assign->arguments[1]); + def_val = id->name.operator String(); + } + } + } + arghint += " = " + def_val; + } + if (i == p_arg_idx) { + arghint += String::chr(0xFFFF); + } + } - GDScriptParser::BlockNode::Type statementType = statement->type; - if (statementType == GDScriptParser::BlockNode::TYPE_LOCAL_VAR) { + if (p_function->arguments.size() > 0) { + arghint += " "; + } + arghint += ")"; - const GDScriptParser::LocalVarNode *lv = static_cast<const GDScriptParser::LocalVarNode *>(statement); - result.insert(lv->name.operator String()); - } else if (statementType == GDScriptParser::BlockNode::TYPE_CONTROL_FLOW) { + return arghint; +} - const GDScriptParser::ControlFlowNode *cf = static_cast<const GDScriptParser::ControlFlowNode *>(statement); - if (cf->cf_type == GDScriptParser::ControlFlowNode::CF_FOR) { +static void _find_enumeration_candidates(const String p_enum_hint, Set<String> &r_result) { - const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(cf->arguments[0]); - result.insert(id->name.operator String()); + if (p_enum_hint.find(".") == -1) { + // Global constant + StringName current_enum = p_enum_hint; + for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { + if (GlobalConstants::get_global_constant_enum(i) == current_enum) { + r_result.insert(GlobalConstants::get_global_constant_name(i)); } } - } -} - -static void _find_identifiers_in_class(GDScriptCompletionContext &context, bool p_static, bool p_only_functions, Set<String> &result) { + } else { + String class_name = p_enum_hint.get_slice(".", 0); + String enum_name = p_enum_hint.get_slice(".", 1); - if (!p_static && !p_only_functions) { + if (!ClassDB::class_exists(class_name)) { + return; + } - for (int i = 0; i < context._class->variables.size(); i++) { - result.insert(context._class->variables[i].identifier); + List<StringName> enum_constants; + ClassDB::get_enum_constants(class_name, enum_name, &enum_constants); + for (List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { + String candidate = class_name + "." + E->get(); + r_result.insert(candidate); } } - if (!p_only_functions) { +} - for (int i = 0; i < context._class->constant_expressions.size(); i++) { - result.insert(context._class->constant_expressions[i].identifier); +static void _find_identifiers_in_block(const GDScriptCompletionContext &p_context, Set<String> &r_result) { + for (Map<StringName, GDScriptParser::LocalVarNode *>::Element *E = p_context.block->variables.front(); E; E = E->next()) { + if (E->get()->line < p_context.line) { + r_result.insert(E->key().operator String()); } + } + if (p_context.block->parent_block) { + GDScriptCompletionContext c = p_context; + c.block = p_context.block->parent_block; + _find_identifiers_in_block(c, r_result); + } +} + +static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result); - for (int i = 0; i < context._class->subclasses.size(); i++) { - result.insert(context._class->subclasses[i]->name); +static void _find_identifiers_in_class(const GDScriptCompletionContext &p_context, bool p_static, bool p_only_functions, bool p_parent_only, Set<String> &r_result) { + if (!p_parent_only) { + if (!p_static && !p_only_functions) { + for (int i = 0; i < p_context._class->variables.size(); i++) { + r_result.insert(p_context._class->variables[i].identifier); + } } - } - for (int i = 0; i < context._class->static_functions.size(); i++) { - if (context._class->static_functions[i]->arguments.size()) - result.insert(context._class->static_functions[i]->name.operator String() + "("); - else - result.insert(context._class->static_functions[i]->name.operator String() + "()"); - } + if (!p_only_functions) { + for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = p_context._class->constant_expressions.front(); E; E = E->next()) { + r_result.insert(E->key()); + } + for (int i = 0; i < p_context._class->subclasses.size(); i++) { + r_result.insert(p_context._class->subclasses[i]->name); + } + } - if (!p_static) { + for (int i = 0; i < p_context._class->static_functions.size(); i++) { + if (p_context._class->static_functions[i]->arguments.size()) { + r_result.insert(p_context._class->static_functions[i]->name.operator String() + "("); + } else { + r_result.insert(p_context._class->static_functions[i]->name.operator String() + "()"); + } + } - for (int i = 0; i < context._class->functions.size(); i++) { - if (context._class->functions[i]->arguments.size()) - result.insert(context._class->functions[i]->name.operator String() + "("); - else - result.insert(context._class->functions[i]->name.operator String() + "()"); + if (!p_static) { + for (int i = 0; i < p_context._class->functions.size(); i++) { + if (p_context._class->functions[i]->arguments.size()) { + r_result.insert(p_context._class->functions[i]->name.operator String() + "("); + } else { + r_result.insert(p_context._class->functions[i]->name.operator String() + "()"); + } + } } } - //globals - - Ref<Reference> base = _get_parent_class(context); + // Parents + GDScriptCompletionIdentifier base_type; + base_type.type = p_context._class->base_type; + base_type.type.is_meta_type = p_static; + base_type.value = p_context.base; - while (true) { + GDScriptCompletionContext c = p_context; + c.block = NULL; + c.function = NULL; - Ref<GDScript> script = base; - Ref<GDScriptNativeClass> nc = base; - if (script.is_valid()) { + _find_identifiers_in_base(c, base_type, p_only_functions, r_result); +} - if (!p_static && !p_only_functions) { - for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) { - result.insert(E->get().operator String()); +static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Set<String> &r_result) { + GDScriptParser::DataType base_type = p_base.type; + bool _static = base_type.is_meta_type; + + if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { + r_result.insert("new("); + } + + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + GDScriptCompletionContext c = p_context; + c._class = base_type.class_type; + c.block = NULL; + c.function = NULL; + _find_identifiers_in_class(c, _static, p_only_functions, false, r_result); + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> script = base_type.script_type; + if (script.is_valid()) { + if (!_static && !p_only_functions) { + for (const Set<StringName>::Element *E = script->get_members().front(); E; E = E->next()) { + r_result.insert(E->get().operator String()); + } + } + if (!p_only_functions) { + for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) { + r_result.insert(E->key().operator String()); + } + } + for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) { + if (!_static || E->get()->is_static()) { + if (E->get()->get_argument_count()) { + r_result.insert(E->key().operator String() + "("); + } else { + r_result.insert(E->key().operator String() + "()"); + } + } + } + if (!p_only_functions) { + for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) { + r_result.insert(E->key().operator String()); + } + } + base_type = GDScriptParser::DataType(); + if (script->get_base().is_valid()) { + base_type.has_type = true; + base_type.kind = GDScriptParser::DataType::GDSCRIPT; + base_type.script_type = script->get_base(); + } else { + base_type.has_type = script->get_instance_base_type() != StringName(); + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.script_type = script->get_instance_base_type(); + } + } else { + return; } - } + } break; + case GDScriptParser::DataType::SCRIPT: { + Ref<Script> scr = base_type.script_type; + if (scr.is_valid()) { + if (!_static && !p_only_functions) { + List<PropertyInfo> members; + scr->get_script_property_list(&members); + for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { + r_result.insert(E->get().name); + } + } + if (!p_only_functions) { + Map<StringName, Variant> constants; + scr->get_constants(&constants); + for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { + r_result.insert(E->key().operator String()); + } + } - if (!p_only_functions) { - for (const Map<StringName, Variant>::Element *E = script->get_constants().front(); E; E = E->next()) { - result.insert(E->key().operator String()); - } - } + List<MethodInfo> methods; + scr->get_script_method_list(&methods); + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().arguments.size()) { + r_result.insert(E->get().name + "("); + } else { + r_result.insert(E->get().name + "()"); + } + } - for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) { - if (!p_static || E->get()->is_static()) { - if (E->get()->get_argument_count()) - result.insert(E->key().operator String() + "("); - else - result.insert(E->key().operator String() + "()"); + Ref<Script> base_script = scr->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = scr->get_instance_base_type(); + } + } else { + return; } - } - - if (!p_only_functions) { - for (const Map<StringName, Ref<GDScript> >::Element *E = script->get_subclasses().front(); E; E = E->next()) { - result.insert(E->key().operator String()); + } break; + case GDScriptParser::DataType::NATIVE: { + StringName type = base_type.native_type; + if (!ClassDB::class_exists(type)) { + type = String("_") + type; + if (!ClassDB::class_exists(type)) { + return; + } } - } - base = script->get_base(); - if (base.is_null()) - base = script->get_native(); - } else if (nc.is_valid()) { + if (!p_only_functions) { + List<String> constants; + ClassDB::get_integer_constant_list(type, &constants); + for (List<String>::Element *E = constants.front(); E; E = E->next()) { + r_result.insert(E->get()); + } - StringName type = nc->get_name(); + if (!_static) { + List<PropertyInfo> pinfo; + ClassDB::get_property_list(type, &pinfo); + for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { + if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) { + continue; + } + if (E->get().name.find("/") != -1) { + continue; + } + r_result.insert(E->get().name); + } + } + } - if (!p_only_functions) { + if (!_static) { + List<MethodInfo> methods; + ClassDB::get_method_list(type, &methods, false, true); + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name.begins_with("_")) { + continue; + } + if (E->get().arguments.size()) { + r_result.insert(E->get().name + "("); + } else { + r_result.insert(E->get().name + "()"); + } + } + } - List<String> constants; - ClassDB::get_integer_constant_list(type, &constants); - for (List<String>::Element *E = constants.front(); E; E = E->next()) { - result.insert(E->get()); + return; + } break; + case GDScriptParser::DataType::BUILTIN: { + Variant::CallError err; + Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK) { + return; } - List<PropertyInfo> pinfo; + if (!p_only_functions) { + List<PropertyInfo> members; + tmp.get_property_list(&members); - ClassDB::get_property_list(type, &pinfo); + for (List<PropertyInfo>::Element *E = members.front(); E; E = E->next()) { + if (String(E->get().name).find("/") == -1) { + r_result.insert(E->get().name); + } + } + } - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) - continue; - if (String(E->get().name).find("/") != -1) - continue; - result.insert(E->get().name); + List<MethodInfo> methods; + tmp.get_method_list(&methods); + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().arguments.size()) { + r_result.insert(E->get().name + "("); + } else { + r_result.insert(E->get().name + "()"); + } } - } - List<MethodInfo> methods; - ClassDB::get_method_list(type, &methods, false, true); - for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { - if (E->get().name.begins_with("_")) - continue; - if (E->get().arguments.size()) - result.insert(E->get().name + "("); - else - result.insert(E->get().name + "()"); - } - break; - } else - break; + return; + } break; + default: { + return; + } break; + } } } -static void _find_identifiers(GDScriptCompletionContext &context, int p_line, bool p_only_functions, Set<String> &result) { +static void _find_identifiers(const GDScriptCompletionContext &p_context, bool p_only_functions, Set<String> &r_result) { - const GDScriptParser::BlockNode *block = context.block; + const GDScriptParser::BlockNode *block = p_context.block; - if (context.function) { + if (p_context.function) { - const GDScriptParser::FunctionNode *f = context.function; + const GDScriptParser::FunctionNode *f = p_context.function; for (int i = 0; i < f->arguments.size(); i++) { - result.insert(f->arguments[i].operator String()); + r_result.insert(f->arguments[i].operator String()); } } - while (block) { - - GDScriptCompletionContext c = context; + if (!p_only_functions && block) { + GDScriptCompletionContext c = p_context; c.block = block; - - _find_identifiers_in_block(c, p_line, p_only_functions, result); - block = block->parent_block; + _find_identifiers_in_block(c, r_result); } - const GDScriptParser::ClassNode *clss = context._class; - - bool _static = context.function && context.function->_static; + const GDScriptParser::ClassNode *clss = p_context._class; + bool _static = !p_context.function || p_context.function->_static; while (clss) { - GDScriptCompletionContext c = context; + GDScriptCompletionContext c = p_context; c._class = clss; c.block = NULL; c.function = NULL; - _find_identifiers_in_class(c, _static, p_only_functions, result); + _find_identifiers_in_class(c, _static, p_only_functions, false, r_result); + _static = true; clss = clss->owner; } for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { - - result.insert(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))); + MethodInfo mi = GDScriptFunctions::get_info(GDScriptFunctions::Function(i)); + if (mi.arguments.size() || (mi.flags & METHOD_FLAG_VARARG)) { + r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "("); + } else { + r_result.insert(String(GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) + "()"); + } } static const char *_type_names[Variant::VARIANT_MAX] = { @@ -1526,667 +2091,372 @@ static void _find_identifiers(GDScriptCompletionContext &context, int p_line, bo }; for (int i = 0; i < Variant::VARIANT_MAX; i++) { - result.insert(_type_names[i]); + r_result.insert(_type_names[i]); } - List<String> reserved_words; - GDScriptLanguage::get_singleton()->get_reserved_words(&reserved_words); + static const char *_keywords[] = { + "and", "in", "not", "or", "false", "PI", "TAU", "INF", "NAN", "self", "true", "as", "assert", + "breakpoint", "class", "extends", "is", "func", "preload", "setget", "signal", "tool", "yield", + "const", "enum", "export", "onready", "static", "var", "break", "continue", "if", "elif", + "else", "for", "pass", "return", "match", "while", "remote", "sync", "master", "slave", + "remotesync", "mastersync", "slavesync", + 0 + }; - for (List<String>::Element *E = reserved_words.front(); E; E = E->next()) { - result.insert(E->get()); + const char **kw = _keywords; + while (*kw) { + r_result.insert(*kw); + kw++; } - //autoload singletons + // Autoload singletons List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) + if (!s.begins_with("autoload/")) { continue; - String name = s.get_slice("/", 1); + } String path = ProjectSettings::get_singleton()->get(s); if (path.begins_with("*")) { - result.insert(name); + r_result.insert(s.get_slice("/", 1)); } } - for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) { - result.insert(E->key().operator String()); - } -} - -static String _get_visual_datatype(const PropertyInfo &p_info, bool p_isarg = true) { - - String n = p_info.name; - int idx = n.find(":"); - if (idx != -1) { - return n.substr(idx + 1, n.length()); + // Named scripts + List<StringName> named_scripts; + ScriptServer::get_global_class_list(&named_scripts); + for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { + r_result.insert(E->get().operator String()); } - if (p_info.type == Variant::OBJECT && p_info.hint == PROPERTY_HINT_RESOURCE_TYPE) - return p_info.hint_string; - if (p_info.type == Variant::NIL) { - if (p_isarg) - return "var"; - else - return "void"; + // Native classes + for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) { + r_result.insert(E->key().operator String()); } - - return Variant::get_type_name(p_info.type); } -static void _make_function_hint(const GDScriptParser::FunctionNode *p_func, int p_argidx, String &arghint) { - - arghint = "func " + p_func->name + "("; - for (int i = 0; i < p_func->arguments.size(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += p_func->arguments[i].operator String(); - int deffrom = p_func->arguments.size() - p_func->default_values.size(); - - if (i >= deffrom) { - int defidx = deffrom - i; - - if (defidx >= 0 && defidx < p_func->default_values.size()) { - - if (p_func->default_values[defidx]->type == GDScriptParser::Node::TYPE_OPERATOR) { - - const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_func->default_values[defidx]); - if (op->op == GDScriptParser::OperatorNode::OP_ASSIGN) { - const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(op->arguments[1]); - arghint += "=" + cn->value.get_construct_string(); +static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Set<String> &r_result, String &r_arghint) { + Variant base = p_base.value; + GDScriptParser::DataType base_type = p_base.type; + bool _static = false; + + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + for (int i = 0; i < base_type.class_type->static_functions.size(); i++) { + if (base_type.class_type->static_functions[i]->name == p_method) { + r_arghint = _make_arguments_hint(base_type.class_type->static_functions[i], p_argidx); + return; + } + } + if (!_static) { + for (int i = 0; i < base_type.class_type->functions.size(); i++) { + if (base_type.class_type->functions[i]->name == p_method) { + r_arghint = _make_arguments_hint(base_type.class_type->functions[i], p_argidx); + return; + } } - } else { } - } - } - - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - } - if (p_func->arguments.size() > 0) - arghint += " "; - arghint += ")"; -} - -void get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_list) { - - for (int i = 0; i < p_dir->get_subdir_count(); i++) { - get_directory_contents(p_dir->get_subdir(i), r_list); - } - - for (int i = 0; i < p_dir->get_file_count(); i++) { - r_list.insert("\"" + p_dir->get_file_path(i) + "\""); - } -} - -static void _find_type_arguments(GDScriptCompletionContext &context, const GDScriptParser::Node *p_node, int p_line, const StringName &p_method, const GDScriptCompletionIdentifier &id, int p_argidx, Set<String> &result, bool &r_forced, String &arghint) { - - //print_line("find type arguments?"); - if (id.type == Variant::OBJECT && id.obj_type != StringName()) { - - MethodBind *m = ClassDB::get_method(id.obj_type, p_method); - if (!m) { - //not in static method, see script - - //print_line("not in static: "+String(p_method)); - Ref<GDScript> on_script; - - if (id.value.get_type()) { - Object *obj = id.value; - GDScript *scr = Object::cast_to<GDScript>(obj); - if (scr) { - while (scr) { + if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + for (int i = 0; i < base_type.class_type->_signals.size(); i++) { + r_result.insert("\"" + base_type.class_type->_signals[i].name.operator String() + "\""); + } + } - for (const Map<StringName, GDScriptFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { - if (E->get()->is_static() && p_method == E->get()->get_name()) { - arghint = "static func " + String(p_method) + "("; - for (int i = 0; i < E->get()->get_argument_count(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += "var " + E->get()->get_argument_name(i); - int deffrom = E->get()->get_argument_count() - E->get()->get_default_argument_count(); - if (i >= deffrom) { - int defidx = deffrom - i; - if (defidx >= 0 && defidx < E->get()->get_default_argument_count()) { - arghint += "=" + E->get()->get_default_argument(defidx).get_construct_string(); - } - } - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - } - arghint += ")"; - return; //found - } + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> gds = base_type.script_type; + if (gds.is_valid()) { + if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + List<MethodInfo> signals; + gds->get_script_signal_list(&signals); + for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { + r_result.insert("\"" + E->get().name + "\""); } - - if (scr->get_base().is_valid()) - scr = scr->get_base().ptr(); - else - scr = NULL; + } + Ref<GDScript> base_script = gds->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = gds->get_instance_base_type(); } } else { - if (obj) { - on_script = obj->get_script(); + return; + } + } break; + case GDScriptParser::DataType::NATIVE: { + StringName class_name = base_type.native_type; + if (!ClassDB::class_exists(class_name)) { + class_name = String("_") + class_name; + if (!ClassDB::class_exists(class_name)) { + base_type.has_type = false; + break; } } - } - - //print_line("but it has a script?"); - if (!on_script.is_valid() && id.script.is_valid()) { - //print_line("yes"); - on_script = id.script; - } - - if (on_script.is_valid()) { - - GDScript *scr = on_script.ptr(); - if (scr) { - while (scr) { - - String code = scr->get_source_code(); - //print_line("has source code!"); - - if (code != "") { - //if there is code, parse it. This way is slower but updates in real-time - GDScriptParser p; - //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false); - - Error err = p.parse(scr->get_source_code(), scr->get_path().get_base_dir(), true, "", false); - - if (err == OK) { - //print_line("checking the functions..."); - //only if ok, otherwise use what is cached on the script - //GDScriptParser::ClassNode *base = p. - const GDScriptParser::Node *root = p.get_parse_tree(); - ERR_FAIL_COND(root->type != GDScriptParser::Node::TYPE_CLASS); - - const GDScriptParser::ClassNode *cl = static_cast<const GDScriptParser::ClassNode *>(root); - - const GDScriptParser::FunctionNode *func = NULL; - bool st = false; - - for (int i = 0; i < cl->functions.size(); i++) { - //print_line(String(cl->functions[i]->name)+" vs "+String(p_method)); - if (cl->functions[i]->name == p_method) { - func = cl->functions[i]; - } - } - - for (int i = 0; i < cl->static_functions.size(); i++) { - - //print_line(String(cl->static_functions[i]->name)+" vs "+String(p_method)); - if (cl->static_functions[i]->name == p_method) { - func = cl->static_functions[i]; - st = true; - } - } - - if (func) { - - arghint = "func " + String(p_method) + "("; - if (st) - arghint = "static " + arghint; - for (int i = 0; i < func->arguments.size(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += "var " + String(func->arguments[i]); - int deffrom = func->arguments.size() - func->default_values.size(); - if (i >= deffrom) { - int defidx = deffrom - i; + List<MethodInfo> methods; + ClassDB::get_method_list(class_name, &methods); + ClassDB::get_virtual_methods(class_name, &methods); + int method_args = 0; - if (defidx >= 0 && defidx < func->default_values.size() && func->default_values[defidx]->type == GDScriptParser::Node::TYPE_OPERATOR) { - const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(func->default_values[defidx]); - if (op->op == GDScriptParser::OperatorNode::OP_ASSIGN) { - const GDScriptParser::ConstantNode *cn = static_cast<const GDScriptParser::ConstantNode *>(op->arguments[1]); - arghint += "=" + cn->value.get_construct_string(); - } - } - } - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - } - - arghint += " )"; - return; + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name == p_method) { + method_args = E->get().arguments.size(); + if (base.get_type() == Variant::OBJECT) { + Object *obj = base.operator Object *(); + if (obj) { + List<String> options; + obj->get_argument_options(p_method, p_argidx, &options); + for (List<String>::Element *E = options.front(); E; E = E->next()) { + r_result.insert(E->get()); } - } else { - //print_line("failed parsing?"); - code = ""; } } - if (code == "") { - - for (const Map<StringName, GDScriptFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { - if (p_method == E->get()->get_name()) { - arghint = "func " + String(p_method) + "("; - for (int i = 0; i < E->get()->get_argument_count(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += "var " + E->get()->get_argument_name(i); - int deffrom = E->get()->get_argument_count() - E->get()->get_default_argument_count(); - if (i >= deffrom) { - int defidx = deffrom - i; - if (defidx >= 0 && defidx < E->get()->get_default_argument_count()) { - arghint += "=" + E->get()->get_default_argument(defidx).get_construct_string(); - } - } - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - } - arghint += ")"; - return; //found - } + if (p_argidx < method_args) { + PropertyInfo arg_info = E->get().arguments[p_argidx]; + if (arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + _find_enumeration_candidates(arg_info.class_name, r_result); } } - if (scr->get_base().is_valid()) - scr = scr->get_base().ptr(); - else - scr = NULL; + r_arghint = _make_arguments_hint(E->get(), p_argidx); + break; } } - } - - } else { - - //regular method -#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) - if (p_argidx < m->get_argument_count()) { - PropertyInfo pi = m->get_argument_info(p_argidx); - - if (pi.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { - String enumeration = pi.class_name; - if (enumeration.find(".") != -1) { - //class constant - List<StringName> constants; - String cls = enumeration.get_slice(".", 0); - String enm = enumeration.get_slice(".", 1); - - ClassDB::get_enum_constants(cls, enm, &constants); - //constants.sort_custom<StringName::AlphCompare>(); - for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { - String add = cls + "." + E->get(); - result.insert(add); - r_forced = true; - } - } else { - //global constant - StringName current_enum = enumeration; - - for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { - if (GlobalConstants::get_global_constant_enum(i) == current_enum) { - result.insert(GlobalConstants::get_global_constant_name(i)); - r_forced = true; - } - } - //global + if ((p_method == "connect" || p_method == "emit_signal") && p_argidx == 0) { + List<MethodInfo> signals; + ClassDB::get_signal_list(class_name, &signals); + for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { + r_result.insert("\"" + E->get().name + "\""); } } - } -#endif - if (p_method.operator String() == "connect" || (p_method.operator String() == "emit_signal" && p_argidx == 0)) { - - if (p_argidx == 0) { - List<MethodInfo> sigs; - ClassDB::get_signal_list(id.obj_type, &sigs); - - if (id.script.is_valid()) { - id.script->get_script_signal_list(&sigs); - } else if (id.value.get_type() == Variant::OBJECT) { - Object *obj = id.value; - if (obj && !obj->get_script().is_null()) { - Ref<Script> scr = obj->get_script(); - if (scr.is_valid()) { - scr->get_script_signal_list(&sigs); - } - } - } - - for (List<MethodInfo>::Element *E = sigs.front(); E; E = E->next()) { - result.insert("\"" + E->get().name + "\""); - r_forced = true; - } - } else if (p_argidx == 2) { + if (ClassDB::is_parent_class(class_name, "Node") && (p_method == "get_node" || p_method == "has_node") && p_argidx == 0) { + // Get autoloads + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); - if (context._class) { - for (int i = 0; i < context._class->functions.size(); i++) { - result.insert("\"" + context._class->functions[i]->name + "\""); - r_forced = true; + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + String s = E->get().name; + if (!s.begins_with("autoload/")) { + continue; } + String name = s.get_slice("/", 1); + r_result.insert("\"/root/" + name + "\""); } } - /*if (p_argidx==2) { - - ERR_FAIL_COND(p_node->type!=GDScriptParser::Node::TYPE_OPERATOR); - const GDScriptParser::OperatorNode *op=static_cast<const GDScriptParser::OperatorNode *>(p_node); - if (op->arguments.size()>) - - }*/ - } else { - - if (p_argidx == 0 && (String(p_method) == "get_node" || String(p_method) == "has_node") && ClassDB::is_parent_class(id.obj_type, "Node")) { + if (p_argidx == 0 && method_args > 0 && ClassDB::is_parent_class(class_name, "InputEvent") && p_method.operator String().find("action") != -1) { + // Get input actions List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) + if (!s.begins_with("input/")) { continue; - //print_line("found "+s); + } String name = s.get_slice("/", 1); - result.insert("\"/root/" + name + "\""); - r_forced = true; + r_result.insert("\"" + name + "\""); } } - Object *obj = id.value; - if (obj) { - List<String> options; - obj->get_argument_options(p_method, p_argidx, &options); - - for (List<String>::Element *E = options.front(); E; E = E->next()) { - - result.insert(E->get()); - r_forced = true; + base_type.has_type = false; + } break; + case GDScriptParser::DataType::BUILTIN: { + if (base.get_type() == Variant::NIL) { + Variant::CallError err; + base = Variant::construct(base_type.builtin_type, NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK) { + return; } } - } - - arghint = _get_visual_datatype(m->get_return_info(), false) + " " + p_method.operator String() + String("("); - - for (int i = 0; i < m->get_argument_count(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - String n = m->get_argument_info(i).name; - int dp = n.find(":"); - if (dp != -1) - n = n.substr(0, dp); - arghint += _get_visual_datatype(m->get_argument_info(i)) + " " + n; - int deffrom = m->get_argument_count() - m->get_default_argument_count(); - - if (i >= deffrom) { - int defidx = i - deffrom; - if (defidx >= 0 && defidx < m->get_default_argument_count()) { - Variant v = m->get_default_argument(i); - arghint += "=" + v.get_construct_string(); + List<MethodInfo> methods; + base.get_method_list(&methods); + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name == p_method) { + r_arghint = _make_arguments_hint(E->get(), p_argidx); + return; } } - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - } - if (m->get_argument_count() > 0) - arghint += " "; - - arghint += ")"; + base_type.has_type = false; + } break; + default: { + base_type.has_type = false; + } break; } } } -static void _find_call_arguments(GDScriptCompletionContext &context, const GDScriptParser::Node *p_node, int p_line, int p_argidx, Set<String> &result, bool &r_forced, String &arghint) { +static void _find_call_arguments(const GDScriptCompletionContext &p_context, const GDScriptParser::Node *p_node, int p_argidx, Set<String> &r_result, bool &r_forced, String &r_arghint) { if (!p_node || p_node->type != GDScriptParser::Node::TYPE_OPERATOR) { - return; } + Variant base; + GDScriptParser::DataType base_type; + StringName function; + bool _static = false; const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(p_node); - if (op->op != GDScriptParser::OperatorNode::OP_CALL) { + GDScriptCompletionIdentifier connect_base; + if (op->op != GDScriptParser::OperatorNode::OP_CALL && op->op != GDScriptParser::OperatorNode::OP_PARENT_CALL) { return; } - if (op->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { - //complete built-in function - const GDScriptParser::BuiltInFunctionNode *fn = static_cast<const GDScriptParser::BuiltInFunctionNode *>(op->arguments[0]); - MethodInfo mi = GDScriptFunctions::get_info(fn->function); + if (!op->arguments.size()) { + return; + } - if (mi.name == "load" && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { - get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), result); - } + if (op->op == GDScriptParser::OperatorNode::OP_CALL) { + if (op->arguments[0]->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { + // Complete built-in function + const GDScriptParser::BuiltInFunctionNode *fn = static_cast<const GDScriptParser::BuiltInFunctionNode *>(op->arguments[0]); + MethodInfo mi = GDScriptFunctions::get_info(fn->function); - arghint = _get_visual_datatype(mi.return_val, false) + " " + GDScriptFunctions::get_func_name(fn->function) + String("("); - for (int i = 0; i < mi.arguments.size(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx || ((mi.flags & METHOD_FLAG_VARARG) && i > p_argidx)) { - arghint += String::chr(0xFFFF); - } - arghint += _get_visual_datatype(mi.arguments[i]) + " " + mi.arguments[i].name; - if (i == p_argidx || ((mi.flags & METHOD_FLAG_VARARG) && i > p_argidx)) { - arghint += String::chr(0xFFFF); + if ((mi.name == "load" || mi.name == "preload") && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) { + _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result); } - } - if (mi.arguments.size() > 0) - arghint += " "; - arghint += ")"; - } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) { - //complete constructor - const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(op->arguments[0]); + r_arghint = _make_arguments_hint(mi, p_argidx); + return; - List<MethodInfo> mil; - Variant::get_constructor_list(tn->vtype, &mil); + } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_TYPE) { + // Complete constructor + const GDScriptParser::TypeNode *tn = static_cast<const GDScriptParser::TypeNode *>(op->arguments[0]); - for (List<MethodInfo>::Element *E = mil.front(); E; E = E->next()) { + List<MethodInfo> constructors; + Variant::get_constructor_list(tn->vtype, &constructors); - MethodInfo mi = E->get(); - if (mi.arguments.size() == 0) - continue; - if (E->prev()) - arghint += "\n"; - arghint += Variant::get_type_name(tn->vtype) + " " + Variant::get_type_name(tn->vtype) + String("("); - for (int i = 0; i < mi.arguments.size(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += _get_visual_datatype(mi.arguments[i]) + " " + mi.arguments[i].name; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); + int i = 0; + for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) { + if (p_argidx >= E->get().arguments.size()) { + continue; } - } - if (mi.arguments.size() > 0) - arghint += " "; - arghint += ")"; - } - - } else if (op->arguments.size() >= 2 && op->arguments[1]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { - //make sure identifier exists... - - const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]); - if (op->arguments[0]->type == GDScriptParser::Node::TYPE_SELF) { - //self, look up - - for (int i = 0; i < context._class->static_functions.size(); i++) { - if (context._class->static_functions[i]->name == id->name) { - _make_function_hint(context._class->static_functions[i], p_argidx, arghint); - return; + if (i > 0) { + r_arghint += "\n"; } + r_arghint += _make_arguments_hint(E->get(), p_argidx); + i++; } + return; + } else if (op->arguments[0]->type == GDScriptParser::Node::TYPE_SELF) { - if (context.function && !context.function->_static) { - - for (int i = 0; i < context._class->functions.size(); i++) { - if (context._class->functions[i]->name == id->name) { - _make_function_hint(context._class->functions[i], p_argidx, arghint); - return; - } - } + if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { + return; } - Ref<Reference> base = _get_parent_class(context); - - while (true) { - - Ref<GDScript> script = base; - Ref<GDScriptNativeClass> nc = base; - if (script.is_valid()) { - - for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) { + base = p_context.base; - if (E->key() == id->name) { + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]); + function = id->name; + base_type.has_type = true; + base_type.kind = GDScriptParser::DataType::CLASS; + base_type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class); + _static = p_context.function && p_context.function->_static; - if (context.function && context.function->_static && !E->get()->is_static()) - continue; + if (function == "connect" && op->arguments.size() >= 4) { + _guess_expression_type(p_context, op->arguments[3], connect_base); + } - arghint = "func " + id->name.operator String() + String("("); - for (int i = 0; i < E->get()->get_argument_count(); i++) { - if (i > 0) - arghint += ", "; - else - arghint += " "; - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - arghint += E->get()->get_argument_name(i); - int deffrom = E->get()->get_argument_count() - E->get()->get_default_argument_count(); - if (i >= deffrom) { - int defidx = deffrom - i; - if (defidx >= 0 && defidx < E->get()->get_default_argument_count()) { - arghint += "=" + E->get()->get_default_argument(defidx).get_construct_string(); - } - } - if (i == p_argidx) { - arghint += String::chr(0xFFFF); - } - } - if (E->get()->get_argument_count() > 0) - arghint += " "; - arghint += ")"; - return; - } - } + } else { + if (op->arguments.size() < 2 || op->arguments[1]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { + return; + } + const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[1]); + function = id->name; - base = script->get_base(); - if (base.is_null()) - base = script->get_native(); - } else if (nc.is_valid()) { + GDScriptCompletionIdentifier ci; + if (_guess_expression_type(p_context, op->arguments[0], ci)) { + base_type = ci.type; + base = ci.value; + } else { + return; + } + _static = ci.type.is_meta_type; - if (!(context.function && context.function->_static)) { + if (function == "connect" && op->arguments.size() >= 4) { + _guess_expression_type(p_context, op->arguments[3], connect_base); + } + } + } else { + if (!p_context._class || op->arguments.size() < 1 || op->arguments[0]->type != GDScriptParser::Node::TYPE_IDENTIFIER) { + return; + } + base_type.has_type = true; + base_type.kind = GDScriptParser::DataType::CLASS; + base_type.class_type = const_cast<GDScriptParser::ClassNode *>(p_context._class); + base_type.is_meta_type = p_context.function && p_context.function->_static; + base = p_context.base; - GDScriptCompletionIdentifier ci; - ci.type = Variant::OBJECT; - ci.obj_type = nc->get_name(); - if (!context._class->owner) - ci.value = context.base; + function = static_cast<const GDScriptParser::IdentifierNode *>(op->arguments[0])->name; - _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, r_forced, arghint); - //guess type.. - /* - List<MethodInfo> methods; - ClassDB::get_method_list(type,&methods); - for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) { - if (E->get().arguments.size()) - result.insert(E->get().name+"("); - else - result.insert(E->get().name+"()"); - }*/ - } - break; - } else - break; - } - } else { - //indexed lookup + if (function == "connect" && op->arguments.size() >= 4) { + _guess_expression_type(p_context, op->arguments[3], connect_base); + } + } - GDScriptCompletionIdentifier ci; - if (_guess_expression_type(context, op->arguments[0], p_line, ci)) { + GDScriptCompletionIdentifier ci; + ci.type = base_type; + ci.value = base; + _find_call_arguments(p_context, ci, function, p_argidx, _static, r_result, r_arghint); - _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, r_forced, arghint); - return; - } + if (function == "connect" && p_argidx == 2) { + Set<String> methods; + _find_identifiers_in_base(p_context, connect_base, true, methods); + for (Set<String>::Element *E = methods.front(); E; E = E->next()) { + r_result.insert("\"" + E->get().replace("(", "").replace(")", "") + "\""); } } + + r_forced = r_result.size() > 0; } Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) { - GDScriptParser p; + GDScriptParser parser; - p.parse(p_code, p_base_path, false, "", true); - bool isfunction = false; - Set<String> options; + parser.parse(p_code, p_base_path, false, "", true); r_forced = false; + Set<String> options; GDScriptCompletionContext context; - context._class = p.get_completion_class(); - context.block = p.get_completion_block(); - context.function = p.get_completion_function(); + context._class = parser.get_completion_class(); + context.block = parser.get_completion_block(); + context.function = parser.get_completion_function(); context.base = p_owner; context.base_path = p_base_path; + context.line = parser.get_completion_line(); + bool is_function = false; - switch (p.get_completion_type()) { - + switch (parser.get_completion_type()) { case GDScriptParser::COMPLETION_NONE: { } break; case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { List<StringName> constants; - Variant::get_numeric_constants_for_type(p.get_completion_built_in_constant(), &constants); + Variant::get_numeric_constants_for_type(parser.get_completion_built_in_constant(), &constants); for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { options.insert(E->get().operator String()); } - - } break; - case GDScriptParser::COMPLETION_FUNCTION: - isfunction = true; - case GDScriptParser::COMPLETION_IDENTIFIER: { - - _find_identifiers(context, p.get_completion_line(), isfunction, options); } break; case GDScriptParser::COMPLETION_PARENT_FUNCTION: { - + _find_identifiers_in_class(context, !context.function || context.function->_static, true, true, options); + } break; + case GDScriptParser::COMPLETION_FUNCTION: { + is_function = true; + } // fallthrough + case GDScriptParser::COMPLETION_IDENTIFIER: { + _find_identifiers(context, is_function, options); } break; case GDScriptParser::COMPLETION_GET_NODE: { - if (p_owner) { List<String> opts; p_owner->get_argument_options("get_node", 0, &opts); @@ -2204,315 +2474,358 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } } } + + // Get autoloads + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + String s = E->get().name; + if (!s.begins_with("autoload/")) { + continue; + } + String name = s.get_slice("/", 1); + options.insert("\"/root/" + name + "\""); + } } } break; - case GDScriptParser::COMPLETION_METHOD: - isfunction = true; + case GDScriptParser::COMPLETION_METHOD: { + is_function = true; + } // fallthrough case GDScriptParser::COMPLETION_INDEX: { - - const GDScriptParser::Node *node = p.get_completion_node(); - if (node->type != GDScriptParser::Node::TYPE_OPERATOR) + const GDScriptParser::Node *node = parser.get_completion_node(); + if (node->type != GDScriptParser::Node::TYPE_OPERATOR) { break; + } + const GDScriptParser::OperatorNode *op = static_cast<const GDScriptParser::OperatorNode *>(node); + if (op->arguments.size() < 1) { + break; + } - GDScriptCompletionIdentifier t; - if (_guess_expression_type(context, static_cast<const GDScriptParser::OperatorNode *>(node)->arguments[0], p.get_completion_line(), t, true)) { - - if (t.type == Variant::OBJECT && t.obj_type == "GDScriptNativeClass") { - //native enum - Ref<GDScriptNativeClass> gdn = t.value; - if (gdn.is_valid()) { - StringName cn = gdn->get_name(); - List<String> cnames; - ClassDB::get_integer_constant_list(cn, &cnames); - for (List<String>::Element *E = cnames.front(); E; E = E->next()) { - options.insert(E->get()); - } - - List<PropertyInfo> pinfo; - ClassDB::get_property_list(cn, &pinfo); - - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) - continue; - if (String(E->get().name).find("/") != -1) - continue; - options.insert(E->get().name); - } - } - } else if (t.type == Variant::OBJECT && t.obj_type != StringName()) { - - Ref<GDScript> on_script; - - if (t.value.get_type()) { - Object *obj = t.value; - - GDScript *scr = Object::cast_to<GDScript>(obj); - if (scr) { - while (scr) { + GDScriptCompletionIdentifier base; + if (!_guess_expression_type(context, op->arguments[0], base)) { + break; + } - if (!isfunction) { - for (const Map<StringName, Variant>::Element *E = scr->get_constants().front(); E; E = E->next()) { - options.insert(E->key()); - } - } - for (const Map<StringName, GDScriptFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { - if (E->get()->is_static()) - options.insert(E->key()); - } + GDScriptCompletionContext c = context; + c.function = NULL; + c.block = NULL; + c.base = base.value.get_type() == Variant::OBJECT ? base.value.operator Object *() : NULL; + if (base.type.kind == GDScriptParser::DataType::CLASS) { + c._class = base.type.class_type; + } else { + c._class = NULL; + } - if (scr->get_base().is_valid()) - scr = scr->get_base().ptr(); - else - scr = NULL; + _find_identifiers_in_base(c, base, is_function, options); + } break; + case GDScriptParser::COMPLETION_CALL_ARGUMENTS: { + _find_call_arguments(context, parser.get_completion_node(), parser.get_completion_argument_index(), options, r_forced, r_call_hint); + } break; + case GDScriptParser::COMPLETION_VIRTUAL_FUNC: { + GDScriptParser::DataType native_type = context._class->base_type; + while (native_type.has_type && native_type.kind != GDScriptParser::DataType::NATIVE) { + switch (native_type.kind) { + case GDScriptParser::DataType::CLASS: { + native_type = native_type.class_type->base_type; + } break; + case GDScriptParser::DataType::GDSCRIPT: { + Ref<GDScript> gds = native_type.script_type; + if (gds.is_valid()) { + Ref<GDScript> base = gds->get_base_script(); + if (base.is_valid()) { + native_type.script_type = base; + } else { + native_type.native_type = gds->get_instance_base_type(); + native_type.kind = GDScriptParser::DataType::NATIVE; } } else { - if (obj) { - on_script = obj->get_script(); - } + native_type.has_type = false; } - } - - if (!on_script.is_valid() && t.script.is_valid()) { - on_script = t.script; - } - - if (on_script.is_valid()) { - - GDScript *scr = on_script.ptr(); - if (scr) { - while (scr) { - - String code = scr->get_source_code(); - - if (code != "") { - //if there is code, parse it. This way is slower but updates in real-time - GDScriptParser p; - - Error err = p.parse(scr->get_source_code(), scr->get_path().get_base_dir(), true, "", false); - - if (err == OK) { - //only if ok, otherwise use what is cached on the script - //GDScriptParser::ClassNode *base = p. - const GDScriptParser::Node *root = p.get_parse_tree(); - ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, ERR_PARSE_ERROR); - - const GDScriptParser::ClassNode *cl = static_cast<const GDScriptParser::ClassNode *>(root); - - for (int i = 0; i < cl->functions.size(); i++) { - - if (cl->functions[i]->arguments.size()) - options.insert(String(cl->functions[i]->name) + "("); - else - options.insert(String(cl->functions[i]->name) + "()"); - } - - for (int i = 0; i < cl->static_functions.size(); i++) { - - if (cl->static_functions[i]->arguments.size()) - options.insert(String(cl->static_functions[i]->name) + "("); - else - options.insert(String(cl->static_functions[i]->name) + "()"); - } + } break; + default: { + native_type.has_type = false; + } break; + } + } - if (!isfunction) { - for (int i = 0; i < cl->variables.size(); i++) { + if (!native_type.has_type) { + break; + } - options.insert(String(cl->variables[i].identifier)); - } + StringName class_name = native_type.native_type; + if (!ClassDB::class_exists(class_name)) { + class_name = String("_") + class_name; + if (!ClassDB::class_exists(class_name)) { + break; + } + } - for (int i = 0; i < cl->constant_expressions.size(); i++) { + bool use_type_hint = EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints").operator bool(); - options.insert(String(cl->constant_expressions[i].identifier)); - } - } + List<MethodInfo> virtual_methods; + ClassDB::get_virtual_methods(class_name, &virtual_methods); + for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { - } else { - code = ""; //well, then no code - } - } - - if (code == "") { - //use class directly, no code was found - if (!isfunction) { - for (const Map<StringName, Variant>::Element *E = scr->get_constants().front(); E; E = E->next()) { - options.insert(E->key()); - } - } - for (const Map<StringName, GDScriptFunction *>::Element *E = scr->get_member_functions().front(); E; E = E->next()) { - if (E->get()->get_argument_count()) - options.insert(String(E->key()) + "()"); - else - options.insert(String(E->key()) + "("); - } - - for (const Set<StringName>::Element *E = scr->get_members().front(); E; E = E->next()) { - options.insert(E->get()); - } - } + MethodInfo &mi = E->get(); + String method_hint = mi.name; + if (method_hint.find(":") != -1) { + method_hint = method_hint.get_slice(":", 0); + } + method_hint += "("; - if (scr->get_base().is_valid()) - scr = scr->get_base().ptr(); - else - scr = NULL; + if (mi.arguments.size()) { + for (int i = 0; i < mi.arguments.size(); i++) { + if (i > 0) { + method_hint += ", "; + } + String arg = mi.arguments[i].name; + if (arg.find(":") != -1) { + arg = arg.substr(0, arg.find(":")); + } + method_hint += arg; + if (use_type_hint && mi.arguments[i].type != Variant::NIL) { + method_hint += " : "; + if (mi.arguments[i].type == Variant::OBJECT && mi.arguments[i].class_name != StringName()) { + method_hint += mi.arguments[i].class_name.operator String(); + } else { + method_hint += Variant::get_type_name(mi.arguments[i].type); } } } - - if (!isfunction) { - ClassDB::get_integer_constant_list(t.obj_type, r_options); - - List<PropertyInfo> pinfo; - ClassDB::get_property_list(t.obj_type, &pinfo); - - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_GROUP | PROPERTY_USAGE_CATEGORY)) - continue; - if (String(E->get().name).find("/") != -1) - continue; - r_options->push_back(E->get().name); - } + } + method_hint += ")"; + if (use_type_hint && (mi.return_val.type != Variant::NIL || !(mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT))) { + method_hint += " -> "; + if (mi.return_val.type == Variant::NIL) { + method_hint += "void"; + } else if (mi.return_val.type == Variant::OBJECT && mi.return_val.class_name != StringName()) { + method_hint += mi.return_val.class_name.operator String(); + } else { + method_hint += Variant::get_type_name(mi.return_val.type); } + } + method_hint += ":"; - List<MethodInfo> mi; - ClassDB::get_method_list(t.obj_type, &mi, false, true); - for (List<MethodInfo>::Element *E = mi.front(); E; E = E->next()) { - - if (E->get().name.begins_with("_")) - continue; + options.insert(method_hint); + } + } break; + case GDScriptParser::COMPLETION_YIELD: { + const GDScriptParser::Node *node = parser.get_completion_node(); - if (E->get().arguments.size()) - options.insert(E->get().name + "("); - else - options.insert(E->get().name + "()"); - } - } else { + GDScriptCompletionContext c = context; + c.line = node->line; + GDScriptCompletionIdentifier type; + if (!_guess_expression_type(c, node, type)) { + break; + } - //check InputEvent hint - { - if (t.value.get_type() == Variant::NIL) { - Variant::CallError ce; - t.value = Variant::construct(t.type, NULL, 0, ce); + GDScriptParser::DataType base_type = type.type; + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + for (int i = 0; i < base_type.class_type->_signals.size(); i++) { + options.insert("\"" + base_type.class_type->_signals[i].name.operator String() + "\""); } - - if (!isfunction) { - List<PropertyInfo> pl; - t.value.get_property_list(&pl); - for (List<PropertyInfo>::Element *E = pl.front(); E; E = E->next()) { - - if (String(E->get().name).find("/") == -1) - options.insert(E->get().name); + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::SCRIPT: + case GDScriptParser::DataType::GDSCRIPT: { + Ref<Script> scr = base_type.script_type; + if (scr.is_valid()) { + List<MethodInfo> signals; + scr->get_script_signal_list(&signals); + for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { + options.insert("\"" + E->get().name + "\""); + } + Ref<Script> base_script = scr->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = scr->get_instance_base_type(); + } + } else { + base_type.has_type = false; + } + } break; + case GDScriptParser::DataType::NATIVE: { + base_type.has_type = false; + + StringName class_name = base_type.native_type; + if (!ClassDB::class_exists(class_name)) { + class_name = String("_") + class_name; + if (!ClassDB::class_exists(class_name)) { + break; } } - List<MethodInfo> mi; - t.value.get_method_list(&mi); - for (List<MethodInfo>::Element *E = mi.front(); E; E = E->next()) { - if (E->get().arguments.size()) - options.insert(E->get().name + "("); - else - options.insert(E->get().name + "()"); + List<MethodInfo> signals; + ClassDB::get_signal_list(class_name, &signals); + for (List<MethodInfo>::Element *E = signals.front(); E; E = E->next()) { + options.insert("\"" + E->get().name + "\""); } + } break; + default: { + base_type.has_type = false; } } } - } break; - case GDScriptParser::COMPLETION_CALL_ARGUMENTS: { - - _find_call_arguments(context, p.get_completion_node(), p.get_completion_line(), p.get_completion_argument_index(), options, r_forced, r_call_hint); + case GDScriptParser::COMPLETION_RESOURCE_PATH: { + if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) { + _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options); + r_forced = true; + } } break; - case GDScriptParser::COMPLETION_VIRTUAL_FUNC: { - - GDScriptCompletionIdentifier cid = _get_native_class(context); - - if (cid.obj_type != StringName()) { - List<MethodInfo> vm; - ClassDB::get_virtual_methods(cid.obj_type, &vm); - for (List<MethodInfo>::Element *E = vm.front(); E; E = E->next()) { + case GDScriptParser::COMPLETION_ASSIGN: { + GDScriptCompletionIdentifier type; + if (!_guess_expression_type(context, parser.get_completion_node(), type)) { + break; + } - MethodInfo &mi = E->get(); - String m = mi.name; - if (m.find(":") != -1) - m = m.substr(0, m.find(":")); - m += "("; - - if (mi.arguments.size()) { - for (int i = 0; i < mi.arguments.size(); i++) { - if (i > 0) - m += ", "; - String n = mi.arguments[i].name; - if (n.find(":") != -1) - n = n.substr(0, n.find(":")); - m += n; + if (!type.enumeration.empty()) { + _find_enumeration_candidates(type.enumeration, options); + r_forced = options.size() > 0; + } + } break; + case GDScriptParser::COMPLETION_TYPE_HINT: { + const GDScriptParser::ClassNode *clss = context._class; + while (clss) { + for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = clss->constant_expressions.front(); E; E = E->next()) { + GDScriptCompletionIdentifier constant; + GDScriptCompletionContext c = context; + c.function = NULL; + c.block = NULL; + c.line = E->value().expression->line; + if (_guess_expression_type(c, E->value().expression, constant)) { + if (constant.type.has_type && constant.type.is_meta_type) { + options.insert(E->key().operator String()); } } - m += "):"; + } + for (int i = 0; i < clss->subclasses.size(); i++) { + if (clss->subclasses[i]->name != StringName()) { + options.insert(clss->subclasses[i]->name.operator String()); + } + } + clss = clss->owner; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + options.insert(Variant::get_type_name((Variant::Type)i)); + } + } - options.insert(m); + List<StringName> native_classes; + ClassDB::get_class_list(&native_classes); + for (List<StringName>::Element *E = native_classes.front(); E; E = E->next()) { + String class_name = E->get().operator String(); + if (class_name.begins_with("_")) { + class_name = class_name.right(1); + } + if (Engine::get_singleton()->has_singleton(class_name)) { + continue; } + options.insert(class_name); } - } break; - case GDScriptParser::COMPLETION_YIELD: { - const GDScriptParser::Node *node = p.get_completion_node(); + // Named scripts + List<StringName> named_scripts; + ScriptServer::get_global_class_list(&named_scripts); + for (List<StringName>::Element *E = named_scripts.front(); E; E = E->next()) { + options.insert(E->get().operator String()); + } - GDScriptCompletionIdentifier t; - if (!_guess_expression_type(context, node, p.get_completion_line(), t)) + if (parser.get_completion_identifier_is_function()) { + options.insert("void"); + } + r_forced = true; + } break; + case GDScriptParser::COMPLETION_TYPE_HINT_INDEX: { + GDScriptCompletionIdentifier base; + String index = parser.get_completion_cursor().operator String(); + if (!_guess_identifier_type(context, index.get_slice(".", 0), base)) { break; + } - if (t.type == Variant::OBJECT && t.obj_type != StringName()) { + GDScriptCompletionContext c = context; + c._class = NULL; + c.function = NULL; + c.block = NULL; + bool finding = true; + index = index.right(index.find(".") + 1); + while (index.find(".") != -1) { + String id = index.get_slice(".", 0); - List<MethodInfo> sigs; - ClassDB::get_signal_list(t.obj_type, &sigs); - for (List<MethodInfo>::Element *E = sigs.front(); E; E = E->next()) { - options.insert("\"" + E->get().name + "\""); - r_forced = true; + GDScriptCompletionIdentifier sub_base; + if (!_guess_identifier_type_from_base(c, base, id, sub_base)) { + finding = false; + break; } + index = index.right(index.find(".") + 1); + base = sub_base; } - } break; - case GDScriptParser::COMPLETION_RESOURCE_PATH: { - - if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) { - get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options); - r_forced = true; + if (!finding) { + break; } - } break; - case GDScriptParser::COMPLETION_ASSIGN: { -#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) - GDScriptCompletionIdentifier ci; - if (_guess_expression_type(context, p.get_completion_node(), p.get_completion_line(), ci)) { - - String enumeration = ci.enumeration; - if (enumeration.find(".") != -1) { - //class constant - List<StringName> constants; - String cls = enumeration.get_slice(".", 0); - String enm = enumeration.get_slice(".", 1); - - ClassDB::get_enum_constants(cls, enm, &constants); - //constants.sort_custom<StringName::AlphCompare>(); - for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { - String add = cls + "." + E->get(); - r_options->push_back(add); - r_forced = true; - } - } else { - - //global constant - StringName current_enum = enumeration; + GDScriptParser::DataType base_type = base.type; + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + if (base_type.class_type) { + for (Map<StringName, GDScriptParser::ClassNode::Constant>::Element *E = base_type.class_type->constant_expressions.front(); E; E = E->next()) { + GDScriptCompletionIdentifier constant; + GDScriptCompletionContext c = context; + c._class = base_type.class_type; + c.function = NULL; + c.block = NULL; + c.line = E->value().expression->line; + if (_guess_expression_type(c, E->value().expression, constant)) { + if (constant.type.has_type && constant.type.is_meta_type) { + options.insert(E->key().operator String()); + } + } + } + for (int i = 0; i < base_type.class_type->subclasses.size(); i++) { + if (base_type.class_type->subclasses[i]->name != StringName()) { + options.insert(base_type.class_type->subclasses[i]->name.operator String()); + } + } - for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { - if (GlobalConstants::get_global_constant_enum(i) == current_enum) { - r_options->push_back(GlobalConstants::get_global_constant_name(i)); - r_forced = true; + base_type = base_type.class_type->base_type; + } else { + base_type.has_type = false; } - } - //global + } break; + case GDScriptParser::DataType::SCRIPT: + case GDScriptParser::DataType::GDSCRIPT: { + Ref<Script> scr = base_type.script_type; + if (scr.is_valid()) { + Map<StringName, Variant> constants; + scr->get_constants(&constants); + for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { + Ref<Script> const_scr = E->value(); + if (const_scr.is_valid()) { + options.insert(E->key().operator String()); + } + } + Ref<Script> base_script = scr->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.has_type = false; + } + } else { + base_type.has_type = false; + } + } break; + default: { + base_type.has_type = false; + } break; } } -#endif + r_forced = options.size() > 0; } break; } @@ -2531,6 +2844,8 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base #endif +//////// END COMPLETION ////////// + String GDScriptLanguage::_get_indentation() const { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { @@ -2603,7 +2918,7 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t } //print_line(itos(indent_stack.size())+","+itos(tc)+": "+l); - lines[i] = l; + lines.write[i] = l; } p_code = ""; @@ -2616,6 +2931,185 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t #ifdef TOOLS_ENABLED +static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, const String &p_symbol, bool p_is_function, GDScriptLanguage::LookupResult &r_result) { + GDScriptParser::DataType base_type = p_base; + + while (base_type.has_type) { + switch (base_type.kind) { + case GDScriptParser::DataType::CLASS: { + if (base_type.class_type) { + if (p_is_function) { + for (int i = 0; i < base_type.class_type->functions.size(); i++) { + if (base_type.class_type->functions[i]->name == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = base_type.class_type->functions[i]->line; + return OK; + } + } + for (int i = 0; i < base_type.class_type->static_functions.size(); i++) { + if (base_type.class_type->static_functions[i]->name == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = base_type.class_type->static_functions[i]->line; + return OK; + } + } + } else { + if (base_type.class_type->constant_expressions.has(p_symbol)) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = base_type.class_type->constant_expressions[p_symbol].expression->line; + return OK; + } + + for (int i = 0; i < base_type.class_type->variables.size(); i++) { + if (base_type.class_type->variables[i].identifier == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = base_type.class_type->variables[i].line; + return OK; + } + } + } + } + base_type = base_type.class_type->base_type; + } break; + case GDScriptParser::DataType::SCRIPT: + case GDScriptParser::DataType::GDSCRIPT: { + Ref<Script> scr = base_type.script_type; + if (scr.is_valid()) { + int line = scr->get_member_line(p_symbol); + if (line >= 0) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = line; + r_result.script = scr; + return OK; + } + Ref<Script> base_script = scr->get_base_script(); + if (base_script.is_valid()) { + base_type.script_type = base_script; + } else { + base_type.kind = GDScriptParser::DataType::NATIVE; + base_type.native_type = scr->get_instance_base_type(); + } + } else { + base_type.has_type = false; + } + } break; + case GDScriptParser::DataType::NATIVE: { + StringName class_name = base_type.native_type; + if (!ClassDB::class_exists(class_name)) { + class_name = String("_") + class_name; + if (!ClassDB::class_exists(class_name)) { + base_type.has_type = false; + break; + } + } + + if (ClassDB::has_method(class_name, p_symbol, true)) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name = base_type.native_type; + r_result.class_member = p_symbol; + return OK; + } + + List<MethodInfo> virtual_methods; + ClassDB::get_virtual_methods(class_name, &virtual_methods, true); + for (List<MethodInfo>::Element *E = virtual_methods.front(); E; E = E->next()) { + if (E->get().name == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name = base_type.native_type; + r_result.class_member = p_symbol; + return OK; + } + } + + StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true); + if (enum_name != StringName()) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM; + r_result.class_name = base_type.native_type; + r_result.class_member = enum_name; + return OK; + } + + List<String> constants; + ClassDB::get_integer_constant_list(class_name, &constants, true); + for (List<String>::Element *E = constants.front(); E; E = E->next()) { + if (E->get() == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name = base_type.native_type; + r_result.class_member = p_symbol; + return OK; + } + } + + List<PropertyInfo> properties; + ClassDB::get_property_list(class_name, &properties, true); + for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_symbol) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name = base_type.native_type; + r_result.class_member = p_symbol; + return OK; + } + } + + StringName parent = ClassDB::get_parent_class(class_name); + if (parent != StringName()) { + if (String(parent).begins_with("_")) { + base_type.native_type = String(parent).right(1); + } else { + base_type.native_type = parent; + } + } else { + base_type.has_type = false; + } + } break; + case GDScriptParser::DataType::BUILTIN: { + base_type.has_type = false; + + if (Variant::has_numeric_constant(base_type.builtin_type, p_symbol)) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; + r_result.class_name = Variant::get_type_name(base_type.builtin_type); + r_result.class_member = p_symbol; + return OK; + } + + Variant v; + REF v_ref; + if (base_type.builtin_type == Variant::OBJECT) { + v_ref.instance(); + v = v_ref; + } else { + Variant::CallError err; + v = Variant::construct(base_type.builtin_type, NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK) { + break; + } + } + + if (v.has_method(p_symbol)) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; + r_result.class_name = Variant::get_type_name(base_type.builtin_type); + r_result.class_member = p_symbol; + return OK; + } + + bool valid = false; + v.get(p_symbol, &valid); + if (valid) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; + r_result.class_name = Variant::get_type_name(base_type.builtin_type); + r_result.class_member = p_symbol; + return OK; + } + } break; + default: { + base_type.has_type = false; + } break; + } + } + + return ERR_CANT_RESOLVE; +} + Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result) { //before parsing, try the usual stuff @@ -2623,6 +3117,13 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; r_result.class_name = p_symbol; return OK; + } else { + String under_prefix = "_" + p_symbol; + if (ClassDB::class_exists(under_prefix)) { + r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; + r_result.class_name = p_symbol; + return OK; + } } for (int i = 0; i < Variant::VARIANT_MAX; i++) { @@ -2650,17 +3151,18 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol return OK; } - GDScriptParser p; - p.parse(p_code, p_base_path, false, "", true); + GDScriptParser parser; + parser.parse(p_code, p_base_path, false, "", true); - if (p.get_completion_type() == GDScriptParser::COMPLETION_NONE) + if (parser.get_completion_type() == GDScriptParser::COMPLETION_NONE) { return ERR_CANT_RESOLVE; + } GDScriptCompletionContext context; - - context._class = p.get_completion_class(); - context.block = p.get_completion_block(); - context.function = p.get_completion_function(); + context._class = parser.get_completion_class(); + context.function = parser.get_completion_function(); + context.block = parser.get_completion_block(); + context.line = parser.get_completion_line(); context.base = p_owner; context.base_path = p_base_path; @@ -2675,171 +3177,68 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol } } - bool isfunction = false; + bool is_function = false; - switch (p.get_completion_type()) { - - case GDScriptParser::COMPLETION_GET_NODE: - case GDScriptParser::COMPLETION_NONE: { - } break; + switch (parser.get_completion_type()) { case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; - r_result.class_name = Variant::get_type_name(p.get_completion_built_in_constant()); + r_result.class_name = Variant::get_type_name(parser.get_completion_built_in_constant()); r_result.class_member = p_symbol; return OK; - } break; + case GDScriptParser::COMPLETION_PARENT_FUNCTION: case GDScriptParser::COMPLETION_FUNCTION: { - - if (context._class && context._class->functions.size()) { - for (int i = 0; i < context._class->functions.size(); i++) { - if (context._class->functions[i]->name == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = context._class->functions[i]->line; - return OK; - } - } - } - - Ref<GDScript> parent = _get_parent_class(context); - while (parent.is_valid()) { - int line = parent->get_member_line(p_symbol); - if (line >= 0) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = line; - r_result.script = parent; - return OK; - } - - parent = parent->get_base(); - } - - GDScriptCompletionIdentifier identifier = _get_native_class(context); - print_line("identifier: " + String(identifier.obj_type)); - - if (ClassDB::has_method(identifier.obj_type, p_symbol)) { - - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; - r_result.class_name = identifier.obj_type; - r_result.class_member = p_symbol; - return OK; - } - - } break; + is_function = true; + } // fallthrough case GDScriptParser::COMPLETION_IDENTIFIER: { - //check if a function - if (p.get_completion_identifier_is_function()) { - if (context._class && context._class->functions.size()) { - for (int i = 0; i < context._class->functions.size(); i++) { - if (context._class->functions[i]->name == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = context._class->functions[i]->line; - return OK; - } - } - } - - Ref<GDScript> parent = _get_parent_class(context); - while (parent.is_valid()) { - int line = parent->get_member_line(p_symbol); - if (line >= 0) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = line; - r_result.script = parent; - return OK; - } - - parent = parent->get_base(); - } - - GDScriptCompletionIdentifier identifier = _get_native_class(context); - - if (ClassDB::has_method(identifier.obj_type, p_symbol)) { + if (!is_function) { + is_function = parser.get_completion_identifier_is_function(); + } - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; - r_result.class_name = identifier.obj_type; - r_result.class_member = p_symbol; - return OK; + GDScriptParser::DataType base_type; + if (context._class) { + if (parser.get_completion_type() != GDScriptParser::COMPLETION_PARENT_FUNCTION) { + base_type.has_type = true; + base_type.kind = GDScriptParser::DataType::CLASS; + base_type.class_type = const_cast<GDScriptParser::ClassNode *>(context._class); + } else { + base_type = context._class->base_type; } } else { + break; + } - GDScriptCompletionIdentifier gdi = _get_native_class(context); - if (gdi.obj_type != StringName()) { - bool valid; - Variant::Type t = ClassDB::get_property_type(gdi.obj_type, p_symbol, &valid); - if (t != Variant::NIL && valid) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; - r_result.class_name = gdi.obj_type; - r_result.class_member = p_symbol; - return OK; - } - } - + if (!is_function && context.block) { + // Lookup local variables const GDScriptParser::BlockNode *block = context.block; - //search in blocks going up (local var?) while (block) { - - for (int i = 0; i < block->statements.size(); i++) { - - if (block->statements[i]->line > p.get_completion_line()) - continue; - - if (block->statements[i]->type == GDScriptParser::BlockNode::TYPE_LOCAL_VAR) { - - const GDScriptParser::LocalVarNode *lv = static_cast<const GDScriptParser::LocalVarNode *>(block->statements[i]); - - if (lv->assign && lv->name == p_symbol) { - - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = block->statements[i]->line; - return OK; - } - } + if (block->variables.has(p_symbol)) { + r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; + r_result.location = block->variables[p_symbol]->line; + return OK; } block = block->parent_block; } + } - //guess from function arguments - if (context.function && context.function->name != StringName()) { - - for (int i = 0; i < context.function->arguments.size(); i++) { - - if (context.function->arguments[i] == p_symbol) { - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = context.function->line; - return OK; - } - } - } - - //guess in class constants - - for (int i = 0; i < context._class->constant_expressions.size(); i++) { - - if (context._class->constant_expressions[i].identifier == p_symbol) { + if (context.function && context.function->name != StringName()) { + // Lookup function arguments + for (int i = 0; i < context.function->arguments.size(); i++) { + if (context.function->arguments[i] == p_symbol) { r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = context._class->constant_expressions[i].expression->line; + r_result.location = context.function->line; return OK; } } + } - //guess in class variables - if (!(context.function && context.function->_static)) { - - for (int i = 0; i < context._class->variables.size(); i++) { - - if (context._class->variables[i].identifier == p_symbol) { - - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = context._class->variables[i].line; - return OK; - } - } - } + if (_lookup_symbol_from_base(base_type, p_symbol, is_function, r_result) == OK) { + return OK; + } - //guess in autoloads as singletons + if (!is_function) { + // Guess in autoloads as singletons List<PropertyInfo> props; ProjectSettings::get_singleton()->get_property_list(&props); @@ -2856,8 +3255,8 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol String script = path.substr(1, path.length()); if (!script.ends_with(".gd")) { - //not a script, try find the script anyway, - //may have some success + // Not a script, try find the script anyway, + // may have some success script = script.get_basename() + ".gd"; } @@ -2872,7 +3271,7 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol } } - //global + // Global Map<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map(); if (classes.has(p_symbol)) { Variant value = GDScriptLanguage::get_singleton()->get_global_array()[classes[p_symbol]]; @@ -2918,152 +3317,31 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol } } } - - } break; - case GDScriptParser::COMPLETION_PARENT_FUNCTION: { - } break; - case GDScriptParser::COMPLETION_METHOD: - isfunction = true; + case GDScriptParser::COMPLETION_METHOD: { + is_function = true; + } // fallthrough case GDScriptParser::COMPLETION_INDEX: { - - const GDScriptParser::Node *node = p.get_completion_node(); - if (node->type != GDScriptParser::Node::TYPE_OPERATOR) + const GDScriptParser::Node *node = parser.get_completion_node(); + if (node->type != GDScriptParser::Node::TYPE_OPERATOR) { + break; + } + GDScriptCompletionIdentifier base; + if (!_guess_expression_type(context, static_cast<const GDScriptParser::OperatorNode *>(node)->arguments[0], base)) { break; - - GDScriptCompletionIdentifier t; - if (_guess_expression_type(context, static_cast<const GDScriptParser::OperatorNode *>(node)->arguments[0], p.get_completion_line(), t)) { - - if (t.type == Variant::OBJECT && t.obj_type == "GDScriptNativeClass") { - //native enum - Ref<GDScriptNativeClass> gdn = t.value; - if (gdn.is_valid()) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; - r_result.class_name = gdn->get_name(); - r_result.class_member = p_symbol; - return OK; - } - } else if (t.type == Variant::OBJECT && t.obj_type != StringName()) { - - Ref<GDScript> on_script; - - if (t.value.get_type()) { - Object *obj = t.value; - - if (obj) { - - on_script = obj->get_script(); - - if (on_script.is_valid()) { - int loc = on_script->get_member_line(p_symbol); - if (loc >= 0) { - r_result.script = on_script; - r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION; - r_result.location = loc; - return OK; - } - } - } - } - - if (ClassDB::has_method(t.obj_type, p_symbol)) { - - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; - r_result.class_name = t.obj_type; - r_result.class_member = p_symbol; - return OK; - } - - StringName enumName = ClassDB::get_integer_constant_enum(t.obj_type, p_symbol, true); - if (enumName != StringName()) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_ENUM; - r_result.class_name = t.obj_type; - r_result.class_member = enumName; - return OK; - } - - bool success; - ClassDB::get_integer_constant(t.obj_type, p_symbol, &success); - if (success) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; - r_result.class_name = t.obj_type; - r_result.class_member = p_symbol; - return OK; - } - - ClassDB::get_property_type(t.obj_type, p_symbol, &success); - - if (success) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; - r_result.class_name = t.obj_type; - r_result.class_member = p_symbol; - return OK; - } - - } else { - - Variant::CallError ce; - Variant v = Variant::construct(t.type, NULL, 0, ce); - - bool valid; - v.get_numeric_constant_value(t.type, p_symbol, &valid); - if (valid) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; - r_result.class_name = Variant::get_type_name(t.type); - r_result.class_member = p_symbol; - return OK; - } - - //todo check all inputevent types for property - - v.get(p_symbol, &valid); - - if (valid) { - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY; - r_result.class_name = Variant::get_type_name(t.type); - r_result.class_member = p_symbol; - return OK; - } - - if (v.has_method(p_symbol)) { - - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; - r_result.class_name = Variant::get_type_name(t.type); - r_result.class_member = p_symbol; - return OK; - } - } } - } break; - case GDScriptParser::COMPLETION_CALL_ARGUMENTS: { - - return ERR_CANT_RESOLVE; + if (_lookup_symbol_from_base(base.type, p_symbol, is_function, r_result) == OK) { + return OK; + } } break; case GDScriptParser::COMPLETION_VIRTUAL_FUNC: { + GDScriptParser::DataType base_type = context._class->base_type; - GDScriptCompletionIdentifier cid = _get_native_class(context); - - if (cid.obj_type != StringName()) { - List<MethodInfo> vm; - ClassDB::get_virtual_methods(cid.obj_type, &vm); - for (List<MethodInfo>::Element *E = vm.front(); E; E = E->next()) { - - if (p_symbol == E->get().name) { - - r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_METHOD; - r_result.class_name = cid.obj_type; - r_result.class_member = p_symbol; - return OK; - } - } + if (_lookup_symbol_from_base(base_type, p_symbol, true, r_result) == OK) { + return OK; } } break; - case GDScriptParser::COMPLETION_YIELD: { - - return ERR_CANT_RESOLVE; - - } break; } return ERR_CANT_RESOLVE; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 10599f0c38..bae3f48923 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -62,7 +62,7 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta } #endif //member indexing is O(1) - return &p_instance->members[address]; + return &p_instance->members.write[address]; } break; case ADDR_TYPE_CLASS_CONSTANT: { @@ -200,6 +200,12 @@ static String _get_var_type(const Variant *p_type) { &&OPCODE_ASSIGN, \ &&OPCODE_ASSIGN_TRUE, \ &&OPCODE_ASSIGN_FALSE, \ + &&OPCODE_ASSIGN_TYPED_BUILTIN, \ + &&OPCODE_ASSIGN_TYPED_NATIVE, \ + &&OPCODE_ASSIGN_TYPED_SCRIPT, \ + &&OPCODE_CAST_TO_BUILTIN, \ + &&OPCODE_CAST_TO_NATIVE, \ + &&OPCODE_CAST_TO_SCRIPT, \ &&OPCODE_CONSTRUCT, \ &&OPCODE_CONSTRUCT_ARRAY, \ &&OPCODE_CONSTRUCT_DICTIONARY, \ @@ -318,10 +324,28 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a if (_stack_size) { stack = (Variant *)aptr; - for (int i = 0; i < p_argcount; i++) - memnew_placement(&stack[i], Variant(*p_args[i])); - for (int i = p_argcount; i < _stack_size; i++) + for (int i = 0; i < p_argcount; i++) { + if (!argument_types[i].has_type) { + memnew_placement(&stack[i], Variant(*p_args[i])); + continue; + } + + if (!argument_types[i].is_type(*p_args[i], true)) { + r_err.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_err.argument = i; + r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT; + return Variant(); + } + if (argument_types[i].kind == GDScriptDataType::BUILTIN) { + Variant arg = Variant::construct(argument_types[i].builtin_type, &p_args[i], 1, r_err); + memnew_placement(&stack[i], Variant(arg)); + } else { + memnew_placement(&stack[i], Variant(*p_args[i])); + } + } + for (int i = p_argcount; i < _stack_size; i++) { memnew_placement(&stack[i], Variant); + } } else { stack = NULL; } @@ -709,6 +733,215 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_ASSIGN_TYPED_BUILTIN) { + + CHECK_SPACE(4); + Variant::Type var_type = (Variant::Type)_code_ptr[ip + 1]; + GET_VARIANT_PTR(dst, 2); + GET_VARIANT_PTR(src, 3); + + GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX); + +#ifdef DEBUG_ENABLED + if (src->get_type() != var_type) { + if (Variant::can_convert_strict(src->get_type(), var_type)) { + Variant::CallError ce; + *dst = Variant::construct(var_type, const_cast<const Variant **>(&src), 1, ce); + } else { + err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + + "' to a variable of type '" + Variant::get_type_name(var_type) + "'."; + OPCODE_BREAK; + } + } else { +#endif // DEBUG_ENABLED + *dst = *src; +#ifdef DEBUG_ENABLED + } +#endif // DEBUG_ENABLED + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) { + + CHECK_SPACE(4); + GET_VARIANT_PTR(type, 1); + GET_VARIANT_PTR(dst, 2); + GET_VARIANT_PTR(src, 3); + +#ifdef DEBUG_ENABLED + GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *()); + GD_ERR_BREAK(!nc); + if (!src->get_type() != Variant::OBJECT && !src->get_type() != Variant::NIL) { + err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + + "' to a variable of type '" + nc->get_name() + "'."; + OPCODE_BREAK; + } + Object *src_obj = src->operator Object *(); + + if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) { + err_text = "Trying to assign value of type '" + src_obj->get_class_name() + + "' to a variable of type '" + nc->get_name() + "'."; + OPCODE_BREAK; + } +#endif // DEBUG_ENABLED + *dst = *src; + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_ASSIGN_TYPED_SCRIPT) { + + CHECK_SPACE(4); + GET_VARIANT_PTR(type, 1); + GET_VARIANT_PTR(dst, 2); + GET_VARIANT_PTR(src, 3); + +#ifdef DEBUG_ENABLED + Script *base_type = Object::cast_to<Script>(type->operator Object *()); + + GD_ERR_BREAK(!base_type); + + if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) { + err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'."; + OPCODE_BREAK; + } + + if (src->get_type() != Variant::NIL && src->operator Object *() != NULL) { + + ScriptInstance *scr_inst = src->operator Object *()->get_script_instance(); + if (!scr_inst) { + err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() + + "' to a variable of type '" + base_type->get_path().get_file() + "'."; + OPCODE_BREAK; + } + + Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr(); + bool valid = false; + + while (src_type) { + if (src_type == base_type) { + valid = true; + break; + } + src_type = src_type->get_base_script().ptr(); + } + + if (!valid) { + err_text = "Trying to assign value of type '" + src->operator Object *()->get_script_instance()->get_script()->get_path().get_file() + + "' to a variable of type '" + base_type->get_path().get_file() + "'."; + OPCODE_BREAK; + } + } +#endif // DEBUG_ENABLED + + *dst = *src; + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_CAST_TO_BUILTIN) { + + CHECK_SPACE(4); + Variant::Type to_type = (Variant::Type)_code_ptr[ip + 1]; + GET_VARIANT_PTR(src, 2); + GET_VARIANT_PTR(dst, 3); + + GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX); + + Variant::CallError err; + *dst = Variant::construct(to_type, (const Variant **)&src, 1, err); + +#ifdef DEBUG_ENABLED + if (err.error != Variant::CallError::CALL_OK) { + err_text = "Invalid cast: could not convert value to '" + Variant::get_type_name(to_type) + "'."; + OPCODE_BREAK; + } +#endif + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_CAST_TO_NATIVE) { + + CHECK_SPACE(4); + GET_VARIANT_PTR(to_type, 1); + GET_VARIANT_PTR(src, 2); + GET_VARIANT_PTR(dst, 3); + + GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(to_type->operator Object *()); + GD_ERR_BREAK(!nc); + +#ifdef DEBUG_ENABLED + if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) { + err_text = "Invalid cast: can't convert a non-object value to an object type."; + OPCODE_BREAK; + } +#endif + Object *src_obj = src->operator Object *(); + + if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) { + *dst = Variant(); // invalid cast, assign NULL + } else { + *dst = *src; + } + + ip += 4; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_CAST_TO_SCRIPT) { + + CHECK_SPACE(4); + GET_VARIANT_PTR(to_type, 1); + GET_VARIANT_PTR(src, 2); + GET_VARIANT_PTR(dst, 3); + + Script *base_type = Object::cast_to<Script>(to_type->operator Object *()); + + GD_ERR_BREAK(!base_type); + +#ifdef DEBUG_ENABLED + if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) { + err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'."; + OPCODE_BREAK; + } +#endif + + bool valid = false; + + if (src->get_type() != Variant::NIL && src->operator Object *() != NULL) { + + ScriptInstance *scr_inst = src->operator Object *()->get_script_instance(); + + if (scr_inst) { + + Script *src_type = src->operator Object *()->get_script_instance()->get_script().ptr(); + + while (src_type) { + if (src_type == base_type) { + valid = true; + break; + } + src_type = src_type->get_base_script().ptr(); + } + } + } + + if (valid) { + *dst = *src; // Valid cast, copy the source object + } else { + *dst = Variant(); // invalid cast, assign NULL + } + + ip += 4; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_CONSTRUCT) { CHECK_SPACE(2); @@ -1001,7 +1234,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a gdfs->state.stack.resize(alloca_size); //copy variant stack for (int i = 0; i < _stack_size; i++) { - memnew_placement(&gdfs->state.stack[sizeof(Variant) * i], Variant(stack[i])); + memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i])); } gdfs->state.stack_size = _stack_size; gdfs->state.self = self; @@ -1362,7 +1595,7 @@ StringName GDScriptFunction::get_global_name(int p_idx) const { int GDScriptFunction::get_default_argument_count() const { - return default_arguments.size(); + return _default_arg_count; } int GDScriptFunction::get_default_argument_addr(int p_idx) const { @@ -1370,6 +1603,15 @@ int GDScriptFunction::get_default_argument_addr(int p_idx) const { return default_arguments[p_idx]; } +GDScriptDataType GDScriptFunction::get_return_type() const { + return return_type; +} + +GDScriptDataType GDScriptFunction::get_argument_type(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, argument_types.size(), GDScriptDataType()); + return argument_types[p_idx]; +} + StringName GDScriptFunction::get_name() const { return name; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 770d5c8733..3ce84290fd 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -42,6 +42,95 @@ class GDScriptInstance; class GDScript; +struct GDScriptDataType { + bool has_type; + enum { + BUILTIN, + NATIVE, + SCRIPT, + GDSCRIPT + } kind; + Variant::Type builtin_type; + StringName native_type; + Ref<Script> script_type; + + bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const { + if (!has_type) return true; // Can't type check + + switch (kind) { + case BUILTIN: { + Variant::Type var_type = p_variant.get_type(); + bool valid = builtin_type == var_type; + if (!valid && p_allow_implicit_conversion) { + valid = Variant::can_convert_strict(var_type, builtin_type); + } + return valid; + } break; + case NATIVE: { + if (p_variant.get_type() == Variant::NIL) { + return true; + } + if (p_variant.get_type() != Variant::OBJECT) { + return false; + } + Object *obj = p_variant.operator Object *(); + if (obj && !ClassDB::is_parent_class(obj->get_class_name(), native_type)) { + return false; + } + return true; + } break; + case SCRIPT: + case GDSCRIPT: { + if (p_variant.get_type() == Variant::NIL) { + return true; + } + if (p_variant.get_type() != Variant::OBJECT) { + return false; + } + Object *obj = p_variant.operator Object *(); + Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : NULL; + bool valid = false; + while (base.is_valid()) { + if (base == script_type) { + valid = true; + break; + } + base = base->get_base_script(); + } + return valid; + } break; + } + return false; + } + + operator PropertyInfo() const { + PropertyInfo info; + if (has_type) { + switch (kind) { + case BUILTIN: { + info.type = builtin_type; + } break; + case NATIVE: { + info.type = Variant::OBJECT; + info.class_name = native_type; + } break; + case SCRIPT: + case GDSCRIPT: { + info.type = Variant::OBJECT; + info.class_name = script_type->get_instance_base_type(); + } break; + } + } else { + info.type = Variant::NIL; + info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + return info; + } + + GDScriptDataType() : + has_type(false) {} +}; + class GDScriptFunction { public: enum Opcode { @@ -56,6 +145,12 @@ public: OPCODE_ASSIGN, OPCODE_ASSIGN_TRUE, OPCODE_ASSIGN_FALSE, + OPCODE_ASSIGN_TYPED_BUILTIN, + OPCODE_ASSIGN_TYPED_NATIVE, + OPCODE_ASSIGN_TYPED_SCRIPT, + OPCODE_CAST_TO_BUILTIN, + OPCODE_CAST_TO_NATIVE, + OPCODE_CAST_TO_SCRIPT, OPCODE_CONSTRUCT, //only for basic types!! OPCODE_CONSTRUCT_ARRAY, OPCODE_CONSTRUCT_DICTIONARY, @@ -139,6 +234,8 @@ private: #endif Vector<int> default_arguments; Vector<int> code; + Vector<GDScriptDataType> argument_types; + GDScriptDataType return_type; #ifdef TOOLS_ENABLED Vector<StringName> arg_names; @@ -199,6 +296,8 @@ public: int get_max_stack_size() const; int get_default_argument_count() const; int get_default_argument_addr(int p_idx) const; + GDScriptDataType get_return_type() const; + GDScriptDataType get_argument_type(int p_idx) const; GDScript *get_script() const { return _script; } StringName get_source() const { return source; } diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp index ce91e7dff3..f2e52d48dd 100644 --- a/modules/gdscript/gdscript_functions.cpp +++ b/modules/gdscript/gdscript_functions.cpp @@ -1098,7 +1098,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_ for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) { if (d.has(E->key())) { - ins->members[E->get().index] = d[E->key()]; + ins->members.write[E->get().index] = d[E->key()]; } } @@ -1412,7 +1412,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) { MethodInfo GDScriptFunctions::get_info(Function p_func) { -#ifdef TOOLS_ENABLED +#ifdef DEBUG_ENABLED //using a switch, so the compiler generates a jumptable switch (p_func) { @@ -1663,7 +1663,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { MethodInfo mi("weakref", PropertyInfo(Variant::OBJECT, "obj")); mi.return_val.type = Variant::OBJECT; - mi.return_val.name = "WeakRef"; + mi.return_val.class_name = "WeakRef"; return mi; @@ -1672,19 +1672,20 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { MethodInfo mi("funcref", PropertyInfo(Variant::OBJECT, "instance"), PropertyInfo(Variant::STRING, "funcname")); mi.return_val.type = Variant::OBJECT; - mi.return_val.name = "FuncRef"; + mi.return_val.class_name = "FuncRef"; return mi; } break; case TYPE_CONVERT: { - MethodInfo mi("convert", PropertyInfo(Variant::NIL, "what"), PropertyInfo(Variant::INT, "type")); - mi.return_val.type = Variant::OBJECT; + MethodInfo mi("convert", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::INT, "type")); + mi.return_val.type = Variant::NIL; + mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; return mi; } break; case TYPE_OF: { - MethodInfo mi("typeof", PropertyInfo(Variant::NIL, "what")); + MethodInfo mi("typeof", PropertyInfo(Variant::NIL, "what", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::INT; return mi; @@ -1760,7 +1761,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case VAR_TO_STR: { - MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var")); + MethodInfo mi("var2str", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::STRING; return mi; @@ -1773,7 +1774,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case VAR_TO_BYTES: { - MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var")); + MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::POOL_BYTE_ARRAY; return mi; @@ -1796,7 +1797,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { MethodInfo mi("load", PropertyInfo(Variant::STRING, "path")); mi.return_val.type = Variant::OBJECT; - mi.return_val.name = "Resource"; + mi.return_val.class_name = "Resource"; return mi; } break; case INST2DICT: { @@ -1826,13 +1827,13 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { } break; case TO_JSON: { - MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var")); + MethodInfo mi("to_json", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::STRING; return mi; } break; case HASH: { - MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var")); + MethodInfo mi("hash", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::INT; return mi; } break; @@ -1868,7 +1869,7 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) { return mi; } break; case LEN: { - MethodInfo mi("len", PropertyInfo(Variant::NIL, "var")); + MethodInfo mi("len", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)); mi.return_val.type = Variant::INT; return mi; } break; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d62112d3f1..a0e58e3a37 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -30,6 +30,10 @@ #include "gdscript_parser.h" +#include "core/core_string_names.h" +#include "core/engine.h" +#include "core/project_settings.h" +#include "core/reference.h" #include "gdscript.h" #include "io/resource_loader.h" #include "os/file_access.h" @@ -138,8 +142,9 @@ bool GDScriptParser::_parse_arguments(Node *p_parent, Vector<Node *> &p_args, bo } Node *arg = _parse_expression(p_parent, p_static); - if (!arg) + if (!arg) { return false; + } p_args.push_back(arg); @@ -263,6 +268,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s bool need_identifier = true; bool done = false; + int line = tokenizer->get_token_line(); while (!done) { @@ -330,16 +336,19 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_CALL; - + op->line = line; op->arguments.push_back(alloc_node<SelfNode>()); + op->arguments[0]->line = line; IdentifierNode *funcname = alloc_node<IdentifierNode>(); funcname->name = "get_node"; - + funcname->line = line; op->arguments.push_back(funcname); ConstantNode *nodepath = alloc_node<ConstantNode>(); nodepath->value = NodePath(StringName(path)); + nodepath->datatype = _type_from_variant(nodepath->value); + nodepath->line = line; op->arguments.push_back(nodepath); expr = op; @@ -353,6 +362,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = tokenizer->get_token_constant(); + constant->datatype = _type_from_variant(constant->value); tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_PI) { @@ -360,6 +370,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_PI; + constant->datatype = _type_from_variant(constant->value); tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_TAU) { @@ -367,6 +378,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_TAU; + constant->datatype = _type_from_variant(constant->value); tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_INF) { @@ -374,6 +386,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_INF; + constant->datatype = _type_from_variant(constant->value); tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CONST_NAN) { @@ -381,6 +394,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //constant defined by tokenizer ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = Math_NAN; + constant->datatype = _type_from_variant(constant->value); tokenizer->advance(); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_PRELOAD) { @@ -419,15 +433,13 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (subexpr->type == Node::TYPE_IDENTIFIER) { IdentifierNode *in = static_cast<IdentifierNode *>(subexpr); - Vector<ClassNode::Constant> ce = current_class->constant_expressions; // Try to find the constant expression by the identifier - for (int i = 0; i < ce.size(); ++i) { - if (ce[i].identifier == in->name) { - if (ce[i].expression->type == Node::TYPE_CONSTANT) { - cn = static_cast<ConstantNode *>(ce[i].expression); - found_constant = true; - } + if (current_class->constant_expressions.has(in->name)) { + Node *cn_exp = current_class->constant_expressions[in->name].expression; + if (cn_exp->type == Node::TYPE_CONSTANT) { + cn = static_cast<ConstantNode *>(cn_exp); + found_constant = true; } } } @@ -480,15 +492,28 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s _set_error("Expected ')' after 'preload' path"); return NULL; } + + Ref<GDScript> gds = res; + if (gds.is_valid() && !gds->is_valid()) { + _set_error("Could not fully preload the script, possible cyclic reference or compilation error."); + return NULL; + } + tokenizer->advance(); ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = res; + constant->datatype = _type_from_variant(constant->value); expr = constant; } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_YIELD) { - //constant defined by tokenizer + if (!current_function) { + _set_error("yield() can only be used inside function blocks."); + return NULL; + } + + current_function->has_yield = true; tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { @@ -618,6 +643,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = Variant::get_numeric_constant_value(bi_type, identifier); + cn->datatype = _type_from_variant(cn->value); expr = cn; } @@ -695,24 +721,56 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s const ClassNode *cln = current_class; bool bfn = false; StringName identifier; + int id_line = tokenizer->get_token_line(); if (_get_completable_identifier(COMPLETION_IDENTIFIER, identifier)) { } - if (p_parsing_constant) { - for (int i = 0; i < cln->constant_expressions.size(); ++i) { - - if (cln->constant_expressions[i].identifier == identifier) { + BlockNode *b = current_block; + while (b) { + if (b->variables.has(identifier)) { + IdentifierNode *id = alloc_node<IdentifierNode>(); + LocalVarNode *lv = b->variables[identifier]; + id->name = identifier; + id->declared_block = b; + id->line = id_line; + expr = id; + bfn = true; - expr = cln->constant_expressions[i].expression; - bfn = true; - break; + switch (tokenizer->get_token()) { + case GDScriptTokenizer::TK_OP_ASSIGN_ADD: + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR: + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR: + case GDScriptTokenizer::TK_OP_ASSIGN_DIV: + case GDScriptTokenizer::TK_OP_ASSIGN_MOD: + case GDScriptTokenizer::TK_OP_ASSIGN_MUL: + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: + case GDScriptTokenizer::TK_OP_ASSIGN_SUB: { + if (lv->assignments == 0 && !lv->datatype.has_type) { + _set_error("Using assignment with operation on a variable that was never assigned."); + return NULL; + } + } // fallthrough + case GDScriptTokenizer::TK_OP_ASSIGN: { + lv->assignments += 1; + } } + break; } + b = b->parent_block; + } - if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { + if (!bfn && p_parsing_constant) { + if (cln->constant_expressions.has(identifier)) { + expr = cln->constant_expressions[identifier].expression; + bfn = true; + } else if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { //check from constants ConstantNode *constant = alloc_node<ConstantNode>(); constant->value = GDScriptLanguage::get_singleton()->get_global_array()[GDScriptLanguage::get_singleton()->get_global_map()[identifier]]; + constant->datatype = _type_from_variant(constant->value); + constant->line = id_line; expr = constant; bfn = true; } @@ -729,6 +787,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (!bfn) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = identifier; + id->line = id_line; expr = id; } @@ -902,6 +961,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //lua style identifier, easier to write ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = tokenizer->get_token_literal(); + cn->datatype = _type_from_variant(cn->value); key = cn; tokenizer->advance(2); expecting = DICT_EXPECT_VALUE; @@ -941,7 +1001,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = dict; - } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PERIOD && (tokenizer->is_token_literal(1) || tokenizer->get_token(1) == GDScriptTokenizer::TK_CURSOR) && tokenizer->get_token(2) == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_PERIOD && (tokenizer->is_token_literal(1) || tokenizer->get_token(1) == GDScriptTokenizer::TK_CURSOR)) { // We check with is_token_literal, as this allows us to use match/sync/etc. as a name // parent call @@ -953,17 +1013,23 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->arguments.push_back(self); forbidden for now */ StringName identifier; - if (_get_completable_identifier(COMPLETION_PARENT_FUNCTION, identifier)) { - //indexing stuff - } + bool is_completion = _get_completable_identifier(COMPLETION_PARENT_FUNCTION, identifier) && for_completion; IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = identifier; op->arguments.push_back(id); - tokenizer->advance(1); - if (!_parse_arguments(op, op->arguments, p_static)) - return NULL; + if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { + if (!is_completion) { + _set_error("Expected '(' for parent function call."); + return NULL; + } + } else { + tokenizer->advance(); + if (!_parse_arguments(op, op->arguments, p_static)) { + return NULL; + } + } expr = op; @@ -1087,6 +1153,26 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s break; } + /*****************/ + /* Parse Casting */ + /*****************/ + + bool has_casting = expr->type == Node::TYPE_CAST; + if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_AS) { + if (has_casting) { + _set_error("Unexpected 'as'."); + return NULL; + } + CastNode *cn = alloc_node<CastNode>(); + if (!_parse_type(cn->cast_type)) { + _set_error("Expected type after 'as'."); + return NULL; + } + has_casting = true; + cn->source_node = expr; + expr = cn; + } + /******************/ /* Parse Operator */ /******************/ @@ -1110,7 +1196,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s //assign, if allowed is only allowed on the first operator #define _VALIDATE_ASSIGN \ - if (!p_allow_assign) { \ + if (!p_allow_assign || has_casting) { \ _set_error("Unexpected assign."); \ return NULL; \ } \ @@ -1325,8 +1411,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->op = expression[i].op; op->arguments.push_back(expression[i + 1].node); op->line = op_line; //line might have been changed from a \n - expression[i].is_op = false; - expression[i].node = op; + expression.write[i].is_op = false; + expression.write[i].node = op; expression.remove(i + 1); } @@ -1338,11 +1424,11 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s if (next_op >= (expression.size() - 2) || expression[next_op + 2].op != OperatorNode::OP_TERNARY_ELSE) { _set_error("Expected else after ternary if."); - ERR_FAIL_V(NULL); + return NULL; } if (next_op >= (expression.size() - 3)) { _set_error("Expected value after ternary else."); - ERR_FAIL_V(NULL); + return NULL; } OperatorNode *op = alloc_node<OperatorNode>(); @@ -1380,7 +1466,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->arguments.push_back(expression[next_op + 3].node); //expression after next goes as when-false //replace all 3 nodes by this operator and make it an expression - expression[next_op - 1].node = op; + expression.write[next_op - 1].node = op; expression.remove(next_op); expression.remove(next_op); expression.remove(next_op); @@ -1416,7 +1502,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s op->arguments.push_back(expression[next_op + 1].node); //next expression goes as right //replace all 3 nodes by this operator and make it an expression - expression[next_op - 1].node = op; + expression.write[next_op - 1].node = op; expression.remove(next_op); expression.remove(next_op); } @@ -1440,7 +1526,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to for (int i = 0; i < an->elements.size(); i++) { - an->elements[i] = _reduce_expression(an->elements[i], p_to_const); + an->elements.write[i] = _reduce_expression(an->elements[i], p_to_const); if (an->elements[i]->type != Node::TYPE_CONSTANT) all_constants = false; } @@ -1450,13 +1536,13 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to ConstantNode *cn = alloc_node<ConstantNode>(); Array arr; - //print_line("mk array "+itos(!p_to_const)); arr.resize(an->elements.size()); for (int i = 0; i < an->elements.size(); i++) { ConstantNode *acn = static_cast<ConstantNode *>(an->elements[i]); arr[i] = acn->value; } cn->value = arr; + cn->datatype = _type_from_variant(cn->value); return cn; } @@ -1470,10 +1556,10 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to for (int i = 0; i < dn->elements.size(); i++) { - dn->elements[i].key = _reduce_expression(dn->elements[i].key, p_to_const); + dn->elements.write[i].key = _reduce_expression(dn->elements[i].key, p_to_const); if (dn->elements[i].key->type != Node::TYPE_CONSTANT) all_constants = false; - dn->elements[i].value = _reduce_expression(dn->elements[i].value, p_to_const); + dn->elements.write[i].value = _reduce_expression(dn->elements[i].value, p_to_const); if (dn->elements[i].value->type != Node::TYPE_CONSTANT) all_constants = false; } @@ -1490,6 +1576,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to dict[key_c->value] = value_c->value; } cn->value = dict; + cn->datatype = _type_from_variant(cn->value); return cn; } @@ -1505,7 +1592,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to for (int i = 0; i < op->arguments.size(); i++) { - op->arguments[i] = _reduce_expression(op->arguments[i], p_to_const); + op->arguments.write[i] = _reduce_expression(op->arguments[i], p_to_const); if (op->arguments[i]->type != Node::TYPE_CONSTANT) { all_constants = false; last_not_constant = i; @@ -1533,7 +1620,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to for (int i = 0; i < ptrs.size(); i++) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i + 1]); - ptrs[i] = &cn->value; + ptrs.write[i] = &cn->value; } vptr = (const Variant **)&ptrs[0]; @@ -1591,6 +1678,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = v; + cn->datatype = _type_from_variant(v); return cn; } else if (op->arguments[0]->type == Node::TYPE_BUILT_IN_FUNCTION && last_not_constant == 0) { @@ -1620,24 +1708,9 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = v; + cn->datatype = _type_from_variant(v); return cn; - - } /*else if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) { - - ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]); - IdentifierNode *ib = static_cast<IdentifierNode*>(op->arguments[1]); - - bool valid; - Variant v = ca->value.get_named(ib->name,&valid); - if (!valid) { - _set_error("invalid index '"+String(ib->name)+"' in constant expression"); - return op; - } - - ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value=v; - return cn; - }*/ + } return op; @@ -1658,13 +1731,14 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = v; + cn->datatype = _type_from_variant(v); return cn; } return op; } - //validate assignment (don't assign to cosntant expression + //validate assignment (don't assign to constant expression switch (op->op) { case OperatorNode::OP_ASSIGN: @@ -1711,6 +1785,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } \ ConstantNode *cn = alloc_node<ConstantNode>(); \ cn->value = res; \ + cn->datatype = _type_from_variant(res); \ return cn; #define _REDUCE_BINARY(m_vop) \ @@ -1724,6 +1799,7 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to } \ ConstantNode *cn = alloc_node<ConstantNode>(); \ cn->value = res; \ + cn->datatype = _type_from_variant(res); \ return cn; switch (op->op) { @@ -1799,6 +1875,13 @@ GDScriptParser::Node *GDScriptParser::_reduce_expression(Node *p_node, bool p_to case OperatorNode::OP_BIT_XOR: { _REDUCE_BINARY(Variant::OP_BIT_XOR); } break; + case OperatorNode::OP_TERNARY_IF: { + if (static_cast<ConstantNode *>(op->arguments[0])->value.booleanize()) { + return op->arguments[1]; + } else { + return op->arguments[2]; + } + } break; default: { ERR_FAIL_V(op); } } @@ -1905,6 +1988,15 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) { tokenizer->advance(); pattern->pt_type = GDScriptParser::PatternNode::PT_BIND; pattern->bind = tokenizer->get_token_identifier(); + // Check if binding is already used + if (current_block->variables.has(pattern->bind)) { + _set_error("Binding name of '" + pattern->bind.operator String() + "' was already used in the pattern."); + return NULL; + } + // Create local variable for proper identifier detection later + LocalVarNode *lv = alloc_node<LocalVarNode>(); + lv->name = pattern->bind; + current_block->variables.insert(lv->name, lv); tokenizer->advance(); } break; // dictionary @@ -2038,18 +2130,34 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran } PatternBranchNode *branch = alloc_node<PatternBranchNode>(); + branch->body = alloc_node<BlockNode>(); + branch->body->parent_block = p_block; + p_block->sub_blocks.push_back(branch->body); + current_block = branch->body; branch->patterns.push_back(_parse_pattern(p_static)); if (!branch->patterns[0]) { return; } + bool has_binding = branch->patterns[0]->pt_type == PatternNode::PT_BIND; + bool catch_all = has_binding || branch->patterns[0]->pt_type == PatternNode::PT_WILDCARD; + while (tokenizer->get_token() == GDScriptTokenizer::TK_COMMA) { tokenizer->advance(); branch->patterns.push_back(_parse_pattern(p_static)); if (!branch->patterns[branch->patterns.size() - 1]) { return; } + + PatternNode::PatternType pt = branch->patterns[branch->patterns.size() - 1]->pt_type; + + if (pt == PatternNode::PT_BIND) { + _set_error("Cannot use bindings with multipattern."); + return; + } + + catch_all = catch_all || pt == PatternNode::PT_WILDCARD; } if (!_enter_indent_block()) { @@ -2057,54 +2165,76 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran return; } - branch->body = alloc_node<BlockNode>(); - branch->body->parent_block = p_block; - p_block->sub_blocks.push_back(branch->body); - current_block = branch->body; - _parse_block(branch->body, p_static); current_block = p_block; + if (catch_all && branch->body->has_return) { + p_block->has_return = true; + } + p_branches.push_back(branch); } } void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node *> &p_bindings) { + + const DataType &to_match_type = p_node_to_match->get_datatype(); + switch (p_pattern->pt_type) { case PatternNode::PT_CONSTANT: { - // typecheck - BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); - typeof_node->function = GDScriptFunctions::TYPE_OF; + DataType pattern_type = _reduce_node_type(p_pattern->constant); + if (error_set) { + return; + } - OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); - typeof_match_value->op = OperatorNode::OP_CALL; - typeof_match_value->arguments.push_back(typeof_node); - typeof_match_value->arguments.push_back(p_node_to_match); + OperatorNode *type_comp = NULL; - OperatorNode *typeof_pattern_value = alloc_node<OperatorNode>(); - typeof_pattern_value->op = OperatorNode::OP_CALL; - typeof_pattern_value->arguments.push_back(typeof_node); - typeof_pattern_value->arguments.push_back(p_pattern->constant); + // static type check if possible + if (pattern_type.has_type && to_match_type.has_type) { + if (!_is_type_compatible(to_match_type, pattern_type) && !_is_type_compatible(pattern_type, to_match_type)) { + _set_error("Pattern type (" + pattern_type.to_string() + ") is not compatible with the type of the value to match (" + to_match_type.to_string() + ").", + p_pattern->line); + return; + } + } else { + // runtime typecheck + BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); + typeof_node->function = GDScriptFunctions::TYPE_OF; - OperatorNode *type_comp = alloc_node<OperatorNode>(); - type_comp->op = OperatorNode::OP_EQUAL; - type_comp->arguments.push_back(typeof_match_value); - type_comp->arguments.push_back(typeof_pattern_value); + OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); + typeof_match_value->op = OperatorNode::OP_CALL; + typeof_match_value->arguments.push_back(typeof_node); + typeof_match_value->arguments.push_back(p_node_to_match); + + OperatorNode *typeof_pattern_value = alloc_node<OperatorNode>(); + typeof_pattern_value->op = OperatorNode::OP_CALL; + typeof_pattern_value->arguments.push_back(typeof_node); + typeof_pattern_value->arguments.push_back(p_pattern->constant); + + type_comp = alloc_node<OperatorNode>(); + type_comp->op = OperatorNode::OP_EQUAL; + type_comp->arguments.push_back(typeof_match_value); + type_comp->arguments.push_back(typeof_pattern_value); + } - // comare the actual values + // compare the actual values OperatorNode *value_comp = alloc_node<OperatorNode>(); value_comp->op = OperatorNode::OP_EQUAL; value_comp->arguments.push_back(p_pattern->constant); value_comp->arguments.push_back(p_node_to_match); - OperatorNode *comparison = alloc_node<OperatorNode>(); - comparison->op = OperatorNode::OP_AND; - comparison->arguments.push_back(type_comp); - comparison->arguments.push_back(value_comp); + if (type_comp) { + OperatorNode *full_comparison = alloc_node<OperatorNode>(); + full_comparison->op = OperatorNode::OP_AND; + full_comparison->arguments.push_back(type_comp); + full_comparison->arguments.push_back(value_comp); - p_resulting_node = comparison; + p_resulting_node = full_comparison; + } else { + p_resulting_node = value_comp; + } } break; case PatternNode::PT_BIND: { @@ -2129,22 +2259,32 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() == length { - // typecheck - BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); - typeof_node->function = GDScriptFunctions::TYPE_OF; - - OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); - typeof_match_value->op = OperatorNode::OP_CALL; - typeof_match_value->arguments.push_back(typeof_node); - typeof_match_value->arguments.push_back(p_node_to_match); - - IdentifierNode *typeof_array = alloc_node<IdentifierNode>(); - typeof_array->name = "TYPE_ARRAY"; - - OperatorNode *type_comp = alloc_node<OperatorNode>(); - type_comp->op = OperatorNode::OP_EQUAL; - type_comp->arguments.push_back(typeof_match_value); - type_comp->arguments.push_back(typeof_array); + OperatorNode *type_comp = NULL; + // static type check if possible + if (to_match_type.has_type) { + // must be an array + if (to_match_type.kind != DataType::BUILTIN || to_match_type.builtin_type != Variant::ARRAY) { + _set_error("Cannot match an array pattern with a non-array expression.", p_pattern->line); + return; + } + } else { + // runtime typecheck + BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); + typeof_node->function = GDScriptFunctions::TYPE_OF; + + OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); + typeof_match_value->op = OperatorNode::OP_CALL; + typeof_match_value->arguments.push_back(typeof_node); + typeof_match_value->arguments.push_back(p_node_to_match); + + IdentifierNode *typeof_array = alloc_node<IdentifierNode>(); + typeof_array->name = "TYPE_ARRAY"; + + type_comp = alloc_node<OperatorNode>(); + type_comp->op = OperatorNode::OP_EQUAL; + type_comp->arguments.push_back(typeof_match_value); + type_comp->arguments.push_back(typeof_array); + } // size ConstantNode *length = alloc_node<ConstantNode>(); @@ -2163,12 +2303,16 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m length_comparison->arguments.push_back(call); length_comparison->arguments.push_back(length); - OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>(); - type_and_length_comparison->op = OperatorNode::OP_AND; - type_and_length_comparison->arguments.push_back(type_comp); - type_and_length_comparison->arguments.push_back(length_comparison); + if (type_comp) { + OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>(); + type_and_length_comparison->op = OperatorNode::OP_AND; + type_and_length_comparison->arguments.push_back(type_comp); + type_and_length_comparison->arguments.push_back(length_comparison); - p_resulting_node = type_and_length_comparison; + p_resulting_node = type_and_length_comparison; + } else { + p_resulting_node = length_comparison; + } } for (int i = 0; i < p_pattern->array.size(); i++) { @@ -2208,22 +2352,32 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m // typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() == length { - // typecheck - BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); - typeof_node->function = GDScriptFunctions::TYPE_OF; - - OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); - typeof_match_value->op = OperatorNode::OP_CALL; - typeof_match_value->arguments.push_back(typeof_node); - typeof_match_value->arguments.push_back(p_node_to_match); - - IdentifierNode *typeof_dictionary = alloc_node<IdentifierNode>(); - typeof_dictionary->name = "TYPE_DICTIONARY"; - - OperatorNode *type_comp = alloc_node<OperatorNode>(); - type_comp->op = OperatorNode::OP_EQUAL; - type_comp->arguments.push_back(typeof_match_value); - type_comp->arguments.push_back(typeof_dictionary); + OperatorNode *type_comp = NULL; + // static type check if possible + if (to_match_type.has_type) { + // must be an dictionary + if (to_match_type.kind != DataType::BUILTIN || to_match_type.builtin_type != Variant::DICTIONARY) { + _set_error("Cannot match an dictionary pattern with a non-dictionary expression.", p_pattern->line); + return; + } + } else { + // runtime typecheck + BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>(); + typeof_node->function = GDScriptFunctions::TYPE_OF; + + OperatorNode *typeof_match_value = alloc_node<OperatorNode>(); + typeof_match_value->op = OperatorNode::OP_CALL; + typeof_match_value->arguments.push_back(typeof_node); + typeof_match_value->arguments.push_back(p_node_to_match); + + IdentifierNode *typeof_dictionary = alloc_node<IdentifierNode>(); + typeof_dictionary->name = "TYPE_DICTIONARY"; + + type_comp = alloc_node<OperatorNode>(); + type_comp->op = OperatorNode::OP_EQUAL; + type_comp->arguments.push_back(typeof_match_value); + type_comp->arguments.push_back(typeof_dictionary); + } // size ConstantNode *length = alloc_node<ConstantNode>(); @@ -2242,12 +2396,16 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m length_comparison->arguments.push_back(call); length_comparison->arguments.push_back(length); - OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>(); - type_and_length_comparison->op = OperatorNode::OP_AND; - type_and_length_comparison->arguments.push_back(type_comp); - type_and_length_comparison->arguments.push_back(length_comparison); + if (type_comp) { + OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>(); + type_and_length_comparison->op = OperatorNode::OP_AND; + type_and_length_comparison->arguments.push_back(type_comp); + type_and_length_comparison->arguments.push_back(length_comparison); - p_resulting_node = type_and_length_comparison; + p_resulting_node = type_and_length_comparison; + } else { + p_resulting_node = length_comparison; + } } for (Map<ConstantNode *, PatternNode *>::Element *e = p_pattern->dictionary.front(); e; e = e->next()) { @@ -2308,9 +2466,20 @@ void GDScriptParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_m } } -void GDScriptParser::_transform_match_statment(BlockNode *p_block, MatchNode *p_match_statement) { +void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = "#match_value"; + id->line = p_match_statement->line; + id->datatype = _reduce_node_type(p_match_statement->val_to_match); + if (id->datatype.has_type) { + _mark_line_as_safe(id->line); + } else { + _mark_line_as_unsafe(id->line); + } + + if (error_set) { + return; + } for (int i = 0; i < p_match_statement->branches.size(); i++) { @@ -2323,11 +2492,16 @@ void GDScriptParser::_transform_match_statment(BlockNode *p_block, MatchNode *p_ for (int j = 0; j < branch->patterns.size(); j++) { PatternNode *pattern = branch->patterns[j]; + _mark_line_as_safe(pattern->line); Map<StringName, Node *> bindings; - Node *resulting_node; + Node *resulting_node = NULL; _generate_pattern(pattern, id, resulting_node, bindings); + if (!resulting_node) { + return; + } + if (!binding.empty() && !bindings.empty()) { _set_error("Multipatterns can't contain bindings"); return; @@ -2335,6 +2509,14 @@ void GDScriptParser::_transform_match_statment(BlockNode *p_block, MatchNode *p_ binding = bindings; } + // Result is always a boolean + DataType resulting_node_type; + resulting_node_type.has_type = true; + resulting_node_type.is_constant = true; + resulting_node_type.kind = DataType::BUILTIN; + resulting_node_type.builtin_type = Variant::BOOL; + resulting_node->set_datatype(resulting_node_type); + if (compiled_branch.compiled_pattern) { OperatorNode *or_node = alloc_node<OperatorNode>(); or_node->op = OperatorNode::OP_OR; @@ -2350,12 +2532,19 @@ void GDScriptParser::_transform_match_statment(BlockNode *p_block, MatchNode *p_ // prepare the body ...hehe for (Map<StringName, Node *>::Element *e = binding.front(); e; e = e->next()) { - LocalVarNode *local_var = alloc_node<LocalVarNode>(); - local_var->name = e->key(); + if (!branch->body->variables.has(e->key())) { + _set_error("Parser bug: missing pattern bind variable.", branch->line); + ERR_FAIL(); + } + + LocalVarNode *local_var = branch->body->variables[e->key()]; local_var->assign = e->value(); + local_var->set_datatype(local_var->assign->get_datatype()); IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = local_var->name; + id->declared_block = branch->body; + id->set_datatype(local_var->assign->get_datatype()); OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_ASSIGN; @@ -2413,7 +2602,21 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } switch (token) { - + case GDScriptTokenizer::TK_EOF: + case GDScriptTokenizer::TK_ERROR: + case GDScriptTokenizer::TK_NEWLINE: + case GDScriptTokenizer::TK_CF_PASS: { + // will check later + } break; + default: { + // TODO: Make this a warning + /*if (p_block->has_return) { + _set_error("Unreacheable code."); + return; + }*/ + } break; + } + switch (token) { case GDScriptTokenizer::TK_EOF: p_block->end_line = tokenizer->get_token_line(); case GDScriptTokenizer::TK_ERROR: { @@ -2443,6 +2646,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { _set_error("Expected ';' or <NewLine>."); return; } + _mark_line_as_safe(tokenizer->get_token_line()); tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_SEMICOLON) { // Ignore semicolon after 'pass' @@ -2453,6 +2657,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { //variale declaration and (eventual) initialization tokenizer->advance(); + int var_line = tokenizer->get_token_line(); if (!tokenizer->is_token_literal(0, true)) { _set_error("Expected identifier for local variable name."); @@ -2470,24 +2675,34 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } BlockNode *check_block = p_block; while (check_block) { - for (int i = 0; i < check_block->variables.size(); i++) { - if (n == check_block->variables[i]) { - _set_error("Variable '" + String(n) + "' already defined in the scope (at line: " + itos(check_block->variable_lines[i]) + ")."); - return; - } + if (check_block->variables.has(n)) { + _set_error("Variable '" + String(n) + "' already defined in the scope (at line: " + itos(check_block->variables[n]->line) + ")."); + return; } check_block = check_block->parent_block; } - int var_line = tokenizer->get_token_line(); - //must know when the local variable is declared LocalVarNode *lv = alloc_node<LocalVarNode>(); lv->name = n; + lv->line = var_line; p_block->statements.push_back(lv); Node *assigned = NULL; + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + lv->datatype = DataType(); +#ifdef DEBUG_ENABLED + lv->datatype.infer_type = true; +#endif + tokenizer->advance(); + } else if (!_parse_type(lv->datatype)) { + _set_error("Expected type for variable."); + return; + } + } + if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { tokenizer->advance(); @@ -2499,26 +2714,36 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } - lv->assign = subexpr; + lv->assignments++; assigned = subexpr; } else { ConstantNode *c = alloc_node<ConstantNode>(); - c->value = Variant(); + if (lv->datatype.has_type && lv->datatype.kind == DataType::BUILTIN) { + Variant::CallError err; + c->value = Variant::construct(lv->datatype.builtin_type, NULL, 0, err); + } else { + c->value = Variant(); + } + c->line = var_line; assigned = c; } //must be added later, to avoid self-referencing. - p_block->variables.push_back(n); //line? - p_block->variable_lines.push_back(var_line); + p_block->variables.insert(n, lv); IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = n; + id->declared_block = p_block; + id->line = var_line; OperatorNode *op = alloc_node<OperatorNode>(); op->op = OperatorNode::OP_ASSIGN; op->arguments.push_back(id); op->arguments.push_back(assigned); + op->line = var_line; p_block->statements.push_back(op); + lv->assign_op = op; + lv->assign = assigned; if (!_end_statement()) { _set_error("Expected end of statement (var)"); @@ -2563,6 +2788,9 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; p_block->statements.push_back(cf_if); + bool all_have_return = cf_if->body->has_return; + bool have_else = false; + while (true) { while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline()) @@ -2619,6 +2847,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { if (error_set) return; + all_have_return = all_have_return && cf_else->body->has_return; + } else if (tokenizer->get_token() == GDScriptTokenizer::TK_CF_ELSE) { if (tab_level.back()->get() > indent_level) { @@ -2642,12 +2872,19 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { if (error_set) return; + all_have_return = all_have_return && cf_if->body_else->has_return; + have_else = true; + break; //after else, exit } else break; } + cf_if->body->has_return = all_have_return; + // If there's no else block, path out of the if might not have a return + p_block->has_return = all_have_return && have_else; + } break; case GDScriptTokenizer::TK_CF_WHILE: { @@ -2680,6 +2917,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { current_block = p_block; if (error_set) return; + p_block->has_return = cf_while->body->has_return; p_block->statements.push_back(cf_while); } break; case GDScriptTokenizer::TK_CF_FOR: { @@ -2711,6 +2949,9 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } + DataType iter_type; + iter_type.is_constant = true; + if (container->type == Node::TYPE_OPERATOR) { OperatorNode *op = static_cast<OperatorNode *>(container); @@ -2745,6 +2986,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { case 2: cn->value = Vector2(constants[0], constants[1]); break; case 3: cn->value = Vector3(constants[0], constants[1], constants[2]); break; } + cn->datatype = _type_from_variant(cn->value); container = cn; } else { OperatorNode *on = alloc_node<OperatorNode>(); @@ -2766,6 +3008,10 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { container = on; } } + + iter_type.has_type = true; + iter_type.kind = DataType::BUILTIN; + iter_type.builtin_type = Variant::INT; } } @@ -2789,15 +3035,20 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { // this is for checking variable for redefining // inside this _parse_block - cf_for->body->variables.push_back(id->name); - cf_for->body->variable_lines.push_back(id->line); + LocalVarNode *lv = alloc_node<LocalVarNode>(); + lv->name = id->name; + lv->line = id->line; + lv->assignments++; + id->declared_block = cf_for->body; + lv->set_datatype(iter_type); + id->set_datatype(iter_type); + cf_for->body->variables.insert(id->name, lv); _parse_block(cf_for->body, p_static); - cf_for->body->variables.remove(0); - cf_for->body->variable_lines.remove(0); current_block = p_block; if (error_set) return; + p_block->has_return = cf_for->body->has_return; p_block->statements.push_back(cf_for); } break; case GDScriptTokenizer::TK_CF_CONTINUE: { @@ -2827,6 +3078,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { tokenizer->advance(); ControlFlowNode *cf_return = alloc_node<ControlFlowNode>(); cf_return->cf_type = ControlFlowNode::CF_RETURN; + cf_return->line = tokenizer->get_token_line(-1); if (tokenizer->get_token() == GDScriptTokenizer::TK_SEMICOLON || tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE || tokenizer->get_token() == GDScriptTokenizer::TK_EOF) { //expect end of statement @@ -2850,6 +3102,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { return; } } + p_block->has_return = true; } break; case GDScriptTokenizer::TK_CF_MATCH: { @@ -2882,12 +3135,14 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { _parse_pattern_block(compiled_branches, match_node->branches, p_static); - _transform_match_statment(compiled_branches, match_node); + if (error_set) return; ControlFlowNode *match_cf_node = alloc_node<ControlFlowNode>(); match_cf_node->cf_type = ControlFlowNode::CF_MATCH; match_cf_node->match = match_node; + match_cf_node->body = compiled_branches; + p_block->has_return = p_block->has_return || compiled_branches->has_return; p_block->statements.push_back(match_cf_node); _end_statement(); @@ -2938,16 +3193,6 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { } } break; - /* - case GDScriptTokenizer::TK_CF_LOCAL: { - - if (tokenizer->get_token(1)!=GDScriptTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDScriptTokenizer::TK_NEWLINE ) { - - _set_error("Expected ';' or <NewLine>."); - } - tokenizer->advance(); - } break; - */ } } } @@ -3087,6 +3332,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { switch (token) { + case GDScriptTokenizer::TK_CURSOR: { + tokenizer->advance(); + } break; case GDScriptTokenizer::TK_EOF: p_class->end_line = tokenizer->get_token_line(); case GDScriptTokenizer::TK_ERROR: { @@ -3103,6 +3351,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } break; case GDScriptTokenizer::TK_PR_EXTENDS: { + _mark_line_as_safe(tokenizer->get_token_line()); _parse_extends(p_class); if (error_set) return; @@ -3131,6 +3380,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } + if (ClassDB::class_exists(p_class->name)) { + _set_error("Class '" + p_class->name + "' shadows a native class."); + return; + } + tokenizer->advance(2); } break; @@ -3150,7 +3404,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { //class inside class :D StringName name; - StringName extends; if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) { @@ -3160,10 +3413,30 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { name = tokenizer->get_token_identifier(1); tokenizer->advance(2); + // Check if name is shadowing something else + if (ClassDB::class_exists(name) || ClassDB::class_exists("_" + name.operator String())) { + _set_error("Class '" + String(name) + "' shadows a native class."); + return; + } if (ScriptServer::is_global_class(name)) { _set_error("Can't override name of unique global class '" + name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name)); return; } + ClassNode *outer_class = p_class; + while (outer_class) { + for (int i = 0; i < outer_class->subclasses.size(); i++) { + if (outer_class->subclasses[i]->name == name) { + _set_error("Another class named '" + String(name) + "' already exists in this scope (at line " + itos(outer_class->subclasses[i]->line) + ")."); + return; + } + } + if (outer_class->constant_expressions.has(name)) { + _set_error("A constant named '" + String(name) + "' already exists in the outer class scope (at line" + itos(outer_class->constant_expressions[name].expression->line) + ")."); + return; + } + + outer_class = outer_class->owner; + } ClassNode *newclass = alloc_node<ClassNode>(); newclass->initializer = alloc_node<BlockNode>(); @@ -3249,6 +3522,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); Vector<StringName> arguments; + Vector<DataType> argument_types; Vector<Node *> default_values; int fnline = tokenizer->get_token_line(); @@ -3279,6 +3553,18 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); + DataType argtype; + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + argtype.infer_type = true; + tokenizer->advance(); + } else if (!_parse_type(argtype)) { + _set_error("Expected type for argument."); + return; + } + } + argument_types.push_back(argtype); + if (defaulting && tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) { _set_error("Default parameter expected."); @@ -3296,9 +3582,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { OperatorNode *on = alloc_node<OperatorNode>(); on->op = OperatorNode::OP_ASSIGN; + on->line = fnline; IdentifierNode *in = alloc_node<IdentifierNode>(); in->name = argname; + in->line = fnline; on->arguments.push_back(in); on->arguments.push_back(defval); @@ -3335,6 +3623,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (name == "_init") { + if (_static) { + _set_error("Constructor cannot be static."); + return; + } + if (p_class->extends_used) { OperatorNode *cparent = alloc_node<OperatorNode>(); @@ -3349,6 +3642,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { tokenizer->advance(); if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { _set_error("expected '(' for parent constructor arguments."); + return; } tokenizer->advance(); @@ -3386,6 +3680,15 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } + DataType return_type; + if (tokenizer->get_token() == GDScriptTokenizer::TK_FORWARD_ARROW) { + + if (!_parse_type(return_type, true)) { + _set_error("Expected return type for function."); + return; + } + } + if (!_enter_indent_block(block)) { _set_error("Indented block expected."); @@ -3394,7 +3697,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { FunctionNode *function = alloc_node<FunctionNode>(); function->name = name; + function->return_type = return_type; function->arguments = arguments; + function->argument_types = argument_types; function->default_values = default_values; function->_static = _static; function->line = fnline; @@ -3888,6 +4193,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; current_export.hint_string = native_class->get_name(); + current_export.class_name = native_class->get_name(); } else { current_export = PropertyInfo(); @@ -4109,10 +4415,37 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member.line = tokenizer->get_token_line(); member.rpc_mode = rpc_mode; + if (current_class->constant_expressions.has(member.identifier)) { + _set_error("A constant named '" + String(member.identifier) + "' alread exists in this class (at line: " + + itos(current_class->constant_expressions[member.identifier].expression->line) + ")."); + return; + } + + for (int i = 0; i < current_class->variables.size(); i++) { + if (current_class->variables[i].identifier == member.identifier) { + _set_error("Variable '" + String(member.identifier) + "' alread exists in this class (at line: " + + itos(current_class->variables[i].line) + ")."); + return; + } + } + tokenizer->advance(); rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + member.data_type = DataType(); +#ifdef DEBUG_ENABLED + member.data_type.infer_type = true; +#endif + tokenizer->advance(); + } else if (!_parse_type(member.data_type)) { + _set_error("Expected type for class variable."); + return; + } + } + if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) { #ifdef DEBUG_ENABLED @@ -4144,42 +4477,31 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member.expression = subexpr; - if (autoexport) { - if (1) /*(subexpr->type==Node::TYPE_ARRAY) { - - member._export.type=Variant::ARRAY; - - } else if (subexpr->type==Node::TYPE_DICTIONARY) { - - member._export.type=Variant::DICTIONARY; + if (autoexport && !member.data_type.has_type) { - } else*/ - { - - if (subexpr->type != Node::TYPE_CONSTANT) { + if (subexpr->type != Node::TYPE_CONSTANT) { - _set_error("Type-less export needs a constant expression assigned to infer type."); - return; - } + _set_error("Type-less export needs a constant expression assigned to infer type."); + return; + } - ConstantNode *cn = static_cast<ConstantNode *>(subexpr); - if (cn->value.get_type() == Variant::NIL) { + ConstantNode *cn = static_cast<ConstantNode *>(subexpr); + if (cn->value.get_type() == Variant::NIL) { - _set_error("Can't accept a null constant expression for inferring export type."); + _set_error("Can't accept a null constant expression for inferring export type."); + return; + } + member._export.type = cn->value.get_type(); + member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; + if (cn->value.get_type() == Variant::OBJECT) { + Object *obj = cn->value; + Resource *res = Object::cast_to<Resource>(obj); + if (res == NULL) { + _set_error("Exported constant not a type or resource."); return; } - member._export.type = cn->value.get_type(); - member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; - if (cn->value.get_type() == Variant::OBJECT) { - Object *obj = cn->value; - Resource *res = Object::cast_to<Resource>(obj); - if (res == NULL) { - _set_error("Exported constant not a type or resource."); - return; - } - member._export.hint = PROPERTY_HINT_RESOURCE_TYPE; - member._export.hint_string = res->get_class(); - } + member._export.hint = PROPERTY_HINT_RESOURCE_TYPE; + member._export.hint_string = res->get_class(); } } #ifdef TOOLS_ENABLED @@ -4213,15 +4535,37 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { else p_class->initializer->statements.push_back(op); - } else { + member.initial_assignment = op; - if (autoexport) { + } else { + if (autoexport && !member.data_type.has_type) { _set_error("Type-less export needs a constant expression assigned to infer type."); return; } } + if (autoexport && member.data_type.has_type) { + if (member.data_type.kind == DataType::BUILTIN) { + member._export.type = member.data_type.builtin_type; + } else if (member.data_type.kind == DataType::NATIVE) { + if (ClassDB::is_parent_class(member.data_type.native_type, "Resource")) { + member._export.type = Variant::OBJECT; + member._export.hint = PROPERTY_HINT_RESOURCE_TYPE; + member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; + member._export.hint_string = member.data_type.native_type; + member._export.class_name = member.data_type.native_type; + } else { + _set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line); + return; + } + + } else { + _set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line); + return; + } + } + if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_SETGET) { tokenizer->advance(); @@ -4258,7 +4602,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } break; case GDScriptTokenizer::TK_PR_CONST: { - //variale declaration and (eventual) initialization + // constant declaration and initialization ClassNode::Constant constant; @@ -4269,9 +4613,38 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } - constant.identifier = tokenizer->get_token_literal(); + StringName const_id = tokenizer->get_token_literal(); + int line = tokenizer->get_token_line(); + + if (current_class->constant_expressions.has(const_id)) { + _set_error("Constant '" + String(const_id) + "' alread exists in this class (at line: " + + itos(current_class->constant_expressions[const_id].expression->line) + ")."); + return; + } + + for (int i = 0; i < current_class->variables.size(); i++) { + if (current_class->variables[i].identifier == const_id) { + _set_error("A variable named '" + String(const_id) + "' alread exists in this class (at line: " + + itos(current_class->variables[i].line) + ")."); + return; + } + } + tokenizer->advance(); + if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) { + if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) { + constant.type = DataType(); +#ifdef DEBUG_ENABLED + constant.type.infer_type = true; +#endif + tokenizer->advance(); + } else if (!_parse_type(constant.type)) { + _set_error("Expected type for class constant."); + return; + } + } + if (tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) { _set_error("Constant expects assignment."); return; @@ -4288,14 +4661,16 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } if (subexpr->type != Node::TYPE_CONSTANT) { - _set_error("Expected constant expression"); + _set_error("Expected constant expression", line); + return; } + subexpr->line = line; constant.expression = subexpr; - p_class->constant_expressions.push_back(constant); + p_class->constant_expressions.insert(const_id, constant); if (!_end_statement()) { - _set_error("Expected end of statement (constant)"); + _set_error("Expected end of statement (constant)", line); return; } @@ -4338,7 +4713,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } else { // tokenizer->is_token_literal(0, true) ClassNode::Constant constant; - constant.identifier = tokenizer->get_token_literal(); + StringName const_id = tokenizer->get_token_literal(); tokenizer->advance(); @@ -4355,22 +4730,25 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (subexpr->type != Node::TYPE_CONSTANT) { _set_error("Expected constant expression"); + return; } - const ConstantNode *subexpr_const = static_cast<const ConstantNode *>(subexpr); + ConstantNode *subexpr_const = static_cast<ConstantNode *>(subexpr); if (subexpr_const->value.get_type() != Variant::INT) { _set_error("Expected an int value for enum"); + return; } last_assign = subexpr_const->value; - constant.expression = subexpr; + constant.expression = subexpr_const; } else { last_assign = last_assign + 1; ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = last_assign; + cn->datatype = _type_from_variant(cn->value); constant.expression = cn; } @@ -4380,20 +4758,25 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { if (enum_name != "") { const ConstantNode *cn = static_cast<const ConstantNode *>(constant.expression); - enum_dict[constant.identifier] = cn->value; + enum_dict[const_id] = cn->value; } - p_class->constant_expressions.push_back(constant); + constant.type.has_type = true; + constant.type.kind = DataType::BUILTIN; + constant.type.builtin_type = Variant::INT; + p_class->constant_expressions.insert(const_id, constant); } } if (enum_name != "") { ClassNode::Constant enum_constant; - enum_constant.identifier = enum_name; ConstantNode *cn = alloc_node<ConstantNode>(); cn->value = enum_dict; + cn->datatype = _type_from_variant(cn->value); + enum_constant.expression = cn; - p_class->constant_expressions.push_back(enum_constant); + enum_constant.type = cn->datatype; + p_class->constant_expressions.insert(enum_name, enum_constant); } if (!_end_statement()) { @@ -4423,6 +4806,2747 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } +void GDScriptParser::_determine_inheritance(ClassNode *p_class) { + + if (p_class->extends_used) { + //do inheritance + String path = p_class->extends_file; + + Ref<GDScript> script; + StringName native; + ClassNode *base_class = NULL; + + if (path != "") { + //path (and optionally subclasses) + + if (path.is_rel_path()) { + + String base = base_path; + + if (base == "" || base.is_rel_path()) { + _set_error("Could not resolve relative path for parent class: " + path, p_class->line); + return; + } + path = base.plus_file(path).simplify_path(); + } + script = ResourceLoader::load(path); + if (script.is_null()) { + _set_error("Could not load base class: " + path, p_class->line); + return; + } + if (!script->is_valid()) { + + _set_error("Script not fully loaded (cyclic preload?): " + path, p_class->line); + return; + } + + if (p_class->extends_class.size()) { + + for (int i = 0; i < p_class->extends_class.size(); i++) { + + String sub = p_class->extends_class[i]; + if (script->get_subclasses().has(sub)) { + + Ref<Script> subclass = script->get_subclasses()[sub]; //avoid reference from disappearing + script = subclass; + } else { + + _set_error("Could not find subclass: " + sub, p_class->line); + return; + } + } + } + + } else { + + if (p_class->extends_class.size() == 0) { + _set_error("Parser bug: undecidable inheritance.", p_class->line); + ERR_FAIL(); + } + //look around for the subclasses + + int extend_iter = 1; + String base = p_class->extends_class[0]; + ClassNode *p = p_class->owner; + Ref<GDScript> base_script; + + if (ScriptServer::is_global_class(base)) { + base_script = ResourceLoader::load(ScriptServer::get_global_class_path(base)); + if (!base_script.is_valid()) { + _set_error("Class '" + base + "' could not be fully loaded (script error or cyclic inheritance).", p_class->line); + return; + } + p = NULL; + } + + while (p) { + + bool found = false; + + for (int i = 0; i < p->subclasses.size(); i++) { + if (p->subclasses[i]->name == base) { + ClassNode *test = p->subclasses[i]; + while (test) { + if (test == p_class) { + _set_error("Cyclic inheritance.", test->line); + return; + } + if (test->base_type.kind == DataType::CLASS) { + test = test->base_type.class_type; + } else { + break; + } + } + found = true; + if (extend_iter < p_class->extends_class.size()) { + // Keep looking at current classes if possible + base = p_class->extends_class[extend_iter++]; + p = p->subclasses[i]; + } else { + base_class = p->subclasses[i]; + } + break; + } + } + + if (base_class) break; + if (found) continue; + + if (p->constant_expressions.has(base)) { + if (!p->constant_expressions[base].expression->type == Node::TYPE_CONSTANT) { + _set_error("Could not resolve constant '" + base + "'.", p_class->line); + return; + } + const ConstantNode *cn = static_cast<const ConstantNode *>(p->constant_expressions[base].expression); + base_script = cn->value; + if (base_script.is_null()) { + _set_error("Constant is not a class: " + base, p_class->line); + return; + } + break; + } + + p = p->owner; + } + + if (base_script.is_valid()) { + + String ident = base; + + for (int i = extend_iter; i < p_class->extends_class.size(); i++) { + + String subclass = p_class->extends_class[i]; + + ident += ("." + subclass); + + if (base_script->get_subclasses().has(subclass)) { + + base_script = base_script->get_subclasses()[subclass]; + } else if (base_script->get_constants().has(subclass)) { + + Ref<GDScript> new_base_class = base_script->get_constants()[subclass]; + if (new_base_class.is_null()) { + _set_error("Constant is not a class: " + ident, p_class->line); + return; + } + base_script = new_base_class; + } else { + + _set_error("Could not find subclass: " + ident, p_class->line); + return; + } + } + + script = base_script; + + } else if (!base_class) { + + if (p_class->extends_class.size() > 1) { + + _set_error("Invalid inheritance (unknown class + subclasses)", p_class->line); + return; + } + //if not found, try engine classes + if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) { + + _set_error("Unknown class: '" + base + "'", p_class->line); + return; + } + + native = base; + } + } + + if (base_class) { + p_class->base_type.has_type = true; + p_class->base_type.kind = DataType::CLASS; + p_class->base_type.class_type = base_class; + } else if (script.is_valid()) { + p_class->base_type.has_type = true; + p_class->base_type.kind = DataType::GDSCRIPT; + p_class->base_type.script_type = script; + p_class->base_type.native_type = script->get_instance_base_type(); + } else if (native != StringName()) { + p_class->base_type.has_type = true; + p_class->base_type.kind = DataType::NATIVE; + p_class->base_type.native_type = native; + } else { + _set_error("Could not determine inheritance", p_class->line); + return; + } + + } else { + // without extends, implicitly extend Reference + p_class->base_type.has_type = true; + p_class->base_type.kind = DataType::NATIVE; + p_class->base_type.native_type = "Reference"; + } + + // Recursively determine subclasses + for (int i = 0; i < p_class->subclasses.size(); i++) { + _determine_inheritance(p_class->subclasses[i]); + } +} + +String GDScriptParser::DataType::to_string() const { + if (!has_type) return "var"; + switch (kind) { + case BUILTIN: { + if (builtin_type == Variant::NIL) return "null"; + return Variant::get_type_name(builtin_type); + } break; + case NATIVE: { + if (is_meta_type) { + return "GDScriptNativeClass"; + } + return native_type.operator String(); + } break; + + case GDSCRIPT: { + Ref<GDScript> gds = script_type; + const String &gds_class = gds->get_script_class_name(); + if (!gds_class.empty()) { + return gds_class; + } + } // fallthrough + case SCRIPT: { + if (is_meta_type) { + return script_type->get_class_name().operator String(); + } + String name = script_type->get_name(); + if (name != String()) { + return name; + } + name = script_type->get_path().get_file(); + if (name != String()) { + return name; + } + return native_type.operator String(); + } break; + case CLASS: { + ERR_FAIL_COND_V(!class_type, String()); + if (is_meta_type) { + return "GDScript"; + } + if (class_type->name == StringName()) { + return "self"; + } + return class_type->name.operator String(); + } break; + } + + return "Unresolved"; +} + +bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) { + tokenizer->advance(); + r_type.has_type = true; + + bool finished = false; + bool can_index = false; + String full_name; + + if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { + completion_cursor = StringName(); + completion_type = COMPLETION_TYPE_HINT; + completion_class = current_class; + completion_function = current_function; + completion_line = tokenizer->get_token_line(); + completion_argument = 0; + completion_block = current_block; + completion_found = true; + completion_ident_is_call = p_can_be_void; + tokenizer->advance(); + } + + switch (tokenizer->get_token()) { + case GDScriptTokenizer::TK_PR_VOID: { + if (!p_can_be_void) { + return false; + } + r_type.kind = DataType::BUILTIN; + r_type.builtin_type = Variant::NIL; + } break; + case GDScriptTokenizer::TK_BUILT_IN_TYPE: { + r_type.builtin_type = tokenizer->get_token_type(); + if (tokenizer->get_token_type() == Variant::OBJECT) { + r_type.kind = DataType::NATIVE; + r_type.native_type = "Object"; + } else { + r_type.kind = DataType::BUILTIN; + } + } break; + case GDScriptTokenizer::TK_IDENTIFIER: { + r_type.native_type = tokenizer->get_token_identifier(); + if (ClassDB::class_exists(r_type.native_type) || ClassDB::class_exists("_" + r_type.native_type.operator String())) { + r_type.kind = DataType::NATIVE; + } else { + r_type.kind = DataType::UNRESOLVED; + can_index = true; + full_name = r_type.native_type; + } + } break; + default: { + return false; + } + } + + tokenizer->advance(); + + if (tokenizer->get_token() == GDScriptTokenizer::TK_CURSOR) { + completion_cursor = r_type.native_type; + completion_type = COMPLETION_TYPE_HINT; + completion_class = current_class; + completion_function = current_function; + completion_line = tokenizer->get_token_line(); + completion_argument = 0; + completion_block = current_block; + completion_found = true; + completion_ident_is_call = p_can_be_void; + tokenizer->advance(); + } + + if (can_index) { + while (!finished) { + switch (tokenizer->get_token()) { + case GDScriptTokenizer::TK_PERIOD: { + if (!can_index) { + _set_error("Unexpected '.'."); + return false; + } + can_index = false; + tokenizer->advance(); + } break; + case GDScriptTokenizer::TK_IDENTIFIER: { + if (can_index) { + _set_error("Unexpected identifier."); + return false; + } + + StringName id; + bool has_completion = _get_completable_identifier(COMPLETION_TYPE_HINT_INDEX, id); + if (id == StringName()) { + id = "@temp"; + } + + full_name += "." + id.operator String(); + can_index = true; + if (has_completion) { + completion_cursor = full_name; + } + } break; + default: { + finished = true; + } break; + } + } + + if (tokenizer->get_token(-1) == GDScriptTokenizer::TK_PERIOD) { + _set_error("Expected subclass identifier."); + return false; + } + + r_type.native_type = full_name; + } + + return true; +} + +GDScriptParser::DataType GDScriptParser::_resolve_type(const DataType &p_source, int p_line) { + if (!p_source.has_type) return p_source; + if (p_source.kind != DataType::UNRESOLVED) return p_source; + + Vector<String> full_name = p_source.native_type.operator String().split(".", false); + int name_part = 0; + + DataType result; + result.has_type = true; + + while (name_part < full_name.size()) { + + bool found = false; + StringName id = full_name[name_part]; + DataType base_type = result; + + ClassNode *p = NULL; + if (name_part == 0) { + if (ScriptServer::is_global_class(id)) { + String script_path = ScriptServer::get_global_class_path(id); + if (script_path == self_path) { + result.kind = DataType::CLASS; + result.class_type = current_class; + } else { + Ref<Script> script = ResourceLoader::load(script_path); + Ref<GDScript> gds = script; + if (gds.is_valid()) { + if (!gds->is_valid()) { + _set_error("Class '" + id + "' could not be fully loaded (script error or cyclic inheritance).", p_line); + return DataType(); + } + result.kind = DataType::GDSCRIPT; + result.script_type = gds; + } else if (script.is_valid()) { + result.kind = DataType::SCRIPT; + result.script_type = script; + } else { + _set_error("Class '" + id + "' was found in global scope but its script could not be loaded.", p_line); + return DataType(); + } + } + name_part++; + continue; + } else { + p = current_class; + } + } else if (base_type.kind == DataType::CLASS) { + p = base_type.class_type; + } + while (p) { + if (p->constant_expressions.has(id)) { + if (p->constant_expressions[id].expression->type != Node::TYPE_CONSTANT) { + _set_error("Parser bug: unresolved constant.", p_line); + ERR_FAIL_V(result); + } + const ConstantNode *cn = static_cast<const ConstantNode *>(p->constant_expressions[id].expression); + Ref<GDScript> gds = cn->value; + if (gds.is_valid()) { + result.kind = DataType::GDSCRIPT; + result.script_type = gds; + found = true; + } else { + Ref<Script> scr = cn->value; + if (scr.is_valid()) { + result.kind = DataType::SCRIPT; + result.script_type = scr; + found = true; + } + } + break; + } + + // Inner classes + ClassNode *outer_class = p; + while (outer_class) { + for (int i = 0; i < outer_class->subclasses.size(); i++) { + if (outer_class->subclasses[i] == p) { + continue; + } + if (outer_class->subclasses[i]->name == id) { + found = true; + result.kind = DataType::CLASS; + result.class_type = outer_class->subclasses[i]; + break; + } + } + if (found) { + break; + } + outer_class = outer_class->owner; + } + + if (!found && p->base_type.kind == DataType::CLASS) { + p = p->base_type.class_type; + } else { + base_type = p->base_type; + break; + } + } + + // Still look for class constants in parent script + if (!found && (base_type.kind == DataType::GDSCRIPT || base_type.kind == DataType::SCRIPT)) { + Ref<Script> scr = base_type.script_type; + ERR_FAIL_COND_V(scr.is_null(), result); + Map<StringName, Variant> constants; + scr->get_constants(&constants); + + if (constants.has(id)) { + Ref<GDScript> gds = constants[id]; + + if (gds.is_valid()) { + result.kind = DataType::GDSCRIPT; + result.script_type = gds; + found = true; + } else { + Ref<Script> scr = constants[id]; + if (scr.is_valid()) { + result.kind = DataType::SCRIPT; + result.script_type = scr; + found = true; + } + } + } + } + + if (!found && !for_completion) { + String base; + if (name_part == 0) { + base = "self"; + } else { + base = result.to_string(); + } + _set_error("Identifier '" + String(id) + "' is not a valid type (not a script or class), or could not be found on base '" + + base + "'.", + p_line); + return DataType(); + } + + name_part++; + } + + return result; +} + +GDScriptParser::DataType GDScriptParser::_type_from_variant(const Variant &p_value) const { + DataType result; + result.has_type = true; + result.is_constant = true; + result.kind = DataType::BUILTIN; + result.builtin_type = p_value.get_type(); + + if (result.builtin_type == Variant::OBJECT) { + Object *obj = p_value.operator Object *(); + if (!obj) { + return DataType(); + } + result.native_type = obj->get_class_name(); + Ref<Script> scr = p_value; + if (scr.is_valid()) { + result.is_meta_type = true; + } else { + result.is_meta_type = false; + scr = obj->get_script(); + } + if (scr.is_valid()) { + result.script_type = scr; + Ref<GDScript> gds = scr; + if (gds.is_valid()) { + result.kind = DataType::GDSCRIPT; + } else { + result.kind = DataType::SCRIPT; + } + result.native_type = scr->get_instance_base_type(); + } else { + result.kind = DataType::NATIVE; + } + } + + return result; +} + +GDScriptParser::DataType GDScriptParser::_type_from_property(const PropertyInfo &p_property, bool p_nil_is_variant) const { + DataType ret; + if (p_property.type == Variant::NIL && (p_nil_is_variant || (p_property.usage & PROPERTY_USAGE_NIL_IS_VARIANT))) { + // Variant + return ret; + } + ret.has_type = true; + ret.builtin_type = p_property.type; + if (p_property.type == Variant::OBJECT) { + ret.kind = DataType::NATIVE; + ret.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name; + } else { + ret.kind = DataType::BUILTIN; + } + return ret; +} + +GDScriptParser::DataType GDScriptParser::_type_from_gdtype(const GDScriptDataType &p_gdtype) const { + DataType result; + if (!p_gdtype.has_type) { + return result; + } + + result.has_type = true; + result.builtin_type = p_gdtype.builtin_type; + result.native_type = p_gdtype.native_type; + result.script_type = p_gdtype.script_type; + + switch (p_gdtype.kind) { + case GDScriptDataType::BUILTIN: { + result.kind = DataType::BUILTIN; + } break; + case GDScriptDataType::NATIVE: { + result.kind = DataType::NATIVE; + } break; + case GDScriptDataType::GDSCRIPT: { + result.kind = DataType::GDSCRIPT; + } break; + case GDScriptDataType::SCRIPT: { + result.kind = DataType::SCRIPT; + } break; + } + return result; +} + +GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Operator p_op, const DataType &p_a, const DataType &p_b, bool &r_valid) const { + if (!p_a.has_type || !p_b.has_type) { + r_valid = true; + return DataType(); + } + + Variant::Type a_type = p_a.kind == DataType::BUILTIN ? p_a.builtin_type : Variant::OBJECT; + Variant::Type b_type = p_b.kind == DataType::BUILTIN ? p_b.builtin_type : Variant::OBJECT; + + Variant a; + REF a_ref; + if (a_type == Variant::OBJECT) { + a_ref.instance(); + a = a_ref; + } else { + Variant::CallError err; + a = Variant::construct(a_type, NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK) { + r_valid = false; + return DataType(); + } + } + Variant b; + REF b_ref; + if (b_type == Variant::OBJECT) { + b_ref.instance(); + b = b_ref; + } else { + Variant::CallError err; + b = Variant::construct(b_type, NULL, 0, err); + if (err.error != Variant::CallError::CALL_OK) { + r_valid = false; + return DataType(); + } + } + + // Avoid division by zero + if (a_type == Variant::INT || a_type == Variant::REAL) { + Variant::evaluate(Variant::OP_ADD, a, 1, a, r_valid); + } + if (b_type == Variant::INT || b_type == Variant::REAL) { + Variant::evaluate(Variant::OP_ADD, b, 1, b, r_valid); + } + if (a_type == Variant::STRING) { + a = "%s"; // Work around for formatting operator (%) + } + + Variant ret; + Variant::evaluate(p_op, a, b, ret, r_valid); + + if (r_valid) { + return _type_from_variant(ret); + } + + return DataType(); +} + +Variant::Operator GDScriptParser::_get_variant_operation(const OperatorNode::Operator &p_op) const { + switch (p_op) { + case OperatorNode::OP_NEG: { + return Variant::OP_NEGATE; + } break; + case OperatorNode::OP_POS: { + return Variant::OP_POSITIVE; + } break; + case OperatorNode::OP_NOT: { + return Variant::OP_NOT; + } break; + case OperatorNode::OP_BIT_INVERT: { + return Variant::OP_BIT_NEGATE; + } break; + case OperatorNode::OP_IN: { + return Variant::OP_IN; + } break; + case OperatorNode::OP_EQUAL: { + return Variant::OP_EQUAL; + } break; + case OperatorNode::OP_NOT_EQUAL: { + return Variant::OP_NOT_EQUAL; + } break; + case OperatorNode::OP_LESS: { + return Variant::OP_LESS; + } break; + case OperatorNode::OP_LESS_EQUAL: { + return Variant::OP_LESS_EQUAL; + } break; + case OperatorNode::OP_GREATER: { + return Variant::OP_GREATER; + } break; + case OperatorNode::OP_GREATER_EQUAL: { + return Variant::OP_GREATER_EQUAL; + } break; + case OperatorNode::OP_AND: { + return Variant::OP_AND; + } break; + case OperatorNode::OP_OR: { + return Variant::OP_OR; + } break; + case OperatorNode::OP_ASSIGN_ADD: + case OperatorNode::OP_ADD: { + return Variant::OP_ADD; + } break; + case OperatorNode::OP_ASSIGN_SUB: + case OperatorNode::OP_SUB: { + return Variant::OP_SUBTRACT; + } break; + case OperatorNode::OP_ASSIGN_MUL: + case OperatorNode::OP_MUL: { + return Variant::OP_MULTIPLY; + } break; + case OperatorNode::OP_ASSIGN_DIV: + case OperatorNode::OP_DIV: { + return Variant::OP_DIVIDE; + } break; + case OperatorNode::OP_ASSIGN_MOD: + case OperatorNode::OP_MOD: { + return Variant::OP_MODULE; + } break; + case OperatorNode::OP_ASSIGN_BIT_AND: + case OperatorNode::OP_BIT_AND: { + return Variant::OP_BIT_AND; + } break; + case OperatorNode::OP_ASSIGN_BIT_OR: + case OperatorNode::OP_BIT_OR: { + return Variant::OP_BIT_OR; + } break; + case OperatorNode::OP_ASSIGN_BIT_XOR: + case OperatorNode::OP_BIT_XOR: { + return Variant::OP_BIT_XOR; + } break; + case OperatorNode::OP_ASSIGN_SHIFT_LEFT: + case OperatorNode::OP_SHIFT_LEFT: { + return Variant::OP_SHIFT_LEFT; + } + case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + case OperatorNode::OP_SHIFT_RIGHT: { + return Variant::OP_SHIFT_RIGHT; + } + default: { + return Variant::OP_MAX; + } break; + } +} + +bool GDScriptParser::_is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion) const { + // Ignore for completion + if (!check_types || for_completion) { + return true; + } + // Can't test if not all have type + if (!p_container.has_type || !p_expression.has_type) { + return true; + } + + // Should never get here unresolved + ERR_FAIL_COND_V(p_container.kind == DataType::UNRESOLVED, false); + ERR_FAIL_COND_V(p_expression.kind == DataType::UNRESOLVED, false); + + if (p_container.kind == DataType::BUILTIN && p_expression.kind == DataType::BUILTIN) { + bool valid = p_container.builtin_type == p_expression.builtin_type; + if (p_allow_implicit_conversion) { + valid = valid || (p_container.builtin_type == Variant::INT && p_expression.builtin_type == Variant::REAL); + valid = valid || (p_container.builtin_type == Variant::REAL && p_expression.builtin_type == Variant::INT); + valid = valid || (p_container.builtin_type == Variant::STRING && p_expression.builtin_type == Variant::NODE_PATH); + valid = valid || (p_container.builtin_type == Variant::NODE_PATH && p_expression.builtin_type == Variant::STRING); + valid = valid || (p_container.builtin_type == Variant::BOOL && p_expression.builtin_type == Variant::REAL); + valid = valid || (p_container.builtin_type == Variant::BOOL && p_expression.builtin_type == Variant::INT); + valid = valid || (p_container.builtin_type == Variant::INT && p_expression.builtin_type == Variant::BOOL); + valid = valid || (p_container.builtin_type == Variant::REAL && p_expression.builtin_type == Variant::BOOL); + } + return valid; + } + + if (p_container.kind == DataType::BUILTIN || (p_expression.kind == DataType::BUILTIN && p_expression.builtin_type != Variant::NIL)) { + // Can't mix built-ins with objects + return false; + } + + // From now on everything is objects, check polymorphism + // The container must be the same class or a superclass of the expression + + if (p_expression.kind == DataType::BUILTIN && p_expression.builtin_type == Variant::NIL) { + // Null can be assigned to object types + return true; + } + + StringName expr_native; + Ref<Script> expr_script; + ClassNode *expr_class = NULL; + + switch (p_expression.kind) { + case DataType::NATIVE: { + if (p_container.kind != DataType::NATIVE) { + // Non-native type can't be a superclass of a native type + return false; + } + if (p_expression.is_meta_type) { + expr_native = GDScriptNativeClass::get_class_static(); + } else { + expr_native = p_expression.native_type; + } + } break; + case DataType::SCRIPT: + case DataType::GDSCRIPT: { + if (p_container.kind == DataType::CLASS) { + // This cannot be resolved without cyclic dependencies, so just bail out + return false; + } + if (p_expression.is_meta_type) { + expr_native = p_expression.script_type->get_class_name(); + } else { + expr_script = p_expression.script_type; + expr_native = expr_script->get_instance_base_type(); + } + } break; + case DataType::CLASS: { + if (p_expression.is_meta_type) { + expr_native = GDScript::get_class_static(); + } else { + expr_class = p_expression.class_type; + ClassNode *base = expr_class; + while (base->base_type.kind == DataType::CLASS) { + base = base->base_type.class_type; + } + expr_native = base->base_type.native_type; + expr_script = base->base_type.script_type; + } + } + } + + switch (p_container.kind) { + case DataType::NATIVE: { + if (p_container.is_meta_type) { + return ClassDB::is_parent_class(expr_native, GDScriptNativeClass::get_class_static()); + } else { + return ClassDB::is_parent_class(expr_native, p_container.native_type); + } + } break; + case DataType::SCRIPT: + case DataType::GDSCRIPT: { + if (p_container.is_meta_type) { + return ClassDB::is_parent_class(expr_native, GDScript::get_class_static()); + } + if (expr_class == head && p_container.script_type->get_path() == self_path) { + // Special case: container is self script and expression is self + return true; + } + while (expr_script.is_valid()) { + if (expr_script == p_container.script_type) { + return true; + } + expr_script = expr_script->get_base_script(); + } + return false; + } break; + case DataType::CLASS: { + if (p_container.is_meta_type) { + return ClassDB::is_parent_class(expr_native, GDScript::get_class_static()); + } + if (p_container.class_type == head && expr_script.is_valid() && expr_script->get_path() == self_path) { + // Special case: container is self and expression is self script + return true; + } + while (expr_class) { + if (expr_class == p_container.class_type) { + return true; + } + expr_class = expr_class->base_type.class_type; + } + return false; + } + } + + return false; +} + +GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { + if (p_node->get_datatype().has_type) { + return p_node->get_datatype(); + } + + DataType node_type; + + switch (p_node->type) { + case Node::TYPE_CONSTANT: { + node_type = _type_from_variant(static_cast<ConstantNode *>(p_node)->value); + } break; + case Node::TYPE_ARRAY: { + node_type.has_type = true; + node_type.kind = DataType::BUILTIN; + node_type.builtin_type = Variant::ARRAY; + } break; + case Node::TYPE_DICTIONARY: { + node_type.has_type = true; + node_type.kind = DataType::BUILTIN; + node_type.builtin_type = Variant::DICTIONARY; + } break; + case Node::TYPE_SELF: { + node_type.has_type = true; + node_type.kind = DataType::CLASS; + node_type.class_type = current_class; + } break; + case Node::TYPE_IDENTIFIER: { + IdentifierNode *id = static_cast<IdentifierNode *>(p_node); + if (id->declared_block) { + node_type = id->declared_block->variables[id->name]->get_datatype(); + } else if (id->name == "#match_value") { + // It's a special id just for the match statetement, ignore + break; + } else if (current_function && current_function->arguments.find(id->name) >= 0) { + int idx = current_function->arguments.find(id->name); + node_type = current_function->argument_types[idx]; + } else { + node_type = _reduce_identifier_type(NULL, id->name, id->line); + } + } break; + case Node::TYPE_CAST: { + CastNode *cn = static_cast<CastNode *>(p_node); + + DataType source_type = _reduce_node_type(cn->source_node); + cn->cast_type = _resolve_type(cn->cast_type, cn->line); + if (source_type.has_type) { + + bool valid = false; + if (check_types) { + if (cn->cast_type.kind == DataType::BUILTIN && source_type.kind == DataType::BUILTIN) { + valid = Variant::can_convert(source_type.builtin_type, cn->cast_type.builtin_type); + } + if (cn->cast_type.kind != DataType::BUILTIN && source_type.kind != DataType::BUILTIN) { + valid = _is_type_compatible(cn->cast_type, source_type) || _is_type_compatible(source_type, cn->cast_type); + } + + if (!valid) { + _set_error("Invalid cast. Cannot convert from '" + source_type.to_string() + + "' to '" + cn->cast_type.to_string() + "'.", + cn->line); + return DataType(); + } + } + } else { + _mark_line_as_unsafe(cn->line); + } + + node_type = cn->cast_type; + + } break; + case Node::TYPE_OPERATOR: { + OperatorNode *op = static_cast<OperatorNode *>(p_node); + + switch (op->op) { + case OperatorNode::OP_CALL: + case OperatorNode::OP_PARENT_CALL: { + node_type = _reduce_function_call_type(op); + } break; + case OperatorNode::OP_YIELD: { + if (op->arguments.size() == 2) { + DataType base_type = _reduce_node_type(op->arguments[0]); + DataType signal_type = _reduce_node_type(op->arguments[1]); + // TODO: Check if signal exists when it's a constant + if (base_type.has_type && base_type.kind == DataType::BUILTIN && base_type.builtin_type != Variant::NIL && base_type.builtin_type != Variant::OBJECT) { + _set_error("First argument of 'yield()' must be an object.", op->line); + return DataType(); + } + if (signal_type.has_type && (signal_type.kind != DataType::BUILTIN || signal_type.builtin_type != Variant::STRING)) { + _set_error("Second argument of 'yield()' must be a string.", op->line); + return DataType(); + } + } + // yield can return anything + node_type.has_type = false; + } break; + case OperatorNode::OP_IS: { + + if (op->arguments.size() != 2) { + _set_error("Parser bug: binary operation without 2 arguments.", op->line); + ERR_FAIL_V(DataType()); + } + + DataType value_type = _reduce_node_type(op->arguments[0]); + DataType type_type = _reduce_node_type(op->arguments[1]); + + if (check_types && type_type.has_type) { + if (!type_type.is_meta_type && (type_type.kind != DataType::NATIVE || !ClassDB::is_parent_class(type_type.native_type, "Script"))) { + _set_error("Invalid 'is' test: right operand is not a type (not a native type nor a script).", op->line); + return DataType(); + } + type_type.is_meta_type = false; // Test the actual type + if (!_is_type_compatible(type_type, value_type) && !_is_type_compatible(value_type, type_type)) { + // TODO: Make this a warning? + _set_error("A value of type '" + value_type.to_string() + "' will never be an instance of '" + type_type.to_string() + "'.", op->line); + return DataType(); + } + } + + node_type.has_type = true; + node_type.is_constant = true; + node_type.is_meta_type = false; + node_type.kind = DataType::BUILTIN; + node_type.builtin_type = Variant::BOOL; + } break; + // Unary operators + case OperatorNode::OP_NEG: + case OperatorNode::OP_POS: + case OperatorNode::OP_NOT: + case OperatorNode::OP_BIT_INVERT: { + + DataType argument_type = _reduce_node_type(op->arguments[0]); + if (!argument_type.has_type) { + break; + } + + Variant::Operator var_op = _get_variant_operation(op->op); + bool valid = false; + node_type = _get_operation_type(var_op, argument_type, argument_type, valid); + + if (check_types && !valid) { + _set_error("Invalid operand type ('" + argument_type.to_string() + + "') to unary operator '" + Variant::get_operator_name(var_op) + "'.", + op->line, op->column); + return DataType(); + } + + } break; + // Binary operators + case OperatorNode::OP_IN: + case OperatorNode::OP_EQUAL: + case OperatorNode::OP_NOT_EQUAL: + case OperatorNode::OP_LESS: + case OperatorNode::OP_LESS_EQUAL: + case OperatorNode::OP_GREATER: + case OperatorNode::OP_GREATER_EQUAL: + case OperatorNode::OP_AND: + case OperatorNode::OP_OR: + case OperatorNode::OP_ADD: + case OperatorNode::OP_SUB: + case OperatorNode::OP_MUL: + case OperatorNode::OP_DIV: + case OperatorNode::OP_MOD: + case OperatorNode::OP_SHIFT_LEFT: + case OperatorNode::OP_SHIFT_RIGHT: + case OperatorNode::OP_BIT_AND: + case OperatorNode::OP_BIT_OR: + case OperatorNode::OP_BIT_XOR: { + + if (op->arguments.size() != 2) { + _set_error("Parser bug: binary operation without 2 arguments.", op->line); + ERR_FAIL_V(DataType()); + } + + DataType argument_a_type = _reduce_node_type(op->arguments[0]); + DataType argument_b_type = _reduce_node_type(op->arguments[1]); + if (!argument_a_type.has_type || !argument_b_type.has_type) { + _mark_line_as_unsafe(op->line); + break; + } + + Variant::Operator var_op = _get_variant_operation(op->op); + bool valid = false; + node_type = _get_operation_type(var_op, argument_a_type, argument_b_type, valid); + + if (check_types && !valid) { + _set_error("Invalid operand types ('" + argument_a_type.to_string() + "' and '" + + argument_b_type.to_string() + "') to operator '" + Variant::get_operator_name(var_op) + "'.", + op->line, op->column); + return DataType(); + } + + } break; + // Ternary operators + case OperatorNode::OP_TERNARY_IF: { + if (op->arguments.size() != 3) { + _set_error("Parser bug: ternary operation without 3 arguments"); + ERR_FAIL_V(DataType()); + } + + DataType true_type = _reduce_node_type(op->arguments[1]); + DataType false_type = _reduce_node_type(op->arguments[2]); + + // If types are equal, then the expression is of the same type + // If they are compatible, return the broader type + if (true_type == false_type || _is_type_compatible(true_type, false_type)) { + node_type = true_type; + } else if (_is_type_compatible(false_type, true_type)) { + node_type = false_type; + } + + // TODO: Warn if types aren't compatible + + } break; + // Assignment should never happen within an expression + case OperatorNode::OP_ASSIGN: + case OperatorNode::OP_ASSIGN_ADD: + case OperatorNode::OP_ASSIGN_SUB: + case OperatorNode::OP_ASSIGN_MUL: + case OperatorNode::OP_ASSIGN_DIV: + case OperatorNode::OP_ASSIGN_MOD: + case OperatorNode::OP_ASSIGN_SHIFT_LEFT: + case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + case OperatorNode::OP_ASSIGN_BIT_AND: + case OperatorNode::OP_ASSIGN_BIT_OR: + case OperatorNode::OP_ASSIGN_BIT_XOR: + case OperatorNode::OP_INIT_ASSIGN: { + + _set_error("Assignment inside expression is not allowed (parser bug?).", op->line); + return DataType(); + + } break; + case OperatorNode::OP_INDEX_NAMED: { + if (op->arguments.size() != 2) { + _set_error("Parser bug: named index with invalid arguments.", op->line); + ERR_FAIL_V(DataType()); + } + if (op->arguments[1]->type != Node::TYPE_IDENTIFIER) { + _set_error("Parser bug: named index without identifier argument.", op->line); + ERR_FAIL_V(DataType()); + } + + DataType base_type = _reduce_node_type(op->arguments[0]); + IdentifierNode *member_id = static_cast<IdentifierNode *>(op->arguments[1]); + + if (base_type.has_type) { + if (check_types && base_type.kind == DataType::BUILTIN) { + // Variant type, just test if it's possible + DataType result; + switch (base_type.builtin_type) { + case Variant::NIL: + case Variant::DICTIONARY: { + result.has_type = false; + } break; + default: { + Variant::CallError err; + Variant temp = Variant::construct(base_type.builtin_type, NULL, 0, err); + + bool valid = false; + Variant res = temp.get(member_id->name.operator String(), &valid); + + if (valid) { + result = _type_from_variant(res); + } else if (check_types) { + _set_error("Can't get index '" + String(member_id->name.operator String()) + "' on base '" + + base_type.to_string() + "'.", + op->line); + return DataType(); + } + } break; + } + result.is_constant = false; + node_type = result; + } else { + node_type = _reduce_identifier_type(&base_type, member_id->name, op->line); + } + } else { + _mark_line_as_unsafe(op->line); + } + if (error_set) { + return DataType(); + } + } break; + case OperatorNode::OP_INDEX: { + + if (op->arguments[1]->type == Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[1]); + if (cn->value.get_type() == Variant::STRING) { + // Treat this as named indexing + + IdentifierNode *id = alloc_node<IdentifierNode>(); + id->name = cn->value.operator StringName(); + + op->op = OperatorNode::OP_INDEX_NAMED; + op->arguments.write[1] = id; + + return _reduce_node_type(op); + } + } + + DataType base_type = _reduce_node_type(op->arguments[0]); + DataType index_type = _reduce_node_type(op->arguments[1]); + + if (!base_type.has_type) { + _mark_line_as_unsafe(op->line); + break; + } + + if (check_types && index_type.has_type) { + if (base_type.kind == DataType::BUILTIN) { + // Check if indexing is valid + bool error = index_type.kind != DataType::BUILTIN; + if (!error) { + switch (base_type.builtin_type) { + // Expect int or real as index + case Variant::POOL_BYTE_ARRAY: + case Variant::POOL_COLOR_ARRAY: + case Variant::POOL_INT_ARRAY: + case Variant::POOL_REAL_ARRAY: + case Variant::POOL_STRING_ARRAY: + case Variant::POOL_VECTOR2_ARRAY: + case Variant::POOL_VECTOR3_ARRAY: + case Variant::ARRAY: + case Variant::STRING: { + error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::REAL; + } break; + // Expect String only + case Variant::RECT2: + case Variant::PLANE: + case Variant::QUAT: + case Variant::AABB: + case Variant::OBJECT: { + error = index_type.builtin_type != Variant::STRING; + } break; + // Expect String or number + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::TRANSFORM2D: + case Variant::BASIS: + case Variant::TRANSFORM: { + error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::REAL && + index_type.builtin_type != Variant::STRING; + } break; + // Expect String or int + case Variant::COLOR: { + error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::STRING; + } break; + } + } + if (error) { + _set_error("Invalid index type (" + index_type.to_string() + ") for base '" + base_type.to_string() + "'.", + op->line); + return DataType(); + } + + if (op->arguments[1]->type == GDScriptParser::Node::TYPE_CONSTANT) { + ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[1]); + // Index is a constant, just try it if possible + switch (base_type.builtin_type) { + // Arrays/string have variable indexing, can't test directly + case Variant::STRING: + case Variant::ARRAY: + case Variant::DICTIONARY: + case Variant::POOL_BYTE_ARRAY: + case Variant::POOL_COLOR_ARRAY: + case Variant::POOL_INT_ARRAY: + case Variant::POOL_REAL_ARRAY: + case Variant::POOL_STRING_ARRAY: + case Variant::POOL_VECTOR2_ARRAY: + case Variant::POOL_VECTOR3_ARRAY: { + break; + } + default: { + Variant::CallError err; + Variant temp = Variant::construct(base_type.builtin_type, NULL, 0, err); + + bool valid = false; + Variant res = temp.get(cn->value, &valid); + + if (valid) { + node_type = _type_from_variant(res); + node_type.is_constant = false; + } else if (check_types) { + _set_error("Can't get index '" + String(cn->value) + "' on base '" + + base_type.to_string() + "'.", + op->line); + return DataType(); + } + } break; + } + } else { + _mark_line_as_unsafe(op->line); + } + } else if (!for_completion && (index_type.kind != DataType::BUILTIN || index_type.builtin_type != Variant::STRING)) { + _set_error("Only strings can be used as index in the base type '" + base_type.to_string() + "'.", op->line); + return DataType(); + } + } + if (check_types && !node_type.has_type) { + // Can infer indexing type for some variant types + DataType result; + result.has_type = true; + result.kind = DataType::BUILTIN; + switch (base_type.builtin_type) { + // Can't index at all + case Variant::NIL: + case Variant::BOOL: + case Variant::INT: + case Variant::REAL: + case Variant::NODE_PATH: + case Variant::_RID: { + _set_error("Can't index on a value of type '" + base_type.to_string() + "'.", op->line); + return DataType(); + } break; + // Return int + case Variant::POOL_BYTE_ARRAY: + case Variant::POOL_INT_ARRAY: { + result.builtin_type = Variant::INT; + } break; + // Return real + case Variant::POOL_REAL_ARRAY: + case Variant::VECTOR2: + case Variant::VECTOR3: + case Variant::QUAT: { + result.builtin_type = Variant::REAL; + } break; + // Return color + case Variant::POOL_COLOR_ARRAY: { + result.builtin_type = Variant::COLOR; + } break; + // Return string + case Variant::POOL_STRING_ARRAY: + case Variant::STRING: { + result.builtin_type = Variant::STRING; + } break; + // Return Vector2 + case Variant::POOL_VECTOR2_ARRAY: + case Variant::TRANSFORM2D: + case Variant::RECT2: { + result.builtin_type = Variant::VECTOR2; + } break; + // Return Vector3 + case Variant::POOL_VECTOR3_ARRAY: + case Variant::AABB: + case Variant::BASIS: { + result.builtin_type = Variant::VECTOR3; + } break; + // Depends on the index + case Variant::TRANSFORM: + case Variant::PLANE: + case Variant::COLOR: + default: { + result.has_type = false; + } break; + } + node_type = result; + } + } break; + default: { + _set_error("Parser bug: unhandled operation.", op->line); + ERR_FAIL_V(DataType()); + } + } + } break; + } + + p_node->set_datatype(_resolve_type(node_type, p_node->line)); + return node_type; +} + +bool GDScriptParser::_get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const { + + r_static = false; + r_default_arg_count = 0; + + DataType original_type = p_base_type; + ClassNode *base = NULL; + FunctionNode *callee = NULL; + + if (p_base_type.kind == DataType::CLASS) { + base = p_base_type.class_type; + } + + // Look up the current file (parse tree) + while (!callee && base) { + for (int i = 0; i < base->static_functions.size(); i++) { + FunctionNode *func = base->static_functions[i]; + if (p_function == func->name) { + r_static = true; + callee = func; + break; + } + } + if (!callee && !p_base_type.is_meta_type) { + for (int i = 0; i < base->functions.size(); i++) { + FunctionNode *func = base->functions[i]; + if (p_function == func->name) { + callee = func; + break; + } + } + } + p_base_type = base->base_type; + if (p_base_type.kind == DataType::CLASS) { + base = p_base_type.class_type; + } else { + break; + } + } + + if (callee) { + r_return_type = callee->get_datatype(); + for (int i = 0; i < callee->argument_types.size(); i++) { + r_arg_types.push_back(callee->argument_types[i]); + } + r_default_arg_count = callee->default_values.size(); + return true; + } + + // Nothing in current file, check parent script + Ref<GDScript> base_gdscript; + Ref<Script> base_script; + StringName native; + if (p_base_type.kind == DataType::GDSCRIPT) { + base_gdscript = p_base_type.script_type; + } else if (p_base_type.kind == DataType::SCRIPT) { + base_script = p_base_type.script_type; + } else if (p_base_type.kind == DataType::NATIVE) { + native = p_base_type.native_type; + } + + while (base_gdscript.is_valid()) { + native = base_gdscript->get_instance_base_type(); + + Map<StringName, GDScriptFunction *> funcs = base_gdscript->get_member_functions(); + + if (funcs.has(p_function)) { + GDScriptFunction *f = funcs[p_function]; + r_static = f->is_static(); + r_default_arg_count = f->get_default_argument_count(); + r_return_type = _type_from_gdtype(f->get_return_type()); + for (int i = 0; i < f->get_argument_count(); i++) { + r_arg_types.push_back(_type_from_gdtype(f->get_argument_type(i))); + } + return true; + } + + base_gdscript = base_gdscript->get_base_script(); + } + + while (base_script.is_valid()) { + native = base_script->get_instance_base_type(); + MethodInfo mi = base_script->get_method_info(p_function); + + if (!(mi == MethodInfo())) { + r_return_type = _type_from_property(mi.return_val, false); + r_default_arg_count = mi.default_arguments.size(); + for (List<PropertyInfo>::Element *E = mi.arguments.front(); E; E = E->next()) { + r_arg_types.push_back(_type_from_property(E->get())); + } + return true; + } + base_script = base_script->get_base_script(); + } + +#ifdef DEBUG_METHODS_ENABLED + + // Only native remains + if (!ClassDB::class_exists(native)) { + native = "_" + native.operator String(); + } + if (!ClassDB::class_exists(native)) { + if (!check_types) return false; + ERR_EXPLAIN("Parser bug: Class '" + String(native) + "' not found."); + ERR_FAIL_V(false); + } + + MethodBind *method = ClassDB::get_method(native, p_function); + + if (!method) { + // Try virtual methods + List<MethodInfo> virtuals; + ClassDB::get_virtual_methods(native, &virtuals); + + for (const List<MethodInfo>::Element *E = virtuals.front(); E; E = E->next()) { + const MethodInfo &mi = E->get(); + if (mi.name == p_function) { + r_default_arg_count = mi.default_arguments.size(); + for (const List<PropertyInfo>::Element *pi = mi.arguments.front(); pi; pi = pi->next()) { + r_arg_types.push_back(_type_from_property(pi->get())); + } + r_return_type = _type_from_property(mi.return_val, false); + r_vararg = mi.flags & METHOD_FLAG_VARARG; + return true; + } + } + + // If the base is a script, it might be trying to access members of the Script class itself + if (original_type.is_meta_type && !(p_function == "new") && (original_type.kind == DataType::SCRIPT || original_type.kind == DataType::GDSCRIPT)) { + method = ClassDB::get_method(original_type.script_type->get_class_name(), p_function); + + if (method) { + r_static = true; + } else { + // Try virtual methods of the script type + virtuals.clear(); + ClassDB::get_virtual_methods(original_type.script_type->get_class_name(), &virtuals); + for (const List<MethodInfo>::Element *E = virtuals.front(); E; E = E->next()) { + const MethodInfo &mi = E->get(); + if (mi.name == p_function) { + r_default_arg_count = mi.default_arguments.size(); + for (const List<PropertyInfo>::Element *pi = mi.arguments.front(); pi; pi = pi->next()) { + r_arg_types.push_back(_type_from_property(pi->get())); + } + r_return_type = _type_from_property(mi.return_val, false); + r_static = true; + r_vararg = mi.flags & METHOD_FLAG_VARARG; + return true; + } + } + return false; + } + } else { + return false; + } + } + + r_default_arg_count = method->get_default_argument_count(); + r_return_type = _type_from_property(method->get_return_info(), false); + r_vararg = method->is_vararg(); + + for (int i = 0; i < method->get_argument_count(); i++) { + r_arg_types.push_back(_type_from_property(method->get_argument_info(i))); + } + return true; +#else + return false; +#endif +} + +GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const OperatorNode *p_call) { + if (p_call->arguments.size() < 1) { + _set_error("Parser bug: function call without enough arguments.", p_call->line); + ERR_FAIL_V(DataType()); + } + + DataType return_type; + List<DataType> arg_types; + int default_args_count = 0; + int arg_count = p_call->arguments.size(); + String callee_name; + bool is_vararg = false; + + switch (p_call->arguments[0]->type) { + case GDScriptParser::Node::TYPE_TYPE: { + // Built-in constructor, special case + TypeNode *tn = static_cast<TypeNode *>(p_call->arguments[0]); + + Vector<DataType> par_types; + par_types.resize(p_call->arguments.size() - 1); + for (int i = 1; i < p_call->arguments.size(); i++) { + par_types.write[i - 1] = _reduce_node_type(p_call->arguments[i]); + } + + if (error_set) return DataType(); + + bool match = false; + List<MethodInfo> constructors; + Variant::get_constructor_list(tn->vtype, &constructors); + PropertyInfo return_type; + + for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) { + MethodInfo &mi = E->get(); + + if (p_call->arguments.size() - 1 < mi.arguments.size() - mi.default_arguments.size()) { + continue; + } + if (p_call->arguments.size() - 1 > mi.arguments.size()) { + continue; + } + + bool types_match = true; + for (int i = 0; i < par_types.size(); i++) { + DataType arg_type; + if (mi.arguments[i].type != Variant::NIL) { + arg_type.has_type = true; + arg_type.kind = mi.arguments[i].type == Variant::OBJECT ? DataType::NATIVE : DataType::BUILTIN; + arg_type.builtin_type = mi.arguments[i].type; + arg_type.native_type = mi.arguments[i].class_name; + } + + if (!_is_type_compatible(arg_type, par_types[i], true)) { + types_match = false; + break; + } + } + + if (types_match) { + match = true; + return_type = mi.return_val; + break; + } + } + + if (match) { + return _type_from_property(return_type, false); + } else if (check_types) { + String err = "No constructor of '"; + err += Variant::get_type_name(tn->vtype); + err += "' matches the signature '"; + err += Variant::get_type_name(tn->vtype) + "("; + for (int i = 0; i < par_types.size(); i++) { + if (i > 0) err += ", "; + err += par_types[i].to_string(); + } + err += ")'."; + _set_error(err, p_call->line, p_call->column); + return DataType(); + } + return DataType(); + } break; + case GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION: { + BuiltInFunctionNode *func = static_cast<BuiltInFunctionNode *>(p_call->arguments[0]); + MethodInfo mi = GDScriptFunctions::get_info(func->function); + + return_type = _type_from_property(mi.return_val, false); + + // Check arguments + + is_vararg = mi.flags & METHOD_FLAG_VARARG; + + default_args_count = mi.default_arguments.size(); + callee_name = mi.name; + arg_count -= 1; + + // Check each argument type + for (List<PropertyInfo>::Element *E = mi.arguments.front(); E; E = E->next()) { + arg_types.push_back(_type_from_property(E->get())); + } + } break; + default: { + if (p_call->op == OperatorNode::OP_CALL && p_call->arguments.size() < 2) { + _set_error("Parser bug: self method call without enough arguments.", p_call->line); + ERR_FAIL_V(DataType()); + } + + int arg_id = p_call->op == OperatorNode::OP_CALL ? 1 : 0; + + if (p_call->arguments[arg_id]->type != Node::TYPE_IDENTIFIER) { + _set_error("Parser bug: invalid function call argument.", p_call->line); + ERR_FAIL_V(DataType()); + } + + IdentifierNode *func_id = static_cast<IdentifierNode *>(p_call->arguments[arg_id]); + callee_name = func_id->name; + arg_count -= 1 + arg_id; + + DataType base_type; + if (p_call->op == OperatorNode::OP_PARENT_CALL) { + base_type = current_class->base_type; + } else { + base_type = _reduce_node_type(p_call->arguments[0]); + } + + if (!base_type.has_type || (base_type.kind == DataType::BUILTIN && base_type.builtin_type == Variant::NIL)) { + _mark_line_as_unsafe(p_call->line); + return DataType(); + } + + if (base_type.kind == DataType::BUILTIN) { + Variant::CallError err; + Variant tmp = Variant::construct(base_type.builtin_type, NULL, 0, err); + + if (check_types) { + if (!tmp.has_method(callee_name)) { + _set_error("Method '" + callee_name + "' is not declared on base '" + base_type.to_string() + "'.", p_call->line); + return DataType(); + } + + default_args_count = Variant::get_method_default_arguments(base_type.builtin_type, callee_name).size(); + const Vector<Variant::Type> &var_arg_types = Variant::get_method_argument_types(base_type.builtin_type, callee_name); + + for (int i = 0; i < var_arg_types.size(); i++) { + DataType argtype; + if (var_arg_types[i] != Variant::NIL) { + argtype.has_type = true; + argtype.kind = DataType::BUILTIN; + argtype.builtin_type = var_arg_types[i]; + } + arg_types.push_back(argtype); + } + } + + return_type.has_type = true; + return_type.kind = DataType::BUILTIN; + return_type.builtin_type = Variant::get_method_return_type(base_type.builtin_type, callee_name); + break; + } + + DataType original_type = base_type; + bool is_initializer = callee_name == "new"; + bool is_static = false; + bool valid = false; + + if (is_initializer && original_type.is_meta_type) { + // Try to check it as initializer + base_type = original_type; + callee_name = "_init"; + base_type.is_meta_type = false; + + valid = _get_function_signature(base_type, callee_name, return_type, arg_types, + default_args_count, is_static, is_vararg); + + if (valid) { + return_type = original_type; + return_type.is_meta_type = false; + } + } + + if (!valid) { + base_type = original_type; + return_type = DataType(); + valid = _get_function_signature(base_type, callee_name, return_type, arg_types, + default_args_count, is_static, is_vararg); + } + + if (!valid) { +#ifdef DEBUG_ENABLED + if (p_call->arguments[0]->type == Node::TYPE_SELF) { + _set_error("Method '" + callee_name + "' is not declared in the current class.", p_call->line); + return DataType(); + } + _mark_line_as_unsafe(p_call->line); +#endif + return DataType(); + } + +#ifdef DEBUG_ENABLED + if (current_function && !for_completion && !is_static && p_call->arguments[0]->type == Node::TYPE_SELF && current_function->_static) { + if (current_function && current_function->_static && p_call->arguments[0]->type == Node::TYPE_SELF) { + _set_error("Can't call non-static function from a static function.", p_call->line); + return DataType(); + } + } + + if (check_types && !is_static && !is_initializer && base_type.is_meta_type) { + _set_error("Non-static function '" + String(callee_name) + "' can only be called from an instance.", p_call->line); + return DataType(); + } +#endif + } break; + } + + if (!check_types) { + return return_type; + } + + if (arg_count < arg_types.size() - default_args_count) { + _set_error("Too few arguments for '" + callee_name + "()' call. Expected at least " + itos(arg_types.size() - default_args_count) + ".", p_call->line); + return return_type; + } + if (!is_vararg && arg_count > arg_types.size()) { + _set_error("Too many arguments for '" + callee_name + "()' call. Expected at most " + itos(arg_types.size()) + ".", p_call->line); + return return_type; + } + + int arg_diff = p_call->arguments.size() - arg_count; + for (int i = arg_diff; i < p_call->arguments.size(); i++) { + DataType par_type = _reduce_node_type(p_call->arguments[i]); + + if ((i - arg_diff) >= arg_types.size()) { + continue; + } + + if (!par_type.has_type) { + _mark_line_as_unsafe(p_call->line); + } else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) { + // Supertypes are acceptable for dynamic compliance + if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) { + _set_error("At '" + callee_name + "()' call, argument " + itos(i - arg_diff + 1) + ". Assigned type (" + + par_type.to_string() + ") doesn't match the function argument's type (" + + arg_types[i - arg_diff].to_string() + ").", + p_call->line); + return DataType(); + } else { + _mark_line_as_unsafe(p_call->line); + } + } + } + + return return_type; +} + +bool GDScriptParser::_get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type) const { + DataType base_type = p_base_type; + + // Check classes in current file + ClassNode *base = NULL; + if (base_type.kind == DataType::CLASS) { + base = base_type.class_type; + } + + while (base) { + if (base->constant_expressions.has(p_member)) { + r_member_type = base->constant_expressions[p_member].expression->get_datatype(); + return true; + } + + if (!base_type.is_meta_type) { + for (int i = 0; i < base->variables.size(); i++) { + ClassNode::Member m = base->variables[i]; + if (m.identifier == p_member) { + r_member_type = m.data_type; + return true; + } + } + } else { + for (int i = 0; i < base->subclasses.size(); i++) { + ClassNode *c = base->subclasses[i]; + if (c->name == p_member) { + DataType class_type; + class_type.has_type = true; + class_type.is_constant = true; + class_type.is_meta_type = true; + class_type.kind = DataType::CLASS; + class_type.class_type = c; + r_member_type = class_type; + return true; + } + } + } + + base_type = base->base_type; + if (base_type.kind == DataType::CLASS) { + base = base_type.class_type; + } else { + break; + } + } + + Ref<GDScript> gds; + if (base_type.kind == DataType::GDSCRIPT) { + gds = base_type.script_type; + } + + Ref<Script> scr; + if (base_type.kind == DataType::SCRIPT) { + scr = base_type.script_type; + } + + StringName native; + if (base_type.kind == DataType::NATIVE) { + native = base_type.native_type; + } + + // Check GDScripts + while (gds.is_valid()) { + if (gds->get_constants().has(p_member)) { + Variant c = gds->get_constants()[p_member]; + r_member_type = _type_from_variant(c); + return true; + } + + if (!base_type.is_meta_type) { + if (gds->get_members().has(p_member)) { + r_member_type = _type_from_gdtype(gds->get_member_type(p_member)); + return true; + } + } + + native = gds->get_instance_base_type(); + if (gds->get_base_script().is_valid()) { + gds = gds->get_base_script(); + scr = gds->get_base_script(); + bool is_meta = base_type.is_meta_type; + base_type = _type_from_variant(scr.operator Variant()); + base_type.is_meta_type = is_meta; + } else { + break; + } + } + + // Check other script types + while (scr.is_valid()) { + Map<StringName, Variant> constants; + scr->get_constants(&constants); + if (constants.has(p_member)) { + r_member_type = _type_from_variant(constants[p_member]); + return true; + } + + List<PropertyInfo> properties; + scr->get_script_property_list(&properties); + for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_member) { + r_member_type = _type_from_property(E->get()); + return true; + } + } + + base_type = _type_from_variant(scr.operator Variant()); + native = scr->get_instance_base_type(); + scr = scr->get_base_script(); + } + + // Check ClassDB + if (!ClassDB::class_exists(native)) { + native = "_" + native.operator String(); + } + if (!ClassDB::class_exists(native)) { + if (!check_types) return false; + ERR_EXPLAIN("Parser bug: Class '" + String(native) + "' not found."); + ERR_FAIL_V(false); + } + + bool valid = false; + ClassDB::get_integer_constant(native, p_member, &valid); + if (valid) { + DataType ct; + ct.has_type = true; + ct.is_constant = true; + ct.kind = DataType::BUILTIN; + ct.builtin_type = Variant::INT; + r_member_type = ct; + return true; + } + + if (!base_type.is_meta_type) { + List<PropertyInfo> properties; + ClassDB::get_property_list(native, &properties); + for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_member) { + // Check if a getter exists + StringName getter_name = ClassDB::get_property_getter(native, p_member); + if (getter_name != StringName()) { + // Use the getter return type +#ifdef DEBUG_METHODS_ENABLED + MethodBind *getter_method = ClassDB::get_method(native, getter_name); + if (getter_method) { + r_member_type = _type_from_property(getter_method->get_return_info()); + } else { + r_member_type = DataType(); + } +#else + r_member_type = DataType(); +#endif + } else { + r_member_type = _type_from_property(E->get()); + } + return true; + } + } + } + + // If the base is a script, it might be trying to access members of the Script class itself + if (p_base_type.is_meta_type && (p_base_type.kind == DataType::SCRIPT || p_base_type.kind == DataType::GDSCRIPT)) { + native = p_base_type.script_type->get_class_name(); + ClassDB::get_integer_constant(native, p_member, &valid); + if (valid) { + DataType ct; + ct.has_type = true; + ct.is_constant = true; + ct.kind = DataType::BUILTIN; + ct.builtin_type = Variant::INT; + r_member_type = ct; + return true; + } + + List<PropertyInfo> properties; + ClassDB::get_property_list(native, &properties); + for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_member) { + // Check if a getter exists + StringName getter_name = ClassDB::get_property_getter(native, p_member); + if (getter_name != StringName()) { + // Use the getter return type +#ifdef DEBUG_METHODS_ENABLED + MethodBind *getter_method = ClassDB::get_method(native, getter_name); + if (getter_method) { + r_member_type = _type_from_property(getter_method->get_return_info()); + } else { + r_member_type = DataType(); + } +#else + r_member_type = DataType(); +#endif + } else { + r_member_type = _type_from_property(E->get()); + } + return true; + } + } + } + + return false; +} + +GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType *p_base_type, const StringName &p_identifier, int p_line) { + + if (p_base_type && !p_base_type->has_type) { + return DataType(); + } + + DataType base_type; + + // Check classes in current file + ClassNode *base = NULL; + if (!p_base_type) { + base = current_class; + base_type.has_type = true; + base_type.is_constant = true; + base_type.kind = DataType::CLASS; + base_type.class_type = base; + } else { + base_type = DataType(*p_base_type); + if (base_type.kind == DataType::CLASS) { + base = base_type.class_type; + } + } + + DataType member_type; + + if (_get_member_type(base_type, p_identifier, member_type)) { + return member_type; + } + + if (!p_base_type) { + // Possibly this is a global, check before failing + + if (ClassDB::class_exists(p_identifier) || ClassDB::class_exists("_" + p_identifier.operator String())) { + DataType result; + result.has_type = true; + result.is_constant = true; + result.is_meta_type = true; + if (Engine::get_singleton()->has_singleton(p_identifier) || Engine::get_singleton()->has_singleton("_" + p_identifier.operator String())) { + result.is_meta_type = false; + } + result.kind = DataType::NATIVE; + result.native_type = p_identifier; + return result; + } + + ClassNode *outer_class = current_class; + while (outer_class) { + if (outer_class->name == p_identifier) { + DataType result; + result.has_type = true; + result.is_constant = true; + result.is_meta_type = true; + result.kind = DataType::CLASS; + result.class_type = outer_class; + return result; + } + if (outer_class->constant_expressions.has(p_identifier)) { + return outer_class->constant_expressions[p_identifier].type; + } + for (int i = 0; i < outer_class->subclasses.size(); i++) { + if (outer_class->subclasses[i] == current_class) { + continue; + } + if (outer_class->subclasses[i]->name == p_identifier) { + DataType result; + result.has_type = true; + result.is_constant = true; + result.is_meta_type = true; + result.kind = DataType::CLASS; + result.class_type = outer_class->subclasses[i]; + return result; + } + } + outer_class = outer_class->owner; + } + + if (ScriptServer::is_global_class(p_identifier)) { + Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_identifier)); + if (scr.is_valid()) { + DataType result; + result.has_type = true; + result.script_type = scr; + result.is_meta_type = true; + Ref<GDScript> gds = scr; + if (gds.is_valid()) { + if (!gds->is_valid()) { + _set_error("Class '" + p_identifier + "' could not be fully loaded (script error or cyclic inheritance)."); + return DataType(); + } + result.kind = DataType::GDSCRIPT; + } else { + result.kind = DataType::SCRIPT; + } + return result; + } + _set_error("Class '" + p_identifier + "' was found in global scope but its script could not be loaded."); + return DataType(); + } + + if (GDScriptLanguage::get_singleton()->get_global_map().has(p_identifier)) { + int idx = GDScriptLanguage::get_singleton()->get_global_map()[p_identifier]; + Variant g = GDScriptLanguage::get_singleton()->get_global_array()[idx]; + return _type_from_variant(g); + } + + if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(p_identifier)) { + Variant g = GDScriptLanguage::get_singleton()->get_named_globals_map()[p_identifier]; + return _type_from_variant(g); + } + + // Non-tool singletons aren't loaded, check project settings + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + String s = E->get().name; + if (!s.begins_with("autoload/")) { + continue; + } + String name = s.get_slice("/", 1); + if (name == p_identifier) { + String script = ProjectSettings::get_singleton()->get(s); + if (script.begins_with("*")) { + script = script.right(1); + } + if (!script.begins_with("res://")) { + script = "res://" + script; + } + Ref<Script> singleton = ResourceLoader::load(script); + if (singleton.is_valid()) { + DataType result; + result.has_type = true; + result.script_type = singleton; + + Ref<GDScript> gds = singleton; + if (gds.is_valid()) { + if (!gds->is_valid()) { + _set_error("Couldn't fully load singleton script '" + p_identifier + "' (possible cyclic reference or parse error).", p_line); + return DataType(); + } + result.kind = DataType::GDSCRIPT; + } else { + result.kind = DataType::SCRIPT; + } + } + } + } + + // This means looking in the current class, which type is always known + _set_error("Identifier '" + p_identifier.operator String() + "' is not declared in the current scope.", p_line); + } + + _mark_line_as_unsafe(p_line); + return DataType(); +} + +void GDScriptParser::_check_class_level_types(ClassNode *p_class) { + + _mark_line_as_safe(p_class->line); + + // Constants + for (Map<StringName, ClassNode::Constant>::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { + ClassNode::Constant &c = E->get(); + _mark_line_as_safe(c.expression->line); + DataType cont = _resolve_type(c.type, c.expression->line); + DataType expr = _resolve_type(c.expression->get_datatype(), c.expression->line); + + if (!_is_type_compatible(cont, expr)) { + _set_error("Constant value type (" + expr.to_string() + ") is not compatible with declared type (" + cont.to_string() + ").", + c.expression->line); + return; + } + + expr.is_constant = true; + c.type = expr; + c.expression->set_datatype(expr); + } + + // Function declarations + for (int i = 0; i < p_class->static_functions.size(); i++) { + _check_function_types(p_class->static_functions[i]); + if (error_set) return; + } + + for (int i = 0; i < p_class->functions.size(); i++) { + _check_function_types(p_class->functions[i]); + if (error_set) return; + } + + // Class variables + for (int i = 0; i < p_class->variables.size(); i++) { + ClassNode::Member &v = p_class->variables.write[i]; + + DataType tmp; + if (_get_member_type(p_class->base_type, v.identifier, tmp)) { + _set_error("Member '" + String(v.identifier) + "' already exists in parent class.", v.line); + return; + } + + _mark_line_as_safe(v.line); + v.data_type = _resolve_type(v.data_type, v.line); + + if (v.expression) { + DataType expr_type = _reduce_node_type(v.expression); + + if (!_is_type_compatible(v.data_type, expr_type)) { + // Try supertype test + if (_is_type_compatible(expr_type, v.data_type)) { + _mark_line_as_unsafe(v.line); + } else { + // Try with implicit conversion + if (v.data_type.kind != DataType::BUILTIN || !_is_type_compatible(v.data_type, expr_type, true)) { + _set_error("Assigned expression type (" + expr_type.to_string() + ") doesn't match the variable's type (" + + v.data_type.to_string() + ").", + v.line); + return; + } + + // Replace assigment with implict conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = v.line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = v.line; + tgt_type->value = (int)v.data_type.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = v.line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(v.expression); + convert_call->arguments.push_back(tgt_type); + + v.expression = convert_call; + v.initial_assignment->arguments.write[1] = convert_call; + } + } + + if (v.data_type.infer_type) { + if (!expr_type.has_type) { + _set_error("Assigned value does not have a set type, variable type cannot be inferred.", v.line); + return; + } + v.data_type = expr_type; + v.data_type.is_constant = false; + } + } else if (v.data_type.has_type && v.data_type.kind == DataType::BUILTIN) { + // Create default value based on the type + IdentifierNode *id = alloc_node<IdentifierNode>(); + id->line = v.line; + id->name = v.identifier; + + ConstantNode *init = alloc_node<ConstantNode>(); + init->line = v.line; + Variant::CallError err; + init->value = Variant::construct(v.data_type.builtin_type, NULL, 0, err); + + OperatorNode *op = alloc_node<OperatorNode>(); + op->line = v.line; + op->op = OperatorNode::OP_INIT_ASSIGN; + op->arguments.push_back(id); + op->arguments.push_back(init); + + p_class->initializer->statements.push_front(op); + v.initial_assignment = op; +#ifdef DEBUG_ENABLED + NewLineNode *nl = alloc_node<NewLineNode>(); + nl->line = v.line - 1; + p_class->initializer->statements.push_front(nl); +#endif + } + + // Check export hint + if (v.data_type.has_type && v._export.type != Variant::NIL) { + DataType export_type = _type_from_property(v._export); + if (!_is_type_compatible(v.data_type, export_type, true)) { + _set_error("Export hint type (" + export_type.to_string() + ") doesn't match the variable's type (" + + v.data_type.to_string() + ").", + v.line); + return; + } + } + + // Setter and getter + if (v.setter == StringName() && v.getter == StringName()) continue; + + bool found_getter = false; + bool found_setter = false; + for (int j = 0; j < p_class->functions.size(); j++) { + if (v.setter == p_class->functions[j]->name) { + found_setter = true; + FunctionNode *setter = p_class->functions[j]; + + if (setter->arguments.size() != 1) { + _set_error("Setter function needs to receive exactly 1 argument. See '" + setter->name + + "()' definition at line " + itos(setter->line) + ".", + v.line); + return; + } + if (!_is_type_compatible(v.data_type, setter->argument_types[0])) { + _set_error("Setter argument type (" + setter->argument_types[0].to_string() + + ") doesn't match the variable's type (" + v.data_type.to_string() + "). See '" + + setter->name + "()' definition at line " + itos(setter->line) + ".", + v.line); + return; + } + continue; + } + if (v.getter == p_class->functions[j]->name) { + found_getter = true; + FunctionNode *getter = p_class->functions[j]; + + if (getter->arguments.size() != 0) { + _set_error("Getter function can't receive arguments. See '" + getter->name + + "()' definition at line " + itos(getter->line) + ".", + v.line); + return; + } + if (!_is_type_compatible(v.data_type, getter->get_datatype())) { + _set_error("Getter return type (" + getter->get_datatype().to_string() + + ") doesn't match the variable's type (" + v.data_type.to_string() + + "). See '" + getter->name + "()' definition at line " + itos(getter->line) + ".", + v.line); + return; + } + } + if (found_getter && found_setter) break; + } + + if ((found_getter || v.getter == StringName()) && (found_setter || v.setter == StringName())) continue; + + // Check for static functions + for (int j = 0; j < p_class->static_functions.size(); j++) { + if (v.setter == p_class->static_functions[j]->name) { + FunctionNode *setter = p_class->static_functions[j]; + _set_error("Setter can't be a static function. See '" + setter->name + "()' definition at line " + itos(setter->line) + ".", v.line); + return; + } + if (v.getter == p_class->static_functions[j]->name) { + FunctionNode *getter = p_class->static_functions[j]; + _set_error("Getter can't be a static function. See '" + getter->name + "()' definition at line " + itos(getter->line) + ".", v.line); + return; + } + } + + if (!found_setter && v.setter != StringName()) { + _set_error("Setter function is not defined.", v.line); + return; + } + + if (!found_getter && v.getter != StringName()) { + _set_error("Getter function is not defined.", v.line); + return; + } + } + + // Inner classes + for (int i = 0; i < p_class->subclasses.size(); i++) { + current_class = p_class->subclasses[i]; + _check_class_level_types(current_class); + if (error_set) return; + current_class = p_class; + } +} + +void GDScriptParser::_check_function_types(FunctionNode *p_function) { + + p_function->return_type = _resolve_type(p_function->return_type, p_function->line); + + // Arguments + int defaults_ofs = p_function->arguments.size() - p_function->default_values.size(); + for (int i = 0; i < p_function->arguments.size(); i++) { + if (i < defaults_ofs) { + p_function->argument_types.write[i] = _resolve_type(p_function->argument_types[i], p_function->line); + } else { + if (p_function->default_values[i - defaults_ofs]->type != Node::TYPE_OPERATOR) { + _set_error("Parser bug: invalid argument default value.", p_function->line, p_function->column); + return; + } + + OperatorNode *op = static_cast<OperatorNode *>(p_function->default_values[i - defaults_ofs]); + + if (op->op != OperatorNode::OP_ASSIGN || op->arguments.size() != 2) { + _set_error("Parser bug: invalid argument default value operation.", p_function->line); + return; + } + + DataType def_type = _reduce_node_type(op->arguments[1]); + + if (p_function->argument_types[i].infer_type) { + def_type.is_constant = false; + p_function->argument_types.write[i] = def_type; + } else { + p_function->return_type = _resolve_type(p_function->return_type, p_function->line); + + if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) { + String arg_name = p_function->arguments[i]; + _set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" + + arg_name + "' (" + p_function->arguments[i] + ")", + p_function->line); + } + } + } + } + + if (!(p_function->name == "_init")) { + // Signature for the initializer may vary +#ifdef DEBUG_ENABLED + DataType return_type; + List<DataType> arg_types; + int default_arg_count = 0; + bool _static = false; + bool vararg = false; + + DataType base_type = current_class->base_type; + if (_get_function_signature(base_type, p_function->name, return_type, arg_types, default_arg_count, _static, vararg)) { + bool valid = _static == p_function->_static; + valid = valid && return_type == p_function->return_type; + int argsize_diff = p_function->arguments.size() - arg_types.size(); + valid = valid && argsize_diff >= 0; + valid = valid && p_function->default_values.size() >= default_arg_count + argsize_diff; + int i = 0; + for (List<DataType>::Element *E = arg_types.front(); valid && E; E = E->next()) { + valid = valid && E->get() == p_function->argument_types[i++]; + } + + if (!valid) { + String parent_signature = return_type.has_type ? return_type.to_string() : "Variant"; + if (parent_signature == "null") { + parent_signature = "void"; + } + parent_signature += " " + p_function->name + "("; + if (arg_types.size()) { + int i = 0; + for (List<DataType>::Element *E = arg_types.front(); E; E = E->next()) { + if (E != arg_types.front()) { + parent_signature += ", "; + } + String arg = E->get().to_string(); + if (arg == "null" || arg == "var") { + arg = "Variant"; + } + parent_signature += arg; + if (i == arg_types.size() - default_arg_count) { + parent_signature += "=default"; + } + + i++; + } + } + parent_signature += ")"; + _set_error("Function signature doesn't match the parent. Parent signature is: '" + parent_signature + "'.", p_function->line); + return; + } + } +#endif // DEBUG_ENABLED + } else { + if (p_function->return_type.has_type && (p_function->return_type.kind != DataType::BUILTIN || p_function->return_type.builtin_type != Variant::NIL)) { + _set_error("Constructor cannot return a value.", p_function->line); + return; + } + } + + if (p_function->return_type.has_type && (p_function->return_type.kind != DataType::BUILTIN || p_function->return_type.builtin_type != Variant::NIL)) { + if (!p_function->body->has_return) { + _set_error("Non-void function must return a value in all possible paths.", p_function->line); + return; + } + } + + if (p_function->has_yield) { + // yield() will make the function return a GDScriptFunctionState, so the type is ambiguous + p_function->return_type.has_type = false; + } +} + +void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { + + // Function blocks + for (int i = 0; i < p_class->static_functions.size(); i++) { + current_function = p_class->static_functions[i]; + current_block = current_function->body; + _mark_line_as_safe(current_function->line); + _check_block_types(current_block); + current_block = NULL; + current_function = NULL; + if (error_set) return; + } + + for (int i = 0; i < p_class->functions.size(); i++) { + current_function = p_class->functions[i]; + current_block = current_function->body; + _mark_line_as_safe(current_function->line); + _check_block_types(current_block); + current_block = NULL; + current_function = NULL; + if (error_set) return; + } + + // Inner classes + for (int i = 0; i < p_class->subclasses.size(); i++) { + current_class = p_class->subclasses[i]; + _check_class_blocks_types(current_class); + if (error_set) return; + current_class = p_class; + } +} + +void GDScriptParser::_check_block_types(BlockNode *p_block) { + + Node *last_var_assign = NULL; + + // Check each statement + for (List<Node *>::Element *E = p_block->statements.front(); E; E = E->next()) { + Node *statement = E->get(); + switch (statement->type) { + case Node::TYPE_NEWLINE: + case Node::TYPE_BREAKPOINT: + case Node::TYPE_ASSERT: { + // Nothing to do + } break; + case Node::TYPE_LOCAL_VAR: { + LocalVarNode *lv = static_cast<LocalVarNode *>(statement); + lv->datatype = _resolve_type(lv->datatype, lv->line); + _mark_line_as_safe(lv->line); + + if (lv->assign) { + DataType assign_type = _reduce_node_type(lv->assign); + if (!_is_type_compatible(lv->datatype, assign_type)) { + // Try supertype test + if (_is_type_compatible(assign_type, lv->datatype)) { + _mark_line_as_unsafe(lv->line); + } else { + // Try implict conversion + if (lv->datatype.kind != DataType::BUILTIN || !_is_type_compatible(lv->datatype, assign_type, true)) { + _set_error("Assigned value type (" + assign_type.to_string() + ") doesn't match the variable's type (" + + lv->datatype.to_string() + ").", + lv->line); + return; + } + // Replace assigment with implict conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = lv->line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = lv->line; + tgt_type->value = (int)lv->datatype.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = lv->line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(lv->assign); + convert_call->arguments.push_back(tgt_type); + + lv->assign = convert_call; + lv->assign_op->arguments.write[1] = convert_call; + } + } + if (lv->datatype.infer_type) { + if (!assign_type.has_type) { + _set_error("Assigned value does not have a set type, variable type cannot be inferred.", lv->line); + return; + } + lv->datatype = assign_type; + lv->datatype.is_constant = false; + } + if (lv->datatype.has_type && !assign_type.has_type) { + _mark_line_as_unsafe(lv->line); + } + } + last_var_assign = lv->assign; + + // TODO: Make a warning + /* + if (lv->assignments == 0) { + _set_error("Variable '" + String(lv->name) + "' is never assigned.", lv->line); + return; + } + */ + } break; + case Node::TYPE_OPERATOR: { + OperatorNode *op = static_cast<OperatorNode *>(statement); + + switch (op->op) { + case OperatorNode::OP_ASSIGN: + case OperatorNode::OP_ASSIGN_ADD: + case OperatorNode::OP_ASSIGN_SUB: + case OperatorNode::OP_ASSIGN_MUL: + case OperatorNode::OP_ASSIGN_DIV: + case OperatorNode::OP_ASSIGN_MOD: + case OperatorNode::OP_ASSIGN_SHIFT_LEFT: + case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: + case OperatorNode::OP_ASSIGN_BIT_AND: + case OperatorNode::OP_ASSIGN_BIT_OR: + case OperatorNode::OP_ASSIGN_BIT_XOR: { + if (op->arguments.size() < 2) { + _set_error("Parser bug: operation without enough arguments.", op->line, op->column); + return; + } + + if (op->arguments[1] == last_var_assign) { + // Assignment was already checked + break; + } + + _mark_line_as_safe(op->line); + + DataType lh_type = _reduce_node_type(op->arguments[0]); + + if (error_set) { + return; + } + + if (!lh_type.has_type) { + if (op->arguments[0]->type == Node::TYPE_OPERATOR) { + _mark_line_as_unsafe(op->line); + } + } else if (lh_type.is_constant) { + _set_error("Cannot assign a new value to a constant.", op->line); + return; + } + + DataType rh_type; + if (op->op != OperatorNode::OP_ASSIGN) { + // Validate operation + DataType arg_type = _reduce_node_type(op->arguments[1]); + if (!arg_type.has_type) { + _mark_line_as_unsafe(op->line); + break; + } + + Variant::Operator oper = _get_variant_operation(op->op); + bool valid = false; + rh_type = _get_operation_type(oper, lh_type, arg_type, valid); + + if (!valid) { + _set_error("Invalid operand types ('" + lh_type.to_string() + "' and '" + arg_type.to_string() + + "') to assignment operator '" + Variant::get_operator_name(oper) + "'.", + op->line); + return; + } + } else { + rh_type = _reduce_node_type(op->arguments[1]); + } + + if (!_is_type_compatible(lh_type, rh_type)) { + // Try supertype test + if (_is_type_compatible(rh_type, lh_type)) { + _mark_line_as_unsafe(op->line); + } else { + // Try implict conversion + if (lh_type.kind != DataType::BUILTIN || !_is_type_compatible(lh_type, rh_type, true)) { + _set_error("Assigned value type (" + rh_type.to_string() + ") doesn't match the variable's type (" + + lh_type.to_string() + ").", + op->line); + return; + } + // Replace assigment with implict conversion + BuiltInFunctionNode *convert = alloc_node<BuiltInFunctionNode>(); + convert->line = op->line; + convert->function = GDScriptFunctions::TYPE_CONVERT; + + ConstantNode *tgt_type = alloc_node<ConstantNode>(); + tgt_type->line = op->line; + tgt_type->value = (int)lh_type.builtin_type; + + OperatorNode *convert_call = alloc_node<OperatorNode>(); + convert_call->line = op->line; + convert_call->op = OperatorNode::OP_CALL; + convert_call->arguments.push_back(convert); + convert_call->arguments.push_back(op->arguments[1]); + convert_call->arguments.push_back(tgt_type); + + op->arguments.write[1] = convert_call; + } + } + if (!rh_type.has_type && (op->op != OperatorNode::OP_ASSIGN || lh_type.has_type || op->arguments[0]->type == Node::TYPE_OPERATOR)) { + _mark_line_as_unsafe(op->line); + } + } break; + case OperatorNode::OP_CALL: + case OperatorNode::OP_PARENT_CALL: { + _mark_line_as_safe(op->line); + _reduce_function_call_type(op); + if (error_set) return; + } break; + default: { + _mark_line_as_safe(op->line); + _reduce_node_type(op); // Test for safety anyway + // TODO: Make this a warning + /*_set_error("Standalone expression, nothing is done in this line.", statement->line); + return; */ + } + } + } break; + case Node::TYPE_CONTROL_FLOW: { + ControlFlowNode *cf = static_cast<ControlFlowNode *>(statement); + _mark_line_as_safe(cf->line); + + switch (cf->cf_type) { + case ControlFlowNode::CF_RETURN: { + DataType function_type = current_function->get_datatype(); + + DataType ret_type; + if (cf->arguments.size() > 0) { + ret_type = _reduce_node_type(cf->arguments[0]); + if (error_set) { + return; + } + } + + if (!function_type.has_type) break; + + if (function_type.kind == DataType::BUILTIN && function_type.builtin_type == Variant::NIL) { + // Return void, should not have arguments + if (cf->arguments.size() > 0) { + _set_error("Void function cannot return a value.", cf->line, cf->column); + return; + } + } else { + // Return something, cannot be empty + if (cf->arguments.size() == 0) { + _set_error("Non-void function must return a value.", cf->line, cf->column); + return; + } + + if (!_is_type_compatible(function_type, ret_type)) { + _set_error("Returned value type (" + ret_type.to_string() + ") doesn't match the function return type (" + + function_type.to_string() + ").", + cf->line, cf->column); + return; + } + } + } break; + case ControlFlowNode::CF_MATCH: { + MatchNode *match_node = cf->match; + _transform_match_statment(match_node); + } break; + default: { + if (cf->body_else) { + _mark_line_as_safe(cf->body_else->line); + } + for (int i = 0; i < cf->arguments.size(); i++) { + _reduce_node_type(cf->arguments[i]); + } + } break; + } + } break; + case Node::TYPE_CONSTANT: { + ConstantNode *cn = static_cast<ConstantNode *>(statement); + // Strings are fine since they can be multiline comments + if (cn->value.get_type() == Variant::STRING) { + break; + } + } // falthrough + default: { + _mark_line_as_safe(statement->line); + _reduce_node_type(statement); // Test for safety anyway + // TODO: Make this a warning + /* _set_error("Standalone expression, nothing is done in this line.", statement->line); + return; */ + } + } + } + + // Parse sub blocks + for (int i = 0; i < p_block->sub_blocks.size(); i++) { + current_block = p_block->sub_blocks[i]; + _check_block_types(current_block); + current_block = p_block; + if (error_set) return; + } +} + void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) { if (error_set) @@ -4467,10 +7591,39 @@ Error GDScriptParser::_parse(const String &p_base_path) { _set_error("Parse Error: " + tokenizer->get_token_error()); } + if (error_set && !for_completion) { + return ERR_PARSE_ERROR; + } + + _determine_inheritance(main_class); + + if (error_set) { + return ERR_PARSE_ERROR; + } + + current_class = main_class; + current_function = NULL; + current_block = NULL; +#ifdef DEBUG_ENABLED + if (for_completion) check_types = false; +#else + check_types = false; +#endif + + // Resolve all class-level stuff before getting into function blocks + _check_class_level_types(main_class); + if (error_set) { + return ERR_PARSE_ERROR; + } + // Resolve the function blocks + _check_class_blocks_types(main_class); + + if (error_set) { return ERR_PARSE_ERROR; } + return OK; } @@ -4488,7 +7641,7 @@ Error GDScriptParser::parse_bytecode(const Vector<uint8_t> &p_bytecode, const St return ret; } -Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion) { +Error GDScriptParser::parse(const String &p_code, const String &p_base_path, bool p_just_validate, const String &p_self_path, bool p_for_completion, Set<int> *r_safe_lines) { clear(); @@ -4498,6 +7651,9 @@ Error GDScriptParser::parse(const String &p_code, const String &p_base_path, boo validating = p_just_validate; for_completion = p_for_completion; +#ifdef DEBUG_ENABLED + safe_lines = r_safe_lines; +#endif // DEBUG_ENABLED tokenizer = tt; Error ret = _parse(p_base_path); memdelete(tt); @@ -4550,7 +7706,11 @@ void GDScriptParser::clear() { pending_newline = -1; parenthesis = 0; current_export.type = Variant::NIL; + check_types = true; error = ""; +#ifdef DEBUG_ENABLED + safe_lines = NULL; +#endif // DEBUG_ENABLED } GDScriptParser::CompletionType GDScriptParser::get_completion_type() { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index b88a59537c..48f256b4c6 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -37,8 +37,68 @@ #include "object.h" #include "script_language.h" +struct GDScriptDataType; + class GDScriptParser { public: + struct ClassNode; + + struct DataType { + enum { + BUILTIN, + NATIVE, + SCRIPT, + GDSCRIPT, + CLASS, + UNRESOLVED + } kind; + + bool has_type; + bool is_constant; + bool is_meta_type; // Whether the value can be used as a type + bool infer_type; + + Variant::Type builtin_type; + StringName native_type; + Ref<Script> script_type; + ClassNode *class_type; + + String to_string() const; + + bool operator==(const DataType &other) const { + if (!has_type || !other.has_type) { + return true; // Can be considered equal for parsing purpose + } + if (kind != other.kind) { + return false; + } + switch (kind) { + case BUILTIN: { + return builtin_type == other.builtin_type; + } break; + case NATIVE: { + return native_type == other.native_type; + } break; + case GDSCRIPT: + case SCRIPT: { + return script_type == other.script_type; + } break; + case CLASS: { + return class_type == other.class_type; + } break; + } + return false; + } + + DataType() : + has_type(false), + is_constant(false), + is_meta_type(false), + infer_type(false), + builtin_type(Variant::NIL), + class_type(NULL) {} + }; + struct Node { enum Type { @@ -55,6 +115,7 @@ public: TYPE_OPERATOR, TYPE_CONTROL_FLOW, TYPE_LOCAL_VAR, + TYPE_CAST, TYPE_ASSERT, TYPE_BREAKPOINT, TYPE_NEWLINE, @@ -65,11 +126,17 @@ public: int column; Type type; + virtual DataType get_datatype() const { return DataType(); } + virtual void set_datatype(const DataType &p_datatype) {} + virtual ~Node() {} }; struct FunctionNode; struct BlockNode; + struct ConstantNode; + struct LocalVarNode; + struct OperatorNode; struct ClassNode : public Node { @@ -78,6 +145,7 @@ public: bool extends_used; StringName extends_file; Vector<StringName> extends_class; + DataType base_type; struct Member { PropertyInfo _export; @@ -85,15 +153,17 @@ public: Variant default_value; #endif StringName identifier; + DataType data_type; StringName setter; StringName getter; int line; Node *expression; + OperatorNode *initial_assignment; MultiplayerAPI::RPCMode rpc_mode; }; struct Constant { - StringName identifier; Node *expression; + DataType type; }; struct Signal { @@ -103,7 +173,7 @@ public: Vector<ClassNode *> subclasses; Vector<Member> variables; - Vector<Constant> constant_expressions; + Map<StringName, Constant> constant_expressions; Vector<FunctionNode *> functions; Vector<FunctionNode *> static_functions; Vector<Signal> _signals; @@ -126,15 +196,22 @@ public: bool _static; MultiplayerAPI::RPCMode rpc_mode; + bool has_yield; StringName name; + DataType return_type; Vector<StringName> arguments; + Vector<DataType> argument_types; Vector<Node *> default_values; BlockNode *body; + virtual DataType get_datatype() const { return return_type; } + virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; } + FunctionNode() { type = TYPE_FUNCTION; _static = false; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; + has_yield = false; } }; @@ -142,10 +219,9 @@ public: ClassNode *parent_class; BlockNode *parent_block; - Map<StringName, int> locals; List<Node *> statements; - Vector<StringName> variables; - Vector<int> variable_lines; + Map<StringName, LocalVarNode *> variables; + bool has_return; Node *if_condition; //tiny hack to improve code completion on if () blocks @@ -158,6 +234,7 @@ public: end_line = -1; parent_block = NULL; parent_class = NULL; + has_return = false; } }; @@ -174,28 +251,53 @@ public: struct IdentifierNode : public Node { StringName name; - IdentifierNode() { type = TYPE_IDENTIFIER; } + BlockNode *declared_block; // Simplify lookup by checking if it is declared locally + DataType datatype; + virtual DataType get_datatype() const { return datatype; } + virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + IdentifierNode() { + type = TYPE_IDENTIFIER; + declared_block = NULL; + } }; struct LocalVarNode : public Node { StringName name; Node *assign; + OperatorNode *assign_op; + int assignments; + DataType datatype; + virtual DataType get_datatype() const { return datatype; } + virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } LocalVarNode() { type = TYPE_LOCAL_VAR; assign = NULL; + assign_op = NULL; + assignments = 0; } }; struct ConstantNode : public Node { Variant value; + DataType datatype; + virtual DataType get_datatype() const { return datatype; } + virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } ConstantNode() { type = TYPE_CONSTANT; } }; struct ArrayNode : public Node { Vector<Node *> elements; - ArrayNode() { type = TYPE_ARRAY; } + DataType datatype; + virtual DataType get_datatype() const { return datatype; } + virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + ArrayNode() { + type = TYPE_ARRAY; + datatype.has_type = true; + datatype.kind = DataType::BUILTIN; + datatype.builtin_type = Variant::ARRAY; + } }; struct DictionaryNode : public Node { @@ -207,7 +309,15 @@ public: }; Vector<Pair> elements; - DictionaryNode() { type = TYPE_DICTIONARY; } + DataType datatype; + virtual DataType get_datatype() const { return datatype; } + virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } + DictionaryNode() { + type = TYPE_DICTIONARY; + datatype.has_type = true; + datatype.kind = DataType::BUILTIN; + datatype.builtin_type = Variant::DICTIONARY; + } }; struct SelfNode : public Node { @@ -229,10 +339,6 @@ public: OP_POS, OP_NOT, OP_BIT_INVERT, - OP_PREINC, - OP_PREDEC, - OP_INC, - OP_DEC, //binary operators (in precedence order) OP_IN, OP_EQUAL, @@ -273,6 +379,9 @@ public: Operator op; Vector<Node *> arguments; + DataType datatype; + virtual DataType get_datatype() const { return datatype; } + virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } OperatorNode() { type = TYPE_OPERATOR; } }; @@ -340,6 +449,15 @@ public: } }; + struct CastNode : public Node { + Node *source_node; + DataType cast_type; + DataType return_type; + virtual DataType get_datatype() const { return return_type; } + virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; } + CastNode() { type = TYPE_CAST; } + }; + struct AssertNode : public Node { Node *condition; AssertNode() { type = TYPE_ASSERT; } @@ -362,76 +480,6 @@ public: }; }; - /* - struct OperatorNode : public Node { - - DataType return_cache; - Operator op; - Vector<Node*> arguments; - virtual DataType get_datatype() const { return return_cache; } - - OperatorNode() { type=TYPE_OPERATOR; return_cache=TYPE_VOID; } - }; - - struct VariableNode : public Node { - - DataType datatype_cache; - StringName name; - virtual DataType get_datatype() const { return datatype_cache; } - - VariableNode() { type=TYPE_VARIABLE; datatype_cache=TYPE_VOID; } - }; - - struct ConstantNode : public Node { - - DataType datatype; - Variant value; - virtual DataType get_datatype() const { return datatype; } - - ConstantNode() { type=TYPE_CONSTANT; } - }; - - struct BlockNode : public Node { - - Map<StringName,DataType> variables; - List<Node*> statements; - BlockNode() { type=TYPE_BLOCK; } - }; - - struct ControlFlowNode : public Node { - - FlowOperation flow_op; - Vector<Node*> statements; - ControlFlowNode() { type=TYPE_CONTROL_FLOW; flow_op=FLOW_OP_IF;} - }; - - struct MemberNode : public Node { - - DataType datatype; - StringName name; - Node* owner; - virtual DataType get_datatype() const { return datatype; } - MemberNode() { type=TYPE_MEMBER; } - }; - - - struct ProgramNode : public Node { - - struct Function { - StringName name; - FunctionNode*function; - }; - - Map<StringName,DataType> builtin_variables; - Map<StringName,DataType> preexisting_variables; - - Vector<Function> functions; - BlockNode *body; - - ProgramNode() { type=TYPE_PROGRAM; } - }; -*/ - enum CompletionType { COMPLETION_NONE, COMPLETION_BUILT_IN_TYPE_CONSTANT, @@ -446,6 +494,8 @@ public: COMPLETION_VIRTUAL_FUNC, COMPLETION_YIELD, COMPLETION_ASSIGN, + COMPLETION_TYPE_HINT, + COMPLETION_TYPE_HINT_INDEX, }; private: @@ -463,6 +513,10 @@ private: String error; int error_line; int error_column; + bool check_types; +#ifdef DEBUG_ENABLED + Set<int> *safe_lines; +#endif // DEBUG_ENABLED int pending_newline; @@ -507,7 +561,7 @@ private: PatternNode *_parse_pattern(bool p_static); void _parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static); - void _transform_match_statment(BlockNode *p_block, MatchNode *p_match_statement); + void _transform_match_statment(MatchNode *p_match_statement); void _generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node *> &p_bindings); void _parse_block(BlockNode *p_block, bool p_static); @@ -515,13 +569,43 @@ private: void _parse_class(ClassNode *p_class); bool _end_statement(); + void _determine_inheritance(ClassNode *p_class); + bool _parse_type(DataType &r_type, bool p_can_be_void = false); + DataType _resolve_type(const DataType &p_source, int p_line); + DataType _type_from_variant(const Variant &p_value) const; + DataType _type_from_property(const PropertyInfo &p_property, bool p_nil_is_variant = true) const; + DataType _type_from_gdtype(const GDScriptDataType &p_gdtype) const; + DataType _get_operation_type(const Variant::Operator p_op, const DataType &p_a, const DataType &p_b, bool &r_valid) const; + Variant::Operator _get_variant_operation(const OperatorNode::Operator &p_op) const; + bool _get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const; + bool _get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type) const; + bool _is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion = false) const; + + DataType _reduce_node_type(Node *p_node); + DataType _reduce_function_call_type(const OperatorNode *p_call); + DataType _reduce_identifier_type(const DataType *p_base_type, const StringName &p_identifier, int p_line); + void _check_class_level_types(ClassNode *p_class); + void _check_class_blocks_types(ClassNode *p_class); + void _check_function_types(FunctionNode *p_function); + void _check_block_types(BlockNode *p_block); + _FORCE_INLINE_ void _mark_line_as_safe(int p_line) const { +#ifdef DEBUG_ENABLED + if (safe_lines) safe_lines->insert(p_line); +#endif // DEBUG_ENABLED + } + _FORCE_INLINE_ void _mark_line_as_unsafe(int p_line) const { +#ifdef DEBUG_ENABLED + if (safe_lines) safe_lines->erase(p_line); +#endif // DEBUG_ENABLED + } + Error _parse(const String &p_base_path); public: String get_error() const; int get_error_line() const; int get_error_column() const; - Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false); + Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL); Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = ""); bool is_tool_script() const; diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 1d30871e3f..7ae7c72ed3 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -101,6 +101,8 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = { "setget", "const", "var", + "as", + "void", "enum", "preload", "assert", @@ -125,6 +127,7 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = { "'.'", "'?'", "':'", + "'->'", "'$'", "'\\n'", "PI", @@ -197,6 +200,8 @@ static const _kws _keyword_list[] = { { GDScriptTokenizer::TK_PR_EXPORT, "export" }, { GDScriptTokenizer::TK_PR_SETGET, "setget" }, { GDScriptTokenizer::TK_PR_VAR, "var" }, + { GDScriptTokenizer::TK_PR_AS, "as" }, + { GDScriptTokenizer::TK_PR_VOID, "void" }, { GDScriptTokenizer::TK_PR_PRELOAD, "preload" }, { GDScriptTokenizer::TK_PR_ASSERT, "assert" }, { GDScriptTokenizer::TK_PR_YIELD, "yield" }, @@ -707,11 +712,9 @@ void GDScriptTokenizerText::_advance() { if (GETCHAR(1) == '=') { _make_token(TK_OP_ASSIGN_SUB); INCPOS(1); - /* - } else if (GETCHAR(1)=='-') { - _make_token(TK_OP_MINUS_MINUS); + } else if (GETCHAR(1) == '>') { + _make_token(TK_FORWARD_ARROW); INCPOS(1); - */ } else { _make_token(TK_OP_SUB); } @@ -1169,15 +1172,15 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) Vector<uint8_t> cs; cs.resize(len); for (int j = 0; j < len; j++) { - cs[j] = b[j] ^ 0xb6; + cs.write[j] = b[j] ^ 0xb6; } - cs[cs.size() - 1] = 0; + cs.write[cs.size() - 1] = 0; String s; s.parse_utf8((const char *)cs.ptr()); b += len; total_len -= len + 4; - identifiers[i] = s; + identifiers.write[i] = s; } constants.resize(constant_count); @@ -1190,7 +1193,7 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) return err; b += len; total_len -= len; - constants[i] = v; + constants.write[i] = v; } ERR_FAIL_COND_V(line_count * 8 > total_len, ERR_INVALID_DATA); @@ -1215,10 +1218,10 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) if ((*b) & TOKEN_BYTE_MASK) { //little endian always ERR_FAIL_COND_V(total_len < 4, ERR_INVALID_DATA); - tokens[i] = decode_uint32(b) & ~TOKEN_BYTE_MASK; + tokens.write[i] = decode_uint32(b) & ~TOKEN_BYTE_MASK; b += 4; } else { - tokens[i] = *b; + tokens.write[i] = *b; b += 1; total_len--; } @@ -1317,15 +1320,15 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) //save header buf.resize(24); - buf[0] = 'G'; - buf[1] = 'D'; - buf[2] = 'S'; - buf[3] = 'C'; - encode_uint32(BYTECODE_VERSION, &buf[4]); - encode_uint32(identifier_map.size(), &buf[8]); - encode_uint32(constant_map.size(), &buf[12]); - encode_uint32(line_map.size(), &buf[16]); - encode_uint32(token_array.size(), &buf[20]); + buf.write[0] = 'G'; + buf.write[1] = 'D'; + buf.write[2] = 'S'; + buf.write[3] = 'C'; + encode_uint32(BYTECODE_VERSION, &buf.write[4]); + encode_uint32(identifier_map.size(), &buf.write[8]); + encode_uint32(constant_map.size(), &buf.write[12]); + encode_uint32(line_map.size(), &buf.write[16]); + encode_uint32(token_array.size(), &buf.write[20]); //save identifiers @@ -1357,7 +1360,7 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code) ERR_FAIL_COND_V(err != OK, Vector<uint8_t>()); int pos = buf.size(); buf.resize(pos + len); - encode_variant(E->get(), &buf[pos], len); + encode_variant(E->get(), &buf.write[pos], len); } for (Map<int, uint32_t>::Element *E = rev_line_map.front(); E; E = E->next()) { diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index c1f611fe73..5bd303224c 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -106,6 +106,8 @@ public: TK_PR_SETGET, TK_PR_CONST, TK_PR_VAR, + TK_PR_AS, + TK_PR_VOID, TK_PR_ENUM, TK_PR_PRELOAD, TK_PR_ASSERT, @@ -131,6 +133,7 @@ public: TK_QUESTION_MARK, TK_COLON, TK_DOLLAR, + TK_FORWARD_ARROW, TK_NEWLINE, TK_CONST_PI, TK_CONST_TAU, diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index 234a59e516..0c5df57d49 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -508,7 +508,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { continue; PhysicsServer::get_singleton()->body_add_shape(g.static_body, shapes[i].shape->get_rid(), xform * shapes[i].local_transform); if (g.collision_debug.is_valid()) { - shapes[i].shape->add_vertices_to_array(col_debug, xform * shapes[i].local_transform); + shapes.write[i].shape->add_vertices_to_array(col_debug, xform * shapes[i].local_transform); } //print_line("PHIS x: "+xform); @@ -758,7 +758,7 @@ void GridMap::_update_visibility() { for (Map<OctantKey, Octant *>::Element *e = octant_map.front(); e; e = e->next()) { Octant *octant = e->value(); for (int i = 0; i < octant->multimesh_instances.size(); i++) { - Octant::MultimeshInstance &mi = octant->multimesh_instances[i]; + const Octant::MultimeshInstance &mi = octant->multimesh_instances[i]; VS::get_singleton()->instance_set_visible(mi.instance, is_visible()); } } diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index 0168be3a26..437c0d57fa 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -121,9 +121,7 @@ static Ref<Image> _jpegd_mem_loader_func(const uint8_t *p_png, int p_size) { Ref<Image> img; img.instance(); Error err = jpeg_load_image_from_buffer(img.ptr(), p_png, p_size); - if (err) - ERR_PRINT("Couldn't initialize ImageLoaderJPG with the given resource."); - + ERR_FAIL_COND_V(err, Ref<Image>()); return img; } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 62a6b96bb5..7d7028a7a6 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -121,7 +121,7 @@ void CSharpLanguage::init() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(&gdsharp_editor_init_callback); - GLOBAL_DEF("mono/export/include_scripts_content", true); + GLOBAL_DEF("mono/export/include_scripts_content", false); #endif } @@ -523,7 +523,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec si.resize(frame_count); for (int i = 0; i < frame_count; i++) { - StackInfo &sif = si[i]; + StackInfo &sif = si.write[i]; MonoObject *frame = mono_array_get(frames, MonoObject *, i); MonoString *file_name; @@ -638,33 +638,41 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft #ifdef TOOLS_ENABLED void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { - if (gdmono->is_runtime_initialized()) { + if (!gdmono->is_runtime_initialized()) + return; - GDMonoAssembly *proj_assembly = gdmono->get_project_assembly(); + GDMonoAssembly *proj_assembly = gdmono->get_project_assembly(); - String name = ProjectSettings::get_singleton()->get("application/config/name"); - if (name.empty()) { - name = "UnnamedProject"; - } + String name = ProjectSettings::get_singleton()->get("application/config/name"); + if (name.empty()) { + name = "UnnamedProject"; + } - if (proj_assembly) { - String proj_asm_path = proj_assembly->get_path(); + name += ".dll"; - if (!FileAccess::exists(proj_assembly->get_path())) { - // Maybe it wasn't loaded from the default path, so check this as well - proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name); - if (!FileAccess::exists(proj_asm_path)) - return; // No assembly to load - } + if (proj_assembly) { + String proj_asm_path = proj_assembly->get_path(); - if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time()) - return; // Already up to date - } else { - if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name))) + if (!FileAccess::exists(proj_assembly->get_path())) { + // Maybe it wasn't loaded from the default path, so check this as well + proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name); + if (!FileAccess::exists(proj_asm_path)) return; // No assembly to load } + + if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time()) + return; // Already up to date + } else { + if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(name))) + return; // No assembly to load } + if (!gdmono->get_core_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) + return; // The core API assembly to load is invalidated + + if (!gdmono->get_editor_api_assembly() && gdmono->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) + return; // The editor API assembly to load is invalidated + #ifndef NO_THREADS lock->lock(); #endif @@ -1609,7 +1617,7 @@ void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_nati bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Vector<Argument> ¶ms) { if (p_delegate->has_attribute(CACHED_CLASS(SignalAttribute))) { - MonoType *raw_type = GDMonoClass::get_raw_type(p_delegate); + MonoType *raw_type = p_delegate->get_mono_type(); if (mono_type_get_type(raw_type) == MONO_TYPE_CLASS) { // Arguments are accessibles as arguments of .Invoke method @@ -1963,8 +1971,6 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call ScriptInstance *CSharpScript::instance_create(Object *p_this) { - ERR_FAIL_COND_V(!valid, NULL); - if (!tool && !ScriptServer::is_scripting_enabled()) { #ifdef TOOLS_ENABLED PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); @@ -1981,13 +1987,15 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { // The project assembly is not loaded ERR_EXPLAIN("Cannot instance script because the project assembly is not loaded. Script: " + get_path()); ERR_FAIL_V(NULL); + } else { + // The project assembly is loaded, but the class could not found + ERR_EXPLAIN("Cannot instance script because the class '" + name + "' could not be found. Script: " + get_path()); + ERR_FAIL_V(NULL); } - - // The project assembly is loaded, but the class could not found - ERR_EXPLAIN("Cannot instance script because the class '" + name + "' could not be found. Script: " + get_path()); - ERR_FAIL_V(NULL); } + ERR_FAIL_COND_V(!valid, NULL); + if (native) { String native_name = native->get_name(); if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) { @@ -2040,6 +2048,9 @@ void CSharpScript::set_source_code(const String &p_code) { bool CSharpScript::has_method(const StringName &p_method) const { + if (!script_class) + return false; + return script_class->has_fetched_method_unknown_params(p_method); } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index df597ba776..7f9732c297 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -292,7 +292,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { return true; } + /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines = NULL) const { return true; } virtual String validate_path(const String &p_path) const; virtual Script *create_script() const; virtual bool has_named_classes() const; diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 6fa317ee70..76907451e7 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -100,8 +100,6 @@ #define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot" #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array" -#define C_METHOD_MANAGED_TO_DICT C_NS_MONOMARSHAL "::mono_object_to_Dictionary" -#define C_METHOD_MANAGED_FROM_DICT C_NS_MONOMARSHAL "::Dictionary_to_mono_object" #define BINDINGS_GENERATOR_VERSION UINT32_C(2) @@ -731,7 +729,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str output.push_back(INDENT1 "public "); bool is_abstract = itype.is_object_type && !ClassDB::can_instance(itype.name) && ClassDB::is_class_enabled(itype.name); // can_instance returns true if there's a constructor and the class is not 'disabled' - output.push_back(itype.is_singleton ? "static class " : (is_abstract ? "abstract class " : "class ")); + output.push_back(itype.is_singleton ? "static partial class " : (is_abstract ? "abstract partial class " : "partial class ")); output.push_back(itype.proxy_name); if (itype.is_singleton) { @@ -1338,7 +1336,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf } else if (return_type->cs_out.empty()) { p_output.push_back("return " + im_call + ";\n"); } else { - p_output.push_back(INDENT3); p_output.push_back(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out)); p_output.push_back("\n"); } @@ -1653,7 +1650,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n" "\t\t" C_LOCAL_PTRCALL_ARGS ".set("); p_output.push_back(real_argc_str); - p_output.push_back(" + i, &varargs[i]);\n\t" CLOSE_BLOCK); + p_output.push_back(" + i, &varargs.write[i]);\n\t" CLOSE_BLOCK); } else { p_output.push_back(c_in_statements); p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "["); @@ -2344,7 +2341,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t) - INSERT_ARRAY(Array, object); INSERT_ARRAY(PoolIntArray, int); INSERT_ARRAY_FULL(PoolByteArray, PoolByteArray, byte); @@ -2362,20 +2358,36 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { #undef INSERT_ARRAY + // Array + itype = TypeInterface(); + itype.name = "Array"; + itype.cname = itype.name; + itype.proxy_name = "Array"; + itype.c_out = "\treturn memnew(Array(%1));\n"; + itype.c_type = itype.name; + itype.c_type_in = itype.c_type + "*"; + itype.c_type_out = itype.c_type + "*"; + itype.cs_type = itype.proxy_name; + itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; + itype.cs_out = "return new Array(%0);"; + itype.im_type_in = "IntPtr"; + itype.im_type_out = "IntPtr"; + builtin_types.insert(itype.cname, itype); + // Dictionary itype = TypeInterface(); itype.name = "Dictionary"; itype.cname = itype.name; - itype.proxy_name = "Dictionary<object, object>"; - itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_DICT "(%1);\n"; - itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_DICT "(%1);\n"; - itype.c_arg_in = "&%s_in"; + itype.proxy_name = "Dictionary"; + itype.c_out = "\treturn memnew(Dictionary(%1));\n"; itype.c_type = itype.name; - itype.c_type_in = "MonoObject*"; - itype.c_type_out = "MonoObject*"; + itype.c_type_in = itype.c_type + "*"; + itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; - itype.im_type_in = itype.proxy_name; - itype.im_type_out = itype.proxy_name; + itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; + itype.cs_out = "return new Dictionary(%0);"; + itype.im_type_in = "IntPtr"; + itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); // void (fictitious type to represent the return type of methods that do not return anything) diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 998da8bda3..faeb58e5a7 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -278,13 +278,11 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { about_label->set_autowrap(true); String about_text = String("C# support in Godot Engine is a brand new feature and a work in progress.\n") + - "It is at the alpha stage and thus not suitable for use in production.\n\n" + - "As of Godot 3.0, C# support is not feature-complete and may crash in some situations. " + - "Bugs and usability issues will be addressed gradually over 3.0.x and 3.x releases, " + + "It is currently in an alpha stage and is not suitable for use in production.\n\n" + + "As of Godot 3.1, C# support is not feature-complete and may crash in some situations. " + + "Bugs and usability issues will be addressed gradually over future 3.x releases, " + "including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" + - "The main missing feature is the ability to export games using C# assemblies - you will therefore be able to develop and run games in the editor, " + - "but not to share them as standalone binaries yet. This feature is of course high on the priority list and should be available as soon as possible.\n\n" + - "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc.:\n\n" + + "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, Mono version, IDE, etc:\n\n" + " https://github.com/godotengine/godot/issues\n\n" + "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!"; about_label->set_text(about_text); diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp new file mode 100644 index 0000000000..0551c1991a --- /dev/null +++ b/modules/mono/glue/collections_glue.cpp @@ -0,0 +1,240 @@ +/*************************************************************************/ +/* collections_glue.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "collections_glue.h" + +#include <mono/metadata/exception.h> + +#include "../mono_gd/gd_mono_class.h" + +Array *godot_icall_Array_Ctor() { + return memnew(Array); +} + +void godot_icall_Array_Dtor(Array *ptr) { + memdelete(ptr); +} + +MonoObject *godot_icall_Array_At(Array *ptr, int index) { + if (index < 0 || index > ptr->size()) { + GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); + return NULL; + } + return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index)); +} + +void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value) { + if (index < 0 || index > ptr->size()) { + GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); + return; + } + ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value); +} + +int godot_icall_Array_Count(Array *ptr) { + return ptr->size(); +} + +void godot_icall_Array_Add(Array *ptr, MonoObject *item) { + ptr->append(GDMonoMarshal::mono_object_to_variant(item)); +} + +void godot_icall_Array_Clear(Array *ptr) { + ptr->clear(); +} + +bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) { + return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1; +} + +void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index) { + int count = ptr->size(); + + if (mono_array_length(array) < (array_index + count)) { + MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); + GDMonoUtils::set_pending_exception(exc); + return; + } + + for (int i = 0; i < count; i++) { + MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i)); + mono_array_setref(array, array_index, boxed); + array_index++; + } +} + +int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) { + return ptr->find(GDMonoMarshal::mono_object_to_variant(item)); +} + +void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) { + if (index < 0 || index > ptr->size()) { + GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); + return; + } + ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item)); +} + +bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) { + int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item)); + if (idx >= 0) { + ptr->remove(idx); + return true; + } + return false; +} + +void godot_icall_Array_RemoveAt(Array *ptr, int index) { + if (index < 0 || index > ptr->size()) { + GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range()); + return; + } + ptr->remove(index); +} + +Dictionary *godot_icall_Dictionary_Ctor() { + return memnew(Dictionary); +} + +void godot_icall_Dictionary_Dtor(Dictionary *ptr) { + memdelete(ptr); +} + +MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) { + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + if (ret == NULL) { + MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr()); +#ifdef DEBUG_ENABLED + CRASH_COND(!exc); +#endif + GDMonoUtils::runtime_object_init(exc); + GDMonoUtils::set_pending_exception((MonoException *)exc); + return NULL; + } + return GDMonoMarshal::variant_to_mono_object(ret); +} + +void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) { + ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value); +} + +Array *godot_icall_Dictionary_Keys(Dictionary *ptr) { + return memnew(Array(ptr->keys())); +} + +Array *godot_icall_Dictionary_Values(Dictionary *ptr) { + return memnew(Array(ptr->values())); +} + +int godot_icall_Dictionary_Count(Dictionary *ptr) { + return ptr->size(); +} + +void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { + Variant varKey = GDMonoMarshal::mono_object_to_variant(key); + Variant *ret = ptr->getptr(varKey); + if (ret != NULL) { + GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists")); + return; + } + ptr->operator[](varKey) = GDMonoMarshal::mono_object_to_variant(value); +} + +void godot_icall_Dictionary_Clear(Dictionary *ptr) { + ptr->clear(); +} + +bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) { + // no dupes + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value); +} + +bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) { + return ptr->has(GDMonoMarshal::mono_object_to_variant(key)); +} + +bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) { + return ptr->erase_checked(GDMonoMarshal::mono_object_to_variant(key)); +} + +bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) { + Variant varKey = GDMonoMarshal::mono_object_to_variant(key); + + // no dupes + Variant *ret = ptr->getptr(varKey); + if (ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value)) { + ptr->erase_checked(varKey); + return true; + } + + return false; +} + +bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) { + Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key)); + if (ret == NULL) { + *value = NULL; + return false; + } + *value = GDMonoMarshal::variant_to_mono_object(ret); + return true; +} + +void godot_register_collections_icalls() { + mono_add_internal_call("Godot.Array::godot_icall_Array_Ctor", (void *)godot_icall_Array_Ctor); + mono_add_internal_call("Godot.Array::godot_icall_Array_Dtor", (void *)godot_icall_Array_Dtor); + mono_add_internal_call("Godot.Array::godot_icall_Array_At", (void *)godot_icall_Array_At); + mono_add_internal_call("Godot.Array::godot_icall_Array_SetAt", (void *)godot_icall_Array_SetAt); + mono_add_internal_call("Godot.Array::godot_icall_Array_Count", (void *)godot_icall_Array_Count); + mono_add_internal_call("Godot.Array::godot_icall_Array_Add", (void *)godot_icall_Array_Add); + mono_add_internal_call("Godot.Array::godot_icall_Array_Clear", (void *)godot_icall_Array_Clear); + mono_add_internal_call("Godot.Array::godot_icall_Array_Contains", (void *)godot_icall_Array_Contains); + mono_add_internal_call("Godot.Array::godot_icall_Array_CopyTo", (void *)godot_icall_Array_CopyTo); + mono_add_internal_call("Godot.Array::godot_icall_Array_IndexOf", (void *)godot_icall_Array_IndexOf); + mono_add_internal_call("Godot.Array::godot_icall_Array_Insert", (void *)godot_icall_Array_Insert); + mono_add_internal_call("Godot.Array::godot_icall_Array_Remove", (void *)godot_icall_Array_Remove); + mono_add_internal_call("Godot.Array::godot_icall_Array_RemoveAt", (void *)godot_icall_Array_RemoveAt); + + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Ctor", (void *)godot_icall_Dictionary_Ctor); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Dtor", (void *)godot_icall_Dictionary_Dtor); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_GetValue", (void *)godot_icall_Dictionary_GetValue); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_SetValue", (void *)godot_icall_Dictionary_SetValue); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Keys", (void *)godot_icall_Dictionary_Keys); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Values", (void *)godot_icall_Dictionary_Values); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Count", (void *)godot_icall_Dictionary_Count); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Add", (void *)godot_icall_Dictionary_Add); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Clear", (void *)godot_icall_Dictionary_Clear); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Contains", (void *)godot_icall_Dictionary_Contains); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_ContainsKey", (void *)godot_icall_Dictionary_ContainsKey); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_RemoveKey", (void *)godot_icall_Dictionary_RemoveKey); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_Remove", (void *)godot_icall_Dictionary_Remove); + mono_add_internal_call("Godot.Dictionary::godot_icall_Dictionary_TryGetValue", (void *)godot_icall_Dictionary_TryGetValue); +} diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h new file mode 100644 index 0000000000..eb5ecfb725 --- /dev/null +++ b/modules/mono/glue/collections_glue.h @@ -0,0 +1,100 @@ +/*************************************************************************/ +/* collections_glue.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 COLLECTIONS_GLUE_H +#define COLLECTIONS_GLUE_H + +#include "core/array.h" + +#include "../mono_gd/gd_mono_marshal.h" + +// Array + +Array *godot_icall_Array_Ctor(); + +void godot_icall_Array_Dtor(Array *ptr); + +MonoObject *godot_icall_Array_At(Array *ptr, int index); + +void godot_icall_Array_SetAt(Array *ptr, int index, MonoObject *value); + +int godot_icall_Array_Count(Array *ptr); + +void godot_icall_Array_Add(Array *ptr, MonoObject *item); + +void godot_icall_Array_Clear(Array *ptr); + +bool godot_icall_Array_Contains(Array *ptr, MonoObject *item); + +void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index); + +int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item); + +void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item); + +bool godot_icall_Array_Remove(Array *ptr, MonoObject *item); + +void godot_icall_Array_RemoveAt(Array *ptr, int index); + +// Dictionary + +Dictionary *godot_icall_Dictionary_Ctor(); + +void godot_icall_Dictionary_Dtor(Dictionary *ptr); + +MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key); + +void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value); + +Array *godot_icall_Dictionary_Keys(Dictionary *ptr); + +Array *godot_icall_Dictionary_Values(Dictionary *ptr); + +int godot_icall_Dictionary_Count(Dictionary *ptr); + +void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value); + +void godot_icall_Dictionary_Clear(Dictionary *ptr); + +bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value); + +bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key); + +bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key); + +bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value); + +bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value); + +// Register internal calls + +void godot_register_collections_icalls(); + +#endif // COLLECTIONS_GLUE_H diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs new file mode 100644 index 0000000000..51f57daef4 --- /dev/null +++ b/modules/mono/glue/cs_files/Array.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Godot +{ + class ArraySafeHandle : SafeHandle + { + public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) + { + this.handle = handle; + } + + public override bool IsInvalid + { + get + { + return handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + Array.godot_icall_Array_Dtor(handle); + return true; + } + } + + public class Array : IList<object>, ICollection<object>, IEnumerable<object>, IDisposable + { + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Array_Ctor(); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Dtor(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Array_At(IntPtr ptr, int index); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Array_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Add(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Clear(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, object[] array, int arrayIndex); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index); + + ArraySafeHandle safeHandle; + bool disposed = false; + + public Array() + { + safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor()); + } + + internal Array(ArraySafeHandle handle) + { + safeHandle = handle; + } + + internal Array(IntPtr handle) + { + safeHandle = new ArraySafeHandle(handle); + } + + internal IntPtr GetPtr() + { + return safeHandle.DangerousGetHandle(); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (safeHandle != null) + { + safeHandle.Dispose(); + safeHandle = null; + } + + disposed = true; + } + + public object this[int index] + { + get + { + return godot_icall_Array_At(GetPtr(), index); + } + set + { + godot_icall_Array_SetAt(GetPtr(), index, value); + } + } + + public int Count + { + get + { + return godot_icall_Array_Count(GetPtr()); + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public void Add(object item) + { + godot_icall_Array_Add(GetPtr(), item); + } + + public void Clear() + { + godot_icall_Array_Clear(GetPtr()); + } + + public bool Contains(object item) + { + return godot_icall_Array_Contains(GetPtr(), item); + } + + public void CopyTo(object[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "Value cannot be null."); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); + + // Internal call may throw ArgumentException + godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex); + } + + public IEnumerator<object> GetEnumerator() + { + int count = Count; + + for (int i = 0; i < count; i++) + { + yield return godot_icall_Array_At(GetPtr(), i); + } + } + + public int IndexOf(object item) + { + return godot_icall_Array_IndexOf(GetPtr(), item); + } + + public void Insert(int index, object item) + { + godot_icall_Array_Insert(GetPtr(), index, item); + } + + public bool Remove(object item) + { + return godot_icall_Array_Remove(GetPtr(), item); + } + + public void RemoveAt(int index) + { + godot_icall_Array_RemoveAt(GetPtr(), index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> + { + Array objectArray; + + public Array() + { + objectArray = new Array(); + } + + public Array(Array array) + { + objectArray = array; + } + + internal Array(IntPtr handle) + { + objectArray = new Array(handle); + } + + internal Array(ArraySafeHandle handle) + { + objectArray = new Array(handle); + } + + public static explicit operator Array(Array<T> from) + { + return from.objectArray; + } + + public T this[int index] + { + get + { + return (T)objectArray[index]; + } + set + { + objectArray[index] = value; + } + } + + public int Count + { + get + { + return objectArray.Count; + } + } + + public bool IsReadOnly + { + get + { + return objectArray.IsReadOnly; + } + } + + public void Add(T item) + { + objectArray.Add(item); + } + + public void Clear() + { + objectArray.Clear(); + } + + public bool Contains(T item) + { + return objectArray.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "Value cannot be null."); + + if (arrayIndex < 0) + throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); + + // TODO This may be quite slow because every element access is an internal call. + // It could be moved entirely to an internal call if we find out how to do the cast there. + + int count = objectArray.Count; + + if (array.Length < (arrayIndex + count)) + throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); + + for (int i = 0; i < count; i++) + { + array[arrayIndex] = (T)objectArray[i]; + arrayIndex++; + } + } + + public IEnumerator<T> GetEnumerator() + { + int count = objectArray.Count; + + for (int i = 0; i < count; i++) + { + yield return (T)objectArray[i]; + } + } + + public int IndexOf(T item) + { + return objectArray.IndexOf(item); + } + + public void Insert(int index, T item) + { + objectArray.Insert(index, item); + } + + public bool Remove(T item) + { + return objectArray.Remove(item); + } + + public void RemoveAt(int index) + { + objectArray.RemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/cs_files/Color.cs index e0d6d27840..1195071bd3 100644 --- a/modules/mono/glue/cs_files/Color.cs +++ b/modules/mono/glue/cs_files/Color.cs @@ -293,28 +293,80 @@ namespace Godot return res; } - public int ToRgba32() + public int ToAbgr32() { - int c = (byte)(r * 255); + int c = (byte)Math.Round(a * 255); c <<= 8; - c |= (byte)(g * 255); + c |= (byte)Math.Round(b * 255); c <<= 8; - c |= (byte)(b * 255); + c |= (byte)Math.Round(g * 255); c <<= 8; - c |= (byte)(a * 255); + c |= (byte)Math.Round(r * 255); + + return c; + } + + public long ToAbgr64() + { + long c = (ushort)Math.Round(a * 65535); + c <<= 16; + c |= (ushort)Math.Round(b * 65535); + c <<= 16; + c |= (ushort)Math.Round(g * 65535); + c <<= 16; + c |= (ushort)Math.Round(r * 65535); return c; } public int ToArgb32() { - int c = (byte)(a * 255); + int c = (byte)Math.Round(a * 255); + c <<= 8; + c |= (byte)Math.Round(r * 255); + c <<= 8; + c |= (byte)Math.Round(g * 255); + c <<= 8; + c |= (byte)Math.Round(b * 255); + + return c; + } + + public long ToArgb64() + { + long c = (ushort)Math.Round(a * 65535); + c <<= 16; + c |= (ushort)Math.Round(r * 65535); + c <<= 16; + c |= (ushort)Math.Round(g * 65535); + c <<= 16; + c |= (ushort)Math.Round(b * 65535); + + return c; + } + + public int ToRgba32() + { + int c = (byte)Math.Round(r * 255); c <<= 8; - c |= (byte)(r * 255); + c |= (byte)Math.Round(g * 255); c <<= 8; - c |= (byte)(g * 255); + c |= (byte)Math.Round(b * 255); c <<= 8; - c |= (byte)(b * 255); + c |= (byte)Math.Round(a * 255); + + return c; + } + + public long ToRgba64() + { + long c = (ushort)Math.Round(r * 65535); + c <<= 16; + c |= (ushort)Math.Round(g * 65535); + c <<= 16; + c |= (ushort)Math.Round(b * 65535); + c <<= 16; + c |= (ushort)Math.Round(a * 65535); return c; } @@ -353,6 +405,17 @@ namespace Godot r = (rgba & 0xFF) / 255.0f; } + public Color(long rgba) + { + a = (rgba & 0xFFFF) / 65535.0f; + rgba >>= 16; + b = (rgba & 0xFFFF) / 65535.0f; + rgba >>= 16; + g = (rgba & 0xFFFF) / 65535.0f; + rgba >>= 16; + r = (rgba & 0xFFFF) / 65535.0f; + } + private static int _parse_col(string str, int ofs) { int ig = 0; @@ -392,7 +455,7 @@ namespace Godot private String _to_hex(float val) { - var v = (int) Mathf.Clamp(val * 255.0f, 0, 255); + int v = Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255)); var ret = string.Empty; diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs new file mode 100644 index 0000000000..57a1960ad9 --- /dev/null +++ b/modules/mono/glue/cs_files/Dictionary.cs @@ -0,0 +1,401 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Godot +{ + class DictionarySafeHandle : SafeHandle + { + public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true) + { + this.handle = handle; + } + + public override bool IsInvalid + { + get + { + return handle == IntPtr.Zero; + } + } + + protected override bool ReleaseHandle() + { + Dictionary.godot_icall_Dictionary_Dtor(handle); + return true; + } + } + + public class Dictionary : + IDictionary<object, object>, + ICollection<KeyValuePair<object, object>>, + IEnumerable<KeyValuePair<object, object>>, + IDisposable + { + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Ctor(); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Dictionary_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); + + DictionarySafeHandle safeHandle; + bool disposed = false; + + public Dictionary() + { + safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor()); + } + + internal Dictionary(DictionarySafeHandle handle) + { + safeHandle = handle; + } + + internal Dictionary(IntPtr handle) + { + safeHandle = new DictionarySafeHandle(handle); + } + + internal IntPtr GetPtr() + { + return safeHandle.DangerousGetHandle(); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (safeHandle != null) + { + safeHandle.Dispose(); + safeHandle = null; + } + + disposed = true; + } + + public object this[object key] + { + get + { + return godot_icall_Dictionary_GetValue(GetPtr(), key); + } + set + { + godot_icall_Dictionary_SetValue(GetPtr(), key, value); + } + } + + public ICollection<object> Keys + { + get + { + IntPtr handle = godot_icall_Dictionary_Keys(GetPtr()); + return new Array(new ArraySafeHandle(handle)); + } + } + + public ICollection<object> Values + { + get + { + IntPtr handle = godot_icall_Dictionary_Values(GetPtr()); + return new Array(new ArraySafeHandle(handle)); + } + } + + public int Count + { + get + { + return godot_icall_Dictionary_Count(GetPtr()); + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public void Add(object key, object value) + { + godot_icall_Dictionary_Add(GetPtr(), key, value); + } + + public void Add(KeyValuePair<object, object> item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + godot_icall_Dictionary_Clear(GetPtr()); + } + + public bool Contains(KeyValuePair<object, object> item) + { + return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value); + } + + public bool ContainsKey(object key) + { + return godot_icall_Dictionary_ContainsKey(GetPtr(), key); + } + + public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex) + { + // TODO 3 internal calls, can reduce to 1 + Array keys = (Array)Keys; + Array values = (Array)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]); + arrayIndex++; + } + } + + public IEnumerator<KeyValuePair<object, object>> GetEnumerator() + { + // TODO 3 internal calls, can reduce to 1 + Array keys = (Array)Keys; + Array values = (Array)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + yield return new KeyValuePair<object, object>(keys[i], values[i]); + } + } + + public bool Remove(object key) + { + return godot_icall_Dictionary_RemoveKey(GetPtr(), key); + } + + public bool Remove(KeyValuePair<object, object> item) + { + return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); + } + + public bool TryGetValue(object key, out object value) + { + object retValue; + bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue); + value = found ? retValue : default(object); + return found; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + + public class Dictionary<TKey, TValue> : + IDictionary<TKey, TValue>, + ICollection<KeyValuePair<TKey, TValue>>, + IEnumerable<KeyValuePair<TKey, TValue>> + { + Dictionary objectDict; + + public Dictionary() + { + objectDict = new Dictionary(); + } + + public Dictionary(Dictionary dictionary) + { + objectDict = dictionary; + } + + internal Dictionary(IntPtr handle) + { + objectDict = new Dictionary(handle); + } + + internal Dictionary(DictionarySafeHandle handle) + { + objectDict = new Dictionary(handle); + } + + public static explicit operator Dictionary(Dictionary<TKey, TValue> from) + { + return from.objectDict; + } + + public TValue this[TKey key] + { + get + { + return (TValue)objectDict[key]; + } + set + { + objectDict[key] = value; + } + } + + public ICollection<TKey> Keys + { + get + { + IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr()); + return new Array<TKey>(new ArraySafeHandle(handle)); + } + } + + public ICollection<TValue> Values + { + get + { + IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr()); + return new Array<TValue>(new ArraySafeHandle(handle)); + } + } + + public int Count + { + get + { + return objectDict.Count; + } + } + + public bool IsReadOnly + { + get + { + return objectDict.IsReadOnly; + } + } + + public void Add(TKey key, TValue value) + { + objectDict.Add(key, value); + } + + public void Add(KeyValuePair<TKey, TValue> item) + { + objectDict.Add(item.Key, item.Value); + } + + public void Clear() + { + objectDict.Clear(); + } + + public bool Contains(KeyValuePair<TKey, TValue> item) + { + return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); + } + + public bool ContainsKey(TKey key) + { + return objectDict.ContainsKey(key); + } + + public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) + { + // TODO 3 internal calls, can reduce to 1 + Array<TKey> keys = (Array<TKey>)Keys; + Array<TValue> values = (Array<TValue>)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]); + arrayIndex++; + } + } + + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { + // TODO 3 internal calls, can reduce to 1 + Array<TKey> keys = (Array<TKey>)Keys; + Array<TValue> values = (Array<TValue>)Values; + int count = Count; + + for (int i = 0; i < count; i++) + { + // TODO 2 internal calls, can reduce to 1 + yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]); + } + } + + public bool Remove(TKey key) + { + return objectDict.Remove(key); + } + + public bool Remove(KeyValuePair<TKey, TValue> item) + { + return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value)); + } + + public bool TryGetValue(TKey key, out TValue value) + { + object retValue; + bool found = objectDict.TryGetValue(key, out retValue); + value = found ? (TValue)retValue : default(TValue); + return found; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs index ec1534cb9a..e2457ff98b 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/cs_files/GD.cs @@ -1,4 +1,9 @@ using System; +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif // TODO: Add comments describing what this class does. It is not obvious. @@ -16,22 +21,22 @@ namespace Godot return NativeCalls.godot_icall_Godot_convert(what, type); } - public static float Db2Linear(float db) + public static real_t Db2Linear(real_t db) { - return (float)Math.Exp(db * 0.11512925464970228420089957273422); + return (real_t)Math.Exp(db * 0.11512925464970228420089957273422); } - public static float Dectime(float value, float amount, float step) + public static real_t DecTime(real_t value, real_t amount, real_t step) { - float sgn = value < 0 ? -1.0f : 1.0f; - float val = Mathf.Abs(value); + real_t sgn = Mathf.Sign(value); + real_t val = Mathf.Abs(value); val -= amount * step; - if (val < 0.0f) - val = 0.0f; + if (val < 0) + val = 0; return val * sgn; } - public static FuncRef Funcref(Object instance, string funcname) + public static FuncRef FuncRef(Object instance, string funcname) { var ret = new FuncRef(); ret.SetInstance(instance); @@ -49,9 +54,9 @@ namespace Godot return NativeCalls.godot_icall_Godot_instance_from_id(instanceId); } - public static double Linear2Db(double linear) + public static real_t Linear2Db(real_t linear) { - return Math.Log(linear) * 8.6858896380650365530225783783321; + return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321); } public static Resource Load(string path) @@ -69,22 +74,22 @@ namespace Godot Print(System.Environment.StackTrace); } - public static void Printerr(params object[] what) + public static void PrintErr(params object[] what) { NativeCalls.godot_icall_Godot_printerr(what); } - public static void Printraw(params object[] what) + public static void PrintRaw(params object[] what) { NativeCalls.godot_icall_Godot_printraw(what); } - public static void Prints(params object[] what) + public static void PrintS(params object[] what) { NativeCalls.godot_icall_Godot_prints(what); } - public static void Printt(params object[] what) + public static void PrintT(params object[] what) { NativeCalls.godot_icall_Godot_printt(what); } @@ -183,7 +188,7 @@ namespace Godot return NativeCalls.godot_icall_Godot_var2str(var); } - public static WeakRef Weakref(Object obj) + public static WeakRef WeakRef(Object obj) { return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj)); } diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/cs_files/MarshalUtils.cs index ff4477cc6c..6ad4b3dcb2 100644 --- a/modules/mono/glue/cs_files/MarshalUtils.cs +++ b/modules/mono/glue/cs_files/MarshalUtils.cs @@ -1,36 +1,17 @@ using System; -using System.Collections.Generic; namespace Godot { - internal static class MarshalUtils + static class MarshalUtils { - private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values) + static bool IsArrayGenericType(Type type) { - var ret = new Dictionary<object, object>(); - - for (int i = 0; i < keys.Length; i++) - { - ret.Add(keys[i], values[i]); - } - - return ret; - } - - private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo) - { - var keys = from.Keys; - keysTo = new object[keys.Count]; - keys.CopyTo(keysTo, 0); - - var values = from.Values; - valuesTo = new object[values.Count]; - values.CopyTo(valuesTo, 0); + return type.GetGenericTypeDefinition() == typeof(Array<>); } - private static Type GetDictionaryType() + static bool IsDictionaryGenericType(Type type) { - return typeof(Dictionary<object, object>); + return type.GetGenericTypeDefinition() == typeof(Dictionary<, >); } } } diff --git a/modules/mono/glue/cs_files/NodeExtensions.cs b/modules/mono/glue/cs_files/NodeExtensions.cs new file mode 100644 index 0000000000..a099b0e400 --- /dev/null +++ b/modules/mono/glue/cs_files/NodeExtensions.cs @@ -0,0 +1,10 @@ +namespace Godot +{ + public partial class Node + { + public T GetNode<T>(NodePath path) where T : Godot.Node + { + return (T)GetNode(path); + } + } +} diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt index b8626c4cff..1e8b314962 100755 --- a/modules/mono/glue/cs_files/VERSION.txt +++ b/modules/mono/glue/cs_files/VERSION.txt @@ -1 +1 @@ -4 +6 diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index cedc8e9992..6a6f3062b4 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -29,6 +29,7 @@ /*************************************************************************/ #include "builtin_types_glue.h" +#include "collections_glue.h" #include "../csharp_script.h" #include "../mono_gd/gd_mono_class.h" @@ -308,4 +309,5 @@ MonoObject *godot_icall_Godot_weakref(Object *p_obj) { void godot_register_header_icalls() { godot_register_builtin_type_icalls(); + godot_register_collections_icalls(); } diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 0f4e211be5..f564b93f8f 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -77,12 +77,12 @@ void setup_runtime_main_args() { Vector<char *> main_args; main_args.resize(cmdline_args.size() + 1); - main_args[0] = execpath.ptrw(); + main_args.write[0] = execpath.ptrw(); int i = 1; for (List<String>::Element *E = cmdline_args.front(); E; E = E->next()) { CharString &stored = cmdline_args_utf8.push_back(E->get().utf8())->get(); - main_args[i] = stored.ptrw(); + main_args.write[i] = stored.ptrw(); i++; } diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 66339d7ae6..ad74f73d74 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -33,23 +33,37 @@ #include <mono/metadata/attrdefs.h> #include "gd_mono_assembly.h" +#include "gd_mono_marshal.h" -MonoType *GDMonoClass::get_raw_type(GDMonoClass *p_class) { +String GDMonoClass::get_full_name(MonoClass *p_mono_class) { + // mono_type_get_full_name is not exposed to embedders, but this seems to do the job + MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class)); - return mono_class_get_type(p_class->get_mono_ptr()); -} + MonoException *exc = NULL; + GD_MONO_BEGIN_RUNTIME_INVOKE; + MonoString *str = mono_object_to_string((MonoObject *)type_obj, (MonoObject **)&exc); + GD_MONO_END_RUNTIME_INVOKE; + UNLIKELY_UNHANDLED_EXCEPTION(exc); -bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const { + return GDMonoMarshal::mono_string_to_godot(str); +} - return mono_class_is_assignable_from(mono_class, p_from->mono_class); +MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) { + return mono_class_get_type(p_mono_class); } String GDMonoClass::get_full_name() const { + return get_full_name(mono_class); +} - String res = namespace_name; - if (res.length()) - res += "."; - return res + class_name; +MonoType *GDMonoClass::get_mono_type() { + // Care, you cannot compare MonoType pointers + return get_mono_type(mono_class); +} + +bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const { + + return mono_class_is_assignable_from(mono_class, p_from->mono_class); } GDMonoClass *GDMonoClass::get_parent_class() { @@ -308,6 +322,12 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo return get_method(method); } +void *GDMonoClass::get_method_thunk(const StringName &p_name, int p_params_count) { + + GDMonoMethod *method = get_method(p_name, p_params_count); + return method ? method->get_thunk() : NULL; +} + GDMonoField *GDMonoClass::get_field(const StringName &p_name) { Map<StringName, GDMonoField *>::Element *result = fields.find(p_name); @@ -483,7 +503,7 @@ GDMonoClass::~GDMonoClass() { } } - deleted_methods[offset] = method; + deleted_methods.write[offset] = method; ++offset; memdelete(method); diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 417c138594..f4e386549a 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -98,7 +98,11 @@ class GDMonoClass { GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly); public: - static MonoType *get_raw_type(GDMonoClass *p_class); + static String get_full_name(MonoClass *p_mono_class); + static MonoType *get_mono_type(MonoClass *p_mono_class); + + String get_full_name() const; + MonoType *get_mono_type(); bool is_assignable_from(GDMonoClass *p_from) const; @@ -108,8 +112,6 @@ public: _FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; } _FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; } - String get_full_name() const; - GDMonoClass *get_parent_class(); #ifdef TOOLS_ENABLED @@ -131,6 +133,8 @@ public: GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); + void *get_method_thunk(const StringName &p_name, int p_params_count = 0); + GDMonoField *get_field(const StringName &p_name); const Vector<GDMonoField *> &get_all_fields(); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 3b91777ed4..d3a673dc1b 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -148,7 +148,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class)); + MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type()); if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) SET_FROM_ARRAY_AND_BREAK(Array); @@ -200,6 +200,18 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } + if (CACHED_CLASS(Dictionary) == type_class) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + + if (CACHED_CLASS(Array) == type_class) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); + mono_field_set_value(p_object, mono_field, managed); + break; + } + ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name()); ERR_FAIL(); } break; @@ -248,10 +260,13 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } case Variant::DICTIONARY: { - MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary()); + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary)); + mono_field_set_value(p_object, mono_field, managed); + } break; + case Variant::ARRAY: { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); mono_field_set_value(p_object, mono_field, managed); } break; - case Variant::ARRAY: SET_FROM_ARRAY_AND_BREAK(Array); case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray); case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray); case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray); @@ -265,8 +280,28 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ } break; case MONO_TYPE_GENERICINST: { - if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) { - MonoObject *managed = GDMonoMarshal::Dictionary_to_mono_object(p_value.operator Dictionary()); + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type()); + + MonoException *exc = NULL; + + GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType); + MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_dict) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), type.type_class); + mono_field_set_value(p_object, mono_field, managed); + break; + } + + exc = NULL; + + GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType); + MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_array) { + MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), type.type_class); mono_field_set_value(p_object, mono_field, managed); break; } diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index 2b5110f0b9..72a5439044 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -45,7 +45,8 @@ struct ManagedType { GDMonoClass *type_class; ManagedType() { - type_class = 0; + type_encoding = 0; + type_class = NULL; } }; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 5cd77d63e2..de91e71bab 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -120,7 +120,7 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class)); + MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) return Variant::ARRAY; @@ -162,12 +162,36 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { if (CACHED_CLASS(RID) == type_class) { return Variant::_RID; } + + if (CACHED_CLASS(Dictionary) == type_class) { + return Variant::DICTIONARY; + } + + if (CACHED_CLASS(Array) == type_class) { + return Variant::ARRAY; + } } break; case MONO_TYPE_GENERICINST: { - if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) { + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type()); + + MonoException *exc = NULL; + GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType); + MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_dict) { return Variant::DICTIONARY; } + + exc = NULL; + GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType); + MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_array) { + return Variant::ARRAY; + } } break; default: { @@ -216,6 +240,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var) { ManagedType type; type.type_encoding = MONO_TYPE_OBJECT; + // type.type_class is not needed when we specify the MONO_TYPE_OBJECT encoding return variant_to_mono_object(p_var, type); } @@ -315,7 +340,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(p_type.type_class)); + MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type()); if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) return (MonoObject *)Array_to_mono_array(p_var->operator Array()); @@ -360,6 +385,14 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty if (CACHED_CLASS(RID) == type_class) { return GDMonoUtils::create_managed_from(p_var->operator RID()); } + + if (CACHED_CLASS(Dictionary) == type_class) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); + } + + if (CACHED_CLASS(Array) == type_class) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); + } } break; case MONO_TYPE_OBJECT: { // Variant @@ -411,9 +444,9 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *()); } case Variant::DICTIONARY: - return Dictionary_to_mono_object(p_var->operator Dictionary()); + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary)); case Variant::ARRAY: - return (MonoObject *)Array_to_mono_array(p_var->operator Array()); + return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); case Variant::POOL_BYTE_ARRAY: return (MonoObject *)PoolByteArray_to_mono_array(p_var->operator PoolByteArray()); case Variant::POOL_INT_ARRAY: @@ -433,8 +466,24 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty } break; case MONO_TYPE_GENERICINST: { - if (CACHED_RAW_MONO_CLASS(Dictionary) == p_type.type_class->get_mono_ptr()) { - return Dictionary_to_mono_object(p_var->operator Dictionary()); + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, p_type.type_class->get_mono_type()); + + MonoException *exc = NULL; + GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType); + MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_dict) { + return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), p_type.type_class); + } + + exc = NULL; + GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType); + MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_array) { + return GDMonoUtils::create_managed_from(p_var->operator Array(), p_type.type_class); } } break; } break; @@ -452,7 +501,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) { GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_object_get_class(p_obj)); ERR_FAIL_COND_V(!tclass, Variant()); - MonoType *raw_type = tclass->get_raw_type(tclass); + MonoType *raw_type = tclass->get_mono_type(); ManagedType type; @@ -531,7 +580,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) { case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: { - MonoArrayType *array_type = mono_type_get_array_type(GDMonoClass::get_raw_type(type.type_class)); + MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type()); if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) return mono_array_to_Array((MonoArray *)p_obj); @@ -579,11 +628,51 @@ Variant mono_object_to_variant(MonoObject *p_obj) { RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj)); return ptr ? Variant(*ptr) : Variant(); } + + if (CACHED_CLASS(Array) == type_class) { + MonoException *exc = NULL; + GDMonoUtils::Array_GetPtr get_ptr = CACHED_METHOD_THUNK(Array, GetPtr); + Array *ptr = get_ptr(p_obj, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return ptr ? Variant(*ptr) : Variant(); + } + + if (CACHED_CLASS(Dictionary) == type_class) { + MonoException *exc = NULL; + GDMonoUtils::Dictionary_GetPtr get_ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr); + Dictionary *ptr = get_ptr(p_obj, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return ptr ? Variant(*ptr) : Variant(); + } } break; case MONO_TYPE_GENERICINST: { - if (CACHED_RAW_MONO_CLASS(Dictionary) == type.type_class->get_mono_ptr()) { - return mono_object_to_Dictionary(p_obj); + MonoReflectionType *reftype = mono_type_get_object(SCRIPTS_DOMAIN, type.type_class->get_mono_type()); + + MonoException *exc = NULL; + + GDMonoUtils::IsDictionaryGenericType type_is_dict = CACHED_METHOD_THUNK(MarshalUtils, IsDictionaryGenericType); + MonoBoolean is_dict = type_is_dict((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_dict) { + MonoException *exc = NULL; + MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return *unbox<Dictionary *>(ret); + } + + exc = NULL; + + GDMonoUtils::IsArrayGenericType type_is_array = CACHED_METHOD_THUNK(MarshalUtils, IsArrayGenericType); + MonoBoolean is_array = type_is_array((MonoObject *)reftype, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + if (is_array) { + MonoException *exc = NULL; + MonoObject *ret = type.type_class->get_method("GetPtr")->invoke(p_obj, &exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + return *unbox<Array *>(ret); } } break; } @@ -822,66 +911,4 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) { return ret; } - -MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict) { - MonoArray *keys = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size()); - MonoArray *values = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_dict.size()); - - int i = 0; - const Variant *dkey = NULL; - while ((dkey = p_dict.next(dkey))) { - mono_array_set(keys, MonoObject *, i, variant_to_mono_object(dkey)); - mono_array_set(values, MonoObject *, i, variant_to_mono_object(p_dict[*dkey])); - i++; - } - - GDMonoUtils::MarshalUtils_ArraysToDict arrays_to_dict = CACHED_METHOD_THUNK(MarshalUtils, ArraysToDictionary); - - MonoException *exc = NULL; - GD_MONO_BEGIN_RUNTIME_INVOKE; - MonoObject *ret = arrays_to_dict(keys, values, (MonoObject **)&exc); - GD_MONO_END_RUNTIME_INVOKE; - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - ERR_FAIL_V(NULL); - } - - return ret; -} - -Dictionary mono_object_to_Dictionary(MonoObject *p_dict) { - Dictionary ret; - - if (!p_dict) - return ret; - - GDMonoUtils::MarshalUtils_DictToArrays dict_to_arrays = CACHED_METHOD_THUNK(MarshalUtils, DictionaryToArrays); - - MonoArray *keys = NULL; - MonoArray *values = NULL; - MonoException *exc = NULL; - GD_MONO_BEGIN_RUNTIME_INVOKE; - dict_to_arrays(p_dict, &keys, &values, (MonoObject **)&exc); - GD_MONO_END_RUNTIME_INVOKE; - - if (exc) { - GDMonoUtils::set_pending_exception(exc); - ERR_FAIL_V(Dictionary()); - } - - int length = mono_array_length(keys); - - for (int i = 0; i < length; i++) { - MonoObject *key_obj = mono_array_get(keys, MonoObject *, i); - MonoObject *value_obj = mono_array_get(values, MonoObject *, i); - - Variant key = key_obj ? mono_object_to_variant(key_obj) : Variant(); - Variant value = value_obj ? mono_object_to_variant(value_obj) : Variant(); - - ret[key] = value; - } - - return ret; -} } // namespace GDMonoMarshal diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 6572408ab5..464f584a0a 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -143,11 +143,6 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array); MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array); PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array); -// Dictionary - -MonoObject *Dictionary_to_mono_object(const Dictionary &p_dict); -Dictionary mono_object_to_Dictionary(MonoObject *p_dict); - #ifdef YOLO_COPY #define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in; #define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in); diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index 1f837a2d78..a1c710c26c 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -139,23 +139,8 @@ bool GDMonoProperty::has_setter() { } void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) { - MonoMethod *prop_method = mono_property_get_set_method(mono_property); - - MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1); - mono_array_set(params, MonoObject *, 0, p_value); - - MonoException *exc = NULL; - GD_MONO_BEGIN_RUNTIME_INVOKE; - mono_runtime_invoke_array(prop_method, p_object, params, (MonoObject **)&exc); - GD_MONO_END_RUNTIME_INVOKE; - - if (exc) { - if (r_exc) { - *r_exc = exc; - } else { - GDMonoUtils::set_pending_exception(exc); - } - } + void *params[1] = { p_value }; + set_value(p_object, params, r_exc); } void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) { diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index a229552b76..21efd4064a 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -87,6 +87,8 @@ void MonoCache::clear_members() { method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL; #endif + class_KeyNotFoundException = NULL; + rawclass_Dictionary = NULL; class_Vector2 = NULL; @@ -107,6 +109,8 @@ void MonoCache::clear_members() { class_Control = NULL; class_Spatial = NULL; class_WeakRef = NULL; + class_Array = NULL; + class_Dictionary = NULL; class_MarshalUtils = NULL; #ifdef DEBUG_ENABLED @@ -134,8 +138,10 @@ void MonoCache::clear_members() { field_Image_ptr = NULL; field_RID_ptr = NULL; - methodthunk_MarshalUtils_DictionaryToArrays = NULL; - methodthunk_MarshalUtils_ArraysToDictionary = NULL; + methodthunk_Array_GetPtr = NULL; + methodthunk_Dictionary_GetPtr = NULL; + methodthunk_MarshalUtils_IsArrayGenericType = NULL; + methodthunk_MarshalUtils_IsDictionaryGenericType = NULL; methodthunk_SignalAwaiter_SignalCallback = NULL; methodthunk_SignalAwaiter_FailureCallback = NULL; methodthunk_GodotTaskScheduler_Activate = NULL; @@ -170,11 +176,13 @@ void update_corlib_cache() { #ifdef DEBUG_ENABLED CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); - CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames")->get_thunk()); + CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames")); CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); #endif + CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException")); + mono_cache.corlib_cache_updated = true; } @@ -198,6 +206,8 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); + CACHE_CLASS_AND_CHECK(Array, GODOT_API_CLASS(Array)); + CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_CLASS(Dictionary)); CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); #ifdef DEBUG_ENABLED @@ -224,34 +234,21 @@ void update_godot_api_cache() { CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD)); CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryToArrays, (MarshalUtils_DictToArrays)CACHED_CLASS(MarshalUtils)->get_method("DictionaryToArrays", 3)->get_thunk()); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArraysToDictionary, (MarshalUtils_ArraysToDict)CACHED_CLASS(MarshalUtils)->get_method("ArraysToDictionary", 2)->get_thunk()); - CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)->get_thunk()); - CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)->get_thunk()); - CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)->get_thunk()); + CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_CLASS(Array)->get_method_thunk("GetPtr", 0)); + CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_CLASS(Dictionary)->get_method_thunk("GetPtr", 0)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsArrayGenericType, (IsArrayGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsArrayGenericType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IsDictionaryGenericType, (IsDictionaryGenericType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IsDictionaryGenericType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1)); + CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0)); + CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0)); #ifdef DEBUG_ENABLED - CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)->get_thunk()); + CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4)); #endif - { - /* - * TODO Right now we only support Dictionary<object, object>. - * It would be great if we could support other key/value types - * without forcing the user to copy the entries. - */ - GDMonoMethod *method_get_dict_type = CACHED_CLASS(MarshalUtils)->get_method("GetDictionaryType", 0); - ERR_FAIL_NULL(method_get_dict_type); - MonoReflectionType *dict_refl_type = (MonoReflectionType *)method_get_dict_type->invoke(NULL); - ERR_FAIL_NULL(dict_refl_type); - MonoType *dict_type = mono_reflection_type_get_type(dict_refl_type); - ERR_FAIL_NULL(dict_type); - - CACHE_RAW_MONO_CLASS_AND_CHECK(Dictionary, mono_class_from_mono_type(dict_type)); - } - + // TODO Move to CSharpLanguage::init() MonoObject *task_scheduler = mono_object_new(SCRIPTS_DOMAIN, GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); - mono_runtime_object_init(task_scheduler); + GDMonoUtils::runtime_object_init(task_scheduler); mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); mono_cache.godot_api_cache_updated = true; @@ -304,6 +301,12 @@ MonoThread *get_current_thread() { return mono_thread_current(); } +void runtime_object_init(MonoObject *p_this_obj) { + GD_MONO_BEGIN_RUNTIME_INVOKE; + mono_runtime_object_init(p_this_obj); + GD_MONO_END_RUNTIME_INVOKE; +} + GDMonoClass *get_object_class(MonoObject *p_object) { return GDMono::get_singleton()->get_class(mono_object_get_class(p_object)); } @@ -358,7 +361,7 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object); // Construct - mono_runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object); return mono_object; } @@ -368,7 +371,7 @@ MonoObject *create_managed_from(const NodePath &p_from) { ERR_FAIL_NULL_V(mono_object, NULL); // Construct - mono_runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object); CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from))); @@ -380,13 +383,73 @@ MonoObject *create_managed_from(const RID &p_from) { ERR_FAIL_NULL_V(mono_object, NULL); // Construct - mono_runtime_object_init(mono_object); + GDMonoUtils::runtime_object_init(mono_object); CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from))); return mono_object; } +MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) { + MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr()); + ERR_FAIL_NULL_V(mono_object, NULL); + + // Search constructor that takes a pointer as parameter + MonoMethod *m; + void *iter = NULL; + while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) { + if (strcmp(mono_method_get_name(m), ".ctor") == 0) { + MonoMethodSignature *sig = mono_method_signature(m); + void *front = NULL; + if (mono_signature_get_param_count(sig) == 1 && + mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) { + break; + } + } + } + + CRASH_COND(m == NULL); + + Array *new_array = memnew(Array(p_from)); + void *args[1] = { &new_array }; + + MonoException *exc = NULL; + mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + return mono_object; +} + +MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) { + MonoObject *mono_object = mono_object_new(SCRIPTS_DOMAIN, p_class->get_mono_ptr()); + ERR_FAIL_NULL_V(mono_object, NULL); + + // Search constructor that takes a pointer as parameter + MonoMethod *m; + void *iter = NULL; + while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) { + if (strcmp(mono_method_get_name(m), ".ctor") == 0) { + MonoMethodSignature *sig = mono_method_signature(m); + void *front = NULL; + if (mono_signature_get_param_count(sig) == 1 && + mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) { + break; + } + } + } + + CRASH_COND(m == NULL); + + Dictionary *new_dict = memnew(Dictionary(p_from)); + void *args[1] = { &new_dict }; + + MonoException *exc = NULL; + mono_runtime_invoke(m, mono_object, args, (MonoObject **)&exc); + UNLIKELY_UNHANDLED_EXCEPTION(exc); + + return mono_object; +} + MonoDomain *create_domain(const String &p_friendly_name) { MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), NULL); @@ -400,10 +463,10 @@ MonoDomain *create_domain(const String &p_friendly_name) { return domain; } -String get_exception_name_and_message(MonoException *p_ex) { +String get_exception_name_and_message(MonoException *p_exc) { String res; - MonoClass *klass = mono_object_get_class((MonoObject *)p_ex); + MonoClass *klass = mono_object_get_class((MonoObject *)p_exc); MonoType *type = mono_class_get_type(klass); char *full_name = mono_type_full_name(type); @@ -413,12 +476,24 @@ String get_exception_name_and_message(MonoException *p_ex) { res += ": "; MonoProperty *prop = mono_class_get_property_from_name(klass, "Message"); - MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_ex, NULL, NULL); + GD_MONO_BEGIN_RUNTIME_INVOKE; + MonoString *msg = (MonoString *)mono_property_get_value(prop, (MonoObject *)p_exc, NULL, NULL); + GD_MONO_END_RUNTIME_INVOKE; res += GDMonoMarshal::mono_string_to_godot(msg); return res; } +void set_exception_message(MonoException *p_exc, String message) { + MonoClass *klass = mono_object_get_class((MonoObject *)p_exc); + MonoProperty *prop = mono_class_get_property_from_name(klass, "Message"); + MonoString *msg = GDMonoMarshal::mono_string_from_godot(message); + void *params[1] = { msg }; + GD_MONO_BEGIN_RUNTIME_INVOKE; + mono_property_set_value(prop, (MonoObject *)p_exc, params, NULL); + GD_MONO_END_RUNTIME_INVOKE; +} + void debug_print_unhandled_exception(MonoException *p_exc) { print_unhandled_exception(p_exc); debug_send_unhandled_exception_error(p_exc); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 4f8e5932cd..d6774ed41d 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -41,14 +41,24 @@ #include "object.h" #include "reference.h" +#define UNLIKELY_UNHANDLED_EXCEPTION(m_exc) \ + if (unlikely(m_exc != NULL)) { \ + GDMonoUtils::debug_unhandled_exception(m_exc); \ + _UNREACHABLE_(); \ + } + namespace GDMonoUtils { -typedef MonoObject *(*MarshalUtils_DictToArrays)(MonoObject *, MonoArray **, MonoArray **, MonoObject **); -typedef MonoObject *(*MarshalUtils_ArraysToDict)(MonoArray *, MonoArray *, MonoObject **); +typedef Array *(*Array_GetPtr)(MonoObject *, MonoObject **); +typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoObject **); typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoObject **); typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoObject **); typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoObject **); typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoObject **); +typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **); +typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **); +typedef MonoBoolean (*IsArrayGenericType)(MonoObject *, MonoObject **); +typedef MonoBoolean (*IsDictionaryGenericType)(MonoObject *, MonoObject **); typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoObject **); struct MonoCache { @@ -79,6 +89,8 @@ struct MonoCache { GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool; #endif + GDMonoClass *class_KeyNotFoundException; + MonoClass *rawclass_Dictionary; // ----------------------------------------------- @@ -100,6 +112,8 @@ struct MonoCache { GDMonoClass *class_Control; GDMonoClass *class_Spatial; GDMonoClass *class_WeakRef; + GDMonoClass *class_Array; + GDMonoClass *class_Dictionary; GDMonoClass *class_MarshalUtils; #ifdef DEBUG_ENABLED @@ -127,8 +141,10 @@ struct MonoCache { GDMonoField *field_Image_ptr; GDMonoField *field_RID_ptr; - MarshalUtils_DictToArrays methodthunk_MarshalUtils_DictionaryToArrays; - MarshalUtils_ArraysToDict methodthunk_MarshalUtils_ArraysToDictionary; + Array_GetPtr methodthunk_Array_GetPtr; + Dictionary_GetPtr methodthunk_Dictionary_GetPtr; + IsArrayGenericType methodthunk_MarshalUtils_IsArrayGenericType; + IsDictionaryGenericType methodthunk_MarshalUtils_IsDictionaryGenericType; SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback; SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback; GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate; @@ -175,6 +191,8 @@ _FORCE_INLINE_ bool is_main_thread() { return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current(); } +void runtime_object_init(MonoObject *p_this_obj); + GDMonoClass *get_object_class(MonoObject *p_object); GDMonoClass *type_get_proxy_class(const StringName &p_type); GDMonoClass *get_class_native_base(GDMonoClass *p_class); @@ -183,10 +201,13 @@ MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringNa MonoObject *create_managed_from(const NodePath &p_from); MonoObject *create_managed_from(const RID &p_from); +MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class); +MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class); MonoDomain *create_domain(const String &p_friendly_name); -String get_exception_name_and_message(MonoException *p_ex); +String get_exception_name_and_message(MonoException *p_exc); +void set_exception_message(MonoException *p_exc, String message); void debug_print_unhandled_exception(MonoException *p_exc); void debug_send_unhandled_exception_error(MonoException *p_exc); diff --git a/modules/recast/navigation_mesh_generator.cpp b/modules/recast/navigation_mesh_generator.cpp index 64c4b85269..c1ce2592a4 100644 --- a/modules/recast/navigation_mesh_generator.cpp +++ b/modules/recast/navigation_mesh_generator.cpp @@ -126,9 +126,9 @@ void NavigationMeshGenerator::_convert_detail_mesh_to_native_navigation_mesh(con for (unsigned int j = 0; j < ntris; j++) { Vector<int> nav_indices; nav_indices.resize(3); - nav_indices[0] = ((int)(bverts + tris[j * 4 + 0])); - nav_indices[1] = ((int)(bverts + tris[j * 4 + 1])); - nav_indices[2] = ((int)(bverts + tris[j * 4 + 2])); + nav_indices.write[0] = ((int)(bverts + tris[j * 4 + 0])); + nav_indices.write[1] = ((int)(bverts + tris[j * 4 + 1])); + nav_indices.write[2] = ((int)(bverts + tris[j * 4 + 2])); p_nav_mesh->add_polygon(nav_indices); } } diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 6f2bb46fc8..733f32277b 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -265,8 +265,8 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end) for (uint32_t i = 0; i < size; i++) { - result->data[i].start = ovector[i * 2]; - result->data[i].end = ovector[i * 2 + 1]; + result->data.write[i].start = ovector[i * 2]; + result->data.write[i].end = ovector[i * 2 + 1]; } pcre2_match_data_free_16(match); @@ -295,8 +295,8 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end) for (uint32_t i = 0; i < size; i++) { - result->data[i].start = ovector[i * 2]; - result->data[i].end = ovector[i * 2 + 1]; + result->data.write[i].start = ovector[i * 2]; + result->data.write[i].end = ovector[i * 2 + 1]; } pcre2_match_data_free_32(match); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index 9331092171..de9b3d5a91 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -771,7 +771,7 @@ void VisualScript::custom_signal_set_argument_type(const StringName &p_func, int ERR_FAIL_COND(instances.size()); ERR_FAIL_COND(!custom_signals.has(p_func)); ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); - custom_signals[p_func][p_argidx].type = p_type; + custom_signals[p_func].write[p_argidx].type = p_type; } Variant::Type VisualScript::custom_signal_get_argument_type(const StringName &p_func, int p_argidx) const { @@ -783,7 +783,7 @@ void VisualScript::custom_signal_set_argument_name(const StringName &p_func, int ERR_FAIL_COND(instances.size()); ERR_FAIL_COND(!custom_signals.has(p_func)); ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); - custom_signals[p_func][p_argidx].name = p_name; + custom_signals[p_func].write[p_argidx].name = p_name; } String VisualScript::custom_signal_get_argument_name(const StringName &p_func, int p_argidx) const { @@ -811,7 +811,7 @@ void VisualScript::custom_signal_swap_argument(const StringName &p_func, int p_a ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size()); ERR_FAIL_INDEX(p_with_argidx, custom_signals[p_func].size()); - SWAP(custom_signals[p_func][p_argidx], custom_signals[p_func][p_with_argidx]); + SWAP(custom_signals[p_func].write[p_argidx], custom_signals[p_func].write[p_with_argidx]); } void VisualScript::remove_custom_signal(const StringName &p_name) { @@ -1333,6 +1333,19 @@ VisualScript::VisualScript() { base_type = "Object"; } +Set<int> VisualScript::get_output_sequence_ports_connected(const String &edited_func, int from_node) { + List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>); + get_sequence_connection_list(edited_func, sc); + Set<int> connected; + for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) { + if (E->get().from_node == from_node) { + connected.insert(E->get().from_output); + } + } + memdelete(sc); + return connected; +} + VisualScript::~VisualScript() { while (!functions.empty()) { @@ -2402,7 +2415,7 @@ void VisualScriptLanguage::make_template(const String &p_class_name, const Strin script->set_instance_base_type(p_base_class_name); } -bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions) const { +bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { return false; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index aaa6dfea11..2ad72a40c0 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -319,6 +319,7 @@ public: void custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx); void remove_custom_signal(const StringName &p_name); void rename_custom_signal(const StringName &p_name, const StringName &p_new_name); + Set<int> get_output_sequence_ports_connected(const String &edited_func, int from_node); void get_custom_signal_list(List<StringName> *r_custom_signals) const; @@ -563,7 +564,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 873cc293c9..ecf220a623 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -33,8 +33,10 @@ #include "core/script_language.h" #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" +#include "object.h" #include "os/input.h" #include "os/keyboard.h" +#include "variant.h" #include "visual_script_expression.h" #include "visual_script_flow_control.h" #include "visual_script_func_nodes.h" @@ -1293,7 +1295,7 @@ void VisualScriptEditor::_on_nodes_duplicate() { Ref<VisualScriptNode> node = script->get_node(edited_func, F->get()); - Ref<VisualScriptNode> dupe = node->duplicate(); + Ref<VisualScriptNode> dupe = node->duplicate(true); int new_id = idc++; to_select.insert(new_id); @@ -1327,6 +1329,10 @@ void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) { } } +void VisualScriptEditor::_generic_search() { + new_connect_node_select->select_from_visual_script(String("")); +} + void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> key = p_event; @@ -1780,7 +1786,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da call->set_base_type(node->get_class()); n = call; - method_select->select_method_from_instance(node); + method_select->select_from_instance(node); selecting_method_id = base_id; } @@ -1917,7 +1923,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } } -void VisualScriptEditor::_selected_method(const String &p_method) { +void VisualScriptEditor::_selected_method(const String &p_method, const String &p_type) { Ref<VisualScriptFunctionCall> vsfc = script->get_node(edited_func, selecting_method_id); if (!vsfc.is_valid()) @@ -1962,22 +1968,16 @@ void VisualScriptEditor::_button_resource_previewed(const String &p_path, const void VisualScriptEditor::apply_code() { } -Ref<Script> VisualScriptEditor::get_edited_script() const { - +RES VisualScriptEditor::get_edited_resource() const { return script; } -Vector<String> VisualScriptEditor::get_functions() { - - return Vector<String>(); -} +void VisualScriptEditor::set_edited_resource(const RES &p_res) { -void VisualScriptEditor::set_edited_script(const Ref<Script> &p_script) { - - script = p_script; - signal_editor->script = p_script; + script = p_res; + signal_editor->script = script; signal_editor->undo_redo = undo_redo; - variable_editor->script = p_script; + variable_editor->script = script; variable_editor->undo_redo = undo_redo; script->connect("node_ports_changed", this, "_node_ports_changed"); @@ -1986,6 +1986,11 @@ void VisualScriptEditor::set_edited_script(const Ref<Script> &p_script) { _update_available_nodes(); } +Vector<String> VisualScriptEditor::get_functions() { + + return Vector<String>(); +} + void VisualScriptEditor::reload_text() { } @@ -2436,33 +2441,19 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro if (!vsn.is_valid()) return; - if (p_from_slot < vsn->get_output_sequence_port_count()) { + port_action_pos = p_release_pos; - port_action_popup->clear(); - port_action_popup->add_item(TTR("Condition"), CREATE_COND); - port_action_popup->add_item(TTR("Sequence"), CREATE_SEQUENCE); - port_action_popup->add_item(TTR("Switch"), CREATE_SWITCH); - port_action_popup->add_item(TTR("Iterator"), CREATE_ITERATOR); - port_action_popup->add_item(TTR("While"), CREATE_WHILE); - port_action_popup->add_item(TTR("Return"), CREATE_RETURN); + if (p_from_slot < vsn->get_output_sequence_port_count()) { port_action_node = p_from.to_int(); port_action_output = p_from_slot; - + _port_action_menu(CREATE_ACTION); } else { - port_action_popup->clear(); - port_action_popup->add_item(TTR("Call"), CREATE_CALL); - port_action_popup->add_item(TTR("Get"), CREATE_GET); - port_action_popup->add_item(TTR("Set"), CREATE_SET); port_action_output = p_from_slot - vsn->get_output_sequence_port_count(); port_action_node = p_from.to_int(); + _port_action_menu(CREATE_CALL_SET_GET); } - - port_action_pos = p_release_pos; - port_action_popup->set_size(Size2(1, 1)); - port_action_popup->set_position(graph->get_global_position() + p_release_pos); - port_action_popup->popup(); } VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes) { @@ -2530,168 +2521,202 @@ void VisualScriptEditor::_port_action_menu(int p_option) { bool seq_connect = false; - Ref<VisualScriptNode> vnode; Set<int> vn; switch (p_option) { - case CREATE_CALL: { - + case CREATE_CALL_SET_GET: { Ref<VisualScriptFunctionCall> n; n.instance(); - vnode = n; VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - if (tg.type == Variant::OBJECT) { - n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); - - if (tg.gdclass != StringName()) { - n->set_base_type(tg.gdclass); - } else { - n->set_base_type("Object"); - } + if (tg.gdclass != StringName()) { + n->set_base_type(tg.gdclass); + } else { + n->set_base_type("Object"); + } + String type_string = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + if (tg.type == Variant::OBJECT) { if (tg.script.is_valid()) { - n->set_base_script(tg.script->get_path()); - new_connect_node_select->select_method_from_script(tg.script); + new_connect_node_select->select_from_script(tg.script, ""); + } else if (type_string != String()) { + new_connect_node_select->select_from_base_type(type_string); } else { - new_connect_node_select->select_method_from_base_type(n->get_base_type()); + new_connect_node_select->select_from_base_type(n->get_base_type()); } - + } else if (tg.type == Variant::NIL) { + new_connect_node_select->select_from_base_type(""); } else { - n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); - n->set_basic_type(tg.type); - new_connect_node_select->select_method_from_basic_type(tg.type); + new_connect_node_select->select_from_basic_type(tg.type); } - } break; - case CREATE_SET: { - - Ref<VisualScriptPropertySet> n; - n.instance(); - vnode = n; - + case CREATE_ACTION: { + seq_connect = true; VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); - + PropertyInfo property_info = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output); if (tg.type == Variant::OBJECT) { - n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); - - if (tg.gdclass != StringName()) { - n->set_base_type(tg.gdclass); + if (property_info.type == Variant::OBJECT && property_info.hint_string != String()) { + new_connect_node_select->select_from_action(property_info.hint_string); } else { - n->set_base_type("Object"); + new_connect_node_select->select_from_action(""); } - - if (tg.script.is_valid()) { - n->set_base_script(tg.script->get_path()); - new_connect_node_select->select_property_from_script(tg.script); - } else { - new_connect_node_select->select_property_from_base_type(n->get_base_type()); - } - + } else if (tg.type == Variant::NIL) { + new_connect_node_select->select_from_action(""); } else { - n->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE); - n->set_basic_type(tg.type); - new_connect_node_select->select_property_from_basic_type(tg.type); + new_connect_node_select->select_from_action(Variant::get_type_name(tg.type)); } } break; - case CREATE_GET: { + } +} - Ref<VisualScriptPropertyGet> n; - n.instance(); - vnode = n; +void VisualScriptEditor::new_node(Ref<VisualScriptNode> vnode, Vector2 ofs) { + Set<int> vn; + Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node); + int new_id = script->get_available_id(); + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode, ofs); + undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id); + undo_redo->add_do_method(this, "_update_graph", new_id); + undo_redo->add_undo_method(this, "_update_graph", new_id); + undo_redo->commit_action(); - VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); + port_action_new_node = new_id; +} - if (tg.type == Variant::OBJECT) { - n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); +void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id) { + undo_redo->create_action(TTR("Connect Node Data")); + VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr()); + if (vnode_return != NULL && vnode_old->get_output_value_port_count() > 0) { + vnode_return->set_enable_return_value(true); + } + if (vnode_old->get_output_value_port_count() <= 0) { + undo_redo->commit_action(); + return; + } + if (vnode->get_input_value_port_count() <= 0) { + undo_redo->commit_action(); + return; + } + int port = port_action_output; + int value_count = vnode_old->get_output_value_port_count(); + if (port >= value_count) { + port = 0; + } + int count = vnode_old->get_output_value_port_count() + vnode_old->get_output_sequence_port_count(); + undo_redo->add_do_method(script.ptr(), "data_connect", edited_func, port_action_node, port, new_id, 0); + undo_redo->add_undo_method(script.ptr(), "data_disconnect", edited_func, port_action_node, port, new_id, 0); + undo_redo->commit_action(); +} - if (tg.gdclass != StringName()) { - n->set_base_type(tg.gdclass); - } else { - n->set_base_type("Object"); - } +void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category) { + Vector2 ofs = graph->get_scroll_ofs() + port_action_pos; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap, snap)); + } + ofs /= EDSCALE; - if (tg.script.is_valid()) { - n->set_base_script(tg.script->get_path()); - new_connect_node_select->select_property_from_script(tg.script); - } else { - new_connect_node_select->select_property_from_base_type(n->get_base_type()); - } + Set<int> vn; + if (p_category == "visualscript") { + Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text); + Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node); + int new_id = script->get_available_id(); + + if (Object::cast_to<VisualScriptOperator>(vnode_new.ptr())) { + Variant::Type type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).type; + Object::cast_to<VisualScriptOperator>(vnode_new.ptr())->set_typed(type); + } + + if (Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())) { + Variant::Type type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).type; + String hint_name = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + + if (type == Variant::OBJECT) { + Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(hint_name); + } else if (type == Variant::NIL) { + Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(""); } else { - n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE); - n->set_basic_type(tg.type); - new_connect_node_select->select_property_from_basic_type(tg.type); + Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(Variant::get_type_name(type)); } + } + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode_new, ofs); + connect_seq(vnode_old, vnode_new, new_id); + connect_data(vnode_old, vnode_new, new_id); + undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); + return; + } - } break; - case CREATE_COND: { + Ref<VisualScriptNode> vnode; + + seq_connect = false; + if (p_category == String("method")) { + + Ref<VisualScriptFunctionCall> n; + n.instance(); + vnode = n; + } else if (p_category == String("set")) { + + Ref<VisualScriptPropertySet> n; + n.instance(); + n->set_property(p_text); + vnode = n; + } else if (p_category == String("get")) { + + Ref<VisualScriptPropertyGet> n; + n.instance(); + n->set_property(p_text); + vnode = n; + } + + if (p_category == String("action")) { + if (p_text == "VisualScriptCondition") { Ref<VisualScriptCondition> n; n.instance(); vnode = n; seq_connect = true; + } + if (p_text == "VisualScriptSwitch") { - } break; - case CREATE_SEQUENCE: { - - Ref<VisualScriptSequence> n; + Ref<VisualScriptSwitch> n; n.instance(); vnode = n; seq_connect = true; + } else if (p_text == "VisualScriptSequence") { - } break; - case CREATE_SWITCH: { - - Ref<VisualScriptSwitch> n; + Ref<VisualScriptSequence> n; n.instance(); vnode = n; seq_connect = true; - - } break; - case CREATE_ITERATOR: { + } else if (p_text == "VisualScriptIterator") { Ref<VisualScriptIterator> n; n.instance(); vnode = n; seq_connect = true; - - } break; - case CREATE_WHILE: { + } else if (p_text == "VisualScriptWhile") { Ref<VisualScriptWhile> n; n.instance(); vnode = n; seq_connect = true; - - } break; - case CREATE_RETURN: { + } else if (p_text == "VisualScriptReturn") { Ref<VisualScriptReturn> n; n.instance(); vnode = n; seq_connect = true; - - } break; - } - - int new_id = script->get_available_id(); - undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode, ofs); - if (seq_connect) { - undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, port_action_output, new_id); + } } - undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id); - undo_redo->add_do_method(this, "_update_graph", new_id); - undo_redo->add_undo_method(this, "_update_graph", new_id); - undo_redo->commit_action(); - - port_action_new_node = new_id; -} -void VisualScriptEditor::_selected_connect_node_method_or_setget(const String &p_text) { + new_node(vnode, ofs); Ref<VisualScriptNode> vsn = script->get_node(edited_func, port_action_new_node); @@ -2699,28 +2724,152 @@ void VisualScriptEditor::_selected_connect_node_method_or_setget(const String &p Ref<VisualScriptFunctionCall> vsfc = vsn; vsfc->set_function(p_text); - script->data_connect(edited_func, port_action_node, port_action_output, port_action_new_node, 0); + + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); + if (tg.type == Variant::OBJECT) { + vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); + + if (tg.gdclass != StringName()) { + vsfc->set_base_type(tg.gdclass); + + } else { + PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; + String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + + if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { + vsfc->set_base_type(base_type); + } + if (p_text == "call" || p_text == "call_deferred") { + vsfc->set_function(""); + } + } + if (tg.script.is_valid()) { + vsfc->set_base_script(tg.script->get_path()); + } + } else if (tg.type == Variant::NIL) { + vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE); + vsfc->set_base_type(script->get_instance_base_type()); + } else { + vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE); + vsfc->set_basic_type(tg.type); + } } if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) { Ref<VisualScriptPropertySet> vsp = vsn; - vsp->set_property(p_text); - script->data_connect(edited_func, port_action_node, port_action_output, port_action_new_node, 0); + + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); + if (tg.type == Variant::OBJECT) { + vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); + + if (tg.gdclass != StringName()) { + vsp->set_base_type(tg.gdclass); + + } else { + PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; + String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + + if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { + vsp->set_base_type(base_type); + } + } + if (tg.script.is_valid()) { + vsp->set_base_script(tg.script->get_path()); + } + } else if (tg.type == Variant::NIL) { + vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); + vsp->set_base_type(script->get_instance_base_type()); + } else { + vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE); + vsp->set_basic_type(tg.type); + } } if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) { - Ref<VisualScriptPropertyGet> vsp = vsn; - vsp->set_property(p_text); - script->data_connect(edited_func, port_action_node, port_action_output, port_action_new_node, 0); + + VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); + if (tg.type == Variant::OBJECT) { + vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); + + if (tg.gdclass != StringName()) { + vsp->set_base_type(tg.gdclass); + + } else { + PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint; + String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string; + + if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) { + vsp->set_base_type(base_type); + } + } + if (tg.script.is_valid()) { + vsp->set_base_script(tg.script->get_path()); + } + } else if (tg.type == Variant::NIL) { + vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); + vsp->set_base_type(script->get_instance_base_type()); + } else { + vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE); + vsp->set_basic_type(tg.type); + } } + Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node); + connect_seq(vnode_old, vnode, port_action_new_node); + connect_data(vnode_old, vnode, port_action_new_node); _update_graph(port_action_new_node); _update_graph_connections(); } -void VisualScriptEditor::_selected_new_virtual_method(const String &p_text) { +void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) { + int seq_count = vnode_old->get_output_sequence_port_count(); + VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr()); + if (vnode_operator != NULL && vnode_operator->has_input_sequence_port() == false) { + return; + } + VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr()); + if (vnode_constructor != NULL) { + return; + } + if (vnode_old->get_output_sequence_port_count() <= 0) { + return; + } + if (vnode_new->has_input_sequence_port() == false) { + return; + } + VisualScriptFunction *vnode_function = Object::cast_to<VisualScriptFunction>(vnode_old.ptr()); + undo_redo->create_action(TTR("Connect Node Sequence")); + int pass_port = -vnode_old->get_output_sequence_port_count() + 1; + int return_port = port_action_output - 1; + if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") && + !script->get_output_sequence_ports_connected(edited_func, port_action_node).has(pass_port)) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, pass_port, new_id); + undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, pass_port, new_id); + } else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") && + !script->get_output_sequence_ports_connected(edited_func, port_action_node).has(return_port)) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, return_port, new_id); + undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, return_port, new_id); + } else { + for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) { + int count = vnode_old->get_output_sequence_port_count(); + if (port_action_output < count && !script->get_output_sequence_ports_connected(edited_func, port_action_node).has(port_action_output)) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, port_action_output, new_id); + undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, port_action_output, new_id); + break; + } else if (!script->get_output_sequence_ports_connected(edited_func, port_action_node).has(port)) { + undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, port, new_id); + undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, port, new_id); + break; + } + } + } + + undo_redo->commit_action(); +} + +void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category) { String name = p_text; if (script->has_function(name)) { @@ -2777,12 +2926,29 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text) { _update_graph(); } -void VisualScriptEditor::_cancel_connect_node_method_or_setget() { - - script->remove_node(edited_func, port_action_new_node); +void VisualScriptEditor::_cancel_connect_node() { + // Causes crashes + //script->remove_node(edited_func, port_action_new_node); _update_graph(); } +void VisualScriptEditor::_create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point) { + Vector2 ofs = graph->get_scroll_ofs() + p_point; + if (graph->is_using_snap()) { + int snap = graph->get_snap(); + ofs = ofs.snapped(Vector2(snap, snap)); + } + ofs /= EDSCALE; + Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text); + int new_id = script->get_available_id(); + undo_redo->create_action(TTR("Add Node")); + undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode, ofs); + undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id); + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); +} + void VisualScriptEditor::_default_value_changed() { Ref<VisualScriptNode> vsn = script->get_node(edited_func, editing_id); @@ -2980,9 +3146,7 @@ void VisualScriptEditor::_menu_option(int p_what) { } break; case EDIT_FIND_NODE_TYPE: { - //popup disappearing grabs focus to owner, so use call deferred - node_filter->call_deferred("grab_focus"); - node_filter->call_deferred("select_all"); + _generic_search(); } break; case EDIT_COPY_NODES: case EDIT_CUT_NODES: { @@ -3006,7 +3170,7 @@ void VisualScriptEditor::_menu_option(int p_what) { return; } if (node.is_valid()) { - clipboard->nodes[id] = node->duplicate(); + clipboard->nodes[id] = node->duplicate(true); clipboard->nodes_positions[id] = script->get_node_position(edited_func, id); } } @@ -3286,10 +3450,11 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_comment_node_resized", &VisualScriptEditor::_comment_node_resized); ClassDB::bind_method("_button_resource_previewed", &VisualScriptEditor::_button_resource_previewed); ClassDB::bind_method("_port_action_menu", &VisualScriptEditor::_port_action_menu); - ClassDB::bind_method("_selected_connect_node_method_or_setget", &VisualScriptEditor::_selected_connect_node_method_or_setget); + ClassDB::bind_method("_selected_connect_node", &VisualScriptEditor::_selected_connect_node); ClassDB::bind_method("_selected_new_virtual_method", &VisualScriptEditor::_selected_new_virtual_method); - ClassDB::bind_method("_cancel_connect_node_method_or_setget", &VisualScriptEditor::_cancel_connect_node_method_or_setget); + ClassDB::bind_method("_cancel_connect_node", &VisualScriptEditor::_cancel_connect_node); + ClassDB::bind_method("_create_new_node", &VisualScriptEditor::_create_new_node); ClassDB::bind_method("_expression_text_changed", &VisualScriptEditor::_expression_text_changed); ClassDB::bind_method("get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw); @@ -3318,6 +3483,8 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_member_option", &VisualScriptEditor::_member_option); ClassDB::bind_method("_update_available_nodes", &VisualScriptEditor::_update_available_nodes); + + ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search); } VisualScriptEditor::VisualScriptEditor() { @@ -3480,25 +3647,21 @@ VisualScriptEditor::VisualScriptEditor() { add_child(default_value_edit); default_value_edit->connect("variant_changed", this, "_default_value_changed"); - method_select = memnew(PropertySelector); + method_select = memnew(VisualScriptPropertySelector); add_child(method_select); method_select->connect("selected", this, "_selected_method"); error_line = -1; - new_connect_node_select = memnew(PropertySelector); + new_connect_node_select = memnew(VisualScriptPropertySelector); add_child(new_connect_node_select); - new_connect_node_select->connect("selected", this, "_selected_connect_node_method_or_setget"); - new_connect_node_select->get_cancel()->connect("pressed", this, "_cancel_connect_node_method_or_setget"); + new_connect_node_select->connect("selected", this, "_selected_connect_node"); + new_connect_node_select->get_cancel()->connect("pressed", this, "_cancel_connect_node"); - new_virtual_method_select = memnew(PropertySelector); + new_virtual_method_select = memnew(VisualScriptPropertySelector); add_child(new_virtual_method_select); new_virtual_method_select->connect("selected", this, "_selected_new_virtual_method"); new_virtual_method_select->get_cancel()->connect("pressed", this, "_selected_new_virtual_method"); - port_action_popup = memnew(PopupMenu); - add_child(port_action_popup); - port_action_popup->connect("id_pressed", this, "_port_action_menu"); - member_popup = memnew(PopupMenu); add_child(member_popup); members->connect("item_rmb_selected", this, "_member_rmb_selected"); @@ -3515,9 +3678,9 @@ VisualScriptEditor::~VisualScriptEditor() { memdelete(variable_editor); } -static ScriptEditorBase *create_editor(const Ref<Script> &p_script) { +static ScriptEditorBase *create_editor(const RES &p_resource) { - if (Object::cast_to<VisualScript>(*p_script)) { + if (Object::cast_to<VisualScript>(*p_resource)) { return memnew(VisualScriptEditor); } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 0bd64d6a1d..e0f8a0aaa7 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -34,9 +34,9 @@ #include "editor/create_dialog.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/property_editor.h" -#include "editor/property_selector.h" #include "scene/gui/graph_edit.h" #include "visual_script.h" +#include "visual_script_property_selector.h" class VisualScriptEditorSignalEdit; class VisualScriptEditorVariableEdit; @@ -62,15 +62,8 @@ class VisualScriptEditor : public ScriptEditorBase { enum PortAction { - CREATE_CALL, - CREATE_SET, - CREATE_GET, - CREATE_COND, - CREATE_SEQUENCE, - CREATE_SWITCH, - CREATE_ITERATOR, - CREATE_WHILE, - CREATE_RETURN, + CREATE_CALL_SET_GET, + CREATE_ACTION, }; enum MemberAction { @@ -102,9 +95,9 @@ class VisualScriptEditor : public ScriptEditorBase { AcceptDialog *edit_signal_dialog; PropertyEditor *edit_signal_edit; - PropertySelector *method_select; - PropertySelector *new_connect_node_select; - PropertySelector *new_virtual_method_select; + VisualScriptPropertySelector *method_select; + VisualScriptPropertySelector *new_connect_node_select; + VisualScriptPropertySelector *new_virtual_method_select; VisualScriptEditorVariableEdit *variable_editor; @@ -162,21 +155,29 @@ class VisualScriptEditor : public ScriptEditorBase { static Clipboard *clipboard; - PopupMenu *port_action_popup; PopupMenu *member_popup; - MemberType member_type; String member_name; + bool seq_connect = false; + PortAction port_action; int port_action_node; int port_action_output; Vector2 port_action_pos; int port_action_new_node; void _port_action_menu(int p_option); - void _selected_connect_node_method_or_setget(const String &p_text); - void _cancel_connect_node_method_or_setget(); - void _selected_new_virtual_method(const String &p_text); + + void new_node(Ref<VisualScriptNode> vnode, Vector2 ofs); + + void connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id); + + void _selected_connect_node(const String &p_text, const String &p_category); + void connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id); + + void _cancel_connect_node(); + void _create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point); + void _selected_new_virtual_method(const String &p_text, const String &p_category); int error_line; @@ -211,6 +212,9 @@ class VisualScriptEditor : public ScriptEditorBase { String revert_on_drag; void _input(const Ref<InputEvent> &p_event); + + void _generic_search(); + void _members_gui_input(const Ref<InputEvent> &p_event); void _on_nodes_delete(); void _on_nodes_duplicate(); @@ -231,7 +235,7 @@ class VisualScriptEditor : public ScriptEditorBase { void _comment_node_resized(const Vector2 &p_new_size, int p_node); int selecting_method_id; - void _selected_method(const String &p_method); + void _selected_method(const String &p_method, const String &p_type); void _draw_color_over_button(Object *obj, Color p_color); void _button_resource_previewed(const String &p_path, const Ref<Texture> &p_preview, Variant p_ud); @@ -250,9 +254,9 @@ public: virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); virtual void apply_code(); - virtual Ref<Script> get_edited_script() const; + virtual RES get_edited_resource() const; + virtual void set_edited_resource(const RES &p_res); virtual Vector<String> get_functions(); - virtual void set_edited_script(const Ref<Script> &p_script); virtual void reload_text(); virtual String get_name(); virtual Ref<Texture> get_icon(); diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index d5f9d21348..868d22b541 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -56,11 +56,11 @@ bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_val int from = inputs.size(); inputs.resize(int(p_value)); for (int i = from; i < inputs.size(); i++) { - inputs[i].name = String::chr('a' + i); + inputs.write[i].name = String::chr('a' + i); if (from == 0) { - inputs[i].type = output_type; + inputs.write[i].type = output_type; } else { - inputs[i].type = inputs[from - 1].type; + inputs.write[i].type = inputs[from - 1].type; } } expression_dirty = true; @@ -78,10 +78,10 @@ bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_val if (what == "type") { - inputs[idx].type = Variant::Type(int(p_value)); + inputs.write[idx].type = Variant::Type(int(p_value)); } else if (what == "name") { - inputs[idx].name = p_value; + inputs.write[idx].name = p_value; } else { return false; } @@ -1153,8 +1153,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() { op->op = expression[i].op; op->nodes[0] = expression[i + 1].node; op->nodes[1] = NULL; - expression[i].is_op = false; - expression[i].node = op; + expression.write[i].is_op = false; + expression.write[i].node = op; expression.remove(i + 1); } @@ -1188,7 +1188,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() { op->nodes[1] = expression[next_op + 1].node; //next expression goes as right //replace all 3 nodes by this operator and make it an expression - expression[next_op - 1].node = op; + expression.write[next_op - 1].node = op; expression.remove(next_op); expression.remove(next_op); } @@ -1370,8 +1370,8 @@ public: bool ret = _execute(p_inputs, constructor->arguments[i], value, r_error_str, ce); if (ret) return true; - arr[i] = value; - argp[i] = &arr[i]; + arr.write[i] = value; + argp.write[i] = &arr[i]; } r_ret = Variant::construct(constructor->data_type, (const Variant **)argp.ptr(), argp.size(), ce); @@ -1397,8 +1397,8 @@ public: bool ret = _execute(p_inputs, bifunc->arguments[i], value, r_error_str, ce); if (ret) return true; - arr[i] = value; - argp[i] = &arr[i]; + arr.write[i] = value; + argp.write[i] = &arr[i]; } VisualScriptBuiltinFunc::exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str); @@ -1429,8 +1429,8 @@ public: bool ret = _execute(p_inputs, call->arguments[i], value, r_error_str, ce); if (ret) return true; - arr[i] = value; - argp[i] = &arr[i]; + arr.write[i] = value; + argp.write[i] = &arr[i]; } r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce); diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index ea23ab1b2a..7535f37ffc 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -684,7 +684,7 @@ bool VisualScriptSwitch::_set(const StringName &p_name, const Variant &p_value) int idx = String(p_name).get_slice("/", 1).to_int(); ERR_FAIL_INDEX_V(idx, case_values.size(), false); - case_values[idx].type = Variant::Type(int(p_value)); + case_values.write[idx].type = Variant::Type(int(p_value)); _change_notify(); ports_changed_notify(); @@ -767,7 +767,7 @@ PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const { PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, ""); + return PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_TYPE_STRING, get_base_type()); } String VisualScriptTypeCast::get_caption() const { diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index bdf5705ecd..ad886bc758 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -43,7 +43,7 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const { - if (method_cache.flags & METHOD_FLAG_CONST || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))) + if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))) return 0; else return 1; @@ -51,7 +51,7 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const { bool VisualScriptFunctionCall::has_input_sequence_port() const { - if (method_cache.flags & METHOD_FLAG_CONST || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))) + if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function))) return false; else return true; @@ -231,7 +231,7 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con if (call_mode == CALL_MODE_INSTANCE) { if (p_idx == 0) { - return PropertyInfo(Variant::OBJECT, "pass"); + return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type()); } else { p_idx--; } @@ -1055,7 +1055,7 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons if (call_mode == CALL_MODE_BASIC_TYPE) { return PropertyInfo(basic_type, "out"); } else if (call_mode == CALL_MODE_INSTANCE) { - return PropertyInfo(Variant::OBJECT, "pass"); + return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type()); } else { return PropertyInfo(); } diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 8b7b809ec0..9f10510d6d 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -54,8 +54,8 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value arguments.resize(new_argc); for (int i = argc; i < new_argc; i++) { - arguments[i].name = "arg" + itos(i + 1); - arguments[i].type = Variant::NIL; + arguments.write[i].name = "arg" + itos(i + 1); + arguments.write[i].type = Variant::NIL; } ports_changed_notify(); _change_notify(); @@ -68,7 +68,7 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value if (what == "type") { Variant::Type new_type = Variant::Type(int(p_value)); - arguments[idx].type = new_type; + arguments.write[idx].type = new_type; ports_changed_notify(); return true; @@ -76,7 +76,7 @@ bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value if (what == "name") { - arguments[idx].name = p_value; + arguments.write[idx].name = p_value; ports_changed_notify(); return true; } @@ -234,7 +234,7 @@ void VisualScriptFunction::set_argument_type(int p_argidx, Variant::Type p_type) ERR_FAIL_INDEX(p_argidx, arguments.size()); - arguments[p_argidx].type = p_type; + arguments.write[p_argidx].type = p_type; ports_changed_notify(); } Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const { @@ -246,7 +246,7 @@ void VisualScriptFunction::set_argument_name(int p_argidx, const String &p_name) ERR_FAIL_INDEX(p_argidx, arguments.size()); - arguments[p_argidx].name = p_name; + arguments.write[p_argidx].name = p_name; ports_changed_notify(); } String VisualScriptFunction::get_argument_name(int p_argidx) const { @@ -2198,7 +2198,7 @@ PropertyInfo VisualScriptSceneTree::get_input_value_port_info(int p_idx) const { PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const { - return PropertyInfo(Variant::OBJECT, "Scene Tree"); + return PropertyInfo(Variant::OBJECT, "Scene Tree", PROPERTY_HINT_TYPE_STRING, "SceneTree"); } String VisualScriptSceneTree::get_caption() const { @@ -3560,8 +3560,8 @@ void VisualScriptDeconstruct::_set_elem_cache(const Array &p_elements) { ERR_FAIL_COND(p_elements.size() % 2 == 1); elements.resize(p_elements.size() / 2); for (int i = 0; i < elements.size(); i++) { - elements[i].name = p_elements[i * 2 + 0]; - elements[i].type = Variant::Type(int(p_elements[i * 2 + 1])); + elements.write[i].name = p_elements[i * 2 + 0]; + elements.write[i].type = Variant::Type(int(p_elements[i * 2 + 1])); } } @@ -3606,7 +3606,7 @@ VisualScriptNodeInstance *VisualScriptDeconstruct::instance(VisualScriptInstance instance->instance = p_instance; instance->outputs.resize(elements.size()); for (int i = 0; i < elements.size(); i++) { - instance->outputs[i] = elements[i].name; + instance->outputs.write[i] = elements[i].name; } return instance; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp new file mode 100644 index 0000000000..123d697081 --- /dev/null +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -0,0 +1,713 @@ +/*************************************************************************/ +/* visual_script_property_selector.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "visual_script_property_selector.h" + +#include "editor_scale.h" +#include "modules/visual_script/visual_script.h" +#include "modules/visual_script/visual_script_builtin_funcs.h" +#include "modules/visual_script/visual_script_flow_control.h" +#include "modules/visual_script/visual_script_func_nodes.h" +#include "modules/visual_script/visual_script_nodes.h" +#include "os/keyboard.h" +#include "scene/main/node.h" +#include "scene/main/viewport.h" + +void VisualScriptPropertySelector::_text_changed(const String &p_newtext) { + _update_search(); +} + +void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) { + + Ref<InputEventKey> k = p_ie; + + if (k.is_valid()) { + + switch (k->get_scancode()) { + case KEY_UP: + case KEY_DOWN: + case KEY_PAGEUP: + case KEY_PAGEDOWN: { + + search_options->call("_gui_input", k); + search_box->accept_event(); + + TreeItem *root = search_options->get_root(); + if (!root->get_children()) + break; + + TreeItem *current = search_options->get_selected(); + + TreeItem *item = search_options->get_next_selected(root); + while (item) { + item->deselect(0); + item = search_options->get_next_selected(item); + } + + current->select(0); + + } break; + } + } +} + +void VisualScriptPropertySelector::_update_search() { + set_title(TTR("Search VisualScript")); + + search_options->clear(); + help_bit->set_text(""); + + TreeItem *root = search_options->create_item(); + bool found = false; + + if (properties) { + + List<PropertyInfo> props; + + if (instance) { + instance->get_property_list(&props, true); + } else if (type != Variant::NIL) { + Variant v; + Variant::CallError ce; + v = Variant::construct(type, NULL, 0, ce); + + v.get_property_list(&props); + } else { + + Object *obj = ObjectDB::get_instance(script); + if (Object::cast_to<Script>(obj)) { + + props.push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CATEGORY)); + Object::cast_to<Script>(obj)->get_script_property_list(&props); + } + + StringName base = base_type; + while (base) { + props.push_back(PropertyInfo(Variant::NIL, base, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CATEGORY)); + ClassDB::get_property_list(base, &props, true); + base = ClassDB::get_parent_class_nocheck(base); + } + } + + TreeItem *category = NULL; + + Ref<Texture> type_icons[Variant::VARIANT_MAX] = { + Control::get_icon("Variant", "EditorIcons"), + Control::get_icon("bool", "EditorIcons"), + Control::get_icon("int", "EditorIcons"), + Control::get_icon("float", "EditorIcons"), + Control::get_icon("String", "EditorIcons"), + Control::get_icon("Vector2", "EditorIcons"), + Control::get_icon("Rect2", "EditorIcons"), + Control::get_icon("Vector3", "EditorIcons"), + Control::get_icon("Transform2D", "EditorIcons"), + Control::get_icon("Plane", "EditorIcons"), + Control::get_icon("Quat", "EditorIcons"), + Control::get_icon("AABB", "EditorIcons"), + Control::get_icon("Basis", "EditorIcons"), + Control::get_icon("Transform", "EditorIcons"), + Control::get_icon("Color", "EditorIcons"), + Control::get_icon("Path", "EditorIcons"), + Control::get_icon("RID", "EditorIcons"), + Control::get_icon("Object", "EditorIcons"), + Control::get_icon("Dictionary", "EditorIcons"), + Control::get_icon("Array", "EditorIcons"), + Control::get_icon("PoolByteArray", "EditorIcons"), + Control::get_icon("PoolIntArray", "EditorIcons"), + Control::get_icon("PoolRealArray", "EditorIcons"), + Control::get_icon("PoolStringArray", "EditorIcons"), + Control::get_icon("PoolVector2Array", "EditorIcons"), + Control::get_icon("PoolVector3Array", "EditorIcons"), + Control::get_icon("PoolColorArray", "EditorIcons") + }; + + if (!seq_connect && visual_script_generic == false) { + get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box); + get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box); + get_visual_node_names("functions/by_type/" + Variant::get_type_name(type), Set<String>(), found, root, search_box); + get_visual_node_names("operators/compare/", Set<String>(), found, root, search_box); + if (type == Variant::INT) { + get_visual_node_names("operators/bitwise/", Set<String>(), found, root, search_box); + } + if (type == Variant::BOOL) { + get_visual_node_names("operators/logic/", Set<String>(), found, root, search_box); + } + if (type == Variant::BOOL || type == Variant::INT || type == Variant::REAL || type == Variant::VECTOR2 || type == Variant::VECTOR3) { + get_visual_node_names("operators/math/", Set<String>(), found, root, search_box); + } + } + + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + if (E->get().usage == PROPERTY_USAGE_CATEGORY) { + if (category && category->get_children() == NULL) { + memdelete(category); //old category was unused + } + category = search_options->create_item(root); + category->set_text(0, E->get().name); + category->set_selectable(0, false); + + Ref<Texture> icon; + if (E->get().name == "Script Variables") { + icon = get_icon("Script", "EditorIcons"); + } else if (has_icon(E->get().name, "EditorIcons")) { + icon = get_icon(E->get().name, "EditorIcons"); + } else { + icon = get_icon("Object", "EditorIcons"); + } + category->set_icon(0, icon); + continue; + } + + if (!(E->get().usage & PROPERTY_USAGE_EDITOR) && !(E->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE)) + continue; + + if (type_filter.size() && type_filter.find(E->get().type) == -1) + continue; + + String get_text_raw = String(TTR("Get")) + String(" ") + E->get().name; + String get_text = get_text_raw.capitalize(); + + String set_text_raw = String(TTR("Set ")) + String(" ") + E->get().name; + String set_text = set_text_raw.capitalize(); + String input = search_box->get_text().capitalize(); + if (input == String() || + get_text_raw.findn(input) != -1 || + get_text.findn(input) != -1) { + TreeItem *item = search_options->create_item(category ? category : root); + item->set_text(0, get_text); + item->set_metadata(0, E->get().name); + item->set_icon(0, type_icons[E->get().type]); + item->set_metadata(1, "get"); + item->set_collapsed(1); + item->set_selectable(1, false); + item->set_selectable(0, true); + } + + if (input == String() || + set_text_raw.findn(input) != -1 && + set_text.findn(input) != -1) { + TreeItem *item = search_options->create_item(category ? category : root); + item->set_text(0, set_text); + item->set_metadata(0, E->get().name); + item->set_icon(0, type_icons[E->get().type]); + item->set_metadata(1, "set"); + item->set_selectable(1, false); + item->set_selectable(0, true); + } + } + + if (category && category->get_children() == NULL) { + memdelete(category); //old category was unused + } + } + + if (seq_connect == true && visual_script_generic == false) { + String text = search_box->get_text(); + create_visualscript_item(String("VisualScriptCondition"), root, text, String("Condition")); + create_visualscript_item(String("VisualScriptSwitch"), root, text, String("Switch")); + create_visualscript_item(String("VisualScriptSequence"), root, text, String("Sequence")); + create_visualscript_item(String("VisualScriptIterator"), root, text, String("Iterator")); + create_visualscript_item(String("VisualScriptWhile"), root, text, String("While")); + create_visualscript_item(String("VisualScriptReturn"), root, text, String("Return")); + get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box); + get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box); + } + + if (visual_script_generic) { + get_visual_node_names("", Set<String>(), found, root, search_box); + } + + List<MethodInfo> methods; + + if (type != Variant::NIL) { + Variant v; + Variant::CallError ce; + v = Variant::construct(type, NULL, 0, ce); + v.get_method_list(&methods); + } else { + + Object *obj = ObjectDB::get_instance(script); + if (Object::cast_to<Script>(obj)) { + + methods.push_back(MethodInfo("*Script Methods")); + Object::cast_to<Script>(obj)->get_script_method_list(&methods); + } + + StringName base = base_type; + while (base) { + methods.push_back(MethodInfo("*" + String(base))); + ClassDB::get_method_list(base, &methods, true, true); + base = ClassDB::get_parent_class_nocheck(base); + } + } + TreeItem *category = NULL; + bool script_methods = false; + + for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name.begins_with("*")) { + if (category && category->get_children() == NULL) { + memdelete(category); //old category was unused + } + category = search_options->create_item(root); + category->set_text(0, E->get().name.replace_first("*", "")); + category->set_selectable(0, false); + + Ref<Texture> icon; + script_methods = false; + print_line("name: " + E->get().name); + String rep = E->get().name.replace("*", ""); + if (E->get().name == "*Script Methods") { + icon = get_icon("Script", "EditorIcons"); + script_methods = true; + } else if (has_icon(rep, "EditorIcons")) { + icon = get_icon(rep, "EditorIcons"); + } else { + icon = get_icon("Object", "EditorIcons"); + } + category->set_icon(0, icon); + + continue; + } + + String name = E->get().name.get_slice(":", 0); + if (!script_methods && name.begins_with("_") && !(E->get().flags & METHOD_FLAG_VIRTUAL)) + continue; + + if (virtuals_only && !(E->get().flags & METHOD_FLAG_VIRTUAL)) + continue; + + if (!virtuals_only && (E->get().flags & METHOD_FLAG_VIRTUAL)) + continue; + + MethodInfo mi = E->get(); + String desc = mi.name.capitalize() + " ("; + + if (search_box->get_text() != String() && + name.findn(search_box->get_text()) == -1 && + desc.findn(search_box->get_text()) == -1) + continue; + + TreeItem *item = search_options->create_item(category ? category : root); + + for (int i = 0; i < mi.arguments.size(); i++) { + + if (i > 0) + desc += ", "; + + if (mi.arguments[i].type == Variant::NIL) + desc += "var"; + else if (mi.arguments[i].name.find(":") != -1) { + desc += mi.arguments[i].name.get_slice(":", 1); + mi.arguments[i].name = mi.arguments[i].name.get_slice(":", 0); + } else + desc += Variant::get_type_name(mi.arguments[i].type); + } + + desc += ")"; + + item->set_text(0, desc); + item->set_icon(0, get_icon("MemberMethod", "EditorIcons")); + item->set_metadata(0, name); + item->set_selectable(0, true); + + item->set_metadata(1, "method"); + item->set_collapsed(1); + item->set_selectable(1, false); + + if (category && category->get_children() == NULL) { + memdelete(category); //old category was unused + } + } + + TreeItem *selected_item = search_options->search_item_text(search_box->get_text()); + if (!found && selected_item != NULL) { + selected_item->select(0); + found = true; + } + + if (category && category->get_children() == NULL) { + memdelete(category); //old category was unused + } + + get_ok()->set_disabled(root->get_children() == NULL); +} + +void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) { + if (search_input == String() || text.findn(search_input) != -1) { + TreeItem *item = search_options->create_item(root); + item->set_text(0, text); + item->set_icon(0, get_icon("VisualScript", "EditorIcons")); + item->set_metadata(0, name); + item->set_metadata(1, "action"); + item->set_selectable(0, true); + item->set_collapsed(1); + item->set_selectable(1, false); + } +} + +void VisualScriptPropertySelector::get_visual_node_names(const String &root_filter, const Set<String> &filter, bool &found, TreeItem *const root, LineEdit *const search_box) { + Map<String, TreeItem *> path_cache; + + List<String> fnodes; + VisualScriptLanguage::singleton->get_registered_node_names(&fnodes); + + for (List<String>::Element *E = fnodes.front(); E; E = E->next()) { + if (!E->get().begins_with(root_filter)) { + continue; + } + Vector<String> path = E->get().split("/"); + bool is_filter = false; + for (Set<String>::Element *E = filter.front(); E; E = E->next()) { + if (path.size() >= 2 && path[1].findn(E->get()) != -1) { + is_filter = true; + break; + } + } + if (is_filter == true) { + continue; + } + + if (search_box->get_text() != String() && E->get().findn(search_box->get_text()) == -1) { + continue; + } + TreeItem *item = search_options->create_item(root); + VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(*VisualScriptLanguage::singleton->create_node_from_name(E->get())); + String type_name; + if (vnode_operator != NULL) { + String type; + if (path.size() >= 2) { + type = path[1]; + } + type_name = type.capitalize() + " "; + } + VisualScriptFunctionCall *vnode_function_call = Object::cast_to<VisualScriptFunctionCall>(*VisualScriptLanguage::singleton->create_node_from_name(E->get())); + if (vnode_function_call != NULL) { + String basic_type = Variant::get_type_name(vnode_function_call->get_basic_type()); + type_name = basic_type.capitalize() + " "; + } + VisualScriptBuiltinFunc *vnode_builtin_function_call = Object::cast_to<VisualScriptBuiltinFunc>(*VisualScriptLanguage::singleton->create_node_from_name(E->get())); + if (vnode_builtin_function_call != NULL) { + type_name = "Builtin "; + } + item->set_text(0, type_name + path[path.size() - 1].capitalize()); + item->set_icon(0, get_icon("VisualScript", "EditorIcons")); + item->set_selectable(0, true); + item->set_metadata(0, E->get()); + item->set_selectable(0, true); + item->set_metadata(1, "visualscript"); + item->set_selectable(1, false); + } +} + +void VisualScriptPropertySelector::_confirmed() { + + TreeItem *ti = search_options->get_selected(); + if (!ti) + return; + emit_signal("selected", ti->get_metadata(0), ti->get_metadata(1)); + hide(); +} + +void VisualScriptPropertySelector::_item_selected() { + + help_bit->set_text(""); + + TreeItem *item = search_options->get_selected(); + if (!item) + return; + String name = item->get_metadata(0); + + String class_type; + if (type) { + class_type = Variant::get_type_name(type); + + } else { + class_type = base_type; + } + + DocData *dd = EditorHelp::get_doc_data(); + String text; + + String at_class = class_type; + + while (at_class != String()) { + + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class); + if (E) { + for (int i = 0; i < E->get().properties.size(); i++) { + if (E->get().properties[i].name == name) { + text = E->get().properties[i].description; + } + } + } + + at_class = ClassDB::get_parent_class_nocheck(at_class); + } + at_class = class_type; + + while (at_class != String()) { + + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class); + if (E) { + for (int i = 0; i < E->get().methods.size(); i++) { + if (E->get().methods[i].name == name) { + text = E->get().methods[i].description; + } + } + } + + at_class = ClassDB::get_parent_class_nocheck(at_class); + } + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(class_type); + if (E) { + for (int i = 0; i < E->get().methods.size(); i++) { + Vector<String> functions = name.rsplit("/", false, 1); + if (E->get().methods[i].name == functions[functions.size() - 1]) { + text = E->get().methods[i].description; + } + } + } + + List<String> *names = memnew(List<String>); + VisualScriptLanguage::singleton->get_registered_node_names(names); + if (names->find(name) != NULL) { + Ref<VisualScriptOperator> operator_node = VisualScriptLanguage::singleton->create_node_from_name(name); + if (operator_node.is_valid()) { + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(operator_node->get_class_name()); + if (E) { + text = Variant::get_operator_name(operator_node->get_operator()); + } + } + Ref<VisualScriptTypeCast> typecast_node = VisualScriptLanguage::singleton->create_node_from_name(name); + if (typecast_node.is_valid()) { + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(typecast_node->get_class_name()); + if (E) { + text = E->get().description; + } + } + + Ref<VisualScriptBuiltinFunc> builtin_node = VisualScriptLanguage::singleton->create_node_from_name(name); + if (builtin_node.is_valid()) { + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(builtin_node->get_class_name()); + if (E) { + for (int i = 0; i < E->get().constants.size(); i++) { + if (E->get().constants[i].value.to_int() == int(builtin_node->get_func())) { + text = E->get().constants[i].description; + } + } + } + } + } + + memdelete(names); + + if (text == String()) + return; + + help_bit->set_text(text); +} + +void VisualScriptPropertySelector::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE) { + + connect("confirmed", this, "_confirmed"); + } +} + +void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const String &p_current, bool p_virtuals_only) { + + base_type = p_base; + selected = p_current; + type = Variant::NIL; + script = 0; + properties = false; + instance = NULL; + virtuals_only = p_virtuals_only; + + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + _update_search(); +} + +void VisualScriptPropertySelector::set_type_filter(const Vector<Variant::Type> &p_type_filter) { + type_filter = p_type_filter; +} + +void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_current /*= ""*/, bool p_virtuals_only /*= false*/, bool p_seq_connect /*= false*/) { + + base_type = p_base; + selected = p_current; + type = Variant::NIL; + script = 0; + properties = true; + instance = NULL; + virtuals_only = p_virtuals_only; + + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + seq_connect = p_seq_connect; + + _update_search(); +} + +void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const String &p_current /*= ""*/) { + ERR_FAIL_COND(p_script.is_null()); + + base_type = p_script->get_instance_base_type(); + selected = p_current; + type = Variant::NIL; + script = p_script->get_instance_id(); + properties = true; + instance = NULL; + virtuals_only = false; + + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + seq_connect = false; + + _update_search(); +} + +void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const String &p_current /*= ""*/) { + ERR_FAIL_COND(p_type == Variant::NIL); + base_type = ""; + selected = p_current; + type = p_type; + script = 0; + properties = true; + instance = NULL; + virtuals_only = false; + + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + seq_connect = false; + + _update_search(); +} + +void VisualScriptPropertySelector::select_from_action(const String &p_type, const String &p_current /*= ""*/) { + base_type = p_type; + selected = p_current; + type = Variant::NIL; + script = 0; + properties = false; + instance = NULL; + virtuals_only = false; + + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + seq_connect = true; + _update_search(); +} + +void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const String &p_current /*= ""*/) { + base_type = ""; + selected = p_current; + type = Variant::NIL; + script = 0; + properties = true; + instance = p_instance; + virtuals_only = false; + + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + seq_connect = false; + + _update_search(); +} + +void VisualScriptPropertySelector::select_from_visual_script(const String &p_base) { + base_type = p_base; + selected = ""; + type = Variant::NIL; + script = 0; + properties = true; + visual_script_generic = true; + instance = NULL; + virtuals_only = false; + show_window(.5f); + search_box->set_text(""); + search_box->grab_focus(); + + _update_search(); +} + +void VisualScriptPropertySelector::show_window(float p_screen_ratio) { + Rect2 rect; + Point2 window_size = get_viewport_rect().size; + rect.size = (window_size * p_screen_ratio).floor(); + rect.size.x = rect.size.x / 1.25f; + rect.position = ((window_size - rect.size) / 2.0f).floor(); + popup(rect); +} + +void VisualScriptPropertySelector::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_text_changed"), &VisualScriptPropertySelector::_text_changed); + ClassDB::bind_method(D_METHOD("_confirmed"), &VisualScriptPropertySelector::_confirmed); + ClassDB::bind_method(D_METHOD("_sbox_input"), &VisualScriptPropertySelector::_sbox_input); + ClassDB::bind_method(D_METHOD("_item_selected"), &VisualScriptPropertySelector::_item_selected); + + ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "name"))); +} + +VisualScriptPropertySelector::VisualScriptPropertySelector() { + + VBoxContainer *vbc = memnew(VBoxContainer); + add_child(vbc); + //set_child_rect(vbc); + search_box = memnew(LineEdit); + vbc->add_margin_child(TTR("Search:"), search_box); + search_box->connect("text_changed", this, "_text_changed"); + search_box->connect("gui_input", this, "_sbox_input"); + search_options = memnew(Tree); + vbc->add_margin_child(TTR("Matches:"), search_options, true); + get_ok()->set_text(TTR("Open")); + get_ok()->set_disabled(true); + register_text_enter(search_box); + set_hide_on_ok(false); + search_options->connect("item_activated", this, "_confirmed"); + search_options->connect("cell_selected", this, "_item_selected"); + search_options->set_hide_root(true); + search_options->set_hide_folding(true); + virtuals_only = false; + help_bit = memnew(EditorHelpBit); + vbc->add_margin_child(TTR("Description:"), help_bit); + help_bit->connect("request_hide", this, "_closed"); + search_options->set_columns(2); + search_options->set_column_expand(1, false); +} diff --git a/modules/visual_script/visual_script_property_selector.h b/modules/visual_script/visual_script_property_selector.h new file mode 100644 index 0000000000..ec536f86a8 --- /dev/null +++ b/modules/visual_script/visual_script_property_selector.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* visual_script_property_selector.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 VISUALSCRIPT_PROPERTYSELECTOR_H +#define VISUALSCRIPT_PROPERTYSELECTOR_H + +#include "editor/property_editor.h" +#include "editor_help.h" +#include "scene/gui/rich_text_label.h" + +class VisualScriptPropertySelector : public ConfirmationDialog { + GDCLASS(VisualScriptPropertySelector, ConfirmationDialog) + + LineEdit *search_box; + Tree *search_options; + + void _update_search(); + + void create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text); + + void get_visual_node_names(const String &root_filter, const Set<String> &filter, bool &found, TreeItem *const root, LineEdit *const search_box); + + void _sbox_input(const Ref<InputEvent> &p_ie); + + void _confirmed(); + void _text_changed(const String &p_newtext); + + EditorHelpBit *help_bit; + + bool properties; + bool visual_script_generic; + String selected; + Variant::Type type; + String base_type; + ObjectID script; + Object *instance; + bool virtuals_only; + + bool seq_connect = false; + + void _item_selected(); + + Vector<Variant::Type> type_filter; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void select_method_from_base_type(const String &p_base, const String &p_current = "", bool p_virtuals_only = false); + void select_from_base_type(const String &p_base, const String &p_current = "", bool p_virtuals_only = false, bool p_seq_connect = false); + void select_from_script(const Ref<Script> &p_script, const String &p_current /*= ""*/); + void select_from_basic_type(Variant::Type p_type, const String &p_current = ""); + void select_from_action(const String &p_type, const String &p_current = ""); + void select_from_instance(Object *p_instance, const String &p_current = ""); + void select_from_visual_script(const String &p_base); + + void show_window(float p_screen_ratio); + + void set_type_filter(const Vector<Variant::Type> &p_type_filter); + + VisualScriptPropertySelector(); +}; + +#endif // VISUALSCRIPT_PROPERTYSELECTOR_H diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index cdf2d75e96..42b2c77777 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -116,64 +116,73 @@ static Ref<Image> _webp_lossy_unpack(const PoolVector<uint8_t> &p_buffer) { return img; } -Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len) { - uint32_t size = f->get_len(); - PoolVector<uint8_t> src_image; - src_image.resize(size); + ERR_FAIL_NULL_V(p_image, ERR_INVALID_PARAMETER); WebPBitstreamFeatures features; - - PoolVector<uint8_t>::Write src_w = src_image.write(); - f->get_buffer(src_w.ptr(), size); - ERR_FAIL_COND_V(f->eof_reached(), ERR_FILE_EOF); - - if (WebPGetFeatures(src_w.ptr(), size, &features) != VP8_STATUS_OK) { - f->close(); - //ERR_EXPLAIN("Error decoding WEBP image: "+p_file); + if (WebPGetFeatures(p_buffer, p_buffer_len, &features) != VP8_STATUS_OK) { + // ERR_EXPLAIN("Error decoding WEBP image"); ERR_FAIL_V(ERR_FILE_CORRUPT); } - /* - print_line("width: " + itos(features.width)); - print_line("height: " + itos(features.height)); - print_line("alpha: " + itos(features.has_alpha)); - */ - - src_w = PoolVector<uint8_t>::Write(); - PoolVector<uint8_t> dst_image; int datasize = features.width * features.height * (features.has_alpha ? 4 : 3); dst_image.resize(datasize); - - PoolVector<uint8_t>::Read src_r = src_image.read(); PoolVector<uint8_t>::Write dst_w = dst_image.write(); bool errdec = false; if (features.has_alpha) { - errdec = WebPDecodeRGBAInto(src_r.ptr(), size, dst_w.ptr(), datasize, 4 * features.width) == NULL; + errdec = WebPDecodeRGBAInto(p_buffer, p_buffer_len, dst_w.ptr(), datasize, 4 * features.width) == NULL; } else { - errdec = WebPDecodeRGBInto(src_r.ptr(), size, dst_w.ptr(), datasize, 3 * features.width) == NULL; + errdec = WebPDecodeRGBInto(p_buffer, p_buffer_len, dst_w.ptr(), datasize, 3 * features.width) == NULL; } + dst_w = PoolVector<uint8_t>::Write(); - //ERR_EXPLAIN("Error decoding webp! - "+p_file); + //ERR_EXPLAIN("Error decoding webp!"); ERR_FAIL_COND_V(errdec, ERR_FILE_CORRUPT); - src_r = PoolVector<uint8_t>::Read(); - dst_w = PoolVector<uint8_t>::Write(); - p_image->create(features.width, features.height, 0, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image); return OK; } +static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { + + Ref<Image> img; + img.instance(); + Error err = webp_load_image_from_buffer(img.ptr(), p_png, p_size); + ERR_FAIL_COND_V(err, Ref<Image>()); + return img; +} + +Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { + + PoolVector<uint8_t> src_image; + int src_image_len = f->get_len(); + ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); + src_image.resize(src_image_len); + + PoolVector<uint8_t>::Write w = src_image.write(); + + f->get_buffer(&w[0], src_image_len); + + f->close(); + + Error err = webp_load_image_from_buffer(p_image.ptr(), w.ptr(), src_image_len); + + w = PoolVector<uint8_t>::Write(); + + return err; +} + void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("webp"); } ImageLoaderWEBP::ImageLoaderWEBP() { - + Image::_webp_mem_loader_func = _webp_mem_loader_func; Image::lossy_packer = _webp_lossy_pack; Image::lossy_unpacker = _webp_lossy_unpack; } diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 1405fa98b0..00c36ebb47 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -64,7 +64,6 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, String str = "ws://"; String proto_string = ""; - int i = 0; if (p_ssl) str = "wss://"; diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp index fd834193dd..28e3ea962f 100644 --- a/platform/android/audio_driver_opensl.cpp +++ b/platform/android/audio_driver_opensl.cpp @@ -146,9 +146,6 @@ void AudioDriverOpenSL::start() { res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void *)&EngineItf); ERR_FAIL_COND(res != SL_RESULT_SUCCESS); - /* Initialize arrays required[] and iidArray[] */ - SLboolean required[MAX_NUMBER_INTERFACES]; - SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; { const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB }; @@ -188,10 +185,7 @@ void AudioDriverOpenSL::start() { //cntxt.pDataBase = (void*)&pcmData; //cntxt.pData = cntxt.pDataBase; //cntxt.size = sizeof(pcmData); - /* Set arrays required[] and iidArray[] for SEEK interface - (PlayItf is implicit) */ - required[0] = SL_BOOLEAN_TRUE; - iidArray[0] = SL_IID_BUFFERQUEUE; + /* Create the music player */ { diff --git a/platform/android/detect.py b/platform/android/detect.py index 971368db17..ada36e2814 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -139,8 +139,13 @@ def configure(env): ## Build type if (env["target"].startswith("release")): - env.Append(LINKFLAGS=['-O2']) - env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(LINKFLAGS=['-O2']) + env.Append(CPPFLAGS=['-O2', '-DNDEBUG', '-ffast-math', '-funsafe-math-optimizations', '-fomit-frame-pointer']) + else: #optimize for size + env.Append(CPPFLAGS=['-Os', '-DNDEBUG']) + env.Append(LINKFLAGS=['-Os']) + if (can_vectorize): env.Append(CPPFLAGS=['-ftree-vectorize']) if (env["target"] == "release_debug"): diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 3e40b59de9..ee5ae156b7 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -153,7 +153,6 @@ String DirAccessJAndroid::get_current_dir() { bool DirAccessJAndroid::file_exists(String p_file) { - JNIEnv *env = ThreadAndroid::get_env(); String sd; if (current_dir == "") sd = p_file; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index c562a47b00..9ad0219746 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -528,11 +528,9 @@ class EditorExportAndroid : public EditorExportPlatform { bool exported = false; for (int i = 0; i < p_so.tags.size(); ++i) { // shared objects can be fat (compatible with multiple ABIs) - int start_pos = 0; int abi_index = abis.find(p_so.tags[i]); if (abi_index != -1) { exported = true; - start_pos = abi_index + 1; String abi = abis[abi_index]; String dst_path = "lib/" + abi + "/" + p_so.path.get_file(); Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path); @@ -667,11 +665,11 @@ class EditorExportAndroid : public EditorExportPlatform { ucstring.resize(len + 1); for (uint32_t j = 0; j < len; j++) { uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]); - ucstring[j] = c; + ucstring.write[j] = c; } string_end = MAX(string_at + 2 + 2 * len, string_end); - ucstring[len] = 0; - string_table[i] = ucstring.ptr(); + ucstring.write[len] = 0; + string_table.write[i] = ucstring.ptr(); } //print_line("String "+itos(i)+": "+string_table[i]); @@ -718,13 +716,13 @@ class EditorExportAndroid : public EditorExportPlatform { if (tname == "manifest" && attrname == "package") { print_line("FOUND package"); - string_table[attr_value] = get_package_name(package_name); + string_table.write[attr_value] = get_package_name(package_name); } if (tname == "manifest" && /*nspace=="android" &&*/ attrname == "versionCode") { print_line("FOUND versionCode"); - encode_uint32(version_code, &p_manifest[iofs + 16]); + encode_uint32(version_code, &p_manifest.write[iofs + 16]); } if (tname == "manifest" && /*nspace=="android" &&*/ attrname == "versionName") { @@ -733,12 +731,12 @@ class EditorExportAndroid : public EditorExportPlatform { if (attr_value == 0xFFFFFFFF) { WARN_PRINT("Version name in a resource, should be plaintext") } else - string_table[attr_value] = version_name; + string_table.write[attr_value] = version_name; } if (tname == "activity" && /*nspace=="android" &&*/ attrname == "screenOrientation") { - encode_uint32(orientation == 0 ? 0 : 1, &p_manifest[iofs + 16]); + encode_uint32(orientation == 0 ? 0 : 1, &p_manifest.write[iofs + 16]); } if (tname == "uses-feature" && /*nspace=="android" &&*/ attrname == "glEsVersion") { @@ -749,19 +747,19 @@ class EditorExportAndroid : public EditorExportPlatform { if (attrname == "smallScreens") { - encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } else if (attrname == "normalScreens") { - encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } else if (attrname == "largeScreens") { - encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } else if (attrname == "xlargeScreens") { - encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest[iofs + 16]); + encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); } } @@ -813,45 +811,45 @@ class EditorExportAndroid : public EditorExportPlatform { } // start tag - encode_uint16(0x102, &p_manifest[ofs]); // type - encode_uint16(16, &p_manifest[ofs + 2]); // headersize - encode_uint32(56, &p_manifest[ofs + 4]); // size - encode_uint32(0, &p_manifest[ofs + 8]); // lineno - encode_uint32(-1, &p_manifest[ofs + 12]); // comment - encode_uint32(-1, &p_manifest[ofs + 16]); // ns - encode_uint32(attr_uses_permission_string, &p_manifest[ofs + 20]); // name - encode_uint16(20, &p_manifest[ofs + 24]); // attr_start - encode_uint16(20, &p_manifest[ofs + 26]); // attr_size - encode_uint16(1, &p_manifest[ofs + 28]); // num_attrs - encode_uint16(0, &p_manifest[ofs + 30]); // id_index - encode_uint16(0, &p_manifest[ofs + 32]); // class_index - encode_uint16(0, &p_manifest[ofs + 34]); // style_index + encode_uint16(0x102, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(56, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name + encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start + encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size + encode_uint16(1, &p_manifest.write[ofs + 28]); // num_attrs + encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index + encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index + encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index // attribute - encode_uint32(ns_android_string, &p_manifest[ofs + 36]); // ns - encode_uint32(attr_name_string, &p_manifest[ofs + 40]); // 'name' - encode_uint32(perm_string, &p_manifest[ofs + 44]); // raw_value - encode_uint16(8, &p_manifest[ofs + 48]); // typedvalue_size - p_manifest[ofs + 50] = 0; // typedvalue_always0 - p_manifest[ofs + 51] = 0x03; // typedvalue_type (string) - encode_uint32(perm_string, &p_manifest[ofs + 52]); // typedvalue reference + encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns + encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' + encode_uint32(perm_string, &p_manifest.write[ofs + 44]); // raw_value + encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size + p_manifest.write[ofs + 50] = 0; // typedvalue_always0 + p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) + encode_uint32(perm_string, &p_manifest.write[ofs + 52]); // typedvalue reference ofs += 56; // end tag - encode_uint16(0x103, &p_manifest[ofs]); // type - encode_uint16(16, &p_manifest[ofs + 2]); // headersize - encode_uint32(24, &p_manifest[ofs + 4]); // size - encode_uint32(0, &p_manifest[ofs + 8]); // lineno - encode_uint32(-1, &p_manifest[ofs + 12]); // comment - encode_uint32(-1, &p_manifest[ofs + 16]); // ns - encode_uint32(attr_uses_permission_string, &p_manifest[ofs + 20]); // name + encode_uint16(0x103, &p_manifest.write[ofs]); // type + encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize + encode_uint32(24, &p_manifest.write[ofs + 4]); // size + encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno + encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment + encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns + encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name ofs += 24; } // copy footer back in - memcpy(&p_manifest[ofs], manifest_end.ptr(), manifest_end.size()); + memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); } } break; } @@ -866,19 +864,19 @@ class EditorExportAndroid : public EditorExportPlatform { for (uint32_t i = 0; i < string_table_begins; i++) { - ret[i] = p_manifest[i]; + ret.write[i] = p_manifest[i]; } ofs = 0; for (int i = 0; i < string_table.size(); i++) { - encode_uint32(ofs, &ret[string_table_begins + i * 4]); + encode_uint32(ofs, &ret.write[string_table_begins + i * 4]); ofs += string_table[i].length() * 2 + 2 + 2; } ret.resize(ret.size() + ofs); string_data_offset = ret.size() - ofs; - uint8_t *chars = &ret[string_data_offset]; + uint8_t *chars = &ret.write[string_data_offset]; for (int i = 0; i < string_table.size(); i++) { String s = string_table[i]; @@ -905,15 +903,15 @@ class EditorExportAndroid : public EditorExportPlatform { uint32_t extra = (p_manifest.size() - string_table_ends); ret.resize(new_stable_end + extra); for (uint32_t i = 0; i < extra; i++) - ret[new_stable_end + i] = p_manifest[string_table_ends + i]; + ret.write[new_stable_end + i] = p_manifest[string_table_ends + i]; while (ret.size() % 4) ret.push_back(0); - encode_uint32(ret.size(), &ret[4]); //update new file size + encode_uint32(ret.size(), &ret.write[4]); //update new file size - encode_uint32(new_stable_end - 8, &ret[12]); //update new string table size - encode_uint32(string_table.size(), &ret[16]); //update new number of strings - encode_uint32(string_data_offset - 8, &ret[28]); //update new string data offset + encode_uint32(new_stable_end - 8, &ret.write[12]); //update new string table size + encode_uint32(string_table.size(), &ret.write[16]); //update new number of strings + encode_uint32(string_data_offset - 8, &ret.write[28]); //update new string data offset //print_line("file size: "+itos(ret.size())); @@ -937,9 +935,9 @@ class EditorExportAndroid : public EditorExportPlatform { Vector<uint8_t> str8; str8.resize(len + 1); for (uint32_t i = 0; i < len; i++) { - str8[i] = p_bytes[offset + i]; + str8.write[i] = p_bytes[offset + i]; } - str8[len] = 0; + str8.write[len] = 0; String str; str.parse_utf8((const char *)str8.ptr()); return str; @@ -1003,18 +1001,18 @@ class EditorExportAndroid : public EditorExportPlatform { for (uint32_t i = 0; i < string_table_begins; i++) { - ret[i] = p_manifest[i]; + ret.write[i] = p_manifest[i]; } int ofs = 0; for (int i = 0; i < string_table.size(); i++) { - encode_uint32(ofs, &ret[string_table_begins + i * 4]); + encode_uint32(ofs, &ret.write[string_table_begins + i * 4]); ofs += string_table[i].length() * 2 + 2 + 2; } ret.resize(ret.size() + ofs); - uint8_t *chars = &ret[ret.size() - ofs]; + uint8_t *chars = &ret.write[ret.size() - ofs]; for (int i = 0; i < string_table.size(); i++) { String s = string_table[i]; @@ -1033,19 +1031,19 @@ class EditorExportAndroid : public EditorExportPlatform { ret.push_back(0); //change flags to not use utf8 - encode_uint32(string_flags & ~0x100, &ret[28]); + encode_uint32(string_flags & ~0x100, &ret.write[28]); //change length - encode_uint32(ret.size() - 12, &ret[16]); + encode_uint32(ret.size() - 12, &ret.write[16]); //append the rest... int rest_from = 12 + string_block_len; int rest_to = ret.size(); int rest_len = (p_manifest.size() - rest_from); ret.resize(ret.size() + (p_manifest.size() - rest_from)); for (int i = 0; i < rest_len; i++) { - ret[rest_to + i] = p_manifest[rest_from + i]; + ret.write[rest_to + i] = p_manifest[rest_from + i]; } //finally update the size - encode_uint32(ret.size(), &ret[4]); + encode_uint32(ret.size(), &ret.write[4]); p_manifest = ret; //printf("end\n"); @@ -1646,7 +1644,7 @@ public: //add comandline Vector<uint8_t> clf; clf.resize(4); - encode_uint32(cl.size(), &clf[0]); + encode_uint32(cl.size(), &clf.write[0]); for (int i = 0; i < cl.size(); i++) { print_line(itos(i) + " param: " + cl[i]); @@ -1656,8 +1654,8 @@ public: if (!length) continue; clf.resize(base + 4 + length); - encode_uint32(length, &clf[base]); - copymem(&clf[base + 4], txt.ptr(), length); + encode_uint32(length, &clf.write[base]); + copymem(&clf.write[base + 4], txt.ptr(), length); } zip_fileinfo zipfi = get_zip_fileinfo(); diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index e6240ad9e9..8bb1c38345 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -880,7 +880,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo const char **cmdline = NULL; int cmdlen = 0; - bool use_apk_expansion = false; if (p_cmdline) { cmdlen = env->GetArrayLength(p_cmdline); if (cmdlen) { @@ -891,9 +890,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i); const char *rawString = env->GetStringUTFChars(string, 0); - if (rawString && strcmp(rawString, "--main-pack") == 0) { - use_apk_expansion = true; - } cmdline[i] = rawString; } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index cc512263bc..f9eda9dff1 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -357,8 +357,8 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> touch.resize(p_points.size()); for (int i = 0; i < p_points.size(); i++) { - touch[i].id = p_points[i].id; - touch[i].pos = p_points[i].pos; + touch.write[i].id = p_points[i].id; + touch.write[i].pos = p_points[i].pos; } //send touch @@ -399,7 +399,7 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> ev->set_position(p_points[idx].pos); ev->set_relative(p_points[idx].pos - touch[i].pos); input->parse_input_event(ev); - touch[i].pos = p_points[idx].pos; + touch.write[i].pos = p_points[idx].pos; } } break; diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp index e85813605f..b13baf69c2 100644 --- a/platform/android/thread_jandroid.cpp +++ b/platform/android/thread_jandroid.cpp @@ -132,7 +132,7 @@ JNIEnv *ThreadAndroid::get_env() { } JNIEnv *env = NULL; - int status = java_vm->AttachCurrentThread(&env, NULL); + java_vm->AttachCurrentThread(&env, NULL); return env; } diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 97fab5ca0d..209cb5cec4 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -80,6 +80,10 @@ const char *OS_Haiku::get_video_driver_name(int p_driver) const { return "GLES3"; } +int OS_Haiku::get_current_video_driver() const { + return video_driver_index; +} + Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { main_loop = NULL; current_video_mode = p_desired; @@ -124,6 +128,8 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p } */ + video_driver_index = p_video_driver; + input = memnew(InputDefault); window->SetInput(input); diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index 615ae682ef..13d4420bde 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -51,6 +51,7 @@ private: Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_video_mode; + int video_driver_index; PowerHaiku *power_manager; #ifdef MEDIA_KIT_ENABLED @@ -66,6 +67,7 @@ private: protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; + virtual int get_current_video_driver() const; virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index 25674c2b47..b13a1e9643 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -47,8 +47,12 @@ def configure(env): if (env["target"].startswith("release")): env.Append(CPPFLAGS=['-DNDEBUG', '-DNS_BLOCK_ASSERTIONS=1']) - env.Append(CPPFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) - env.Append(LINKFLAGS=['-O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CPPFLAGS=['-O2', '-ftree-vectorize', '-fomit-frame-pointer', '-ffast-math', '-funsafe-math-optimizations']) + env.Append(LINKFLAGS=['-O2']) + else: #optimize for size + env.Append(CPPFLAGS=['-Os', '-ftree-vectorize']) + env.Append(LINKFLAGS=['-Os']) if env["target"] == "release_debug": env.Append(CPPFLAGS=['-DDEBUG_ENABLED']) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 4c1e02baf7..e59c81a148 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -276,7 +276,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ CharString cs = strnew.utf8(); pfile.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { - pfile[i] = cs[i]; + pfile.write[i] = cs[i]; } } @@ -489,7 +489,7 @@ private: ret.resize(sizeof(num) * 2); for (int i = 0; i < sizeof(num) * 2; ++i) { uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF; - ret[i] = _hex_char(four_bits); + ret.write[i] = _hex_char(four_bits); } return String::utf8(ret.ptr(), ret.size()); } @@ -587,7 +587,7 @@ void EditorExportPlatformIOS::_add_assets_to_project(Vector<uint8_t> &p_project_ CharString cs = str.utf8(); p_project_data.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { - p_project_data[i] = cs[i]; + p_project_data.write[i] = cs[i]; } } @@ -781,7 +781,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p int ret = unzGoToFirstFile(src_pkg_zip); Vector<uint8_t> project_file_data; while (ret == UNZ_OK) { +#if defined(OSX_ENABLED) || defined(X11_ENABLED) bool is_execute = false; +#endif //get filename unz_file_info info; @@ -812,7 +814,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p continue; //ignore! } found_library = true; +#if defined(OSX_ENABLED) || defined(X11_ENABLED) is_execute = true; +#endif file = "godot_ios.a"; } if (file == project_file) { @@ -855,7 +859,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p f->close(); memdelete(f); -#ifdef OSX_ENABLED +#if defined(OSX_ENABLED) || defined(X11_ENABLED) if (is_execute) { // we need execute rights on this file chmod(file.utf8().get_data(), 0755); diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 9591850662..7cff6ba172 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -95,7 +95,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re CharString cs = str_export.utf8(); p_html.resize(cs.length()); for (int i = 0; i < cs.length(); i++) { - p_html[i] = cs[i]; + p_html.write[i] = cs[i]; } } diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 72b8aa99f8..8a0883eca3 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -39,14 +39,21 @@ def configure(env): ## Build type if (env["target"] == "release"): - env.Prepend(CCFLAGS=['-O3', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O3', '-ffast-math', '-fomit-frame-pointer', '-ftree-vectorize', '-msse2']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os','-ftree-vectorize', '-msse2']) + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): env.Prepend(CCFLAGS=['-g2']) elif (env["target"] == "release_debug"): - env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O2', '-DDEBUG_ENABLED']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os', '-DDEBUG_ENABLED']) if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): @@ -108,8 +115,8 @@ def configure(env): ## Flags env.Append(CPPPATH=['#platform/osx']) - env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED']) - env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) + env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED']) + env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMIDI', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback']) env.Append(LIBS=['pthread']) env.Append(CPPFLAGS=['-mmacosx-version-min=10.9']) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index db265812fa..b630e4f223 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -137,10 +137,10 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ Vector<uint8_t> data; data.resize(8); - data[0] = 'i'; - data[1] = 'c'; - data[2] = 'n'; - data[3] = 's'; + data.write[0] = 'i'; + data.write[1] = 'c'; + data.write[2] = 'n'; + data.write[3] = 's'; const char *name[] = { "ic09", "ic08", "ic07", "icp6", "icp5", "icp4" }; int index = 0; @@ -160,19 +160,19 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ int ofs = data.size(); uint32_t len = f->get_len(); data.resize(data.size() + len + 8); - f->get_buffer(&data[ofs + 8], len); + f->get_buffer(&data.write[ofs + 8], len); memdelete(f); len += 8; len = BSWAP32(len); - copymem(&data[ofs], name[index], 4); - encode_uint32(len, &data[ofs + 4]); + copymem(&data.write[ofs], name[index], 4); + encode_uint32(len, &data.write[ofs + 4]); index++; size /= 2; } uint32_t total_len = data.size(); total_len = BSWAP32(total_len); - encode_uint32(total_len, &data[4]); + encode_uint32(total_len, &data.write[4]); p_data = data; } @@ -210,7 +210,7 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset CharString cs = strnew.utf8(); plist.resize(cs.size() - 1); for (int i = 0; i < cs.size() - 1; i++) { - plist[i] = cs[i]; + plist.write[i] = cs[i]; } } diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index 20ceadca9d..365b39c573 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -271,7 +271,7 @@ void JoypadOSX::_device_removed(int p_id) { ERR_FAIL_COND(device == -1); input->joy_connection_changed(p_id, false, ""); - device_list[device].free(); + device_list.write[device].free(); device_list.remove(device); } @@ -460,19 +460,19 @@ void JoypadOSX::process_joypads() { poll_joypads(); for (int i = 0; i < device_list.size(); i++) { - joypad &joy = device_list[i]; + joypad &joy = device_list.write[i]; for (int j = 0; j < joy.axis_elements.size(); j++) { - rec_element &elem = joy.axis_elements[j]; + rec_element &elem = joy.axis_elements.write[j]; int value = joy.get_hid_element_state(&elem); input->joy_axis(joy.id, j, axis_correct(value, elem.min, elem.max)); } for (int j = 0; j < joy.button_elements.size(); j++) { - int value = joy.get_hid_element_state(&joy.button_elements[j]); + int value = joy.get_hid_element_state(&joy.button_elements.write[j]); input->joy_button(joy.id, j, (value >= 1)); } for (int j = 0; j < joy.hat_elements.size(); j++) { - rec_element &elem = joy.hat_elements[j]; + rec_element &elem = joy.hat_elements.write[j]; int value = joy.get_hid_element_state(&elem); int hat_value = process_hat_value(elem.min, elem.max, value); input->joy_hat(joy.id, hat_value); @@ -495,7 +495,7 @@ void JoypadOSX::process_joypads() { } void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_duration, uint64_t p_timestamp) { - joypad *joy = &device_list[get_joy_index(p_id)]; + joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; joy->ff_effect.dwDuration = p_duration * FF_SECONDS; joy->ff_effect.dwGain = p_magnitude * FF_FFNOMINALMAX; @@ -504,7 +504,7 @@ void JoypadOSX::joypad_vibration_start(int p_id, float p_magnitude, float p_dura } void JoypadOSX::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { - joypad *joy = &device_list[get_joy_index(p_id)]; + joypad *joy = &device_list.write[get_joy_index(p_id)]; joy->ff_timestamp = p_timestamp; FFEffectStop(joy->ff_object); } @@ -596,7 +596,7 @@ JoypadOSX::JoypadOSX() { JoypadOSX::~JoypadOSX() { for (int i = 0; i < device_list.size(); i++) { - device_list[i].free(); + device_list.write[i].free(); } IOHIDManagerUnscheduleFromRunLoop(hid_manager, CFRunLoopGetCurrent(), GODOT_JOY_LOOP_RUN_MODE); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 3d14a6d4fb..686e3f8c90 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -33,6 +33,7 @@ #include "crash_handler_osx.h" #include "drivers/coreaudio/audio_driver_coreaudio.h" +#include "drivers/coremidi/core_midi.h" #include "drivers/unix/os_unix.h" #include "joypad_osx.h" #include "main/input_default.h" @@ -74,6 +75,7 @@ public: IP_Unix *ip_unix; AudioDriverCoreAudio audio_driver; + MIDIDriverCoreMidi midi_driver; InputDefault *input; JoypadOSX *joypad_osx; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 282f5e2d1b..7bf274310d 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -95,7 +95,7 @@ static void push_to_key_event_buffer(const OS_OSX::KeyEvent &p_event) { if (OS_OSX::singleton->key_event_pos >= buffer.size()) { buffer.resize(1 + OS_OSX::singleton->key_event_pos); } - buffer[OS_OSX::singleton->key_event_pos++] = p_event; + buffer.write[OS_OSX::singleton->key_event_pos++] = p_event; } static int mouse_x = 0; @@ -602,8 +602,8 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) { mm->set_position(pos); mm->set_global_position(pos); Vector2 relativeMotion = Vector2(); - relativeMotion.x = [event deltaX] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); - relativeMotion.y = [event deltaY] * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]); + relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]); + relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]); mm->set_relative(relativeMotion); get_key_modifier_state([event modifierFlags], mm); @@ -1351,6 +1351,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a AudioDriverManager::initialize(p_audio_driver); + midi_driver.open(); + input = memnew(InputDefault); joypad_osx = memnew(JoypadOSX); @@ -2403,7 +2405,7 @@ void OS_OSX::process_key_events() { Ref<InputEventKey> k; for (int i = 0; i < key_event_pos; i++) { - KeyEvent &ke = key_event_buffer[i]; + const KeyEvent &ke = key_event_buffer[i]; if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) { k.instance(); diff --git a/platform/server/os_server.h b/platform/server/os_server.h index 8c47bfc591..07d70e5236 100644 --- a/platform/server/os_server.h +++ b/platform/server/os_server.h @@ -47,7 +47,6 @@ class OS_Server : public OS_Unix { - //Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_videomode; List<String> args; @@ -73,7 +72,7 @@ class OS_Server : public OS_Unix { protected: virtual int get_video_driver_count() const; virtual const char *get_video_driver_name(int p_driver) const; - + virtual int get_current_video_driver() const; virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; @@ -86,8 +85,6 @@ protected: public: virtual String get_name(); - virtual int get_current_video_driver() const; - virtual void set_cursor_shape(CursorShape p_shape); virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 35c0b30ce4..ebc2c2d7a2 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -301,37 +301,37 @@ Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) { int offs = 0; // Write magic - offs += buf_put_int32(FILE_HEADER_MAGIC, &buf[offs]); + offs += buf_put_int32(FILE_HEADER_MAGIC, &buf.write[offs]); // Version - offs += buf_put_int16(ZIP_VERSION, &buf[offs]); + offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]); // Special flag - offs += buf_put_int16(GENERAL_PURPOSE, &buf[offs]); + offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]); // Compression - offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf[offs]); + offs += buf_put_int16(p_file_meta.compressed ? Z_DEFLATED : 0, &buf.write[offs]); // File date and time - offs += buf_put_int32(0, &buf[offs]); + offs += buf_put_int32(0, &buf.write[offs]); // CRC-32 - offs += buf_put_int32(p_file_meta.file_crc32, &buf[offs]); + offs += buf_put_int32(p_file_meta.file_crc32, &buf.write[offs]); // Compressed size - offs += buf_put_int32(p_file_meta.compressed_size, &buf[offs]); + offs += buf_put_int32(p_file_meta.compressed_size, &buf.write[offs]); // Uncompressed size - offs += buf_put_int32(p_file_meta.uncompressed_size, &buf[offs]); + offs += buf_put_int32(p_file_meta.uncompressed_size, &buf.write[offs]); // File name length - offs += buf_put_int16(p_file_meta.name.length(), &buf[offs]); + offs += buf_put_int16(p_file_meta.name.length(), &buf.write[offs]); // Extra data length - offs += buf_put_int16(0, &buf[offs]); + offs += buf_put_int16(0, &buf.write[offs]); // File name - offs += buf_put_string(p_file_meta.name, &buf[offs]); + offs += buf_put_string(p_file_meta.name, &buf.write[offs]); // Done! return buf; @@ -344,47 +344,47 @@ void AppxPackager::store_central_dir_header(const FileMeta &p_file, bool p_do_ha buf.resize(buf.size() + BASE_CENTRAL_DIR_SIZE + p_file.name.length()); // Write magic - offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf[offs]); + offs += buf_put_int32(CENTRAL_DIR_MAGIC, &buf.write[offs]); // ZIP versions - offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf[offs]); - offs += buf_put_int16(ZIP_VERSION, &buf[offs]); + offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]); + offs += buf_put_int16(ZIP_VERSION, &buf.write[offs]); // General purpose flag - offs += buf_put_int16(GENERAL_PURPOSE, &buf[offs]); + offs += buf_put_int16(GENERAL_PURPOSE, &buf.write[offs]); // Compression - offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf[offs]); + offs += buf_put_int16(p_file.compressed ? Z_DEFLATED : 0, &buf.write[offs]); // Modification date/time - offs += buf_put_int32(0, &buf[offs]); + offs += buf_put_int32(0, &buf.write[offs]); // Crc-32 - offs += buf_put_int32(p_file.file_crc32, &buf[offs]); + offs += buf_put_int32(p_file.file_crc32, &buf.write[offs]); // File sizes - offs += buf_put_int32(p_file.compressed_size, &buf[offs]); - offs += buf_put_int32(p_file.uncompressed_size, &buf[offs]); + offs += buf_put_int32(p_file.compressed_size, &buf.write[offs]); + offs += buf_put_int32(p_file.uncompressed_size, &buf.write[offs]); // File name length - offs += buf_put_int16(p_file.name.length(), &buf[offs]); + offs += buf_put_int16(p_file.name.length(), &buf.write[offs]); // Extra field length - offs += buf_put_int16(0, &buf[offs]); + offs += buf_put_int16(0, &buf.write[offs]); // Comment length - offs += buf_put_int16(0, &buf[offs]); + offs += buf_put_int16(0, &buf.write[offs]); // Disk number start, internal/external file attributes for (int i = 0; i < 8; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Relative offset - offs += buf_put_int32(p_file.zip_offset, &buf[offs]); + offs += buf_put_int32(p_file.zip_offset, &buf.write[offs]); // File name - offs += buf_put_string(p_file.name, &buf[offs]); + offs += buf_put_string(p_file.name, &buf.write[offs]); // Done! } @@ -397,62 +397,62 @@ Vector<uint8_t> AppxPackager::make_end_of_central_record() { int offs = 0; // Write magic - offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf[offs]); + offs += buf_put_int32(ZIP64_END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]); // Size of this record - offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf[offs]); + offs += buf_put_int64(ZIP64_END_OF_CENTRAL_DIR_SIZE, &buf.write[offs]); // Version (yes, twice) - offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf[offs]); - offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf[offs]); + offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]); + offs += buf_put_int16(ZIP_ARCHIVE_VERSION, &buf.write[offs]); // Disk number for (int i = 0; i < 8; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Number of entries (total and per disk) - offs += buf_put_int64(file_metadata.size(), &buf[offs]); - offs += buf_put_int64(file_metadata.size(), &buf[offs]); + offs += buf_put_int64(file_metadata.size(), &buf.write[offs]); + offs += buf_put_int64(file_metadata.size(), &buf.write[offs]); // Size of central dir - offs += buf_put_int64(central_dir_data.size(), &buf[offs]); + offs += buf_put_int64(central_dir_data.size(), &buf.write[offs]); // Central dir offset - offs += buf_put_int64(central_dir_offset, &buf[offs]); + offs += buf_put_int64(central_dir_offset, &buf.write[offs]); ////// ZIP64 locator // Write magic for zip64 central dir locator - offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf[offs]); + offs += buf_put_int32(ZIP64_END_DIR_LOCATOR_MAGIC, &buf.write[offs]); // Disk number for (int i = 0; i < 4; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Relative offset - offs += buf_put_int64(end_of_central_dir_offset, &buf[offs]); + offs += buf_put_int64(end_of_central_dir_offset, &buf.write[offs]); // Number of disks - offs += buf_put_int32(1, &buf[offs]); + offs += buf_put_int32(1, &buf.write[offs]); /////// End of zip directory // Write magic for end central dir - offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf[offs]); + offs += buf_put_int32(END_OF_CENTRAL_DIR_MAGIC, &buf.write[offs]); // Dummy stuff for Zip64 for (int i = 0; i < 4; i++) { - buf[offs++] = 0x0; + buf.write[offs++] = 0x0; } for (int i = 0; i < 12; i++) { - buf[offs++] = 0xFF; + buf.write[offs++] = 0xFF; } // Size of comments for (int i = 0; i < 2; i++) { - buf[offs++] = 0; + buf.write[offs++] = 0; } // Done! @@ -508,7 +508,7 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t size_t block_size = (p_len - step) > BLOCK_SIZE ? BLOCK_SIZE : (p_len - step); for (uint32_t i = 0; i < block_size; i++) { - strm_in[i] = p_buffer[step + i]; + strm_in.write[i] = p_buffer[step + i]; } BlockHash bh; @@ -530,14 +530,14 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t int start = file_buffer.size(); file_buffer.resize(file_buffer.size() + bh.compressed_size); for (uint32_t i = 0; i < bh.compressed_size; i++) - file_buffer[start + i] = strm_out[i]; + file_buffer.write[start + i] = strm_out[i]; } else { bh.compressed_size = block_size; //package->store_buffer(strm_in.ptr(), block_size); int start = file_buffer.size(); file_buffer.resize(file_buffer.size() + block_size); for (uint32_t i = 0; i < bh.compressed_size; i++) - file_buffer[start + i] = strm_in[i]; + file_buffer.write[start + i] = strm_in[i]; } meta.hashes.push_back(bh); @@ -560,7 +560,7 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t int start = file_buffer.size(); file_buffer.resize(file_buffer.size() + (strm.total_out - total_out_before)); for (uint32_t i = 0; i < (strm.total_out - total_out_before); i++) - file_buffer[start + i] = strm_out[i]; + file_buffer.write[start + i] = strm_out[i]; deflateEnd(&strm); meta.compressed_size = strm.total_out; @@ -864,7 +864,7 @@ class EditorExportUWP : public EditorExportPlatform { r_ret.resize(result.length()); for (int i = 0; i < result.length(); i++) - r_ret[i] = result.utf8().get(i); + r_ret.write[i] = result.utf8().get(i); return r_ret; } @@ -1371,8 +1371,8 @@ public: CharString txt = cl[i].utf8(); int base = clf.size(); clf.resize(base + 4 + txt.length()); - encode_uint32(txt.length(), &clf[base]); - copymem(&clf[base + 4], txt.ptr(), txt.length()); + encode_uint32(txt.length(), &clf.write[base]); + copymem(&clf.write[base + 4], txt.ptr(), txt.length()); print_line(itos(i) + " param: " + cl[i]); } diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 25326ae794..8549a44ce5 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -77,6 +77,10 @@ Size2 OSUWP::get_window_size() const { return size; } +int OSUWP::get_current_video_driver() const { + return video_driver_index; +} + void OSUWP::set_window_size(const Size2 p_size) { Windows::Foundation::Size new_size; @@ -237,6 +241,8 @@ Error OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_au } gl_context->set_use_vsync(vm.use_vsync); + video_driver_index = p_video_driver; + visual_server = memnew(VisualServerRaster); // FIXME: Reimplement threaded rendering? Or remove? /* diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index 0f7f068652..3b48063fe9 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -99,6 +99,7 @@ private: Windows::UI::Core::CoreWindow ^ window; VideoMode video_mode; + int video_driver_index; MainLoop *main_loop; @@ -154,6 +155,7 @@ private: // functions used by main to initialize/deintialize the OS protected: virtual int get_video_driver_count() const; + virtual int get_current_video_driver() const; virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp index d312fbcb12..a158237418 100644 --- a/platform/windows/context_gl_win.cpp +++ b/platform/windows/context_gl_win.cpp @@ -106,9 +106,9 @@ Error ContextGL_Win::initialize() { PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, - 24, + OS::get_singleton()->is_layered_allowed() ? 32 : 24, 0, 0, 0, 0, 0, 0, // Color Bits Ignored - 0, // No Alpha Buffer + OS::get_singleton()->is_layered_allowed() ? 8 : 0, // Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 05806d2fe8..34fc3e09b5 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -166,12 +166,18 @@ def configure_msvc(env, manual_msvc_config): # Build type if (env["target"] == "release"): - env.Append(CCFLAGS=['/O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CCFLAGS=['/O2']) + else: # optimize for size + env.Append(CCFLAGS=['/O1']) env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup']) elif (env["target"] == "release_debug"): - env.Append(CCFLAGS=['/O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CCFLAGS=['/O2']) + else: # optimize for size + env.Append(CCFLAGS=['/O1']) env.AppendUnique(CPPDEFINES = ['DEBUG_ENABLED']) env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE']) @@ -200,7 +206,8 @@ def configure_msvc(env, manual_msvc_config): env.AppendUnique(CPPDEFINES = ['WINDOWS_ENABLED', 'OPENGL_ENABLED', 'RTAUDIO_ENABLED', 'WASAPI_ENABLED', - 'TYPED_METHOD_BIND', 'WIN32', 'MSVC', + 'WINMIDI_ENABLED', 'TYPED_METHOD_BIND', + 'WIN32', 'MSVC', {'WINVER' : '$target_win_version', '_WIN32_WINNT': '$target_win_version'}]) if env["bits"] == "64": @@ -247,10 +254,14 @@ def configure_mingw(env): if (env["target"] == "release"): env.Append(CCFLAGS=['-msse2']) - if (env["bits"] == "64"): - env.Append(CCFLAGS=['-O3']) - else: - env.Append(CCFLAGS=['-O2']) + if (env["optimize"] == "speed"): #optimize for speed (default) + if (env["bits"] == "64"): + env.Append(CCFLAGS=['-O3']) + else: + env.Append(CCFLAGS=['-O2']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os']) + env.Append(LINKFLAGS=['-Wl,--subsystem,windows']) @@ -265,7 +276,11 @@ def configure_mingw(env): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): env.Prepend(CCFLAGS=['-g2']) - + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Append(CCFLAGS=['-O2']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os']) + elif (env["target"] == "debug"): env.Append(CCFLAGS=['-g3', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index ac37e1246d..bd76db8796 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -1219,6 +1219,10 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int AudioDriverManager::initialize(p_audio_driver); +#ifdef WINMIDI_ENABLED + driver_midi.open(); +#endif + TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; @@ -1347,6 +1351,10 @@ void OS_Windows::set_main_loop(MainLoop *p_main_loop) { void OS_Windows::finalize() { +#ifdef WINMIDI_ENABLED + driver_midi.close(); +#endif + if (main_loop) memdelete(main_loop); @@ -2291,7 +2299,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, Vector<CharType> modstr; //windows wants to change this no idea why modstr.resize(cmdline.size()); for (int i = 0; i < cmdline.size(); i++) - modstr[i] = cmdline[i]; + modstr.write[i] = cmdline[i]; int ret = CreateProcessW(NULL, modstr.ptrw(), NULL, NULL, 0, NORMAL_PRIORITY_CLASS, NULL, NULL, si_w, &pi.pi); ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK); @@ -2362,7 +2370,7 @@ void OS_Windows::set_icon(const Ref<Image> &p_icon) { int icon_len = 40 + h * w * 4; Vector<BYTE> v; v.resize(icon_len); - BYTE *icon_bmp = &v[0]; + BYTE *icon_bmp = v.ptrw(); encode_uint32(40, &icon_bmp[0]); encode_uint32(w, &icon_bmp[4]); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index b99d3e3422..69c7d851b8 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -35,6 +35,7 @@ #include "crash_handler_win.h" #include "drivers/rtaudio/audio_driver_rtaudio.h" #include "drivers/wasapi/audio_driver_wasapi.h" +#include "drivers/winmidi/win_midi.h" #include "os/input.h" #include "os/os.h" #include "power_windows.h" @@ -144,6 +145,9 @@ class OS_Windows : public OS { #ifdef XAUDIO2_ENABLED AudioDriverXAudio2 driver_xaudio2; #endif +#ifdef WINMIDI_ENABLED + MIDIDriverWinMidi driver_midi; +#endif CrashHandler crash_handler; diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 09e16ad078..6a7a426804 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -62,6 +62,7 @@ def get_opts(): EnumVariable('debug_symbols', 'Add debugging symbols to release builds', 'yes', ('yes', 'no', 'full')), BoolVariable('separate_debug_symbols', 'Create a separate file containing debugging symbols', False), BoolVariable('touch', 'Enable touch events', True), + BoolVariable('execinfo', 'Use libexecinfo on systems where glibc is not available', False), ] @@ -81,14 +82,22 @@ def configure(env): if (env["target"] == "release"): # -O3 -ffast-math is identical to -Ofast. We need to split it out so we can selectively disable # -ffast-math in code for which it generates wrong results. - env.Prepend(CCFLAGS=['-O3', '-ffast-math']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O3', '-ffast-math']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os']) + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): env.Prepend(CCFLAGS=['-g2']) elif (env["target"] == "release_debug"): - env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + if (env["optimize"] == "speed"): #optimize for speed (default) + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + else: #optimize for size + env.Prepend(CCFLAGS=['-Os', '-DDEBUG_ENABLED']) + if (env["debug_symbols"] == "yes"): env.Prepend(CCFLAGS=['-g1']) if (env["debug_symbols"] == "full"): @@ -240,7 +249,7 @@ def configure(env): if (os.system("pkg-config --exists alsa") == 0): # 0 means found print("Enabling ALSA") - env.Append(CPPFLAGS=["-DALSA_ENABLED"]) + env.Append(CPPFLAGS=["-DALSA_ENABLED", "-DALSAMIDI_ENABLED"]) env.ParseConfig('pkg-config alsa --cflags --libs') else: print("ALSA libraries not found, disabling driver") @@ -276,6 +285,9 @@ def configure(env): env.Append(LIBS=['dl']) if (platform.system().find("BSD") >= 0): + env["execinfo"] = True + + if env["execinfo"]: env.Append(LIBS=['execinfo']) ## Cross-compilation diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index af0e02173f..9d1e3291b7 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -342,6 +342,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a AudioDriverManager::initialize(p_audio_driver); +#ifdef ALSAMIDI_ENABLED + driver_alsamidi.open(); +#endif + ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE); @@ -606,6 +610,9 @@ void OS_X11::finalize() { memdelete(debugger_connection_console); } */ +#ifdef ALSAMIDI_ENABLED + driver_alsamidi.close(); +#endif #ifdef JOYDEV_ENABLED memdelete(joypad); @@ -1831,8 +1838,8 @@ void OS_X11::process_xevents() { GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime); } #ifdef TOUCH_ENABLED - // Grab touch devices to avoid OS gesture interference - /*for (int i = 0; i < touch.devices.size(); ++i) { + // Grab touch devices to avoid OS gesture interference + /*for (int i = 0; i < touch.devices.size(); ++i) { XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask); }*/ #endif @@ -2098,7 +2105,7 @@ void OS_X11::process_xevents() { Vector<String> files = String((char *)p.data).split("\n", false); for (int i = 0; i < files.size(); i++) { - files[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes(); + files.write[i] = files[i].replace("file://", "").replace("%20", " ").strip_escapes(); } main_loop->drop_files(files); @@ -2580,12 +2587,12 @@ void OS_X11::set_icon(const Ref<Image> &p_icon) { pd.resize(2 + w * h); - pd[0] = w; - pd[1] = h; + pd.write[0] = w; + pd.write[1] = h; PoolVector<uint8_t>::Read r = img->get_data().read(); - long *wr = &pd[2]; + long *wr = &pd.write[2]; uint8_t const *pr = r.ptr(); for (int i = 0; i < w * h; i++) { diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 4045a6e7ad..44455a2d8d 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -38,6 +38,7 @@ #include "servers/visual_server.h" //#include "servers/visual/visual_server_wrap_mt.h" #include "drivers/alsa/audio_driver_alsa.h" +#include "drivers/alsamidi/alsa_midi.h" #include "drivers/pulseaudio/audio_driver_pulseaudio.h" #include "joypad_linux.h" #include "main/input_default.h" @@ -168,6 +169,10 @@ class OS_X11 : public OS_Unix { AudioDriverALSA driver_alsa; #endif +#ifdef ALSAMIDI_ENABLED + MIDIDriverALSAMidi driver_alsamidi; +#endif + #ifdef PULSEAUDIO_ENABLED AudioDriverPulseAudio driver_pulseaudio; #endif @@ -196,6 +201,8 @@ class OS_X11 : public OS_Unix { Bool xrandr_ext_ok; protected: + virtual int get_current_video_driver() const; + virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); @@ -207,8 +214,6 @@ protected: bool is_window_maximize_allowed(); public: - virtual int get_current_video_driver() const; - virtual String get_name(); virtual void set_cursor_shape(CursorShape p_shape); diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index b56eedabc7..85e7f8df92 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -235,7 +235,7 @@ void SpriteFrames::_set_frames(const Array &p_frames) { E->get().frames.resize(p_frames.size()); for (int i = 0; i < E->get().frames.size(); i++) - E->get().frames[i] = p_frames[i]; + E->get().frames.write[i] = p_frames[i]; } Array SpriteFrames::_get_frames() const { diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index f6586aff36..cc49465403 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -113,7 +113,7 @@ public: ERR_FAIL_COND(p_idx < 0); if (p_idx >= E->get().frames.size()) return; - E->get().frames[p_idx] = p_frame; + E->get().frames.write[p_idx] = p_frame; } void remove_frame(const StringName &p_anim, int p_idx); void clear(const StringName &p_anim); diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 47326b9be2..a035d9021f 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -411,6 +411,9 @@ void CanvasItem::_enter_canvas() { if (canvas_layer) { break; } + if (Object::cast_to<Viewport>(n)) { + break; + } n = n->get_parent(); } diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index cabd7fddc2..1e2184bd41 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -259,7 +259,7 @@ void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { for (int i = 0; i < E->get().shapes.size(); i++) { if (E->get().shapes[i].index > index_to_remove) { - E->get().shapes[i].index -= 1; + E->get().shapes.write[i].index -= 1; } } } diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 9d2a83fda7..9f19f56e75 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -102,11 +102,11 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() { TriangulatorPoly &tp = I->get(); - decomp[idx].resize(tp.GetNumPoints()); + decomp.write[idx].resize(tp.GetNumPoints()); for (int i = 0; i < tp.GetNumPoints(); i++) { - decomp[idx][i] = tp.GetPoint(i); + decomp.write[idx].write[i] = tp.GetPoint(i); } idx++; diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index e9e895b5bb..ad9775c0b7 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -239,7 +239,7 @@ void Line2D::_draw() { { PoolVector<Vector2>::Read points_read = _points.read(); for (int i = 0; i < len; ++i) { - points[i] = points_read[i]; + points.write[i] = points_read[i]; } } diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index 74ad3e79d0..a3f1b25e05 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -292,7 +292,6 @@ void LineBuilder::build() { color1 = gradient->get_color_at_offset(current_distance1 / total_distance); } if (texture_mode == Line2D::LINE_TEXTURE_TILE) { - uvx0 = current_distance0 / (width * tile_aspect); uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { uvx0 = current_distance0 / total_distance; @@ -306,7 +305,6 @@ void LineBuilder::build() { u0 = u1; f0 = f1; pos0 = pos1; - current_distance0 = current_distance1; if (intersection_result == SEGMENT_INTERSECT) { if (current_joint_mode == Line2D::LINE_JOINT_SHARP) { pos_up0 = pos_up1; diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp index 16e0386952..e3b048fd74 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation2d.cpp @@ -74,7 +74,7 @@ void Navigation2D::_navpoly_link(int p_id) { Vector2 ep = nm.xform.xform(r[idx]); center += ep; e.point = _get_point(ep); - p.edges[j] = e; + p.edges.write[j] = e; int idxn = indices[(j + 1) % plen]; if (idxn < 0 || idxn >= len) { @@ -119,17 +119,17 @@ void Navigation2D::_navpoly_link(int p_id) { ConnectionPending pending; pending.polygon = &p; pending.edge = j; - p.edges[j].P = C->get().pending.push_back(pending); + p.edges.write[j].P = C->get().pending.push_back(pending); continue; //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); } C->get().B = &p; C->get().B_edge = j; - C->get().A->edges[C->get().A_edge].C = &p; - C->get().A->edges[C->get().A_edge].C_edge = j; - p.edges[j].C = C->get().A; - p.edges[j].C_edge = C->get().A_edge; + C->get().A->edges.write[C->get().A_edge].C = &p; + C->get().A->edges.write[C->get().A_edge].C_edge = j; + p.edges.write[j].C = C->get().A; + p.edges.write[j].C_edge = C->get().A_edge; //connection successful. } } @@ -167,10 +167,10 @@ void Navigation2D::_navpoly_unlink(int p_id) { } else if (C->get().B) { //disconnect - C->get().B->edges[C->get().B_edge].C = NULL; - C->get().B->edges[C->get().B_edge].C_edge = -1; - C->get().A->edges[C->get().A_edge].C = NULL; - C->get().A->edges[C->get().A_edge].C_edge = -1; + C->get().B->edges.write[C->get().B_edge].C = NULL; + C->get().B->edges.write[C->get().B_edge].C_edge = -1; + C->get().A->edges.write[C->get().A_edge].C = NULL; + C->get().A->edges.write[C->get().A_edge].C_edge = -1; if (C->get().A == &E->get()) { @@ -187,11 +187,11 @@ void Navigation2D::_navpoly_unlink(int p_id) { C->get().B = cp.polygon; C->get().B_edge = cp.edge; - C->get().A->edges[C->get().A_edge].C = cp.polygon; - C->get().A->edges[C->get().A_edge].C_edge = cp.edge; - cp.polygon->edges[cp.edge].C = C->get().A; - cp.polygon->edges[cp.edge].C_edge = C->get().A_edge; - cp.polygon->edges[cp.edge].P = NULL; + C->get().A->edges.write[C->get().A_edge].C = cp.polygon; + C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; + cp.polygon->edges.write[cp.edge].C = C->get().A; + cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; + cp.polygon->edges.write[cp.edge].P = NULL; } } else { @@ -339,8 +339,8 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect Vector<Vector2> path; path.resize(2); - path[0] = begin_point; - path[1] = end_point; + path.write[0] = begin_point; + path.write[1] = end_point; //print_line("Direct Path"); return path; } @@ -408,7 +408,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect for (int i = 0; i < es; i++) { - Polygon::Edge &e = p->edges[i]; + Polygon::Edge &e = p->edges.write[i]; if (!e.C) continue; @@ -586,7 +586,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect if (!path.size() || path[path.size() - 1].distance_squared_to(begin_point) > CMP_EPSILON) { path.push_back(begin_point); // Add the begin point } else { - path[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point + path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point } path.invert(); @@ -594,7 +594,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect if (path.size() <= 1 || path[path.size() - 1].distance_squared_to(end_point) > CMP_EPSILON) { path.push_back(end_point); // Add the end point } else { - path[path.size() - 1] = end_point; // Replace last midpoint by the exact end point + path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point } return path; diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 6e27bf1c1d..2d6679272a 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -91,7 +91,7 @@ void NavigationPolygon::_set_polygons(const Array &p_array) { polygons.resize(p_array.size()); for (int i = 0; i < p_array.size(); i++) { - polygons[i].indices = p_array[i]; + polygons.write[i].indices = p_array[i]; } } @@ -110,7 +110,7 @@ void NavigationPolygon::_set_outlines(const Array &p_array) { outlines.resize(p_array.size()); for (int i = 0; i < p_array.size(); i++) { - outlines[i] = p_array[i]; + outlines.write[i] = p_array[i]; } rect_cache_dirty = true; } @@ -166,7 +166,7 @@ int NavigationPolygon::get_outline_count() const { void NavigationPolygon::set_outline(int p_idx, const PoolVector<Vector2> &p_outline) { ERR_FAIL_INDEX(p_idx, outlines.size()); - outlines[p_idx] = p_outline; + outlines.write[p_idx] = p_outline; rect_cache_dirty = true; } @@ -432,8 +432,8 @@ void NavigationPolygonInstance::_notification(int p_what) { { PoolVector<Vector2>::Read vr = verts.read(); for (int i = 0; i < vsize; i++) { - vertices[i] = vr[i]; - colors[i] = color; + vertices.write[i] = vr[i]; + colors.write[i] = color; } } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 8787a2c735..9879f43877 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -30,6 +30,7 @@ #include "physics_body_2d.h" +#include "core/core_string_names.h" #include "core/method_bind_ext.gen.inc" #include "engine.h" #include "math_funcs.h" @@ -186,28 +187,75 @@ real_t StaticBody2D::get_constant_angular_velocity() const { return constant_angular_velocity; } +#ifndef DISABLE_DEPRECATED void StaticBody2D::set_friction(real_t p_friction) { + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + ERR_FAIL_COND(p_friction < 0 || p_friction > 1); - friction = p_friction; - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, friction); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_friction(p_friction); + _reload_physics_characteristics(); } + real_t StaticBody2D::get_friction() const { - return friction; + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 1; + } + + return physics_material_override->get_friction(); } void StaticBody2D::set_bounce(real_t p_bounce) { + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); - bounce = p_bounce; - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, bounce); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_bounce(p_bounce); + _reload_physics_characteristics(); } + real_t StaticBody2D::get_bounce() const { - return bounce; + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 0; + } + + return physics_material_override->get_bounce(); +} +#endif + +void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const { + return physics_material_override; } void StaticBody2D::_bind_methods() { @@ -222,23 +270,41 @@ void StaticBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody2D::set_bounce); ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody2D::get_bounce); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody2D::_reload_physics_characteristics); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); } StaticBody2D::StaticBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) { constant_angular_velocity = 0; - bounce = 0; - friction = 1; } StaticBody2D::~StaticBody2D() { } +void StaticBody2D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT); + } else { + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode()); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode()); + } +} + void RigidBody2D::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); @@ -545,28 +611,72 @@ real_t RigidBody2D::get_weight() const { return mass * real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10; } +#ifndef DISABLE_DEPRECATED void RigidBody2D::set_friction(real_t p_friction) { + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED ERR_FAIL_COND(p_friction < 0 || p_friction > 1); - friction = p_friction; - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, friction); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_friction(p_friction); + _reload_physics_characteristics(); } real_t RigidBody2D::get_friction() const { - return friction; + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 1; + } + + return physics_material_override->get_friction(); } void RigidBody2D::set_bounce(real_t p_bounce) { + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); - bounce = p_bounce; - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, bounce); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_bounce(p_bounce); + _reload_physics_characteristics(); } real_t RigidBody2D::get_bounce() const { - return bounce; + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 0; + } + + return physics_material_override->get_bounce(); +} +#endif + +void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const { + return physics_material_override; } void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) { @@ -690,11 +800,19 @@ int RigidBody2D::get_max_contacts_reported() const { return max_contacts_reported; } +void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) { + Physics2DServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); +} + void RigidBody2D::apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) { Physics2DServer::get_singleton()->body_apply_impulse(get_rid(), p_offset, p_impulse); } +void RigidBody2D::apply_torque_impulse(float p_torque) { + Physics2DServer::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque); +} + void RigidBody2D::set_applied_force(const Vector2 &p_force) { Physics2DServer::get_singleton()->body_set_applied_force(get_rid(), p_force); @@ -715,11 +833,19 @@ float RigidBody2D::get_applied_torque() const { return Physics2DServer::get_singleton()->body_get_applied_torque(get_rid()); }; +void RigidBody2D::add_central_force(const Vector2 &p_force) { + Physics2DServer::get_singleton()->body_add_central_force(get_rid(), p_force); +} + void RigidBody2D::add_force(const Vector2 &p_offset, const Vector2 &p_force) { Physics2DServer::get_singleton()->body_add_force(get_rid(), p_offset, p_force); } +void RigidBody2D::add_torque(const float p_torque) { + Physics2DServer::get_singleton()->body_add_torque(get_rid(), p_torque); +} + void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) { ccd_mode = p_mode; @@ -843,6 +969,11 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody2D::set_bounce); ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody2D::get_bounce); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody2D::_reload_physics_characteristics); + ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale); ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale); @@ -871,7 +1002,9 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidBody2D::get_continuous_collision_detection_mode); ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody2D::set_axis_velocity); + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody2D::apply_central_impulse); ClassDB::bind_method(D_METHOD("apply_impulse", "offset", "impulse"), &RigidBody2D::apply_impulse); + ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidBody2D::apply_torque_impulse); ClassDB::bind_method(D_METHOD("set_applied_force", "force"), &RigidBody2D::set_applied_force); ClassDB::bind_method(D_METHOD("get_applied_force"), &RigidBody2D::get_applied_force); @@ -879,7 +1012,9 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_applied_torque", "torque"), &RigidBody2D::set_applied_torque); ClassDB::bind_method(D_METHOD("get_applied_torque"), &RigidBody2D::get_applied_torque); + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody2D::add_central_force); ClassDB::bind_method(D_METHOD("add_force", "offset", "force"), &RigidBody2D::add_force); + ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody2D::add_torque); ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody2D::set_sleeping); ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody2D::is_sleeping); @@ -903,6 +1038,7 @@ void RigidBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode"); @@ -941,9 +1077,7 @@ RigidBody2D::RigidBody2D() : mode = MODE_RIGID; - bounce = 0; mass = 1; - friction = 1; gravity_scale = 1; linear_damp = -1; @@ -969,6 +1103,20 @@ RigidBody2D::~RigidBody2D() { memdelete(contact_monitor); } +void RigidBody2D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT); + } else { + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode()); + Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode()); + } +} + ////////////////////////// Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) { @@ -1225,11 +1373,11 @@ Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) { } if (slide_colliders[p_bounce].is_null()) { - slide_colliders[p_bounce].instance(); - slide_colliders[p_bounce]->owner = this; + slide_colliders.write[p_bounce].instance(); + slide_colliders.write[p_bounce]->owner = this; } - slide_colliders[p_bounce]->collision = colliders[p_bounce]; + slide_colliders.write[p_bounce]->collision = colliders[p_bounce]; return slide_colliders[p_bounce]; } @@ -1327,7 +1475,7 @@ KinematicBody2D::~KinematicBody2D() { for (int i = 0; i < slide_colliders.size(); i++) { if (slide_colliders[i].is_valid()) { - slide_colliders[i]->owner = NULL; + slide_colliders.write[i]->owner = NULL; } } } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 7bda6ce817..0a2ce0918b 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -32,6 +32,7 @@ #define PHYSICS_BODY_2D_H #include "scene/2d/collision_object_2d.h" +#include "scene/resources/physics_material.h" #include "servers/physics_2d_server.h" #include "vset.h" @@ -79,18 +80,21 @@ class StaticBody2D : public PhysicsBody2D { Vector2 constant_linear_velocity; real_t constant_angular_velocity; - real_t bounce; - real_t friction; + Ref<PhysicsMaterial> physics_material_override; protected: static void _bind_methods(); public: +#ifndef DISABLE_DEPRECATED void set_friction(real_t p_friction); real_t get_friction() const; void set_bounce(real_t p_bounce); real_t get_bounce() const; +#endif + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; void set_constant_linear_velocity(const Vector2 &p_vel); void set_constant_angular_velocity(real_t p_vel); @@ -100,6 +104,9 @@ public: StaticBody2D(); ~StaticBody2D(); + +private: + void _reload_physics_characteristics(); }; class RigidBody2D : public PhysicsBody2D { @@ -125,9 +132,8 @@ private: Physics2DDirectBodyState *state; Mode mode; - real_t bounce; real_t mass; - real_t friction; + Ref<PhysicsMaterial> physics_material_override; real_t gravity_scale; real_t linear_damp; real_t angular_damp; @@ -204,11 +210,16 @@ public: void set_weight(real_t p_weight); real_t get_weight() const; +#ifndef DISABLE_DEPRECATED void set_friction(real_t p_friction); real_t get_friction() const; void set_bounce(real_t p_bounce); real_t get_bounce() const; +#endif + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; void set_gravity_scale(real_t p_gravity_scale); real_t get_gravity_scale() const; @@ -245,7 +256,9 @@ public: void set_continuous_collision_detection_mode(CCDMode p_mode); CCDMode get_continuous_collision_detection_mode() const; + void apply_central_impulse(const Vector2 &p_impulse); void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse); + void apply_torque_impulse(float p_torque); void set_applied_force(const Vector2 &p_force); Vector2 get_applied_force() const; @@ -253,7 +266,9 @@ public: void set_applied_torque(const float p_torque); float get_applied_torque() const; + void add_central_force(const Vector2 &p_force); void add_force(const Vector2 &p_offset, const Vector2 &p_force); + void add_torque(float p_torque); Array get_colliding_bodies() const; //function for script @@ -261,6 +276,9 @@ public: RigidBody2D(); ~RigidBody2D(); + +private: + void _reload_physics_characteristics(); }; VARIANT_ENUM_CAST(RigidBody2D::Mode); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 81ed3c63c3..c9e5408f06 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -113,7 +113,7 @@ void Polygon2D::_notification(int p_what) { PoolVector<Vector2>::Read polyr = polygon.read(); for (int i = 0; i < len; i++) { - points[i] = polyr[i] + offset; + points.write[i] = polyr[i] + offset; } } @@ -153,18 +153,18 @@ void Polygon2D::_notification(int p_what) { SWAP(ep[1], ep[4]); SWAP(ep[2], ep[3]); SWAP(ep[5], ep[0]); - SWAP(ep[6], points[highest_idx]); + SWAP(ep[6], points.write[highest_idx]); } points.resize(points.size() + 7); for (int i = points.size() - 1; i >= highest_idx + 7; i--) { - points[i] = points[i - 7]; + points.write[i] = points[i - 7]; } for (int i = 0; i < 7; i++) { - points[highest_idx + i + 1] = ep[i]; + points.write[highest_idx + i + 1] = ep[i]; } len = points.size(); @@ -182,12 +182,12 @@ void Polygon2D::_notification(int p_what) { PoolVector<Vector2>::Read uvr = uv.read(); for (int i = 0; i < len; i++) { - uvs[i] = texmat.xform(uvr[i]) / tex_size; + uvs.write[i] = texmat.xform(uvr[i]) / tex_size; } } else { for (int i = 0; i < len; i++) { - uvs[i] = texmat.xform(points[i]) / tex_size; + uvs.write[i] = texmat.xform(points[i]) / tex_size; } } } @@ -262,10 +262,10 @@ void Polygon2D::_notification(int p_what) { { PoolVector<Color>::Read color_r = vertex_colors.read(); for (int i = 0; i < color_len && i < len; i++) { - colors[i] = color_r[i]; + colors.write[i] = color_r[i]; } for (int i = color_len; i < len; i++) { - colors[i] = color; + colors.write[i] = color; } } @@ -333,13 +333,13 @@ void Polygon2D::_notification(int p_what) { Vector<Vector2> vertices; vertices.resize(loop.size()); for (int j = 0; j < vertices.size(); j++) { - vertices[j] = points[loop[j]]; + vertices.write[j] = points[loop[j]]; } Vector<int> sub_indices = Geometry::triangulate_polygon(vertices); int from = indices.size(); indices.resize(from + sub_indices.size()); for (int j = 0; j < sub_indices.size(); j++) { - indices[from + j] = loop[sub_indices[j]]; + indices.write[from + j] = loop[sub_indices[j]]; } } @@ -538,12 +538,12 @@ void Polygon2D::clear_bones() { void Polygon2D::set_bone_weights(int p_index, const PoolVector<float> &p_weights) { ERR_FAIL_INDEX(p_index, bone_weights.size()); - bone_weights[p_index].weights = p_weights; + bone_weights.write[p_index].weights = p_weights; update(); } void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) { ERR_FAIL_INDEX(p_index, bone_weights.size()); - bone_weights[p_index].path = p_path; + bone_weights.write[p_index].path = p_path; update(); } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 8ceffb3c27..e6e9bde20a 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -191,13 +191,13 @@ void Skeleton2D::_update_bone_setup() { bones.sort(); //sorty so they are always in the same order/index for (int i = 0; i < bones.size(); i++) { - bones[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose - bones[i].bone->skeleton_index = i; + bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose + bones.write[i].bone->skeleton_index = i; Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent()); if (parent_bone) { - bones[i].parent_index = parent_bone->skeleton_index; + bones.write[i].parent_index = parent_bone->skeleton_index; } else { - bones[i].parent_index = -1; + bones.write[i].parent_index = -1; } } @@ -230,9 +230,9 @@ void Skeleton2D::_update_transform() { ERR_CONTINUE(bones[i].parent_index >= i); if (bones[i].parent_index >= 0) { - bones[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform(); + bones.write[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform(); } else { - bones[i].accum_transform = bones[i].bone->get_transform(); + bones.write[i].accum_transform = bones[i].bone->get_transform(); } } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 9a343ca0f0..78637cc097 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -62,7 +62,7 @@ void TileMap::_notification(int p_what) { pending_update = true; _recreate_quadrants(); - _update_dirty_quadrants(); + update_dirty_quadrants(); RID space = get_world_2d()->get_space(); _update_quadrant_transform(); _update_quadrant_space(space); @@ -245,7 +245,7 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const xform.elements[2].y += offset.y; } -void TileMap::_update_dirty_quadrants() { +void TileMap::update_dirty_quadrants() { if (!pending_update) return; @@ -529,8 +529,8 @@ void TileMap::_update_dirty_quadrants() { { PoolVector<Vector2>::Read vr = navigation_polygon_vertices.read(); for (int i = 0; i < vsize; i++) { - vertices[i] = vr[i]; - colors[i] = debug_navigation_color; + vertices.write[i] = vr[i]; + colors.write[i] = debug_navigation_color; } } @@ -721,7 +721,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool updat return; if (update) { - _update_dirty_quadrants(); + call_deferred("update_dirty_quadrants"); } } @@ -1026,7 +1026,7 @@ void TileMap::_recreate_quadrants() { Q->get().cells.insert(E->key()); _make_quadrant_dirty(Q, false); } - _update_dirty_quadrants(); + update_dirty_quadrants(); } void TileMap::_clear_quadrants() { @@ -1611,7 +1611,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose", "autotile_coord"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("set_cellv", "position", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("set_celld", "data"), &TileMap::set_celld); + ClassDB::bind_method(D_METHOD("set_celld", "position", "data"), &TileMap::set_celld); ClassDB::bind_method(D_METHOD("get_cell", "x", "y"), &TileMap::get_cell); ClassDB::bind_method(D_METHOD("get_cellv", "position"), &TileMap::get_cellv); ClassDB::bind_method(D_METHOD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped); @@ -1630,7 +1630,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_clear_quadrants"), &TileMap::_clear_quadrants); ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants); - ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants); + ClassDB::bind_method(D_METHOD("update_dirty_quadrants"), &TileMap::update_dirty_quadrants); ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area); ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2())); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 79d79ca59f..c8aceac17d 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -191,7 +191,6 @@ private: void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update = true); void _recreate_quadrants(); void _clear_quadrants(); - void _update_dirty_quadrants(); void _update_quadrant_space(const RID &p_space); void _update_quadrant_transform(); void _recompute_rect_cache(); @@ -251,6 +250,8 @@ public: void update_cell_bitmask(int p_x, int p_y); void update_dirty_bitmask(); + void update_dirty_quadrants(); + void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 1d5d1b2afe..e19e45b263 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -305,7 +305,7 @@ void CollisionObject::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { for (int i = 0; i < E->get().shapes.size(); i++) { if (E->get().shapes[i].index > index_to_remove) { - E->get().shapes[i].index -= 1; + E->get().shapes.write[i].index -= 1; } } } diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index f31d65e411..f8ef04b78f 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -39,6 +39,7 @@ class CollisionObject : public Spatial { GDCLASS(CollisionObject, Spatial); bool area; + RID rid; struct ShapeData { diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h index c9c91a5824..6ca8e80ea1 100644 --- a/scene/3d/collision_shape.h +++ b/scene/3d/collision_shape.h @@ -49,6 +49,7 @@ class CollisionShape : public Spatial { void resource_changed(RES res); bool disabled; +protected: void _create_debug_shape(); void _update_in_shape_owner(bool p_xform_only = false); diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 2e897c1c73..c3b0196316 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -25,6 +25,8 @@ void CPUParticles::set_emitting(bool p_emitting) { update_mutex->lock(); #endif VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE, true); + #ifndef NO_THREADS update_mutex->unlock(); #endif @@ -446,6 +448,8 @@ float rand_from_seed_m1_p1(uint32_t &seed) { void CPUParticles::_particles_process(float p_delta) { + p_delta *= speed_scale; + int pcount = particles.size(); PoolVector<Particle>::Write w = particles.write(); @@ -475,7 +479,7 @@ void CPUParticles::_particles_process(float p_delta) { if (!emitting && !p.active) continue; - float restart_time = float(i) / float(pcount); + float restart_time = (float(i) / float(pcount)) * lifetime; float local_delta = p_delta; if (randomness_ratio > 0.0) { @@ -643,7 +647,7 @@ void CPUParticles::_particles_process(float p_delta) { uint32_t alt_seed = p.seed; p.time += local_delta; - p.custom[1] += p.time / lifetime; + p.custom[1] = p.time / lifetime; float tex_linear_velocity = 0.0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { @@ -979,6 +983,7 @@ void CPUParticles::_notification(int p_what) { update_mutex->lock(); #endif VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE, true); #ifndef NO_THREADS update_mutex->unlock(); #endif @@ -992,6 +997,7 @@ void CPUParticles::_notification(int p_what) { update_mutex->lock(); #endif VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE, false); #ifndef NO_THREADS update_mutex->unlock(); #endif @@ -1018,6 +1024,8 @@ void CPUParticles::_notification(int p_what) { update_mutex->lock(); #endif VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE, false); + #ifndef NO_THREADS update_mutex->unlock(); #endif diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index e836a6154a..e277cae5b7 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -36,6 +36,7 @@ #include "scene/resources/material.h" #include "scene/scene_string_names.h" #include "skeleton.h" + bool MeshInstance::_set(const StringName &p_name, const Variant &p_value) { //this is not _too_ bad performance wise, really. it only arrives here if the property was not set anywhere else. @@ -256,7 +257,7 @@ void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_ma ERR_FAIL_INDEX(p_surface, materials.size()); - materials[p_surface] = p_material; + materials.write[p_surface] = p_material; if (materials[p_surface].is_valid()) VS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid()); diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index 5d359cd4d5..0dfec538f9 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -41,6 +41,7 @@ class MeshInstance : public GeometryInstance { GDCLASS(MeshInstance, GeometryInstance); +protected: Ref<Mesh> mesh; NodePath skeleton_path; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 77bf703706..f5b77d361c 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -73,7 +73,7 @@ void Navigation::_navmesh_link(int p_id) { Vector3 ep = nm.xform.xform(r[idx]); center += ep; e.point = _get_point(ep); - p.edges[j] = e; + p.edges.write[j] = e; if (j >= 2) { Vector3 epa = nm.xform.xform(r[indices[j - 2]]); @@ -118,7 +118,7 @@ void Navigation::_navmesh_link(int p_id) { ConnectionPending pending; pending.polygon = &p; pending.edge = j; - p.edges[j].P = C->get().pending.push_back(pending); + p.edges.write[j].P = C->get().pending.push_back(pending); continue; //print_line(String()+_get_vertex(ek.a)+" -> "+_get_vertex(ek.b)); } @@ -126,10 +126,10 @@ void Navigation::_navmesh_link(int p_id) { C->get().B = &p; C->get().B_edge = j; - C->get().A->edges[C->get().A_edge].C = &p; - C->get().A->edges[C->get().A_edge].C_edge = j; - p.edges[j].C = C->get().A; - p.edges[j].C_edge = C->get().A_edge; + C->get().A->edges.write[C->get().A_edge].C = &p; + C->get().A->edges.write[C->get().A_edge].C_edge = j; + p.edges.write[j].C = C->get().A; + p.edges.write[j].C_edge = C->get().A_edge; //connection successful. } } @@ -165,10 +165,10 @@ void Navigation::_navmesh_unlink(int p_id) { } else if (C->get().B) { //disconnect - C->get().B->edges[C->get().B_edge].C = NULL; - C->get().B->edges[C->get().B_edge].C_edge = -1; - C->get().A->edges[C->get().A_edge].C = NULL; - C->get().A->edges[C->get().A_edge].C_edge = -1; + C->get().B->edges.write[C->get().B_edge].C = NULL; + C->get().B->edges.write[C->get().B_edge].C_edge = -1; + C->get().A->edges.write[C->get().A_edge].C = NULL; + C->get().A->edges.write[C->get().A_edge].C_edge = -1; if (C->get().A == &E->get()) { @@ -185,11 +185,11 @@ void Navigation::_navmesh_unlink(int p_id) { C->get().B = cp.polygon; C->get().B_edge = cp.edge; - C->get().A->edges[C->get().A_edge].C = cp.polygon; - C->get().A->edges[C->get().A_edge].C_edge = cp.edge; - cp.polygon->edges[cp.edge].C = C->get().A; - cp.polygon->edges[cp.edge].C_edge = C->get().A_edge; - cp.polygon->edges[cp.edge].P = NULL; + C->get().A->edges.write[C->get().A_edge].C = cp.polygon; + C->get().A->edges.write[C->get().A_edge].C_edge = cp.edge; + cp.polygon->edges.write[cp.edge].C = C->get().A; + cp.polygon->edges.write[cp.edge].C_edge = C->get().A_edge; + cp.polygon->edges.write[cp.edge].P = NULL; } } else { @@ -320,8 +320,8 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector Vector<Vector3> path; path.resize(2); - path[0] = begin_point; - path[1] = end_point; + path.write[0] = begin_point; + path.write[1] = end_point; //print_line("Direct Path"); return path; } @@ -375,7 +375,7 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3 &p_start, const Vector for (int i = 0; i < p->edges.size(); i++) { - Polygon::Edge &e = p->edges[i]; + Polygon::Edge &e = p->edges.write[i]; if (!e.C) continue; diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 073e56fdb4..99680b7273 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -55,9 +55,9 @@ void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { for (int j = 0; j < rlen; j += 3) { Vector<int> vi; vi.resize(3); - vi[0] = r[j + 0] + from; - vi[1] = r[j + 1] + from; - vi[2] = r[j + 2] + from; + vi.write[0] = r[j + 0] + from; + vi.write[1] = r[j + 1] + from; + vi.write[2] = r[j + 2] + from; add_polygon(vi); } @@ -215,7 +215,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) { polygons.resize(p_array.size()); for (int i = 0; i < p_array.size(); i++) { - polygons[i].indices = p_array[i]; + polygons.write[i].indices = p_array[i]; } } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 2b3a62fcdc..4900692155 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -185,7 +185,7 @@ void Particles::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) { ERR_FAIL_INDEX(p_pass, draw_passes.size()); - draw_passes[p_pass] = p_mesh; + draw_passes.write[p_pass] = p_mesh; RID mesh_rid; if (p_mesh.is_valid()) diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index e851c8d643..9a78fcfa35 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -30,6 +30,7 @@ #include "physics_body.h" +#include "core/core_string_names.h" #include "engine.h" #include "method_bind_ext.gen.inc" #include "scene/scene_string_names.h" @@ -121,23 +122,23 @@ bool PhysicsBody::get_collision_layer_bit(int p_bit) const { void PhysicsBody::add_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); - PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node); - if (!physics_body) { - ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type"); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); } - ERR_FAIL_COND(!physics_body); - PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid()); + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->body_add_collision_exception(get_rid(), collision_object->get_rid()); } void PhysicsBody::remove_collision_exception_with(Node *p_node) { ERR_FAIL_NULL(p_node); - PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(p_node); - if (!physics_body) { - ERR_EXPLAIN("Collision exception only works between two objects of PhysicsBody type"); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); } - ERR_FAIL_COND(!physics_body); - PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid()); + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } void PhysicsBody::_set_layers(uint32_t p_mask) { @@ -178,28 +179,75 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : collision_mask = 1; } +#ifndef DISABLE_DEPRECATED void StaticBody::set_friction(real_t p_friction) { + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + ERR_FAIL_COND(p_friction < 0 || p_friction > 1); - friction = p_friction; - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_friction(p_friction); + _reload_physics_characteristics(); } + real_t StaticBody::get_friction() const { - return friction; + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 1; + } + + return physics_material_override->get_friction(); } void StaticBody::set_bounce(real_t p_bounce) { + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); - bounce = p_bounce; - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_bounce(p_bounce); + _reload_physics_characteristics(); } + real_t StaticBody::get_bounce() const { - return bounce; + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + + if (physics_material_override.is_null()) { + return 0; + } + + return physics_material_override->get_bounce(); +} +#endif + +void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> StaticBody::get_physics_material_override() const { + return physics_material_override; } void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) { @@ -236,24 +284,39 @@ void StaticBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce); ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics); + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with); ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); - + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); } StaticBody::StaticBody() : PhysicsBody(PhysicsServer::BODY_MODE_STATIC) { - - bounce = 0; - friction = 1; } -StaticBody::~StaticBody() { +StaticBody::~StaticBody() {} + +void StaticBody::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT); + } else { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode()); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode()); + } } void RigidBody::_body_enter_tree(ObjectID p_id) { @@ -550,28 +613,67 @@ real_t RigidBody::get_weight() const { return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)); } +#ifndef DISABLE_DEPRECATED void RigidBody::set_friction(real_t p_friction) { + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED ERR_FAIL_COND(p_friction < 0 || p_friction > 1); - friction = p_friction; - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_friction(p_friction); + _reload_physics_characteristics(); } real_t RigidBody::get_friction() const { - return friction; + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + if (physics_material_override.is_null()) { + return 1; + } + + return physics_material_override->get_friction(); } void RigidBody::set_bounce(real_t p_bounce) { - + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); - bounce = p_bounce; - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce); + if (physics_material_override.is_null()) { + physics_material_override.instance(); + } + physics_material_override->set_bounce(p_bounce); + _reload_physics_characteristics(); } real_t RigidBody::get_bounce() const { + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material") + WARN_DEPRECATED + if (physics_material_override.is_null()) { + return 0; + } - return bounce; + return physics_material_override->get_bounce(); +} +#endif + +void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { + if (physics_material_override.is_valid()) { + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + + physics_material_override = p_physics_material_override; + + if (physics_material_override.is_valid()) { + physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + } + _reload_physics_characteristics(); +} + +Ref<PhysicsMaterial> RigidBody::get_physics_material_override() const { + return physics_material_override; } void RigidBody::set_gravity_scale(real_t p_gravity_scale) { @@ -693,6 +795,22 @@ int RigidBody::get_max_contacts_reported() const { return max_contacts_reported; } +void RigidBody::add_central_force(const Vector3 &p_force) { + PhysicsServer::get_singleton()->body_add_central_force(get_rid(), p_force); +} + +void RigidBody::add_force(const Vector3 &p_force, const Vector3 &p_pos) { + PhysicsServer::get_singleton()->body_add_force(get_rid(), p_force, p_pos); +} + +void RigidBody::add_torque(const Vector3 &p_torque) { + PhysicsServer::get_singleton()->body_add_torque(get_rid(), p_torque); +} + +void RigidBody::apply_central_impulse(const Vector3 &p_impulse) { + PhysicsServer::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse); +} + void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) { PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); @@ -812,6 +930,11 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce); ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override); + + ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody::_reload_physics_characteristics); + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity); ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity); @@ -840,6 +963,12 @@ void RigidBody::_bind_methods() { ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody::is_using_continuous_collision_detection); ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity); + + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidBody::add_central_force); + ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidBody::add_force); + ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidBody::add_torque); + + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody::apply_central_impulse); ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody::apply_impulse); ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody::apply_torque_impulse); @@ -865,6 +994,7 @@ void RigidBody::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection"); @@ -903,9 +1033,7 @@ RigidBody::RigidBody() : mode = MODE_RIGID; - bounce = 0; mass = 1; - friction = 1; max_contacts_reported = 0; state = NULL; @@ -929,6 +1057,21 @@ RigidBody::~RigidBody() { if (contact_monitor) memdelete(contact_monitor); } + +void RigidBody::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT); + } else { + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode()); + PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode()); + } +} + ////////////////////////////////////////////////////// ////////////////////////// @@ -1117,11 +1260,11 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) { } if (slide_colliders[p_bounce].is_null()) { - slide_colliders[p_bounce].instance(); - slide_colliders[p_bounce]->owner = this; + slide_colliders.write[p_bounce].instance(); + slide_colliders.write[p_bounce]->owner = this; } - slide_colliders[p_bounce]->collision = colliders[p_bounce]; + slide_colliders.write[p_bounce]->collision = colliders[p_bounce]; return slide_colliders[p_bounce]; } @@ -1174,7 +1317,7 @@ KinematicBody::~KinematicBody() { for (int i = 0; i < slide_colliders.size(); i++) { if (slide_colliders[i].is_valid()) { - slide_colliders[i]->owner = NULL; + slide_colliders.write[i]->owner = NULL; } } } @@ -2228,6 +2371,7 @@ void PhysicalBone::set_bounce(real_t p_bounce) { bounce = p_bounce; PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce); } + real_t PhysicalBone::get_bounce() const { return bounce; diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 7236eba685..4143989671 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -32,6 +32,7 @@ #define PHYSICS_BODY__H #include "scene/3d/collision_object.h" +#include "scene/resources/physics_material.h" #include "servers/physics_server.h" #include "skeleton.h" #include "vset.h" @@ -81,18 +82,22 @@ class StaticBody : public PhysicsBody { Vector3 constant_linear_velocity; Vector3 constant_angular_velocity; - real_t bounce; - real_t friction; + Ref<PhysicsMaterial> physics_material_override; protected: static void _bind_methods(); public: +#ifndef DISABLE_DEPRECATED void set_friction(real_t p_friction); real_t get_friction() const; void set_bounce(real_t p_bounce); real_t get_bounce() const; +#endif + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; void set_constant_linear_velocity(const Vector3 &p_vel); void set_constant_angular_velocity(const Vector3 &p_vel); @@ -102,6 +107,9 @@ public: StaticBody(); ~StaticBody(); + +private: + void _reload_physics_characteristics(); }; class RigidBody : public PhysicsBody { @@ -121,9 +129,8 @@ protected: PhysicsDirectBodyState *state; Mode mode; - real_t bounce; real_t mass; - real_t friction; + Ref<PhysicsMaterial> physics_material_override; Vector3 linear_velocity; Vector3 angular_velocity; @@ -196,11 +203,16 @@ public: void set_weight(real_t p_weight); real_t get_weight() const; +#ifndef DISABLE_DEPRECATED void set_friction(real_t p_friction); real_t get_friction() const; void set_bounce(real_t p_bounce); real_t get_bounce() const; +#endif + + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); + Ref<PhysicsMaterial> get_physics_material_override() const; void set_linear_velocity(const Vector3 &p_velocity); Vector3 get_linear_velocity() const; @@ -242,6 +254,11 @@ public: Array get_colliding_bodies() const; + void add_central_force(const Vector3 &p_force); + void add_force(const Vector3 &p_force, const Vector3 &p_pos); + void add_torque(const Vector3 &p_torque); + + void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); void apply_torque_impulse(const Vector3 &p_impulse); @@ -249,6 +266,9 @@ public: RigidBody(); ~RigidBody(); + +private: + void _reload_physics_characteristics(); }; VARIANT_ENUM_CAST(RigidBody::Mode); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 8d91b6f09f..4b6b59b2d3 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -66,7 +66,7 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { Array children = p_value; if (is_inside_tree()) { - bones[which].nodes_bound.clear(); + bones.write[which].nodes_bound.clear(); for (int i = 0; i < children.size(); i++) { @@ -176,7 +176,7 @@ void Skeleton::_notification(int p_what) { case NOTIFICATION_UPDATE_SKELETON: { VisualServer *vs = VisualServer::get_singleton(); - Bone *bonesptr = &bones[0]; + Bone *bonesptr = bones.ptrw(); int len = bones.size(); vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens @@ -370,7 +370,7 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) { ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(p_parent != -1 && (p_parent < 0 || p_parent >= p_bone)); - bones[p_bone].parent = p_parent; + bones.write[p_bone].parent = p_parent; rest_global_inverse_dirty = true; _make_dirty(); } @@ -381,19 +381,19 @@ void Skeleton::unparent_bone_and_rest(int p_bone) { int parent = bones[p_bone].parent; while (parent >= 0) { - bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest; + bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest; parent = bones[parent].parent; } - bones[p_bone].parent = -1; - bones[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing + bones.write[p_bone].parent = -1; + bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing _make_dirty(); } void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].ignore_animation = p_ignore; + bones.write[p_bone].ignore_animation = p_ignore; } bool Skeleton::is_bone_ignore_animation(int p_bone) const { @@ -405,7 +405,7 @@ bool Skeleton::is_bone_ignore_animation(int p_bone) const { void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].disable_rest = p_disable; + bones.write[p_bone].disable_rest = p_disable; } bool Skeleton::is_bone_rest_disabled(int p_bone) const { @@ -425,7 +425,7 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].rest = p_rest; + bones.write[p_bone].rest = p_rest; rest_global_inverse_dirty = true; _make_dirty(); } @@ -440,7 +440,7 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].enabled = p_enabled; + bones.write[p_bone].enabled = p_enabled; rest_global_inverse_dirty = true; _make_dirty(); } @@ -457,13 +457,13 @@ void Skeleton::bind_child_node_to_bone(int p_bone, Node *p_node) { uint32_t id = p_node->get_instance_id(); - for (List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { + for (const List<uint32_t>::Element *E = bones[p_bone].nodes_bound.front(); E; E = E->next()) { if (E->get() == id) return; // already here } - bones[p_bone].nodes_bound.push_back(id); + bones.write[p_bone].nodes_bound.push_back(id); } void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) { @@ -471,7 +471,7 @@ void Skeleton::unbind_child_node_from_bone(int p_bone, Node *p_node) { ERR_FAIL_INDEX(p_bone, bones.size()); uint32_t id = p_node->get_instance_id(); - bones[p_bone].nodes_bound.erase(id); + bones.write[p_bone].nodes_bound.erase(id); } void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) const { @@ -499,7 +499,7 @@ void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) { ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(!is_inside_tree()); - bones[p_bone].pose = p_pose; + bones.write[p_bone].pose = p_pose; _make_dirty(); } Transform Skeleton::get_bone_pose(int p_bone) const { @@ -513,8 +513,8 @@ void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) ERR_FAIL_INDEX(p_bone, bones.size()); //ERR_FAIL_COND( !is_inside_scene() ); - bones[p_bone].custom_pose_enable = (p_custom_pose != Transform()); - bones[p_bone].custom_pose = p_custom_pose; + bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform()); + bones.write[p_bone].custom_pose = p_custom_pose; _make_dirty(); } @@ -553,14 +553,14 @@ void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_b ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(bones[p_bone].physical_bone); ERR_FAIL_COND(!p_physical_bone); - bones[p_bone].physical_bone = p_physical_bone; + bones.write[p_bone].physical_bone = p_physical_bone; _rebuild_physical_bones_cache(); } void Skeleton::unbind_physical_bone_from_bone(int p_bone) { ERR_FAIL_INDEX(p_bone, bones.size()); - bones[p_bone].physical_bone = NULL; + bones.write[p_bone].physical_bone = NULL; _rebuild_physical_bones_cache(); } @@ -600,7 +600,7 @@ PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) { void Skeleton::_rebuild_physical_bones_cache() { const int b_size = bones.size(); for (int i = 0; i < b_size; ++i) { - bones[i].cache_parent_physical_bone = _get_physical_bone_parent(i); + bones.write[i].cache_parent_physical_bone = _get_physical_bone_parent(i); if (bones[i].physical_bone) bones[i].physical_bone->_on_bone_parent_changed(); } @@ -660,7 +660,7 @@ void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { if (Variant::STRING == p_bones.get(i).get_type()) { int bone_id = find_bone(p_bones.get(i)); if (bone_id != -1) - sim_bones[c++] = bone_id; + sim_bones.write[c++] = bone_id; } } sim_bones.resize(c); diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp new file mode 100644 index 0000000000..8498dc34c0 --- /dev/null +++ b/scene/3d/soft_body.cpp @@ -0,0 +1,740 @@ +/*************************************************************************/ +/* soft_physics_body.cpp */ +/* Author: AndreaCatania */ +/*************************************************************************/ +/* 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 "soft_body.h" +#include "os/os.h" +#include "scene/3d/collision_object.h" +#include "scene/3d/skeleton.h" +#include "servers/physics_server.h" + +SoftBodyVisualServerHandler::SoftBodyVisualServerHandler() {} + +void SoftBodyVisualServerHandler::prepare(RID p_mesh, int p_surface) { + clear(); + + ERR_FAIL_COND(!p_mesh.is_valid()); + + mesh = p_mesh; + surface = p_surface; + + const uint32_t surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, surface); + const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface); + const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface); + uint32_t surface_offsets[VS::ARRAY_MAX]; + + buffer = VS::get_singleton()->mesh_surface_get_array(mesh, surface); + stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets); + offset_vertices = surface_offsets[VS::ARRAY_VERTEX]; + offset_normal = surface_offsets[VS::ARRAY_NORMAL]; +} + +void SoftBodyVisualServerHandler::clear() { + + if (mesh.is_valid()) { + buffer.resize(0); + } + + mesh = RID(); +} + +void SoftBodyVisualServerHandler::open() { + write_buffer = buffer.write(); +} + +void SoftBodyVisualServerHandler::close() { + write_buffer = PoolVector<uint8_t>::Write(); +} + +void SoftBodyVisualServerHandler::commit_changes() { + VS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer); +} + +void SoftBodyVisualServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) { + copymem(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3); +} + +void SoftBodyVisualServerHandler::set_normal(int p_vertex_id, const void *p_vector3) { + copymem(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3); +} + +void SoftBodyVisualServerHandler::set_aabb(const AABB &p_aabb) { + VS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb); +} + +SoftBody::PinnedPoint::PinnedPoint() : + point_index(-1), + spatial_attachment(NULL) { +} + +SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) { + point_index = obj_tocopy.point_index; + spatial_attachment_path = obj_tocopy.spatial_attachment_path; + spatial_attachment = obj_tocopy.spatial_attachment; + vertex_offset_transform = obj_tocopy.vertex_offset_transform; +} + +void SoftBody::_update_pickable() { + if (!is_inside_tree()) + return; + bool pickable = ray_pickable && is_inside_tree() && is_visible_in_tree(); + PhysicsServer::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable); +} + +bool SoftBody::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + String which = name.get_slicec('/', 0); + + if ("pinned_points" == which) { + + return _set_property_pinned_points_indices(p_value); + + } else if ("attachments" == which) { + + int idx = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + + return _set_property_pinned_points_attachment(idx, what, p_value); + } + + return false; +} + +bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + String which = name.get_slicec('/', 0); + + if ("pinned_points" == which) { + Array arr_ret; + const int pinned_points_indices_size = pinned_points_indices.size(); + PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + arr_ret.resize(pinned_points_indices_size); + + for (int i = 0; i < pinned_points_indices_size; ++i) { + arr_ret[i] = r[i].point_index; + } + + r_ret = arr_ret; + return true; + + } else if ("attachments" == which) { + + int idx = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + + return _get_property_pinned_points(idx, what, r_ret); + } + + return false; +} + +void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const { + + const int pinned_points_indices_size = pinned_points_indices.size(); + + p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points")); + + for (int i = 0; i < pinned_points_indices_size; ++i) { + p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index")); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path")); + } +} + +bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) { + + const int p_indices_size = p_indices.size(); + + { // Remove the pined points on physics server that will be removed by resize + PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + if (p_indices_size < pinned_points_indices.size()) { + for (int i = pinned_points_indices.size() - 1; i >= p_indices_size; --i) { + pin_point(r[i].point_index, false); + } + } + } + + pinned_points_indices.resize(p_indices_size); + + PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); + int point_index; + for (int i = 0; i < p_indices_size; ++i) { + point_index = p_indices.get(i); + if (w[i].point_index != point_index) { + if (-1 != w[i].point_index) + pin_point(w[i].point_index, false); + w[i].point_index = point_index; + pin_point(w[i].point_index, true); + } + } + return true; +} + +bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) { + if (pinned_points_indices.size() <= p_item) { + return false; + } + + if ("spatial_attachment_path" == p_what) { + PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); + pin_point(w[p_item].point_index, true, p_value); + } else { + return false; + } + + return true; +} + +bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const { + if (pinned_points_indices.size() <= p_item) { + return false; + } + PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + + if ("point_index" == p_what) { + r_ret = r[p_item].point_index; + } else if ("spatial_attachment_path" == p_what) { + r_ret = r[p_item].spatial_attachment_path; + } else { + return false; + } + + return true; +} + +void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) { +#ifdef TOOLS_ENABLED + if (p_changed == this) { + update_configuration_warning(); + } +#endif +} + +void SoftBody::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_WORLD: { + + if (Engine::get_singleton()->is_editor_hint()) + add_change_receptor(this); + + RID space = get_world()->get_space(); + PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space); + PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); + update_physics_server(); + } break; + case NOTIFICATION_READY: { + if (!parent_collision_ignore.is_empty()) + add_collision_exception_with(get_node(parent_collision_ignore)); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (!simulation_started) { + PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); + + _update_cache_pin_points_datas(); + // Submit bone attachment + const int pinned_points_indices_size = pinned_points_indices.size(); + PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + for (int i = 0; i < pinned_points_indices_size; ++i) { + if (!r[i].spatial_attachment) { + // Use soft body position to update the point position + PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, (get_global_transform() * r[i].vertex_offset_transform).origin); + } else { + PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, (r[i].spatial_attachment->get_global_transform() * r[i].vertex_offset_transform).origin); + } + } + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + + _update_pickable(); + + } break; + case NOTIFICATION_EXIT_WORLD: { + + PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, RID()); + + } break; + } + +#ifdef TOOLS_ENABLED + + if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warning(); + } + } + +#endif +} + +void SoftBody::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_draw_soft_mesh"), &SoftBody::_draw_soft_mesh); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody::set_collision_layer); + ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody::get_collision_layer); + + ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &SoftBody::set_collision_mask_bit); + ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &SoftBody::get_collision_mask_bit); + + ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &SoftBody::set_collision_layer_bit); + ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &SoftBody::get_collision_layer_bit); + + ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody::set_parent_collision_ignore); + ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody::get_parent_collision_ignore); + + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody::add_collision_exception_with); + ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody::remove_collision_exception_with); + + ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody::set_simulation_precision); + ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody::get_simulation_precision); + + ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody::set_total_mass); + ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody::get_total_mass); + + ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody::set_linear_stiffness); + ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody::get_linear_stiffness); + + ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody::set_areaAngular_stiffness); + ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody::get_areaAngular_stiffness); + + ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody::set_volume_stiffness); + ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody::get_volume_stiffness); + + ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody::set_pressure_coefficient); + ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody::get_pressure_coefficient); + + ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody::set_pose_matching_coefficient); + ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody::get_pose_matching_coefficient); + + ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody::set_damping_coefficient); + ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody::get_damping_coefficient); + + ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody::set_drag_coefficient); + ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody::get_drag_coefficient); + + ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody::set_ray_pickable); + ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody::is_ray_pickable); + + ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE, "Parent collision object"), "set_parent_collision_ignore", "get_parent_collision_ignore"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient"); +} + +String SoftBody::get_configuration_warning() const { + + String warning = MeshInstance::get_configuration_warning(); + + if (get_mesh().is_null()) { + if (!warning.empty()) + warning += "\n\n"; + + warning += TTR("This body will be ignored until you set a mesh"); + } + + Transform t = get_transform(); + if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) { + if (!warning.empty()) + warning += "\n\n"; + + warning += TTR("Size changes to SoftBody will be overriden by the physics engine when running.\nChange the size in children collision shapes instead."); + } + + return warning; +} + +void SoftBody::_draw_soft_mesh() { + if (get_mesh().is_null()) + return; + + if (!visual_server_handler.is_ready()) { + + visual_server_handler.prepare(get_mesh()->get_rid(), 0); + + /// Necessary in order to render the mesh correctly (Soft body nodes are in global space) + simulation_started = true; + call_deferred("set_as_toplevel", true); + call_deferred("set_transform", Transform()); + } + + visual_server_handler.open(); + PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler); + visual_server_handler.close(); + + visual_server_handler.commit_changes(); +} + +void SoftBody::update_physics_server() { + + if (Engine::get_singleton()->is_editor_hint()) + return; + + if (get_mesh().is_valid()) { + + become_mesh_owner(); + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); + VS::get_singleton()->connect("frame_pre_draw", this, "_draw_soft_mesh"); + } else { + + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL); + VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh"); + } +} + +void SoftBody::become_mesh_owner() { + if (mesh.is_null()) + return; + + if (!mesh_owner) { + mesh_owner = true; + + ERR_FAIL_COND(!mesh->get_surface_count()); + + // Get current mesh array and create new mesh array with necessary flag for softbody + Array surface_arrays = mesh->surface_get_arrays(0); + Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0); + uint32_t surface_format = mesh->surface_get_format(0); + + surface_format &= ~(Mesh::ARRAY_COMPRESS_VERTEX | Mesh::ARRAY_COMPRESS_NORMAL); + surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; + + Ref<ArrayMesh> soft_mesh; + soft_mesh.instance(); + soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format); + + set_mesh(soft_mesh); + + Vector<Ref<Material> > copy_materials; + copy_materials.append_array(materials); + for (int i = copy_materials.size() - 1; 0 <= i; --i) { + set_surface_material(i, copy_materials[i]); + } + } +} + +void SoftBody::set_collision_mask(uint32_t p_mask) { + collision_mask = p_mask; + PhysicsServer::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask); +} + +uint32_t SoftBody::get_collision_mask() const { + return collision_mask; +} +void SoftBody::set_collision_layer(uint32_t p_layer) { + collision_layer = p_layer; + PhysicsServer::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer); +} + +uint32_t SoftBody::get_collision_layer() const { + return collision_layer; +} + +void SoftBody::set_collision_mask_bit(int p_bit, bool p_value) { + uint32_t mask = get_collision_mask(); + if (p_value) + mask |= 1 << p_bit; + else + mask &= ~(1 << p_bit); + set_collision_mask(mask); +} + +bool SoftBody::get_collision_mask_bit(int p_bit) const { + return get_collision_mask() & (1 << p_bit); +} + +void SoftBody::set_collision_layer_bit(int p_bit, bool p_value) { + uint32_t layer = get_collision_layer(); + if (p_value) + layer |= 1 << p_bit; + else + layer &= ~(1 << p_bit); + set_collision_layer(layer); +} + +bool SoftBody::get_collision_layer_bit(int p_bit) const { + return get_collision_layer() & (1 << p_bit); +} + +void SoftBody::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) { + parent_collision_ignore = p_parent_collision_ignore; +} + +const NodePath &SoftBody::get_parent_collision_ignore() const { + return parent_collision_ignore; +} + +void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) { + pinned_points_indices = p_pinned_points_indices; + PoolVector<PinnedPoint>::Read w = pinned_points_indices.read(); + for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + pin_point(p_pinned_points_indices[i].point_index, true); + } +} + +PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() { + return pinned_points_indices; +} + +void SoftBody::add_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); + } + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid()); +} + +void SoftBody::remove_collision_exception_with(Node *p_node) { + ERR_FAIL_NULL(p_node); + CollisionObject *collision_object = Object::cast_to<CollisionObject>(p_node); + if (!collision_object) { + ERR_EXPLAIN("Collision exception only works between two CollisionObject"); + } + ERR_FAIL_COND(!collision_object); + PhysicsServer::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid()); +} + +int SoftBody::get_simulation_precision() { + return PhysicsServer::get_singleton()->soft_body_get_simulation_precision(physics_rid); +} + +void SoftBody::set_simulation_precision(int p_simulation_precision) { + PhysicsServer::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision); +} + +real_t SoftBody::get_total_mass() { + return PhysicsServer::get_singleton()->soft_body_get_total_mass(physics_rid); +} + +void SoftBody::set_total_mass(real_t p_total_mass) { + PhysicsServer::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass); +} + +void SoftBody::set_linear_stiffness(real_t p_linear_stiffness) { + PhysicsServer::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness); +} + +real_t SoftBody::get_linear_stiffness() { + return PhysicsServer::get_singleton()->soft_body_get_linear_stiffness(physics_rid); +} + +void SoftBody::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) { + PhysicsServer::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness); +} + +real_t SoftBody::get_areaAngular_stiffness() { + return PhysicsServer::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid); +} + +void SoftBody::set_volume_stiffness(real_t p_volume_stiffness) { + PhysicsServer::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness); +} + +real_t SoftBody::get_volume_stiffness() { + return PhysicsServer::get_singleton()->soft_body_get_volume_stiffness(physics_rid); +} + +real_t SoftBody::get_pressure_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_pressure_coefficient(physics_rid); +} + +void SoftBody::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient); +} + +real_t SoftBody::get_pose_matching_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid); +} + +void SoftBody::set_pressure_coefficient(real_t p_pressure_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient); +} + +real_t SoftBody::get_damping_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_damping_coefficient(physics_rid); +} + +void SoftBody::set_damping_coefficient(real_t p_damping_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient); +} + +real_t SoftBody::get_drag_coefficient() { + return PhysicsServer::get_singleton()->soft_body_get_drag_coefficient(physics_rid); +} + +void SoftBody::set_drag_coefficient(real_t p_drag_coefficient) { + PhysicsServer::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient); +} + +Vector3 SoftBody::get_point_transform(int p_point_index) { + return PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index); +} + +void SoftBody::pin_point_toggle(int p_point_index) { + pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index))); +} + +void SoftBody::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) { + _pin_point_on_physics_server(p_point_index, pin); + if (pin) { + _add_pinned_point(p_point_index, p_spatial_attachment_path); + } else { + _remove_pinned_point(p_point_index); + } +} + +bool SoftBody::is_point_pinned(int p_point_index) const { + return -1 != _has_pinned_point(p_point_index); +} + +void SoftBody::set_ray_pickable(bool p_ray_pickable) { + + ray_pickable = p_ray_pickable; + _update_pickable(); +} + +bool SoftBody::is_ray_pickable() const { + + return ray_pickable; +} + +SoftBody::SoftBody() : + MeshInstance(), + physics_rid(PhysicsServer::get_singleton()->soft_body_create()), + mesh_owner(false), + collision_mask(1), + collision_layer(1), + simulation_started(false), + pinned_points_cache_dirty(true) { + + PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id()); +} + +SoftBody::~SoftBody() { +} + +void SoftBody::reset_softbody_pin() { + PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid); + PoolVector<PinnedPoint>::Read pps = pinned_points_indices.read(); + for (int i = pinned_points_indices.size() - 1; 0 < i; --i) { + PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true); + } +} + +void SoftBody::_update_cache_pin_points_datas() { + if (pinned_points_cache_dirty) { + pinned_points_cache_dirty = false; + + PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); + for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + + if (!w[i].spatial_attachment_path.is_empty()) { + w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path)); + if (w[i].spatial_attachment) { + + Transform point_global_transform(get_global_transform()); + point_global_transform.translate(PhysicsServer::get_singleton()->soft_body_get_point_offset(physics_rid, w[i].point_index)); + + // Local transform relative to spatial attachment node + w[i].vertex_offset_transform = w[i].spatial_attachment->get_global_transform().affine_inverse() * point_global_transform; + continue; + } else { + ERR_PRINTS("The node with path: " + String(w[i].spatial_attachment_path) + " was not found or is not a spatial node."); + } + } + // Local transform relative to Soft body + w[i].vertex_offset_transform.origin = PhysicsServer::get_singleton()->soft_body_get_point_offset(physics_rid, w[i].point_index); + w[i].vertex_offset_transform.basis = Basis(); + } + } +} + +void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) { + PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin); +} + +void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) { + SoftBody::PinnedPoint *pinned_point; + if (-1 == _get_pinned_point(p_point_index, pinned_point)) { + // Create new + PinnedPoint pp; + pp.point_index = p_point_index; + pp.spatial_attachment_path = p_spatial_attachment_path; + pinned_points_indices.push_back(pp); + } else { + // Update + pinned_point->point_index = p_point_index; + pinned_point->spatial_attachment_path = p_spatial_attachment_path; + } +} + +void SoftBody::_remove_pinned_point(int p_point_index) { + const int id(_has_pinned_point(p_point_index)); + if (-1 != id) { + pinned_points_indices.remove(id); + } +} + +int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_point) const { + const int id = _has_pinned_point(p_point_index); + if (-1 == id) { + r_point = NULL; + return -1; + } else { + r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points_indices.read()[id]); + return id; + } +} + +int SoftBody::_has_pinned_point(int p_point_index) const { + PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + if (p_point_index == r[i].point_index) { + return i; + } + } + return -1; +} diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h new file mode 100644 index 0000000000..f44f337698 --- /dev/null +++ b/scene/3d/soft_body.h @@ -0,0 +1,197 @@ +/*************************************************************************/ +/* soft_physics_body.h */ +/* Author: AndreaCatania */ +/*************************************************************************/ +/* 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 SOFT_PHYSICS_BODY_H +#define SOFT_PHYSICS_BODY_H + +#include "scene/3d/mesh_instance.h" + +class SoftBody; + +class SoftBodyVisualServerHandler { + + friend class SoftBody; + + RID mesh; + int surface; + PoolVector<uint8_t> buffer; + uint32_t stride; + uint32_t offset_vertices; + uint32_t offset_normal; + + PoolVector<uint8_t>::Write write_buffer; + +private: + SoftBodyVisualServerHandler(); + bool is_ready() { return mesh.is_valid(); } + void prepare(RID p_mesh_rid, int p_surface); + void clear(); + void open(); + void close(); + void commit_changes(); + +public: + void set_vertex(int p_vertex_id, const void *p_vector3); + void set_normal(int p_vertex_id, const void *p_vector3); + void set_aabb(const AABB &p_aabb); +}; + +class SoftBody : public MeshInstance { + GDCLASS(SoftBody, MeshInstance); + +public: + struct PinnedPoint { + int point_index; + NodePath spatial_attachment_path; + Spatial *spatial_attachment; // Cache + /// This is the offset from the soft body to point or attachment to point + /// Depend if the spatial_attachment_node is NULL or not + Transform vertex_offset_transform; // Cache + + PinnedPoint(); + PinnedPoint(const PinnedPoint &obj_tocopy); + }; + +private: + SoftBodyVisualServerHandler visual_server_handler; + + RID physics_rid; + + bool mesh_owner; + uint32_t collision_mask; + uint32_t collision_layer; + NodePath parent_collision_ignore; + PoolVector<PinnedPoint> pinned_points_indices; + bool simulation_started; + bool pinned_points_cache_dirty; + + Ref<ArrayMesh> debug_mesh_cache; + class MeshInstance *debug_mesh; + + bool capture_input_on_drag; + bool ray_pickable; + + void _update_pickable(); + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + bool _set_property_pinned_points_indices(const Array &p_indices); + bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value); + bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const; + + virtual void _changed_callback(Object *p_changed, const char *p_prop); + + void _notification(int p_what); + static void _bind_methods(); + + virtual String get_configuration_warning() const; + +protected: + void _draw_soft_mesh(); + +public: + void update_physics_server(); + void become_mesh_owner(); + + void set_collision_mask(uint32_t p_mask); + uint32_t get_collision_mask() const; + + void set_collision_layer(uint32_t p_layer); + uint32_t get_collision_layer() const; + + void set_collision_mask_bit(int p_bit, bool p_value); + bool get_collision_mask_bit(int p_bit) const; + + void set_collision_layer_bit(int p_bit, bool p_value); + bool get_collision_layer_bit(int p_bit) const; + + void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore); + const NodePath &get_parent_collision_ignore() const; + + void set_pinned_points_indices(PoolVector<PinnedPoint> p_pinned_points_indices); + PoolVector<PinnedPoint> get_pinned_points_indices(); + + void set_simulation_precision(int p_simulation_precision); + int get_simulation_precision(); + + void set_total_mass(real_t p_total_mass); + real_t get_total_mass(); + + void set_linear_stiffness(real_t p_linear_stiffness); + real_t get_linear_stiffness(); + + void set_areaAngular_stiffness(real_t p_areaAngular_stiffness); + real_t get_areaAngular_stiffness(); + + void set_volume_stiffness(real_t p_volume_stiffness); + real_t get_volume_stiffness(); + + void set_pressure_coefficient(real_t p_pressure_coefficient); + real_t get_pressure_coefficient(); + + void set_pose_matching_coefficient(real_t p_pose_matching_coefficient); + real_t get_pose_matching_coefficient(); + + void set_damping_coefficient(real_t p_damping_coefficient); + real_t get_damping_coefficient(); + + void set_drag_coefficient(real_t p_drag_coefficient); + real_t get_drag_coefficient(); + + void add_collision_exception_with(Node *p_node); + void remove_collision_exception_with(Node *p_node); + + Vector3 get_point_transform(int p_point_index); + + void pin_point_toggle(int p_point_index); + void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath()); + bool is_point_pinned(int p_point_index) const; + + void set_ray_pickable(bool p_ray_pickable); + bool is_ray_pickable() const; + + SoftBody(); + ~SoftBody(); + +private: + void reset_softbody_pin(); + void _update_cache_pin_points_datas(); + void _pin_point_on_physics_server(int p_point_index, bool pin); + void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path); + void _remove_pinned_point(int p_point_index); + int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const; + int _has_pinned_point(int p_point_index) const; +}; + +#endif // SOFT_PHYSICS_BODY_H diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 9b27faed6a..64cb9ec4ca 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -645,19 +645,15 @@ void Spatial::scale_object_local(const Vector3 &p_scale) { void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) { - Basis rotation(p_axis, p_angle); Transform t = get_global_transform(); - t.basis = rotation * t.basis; + t.basis.rotate(p_axis, p_angle); set_global_transform(t); } void Spatial::global_scale(const Vector3 &p_scale) { - Basis s; - s.set_scale(p_scale); - Transform t = get_global_transform(); - t.basis = s * t.basis; + t.basis.scale(p_scale); set_global_transform(t); } diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp index c547e76e30..d96b003a81 100644 --- a/scene/3d/spatial_velocity_tracker.cpp +++ b/scene/3d/spatial_velocity_tracker.cpp @@ -53,11 +53,11 @@ void SpatialVelocityTracker::update_position(const Vector3 &p_position) { if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest position_history_len = MIN(position_history.size(), position_history_len + 1); for (int i = position_history_len - 1; i > 0; i--) { - position_history[i] = position_history[i - 1]; + position_history.write[i] = position_history[i - 1]; } } - position_history[0] = ph; + position_history.write[0] = ph; } Vector3 SpatialVelocityTracker::get_tracked_linear_velocity() const { @@ -114,7 +114,7 @@ void SpatialVelocityTracker::reset(const Vector3 &p_new_pos) { ph.frame = Engine::get_singleton()->get_idle_frame_ticks(); } - position_history[0] = ph; + position_history.write[0] = ph; position_history_len = 1; } diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index 385956dc16..26958930e4 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -524,7 +524,7 @@ void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) { //bilateral constraint between two dynamic objects void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, - PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence) { + PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence) { real_t normalLenSqr = normal.length_squared(); //ERR_FAIL_COND( normalLenSqr < real_t(1.1)); @@ -677,8 +677,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { //collapse all those loops into one! for (int i = 0; i < wheels.size(); i++) { - m_sideImpulse[i] = real_t(0.); - m_forwardImpulse[i] = real_t(0.); + m_sideImpulse.write[i] = real_t(0.); + m_forwardImpulse.write[i] = real_t(0.); } { @@ -693,22 +693,22 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { Basis wheelBasis0 = wheelInfo.m_worldTransform.basis; //get_global_transform().basis; - m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X); + m_axle.write[i] = wheelBasis0.get_axis(Vector3::AXIS_X); //m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS; const Vector3 &surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS; real_t proj = m_axle[i].dot(surfNormalWS); - m_axle[i] -= surfNormalWS * proj; - m_axle[i] = m_axle[i].normalized(); + m_axle.write[i] -= surfNormalWS * proj; + m_axle.write[i] = m_axle[i].normalized(); - m_forwardWS[i] = surfNormalWS.cross(m_axle[i]); - m_forwardWS[i].normalize(); + m_forwardWS.write[i] = surfNormalWS.cross(m_axle[i]); + m_forwardWS.write[i].normalize(); _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS, wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, - m_axle[i], m_sideImpulse[i], wheelInfo.m_rollInfluence); + m_axle[i], m_sideImpulse.write[i], wheelInfo.m_rollInfluence); - m_sideImpulse[i] *= sideFrictionStiffness2; + m_sideImpulse.write[i] *= sideFrictionStiffness2; } } } @@ -739,7 +739,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break) - m_forwardImpulse[wheel] = real_t(0.); + m_forwardImpulse.write[wheel] = real_t(0.); wheelInfo.m_skidInfo = real_t(1.); if (wheelInfo.m_raycastInfo.m_isInContact) { @@ -750,7 +750,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { real_t maximpSquared = maximp * maximpSide; - m_forwardImpulse[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep; + m_forwardImpulse.write[wheel] = rollingFriction; //wheelInfo.m_engineForce* timeStep; real_t x = (m_forwardImpulse[wheel]) * fwdFactor; real_t y = (m_sideImpulse[wheel]) * sideFactor; @@ -772,8 +772,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { for (int wheel = 0; wheel < wheels.size(); wheel++) { if (m_sideImpulse[wheel] != real_t(0.)) { if (wheels[wheel]->m_skidInfo < real_t(1.)) { - m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo; - m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo; + m_forwardImpulse.write[wheel] *= wheels[wheel]->m_skidInfo; + m_sideImpulse.write[wheel] *= wheels[wheel]->m_skidInfo; } } } @@ -942,8 +942,6 @@ VehicleBody::VehicleBody() : engine_force = 0; brake = 0; - friction = 1; - state = NULL; ccd = false; diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h index 1ac3693cc4..68fbf8d873 100644 --- a/scene/3d/vehicle_body.h +++ b/scene/3d/vehicle_body.h @@ -168,7 +168,7 @@ class VehicleBody : public RigidBody { btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse); }; - void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence); + void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, const real_t p_rollInfluence); real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint); void _update_friction(PhysicsDirectBodyState *s); diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index ba2807d4e8..f3abdc6bbe 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -409,16 +409,16 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p } //put this temporarily here, corrected in a later step - bake_cells[p_idx].albedo[0] += albedo_accum.r; - bake_cells[p_idx].albedo[1] += albedo_accum.g; - bake_cells[p_idx].albedo[2] += albedo_accum.b; - bake_cells[p_idx].emission[0] += emission_accum.r; - bake_cells[p_idx].emission[1] += emission_accum.g; - bake_cells[p_idx].emission[2] += emission_accum.b; - bake_cells[p_idx].normal[0] += normal_accum.x; - bake_cells[p_idx].normal[1] += normal_accum.y; - bake_cells[p_idx].normal[2] += normal_accum.z; - bake_cells[p_idx].alpha += alpha; + bake_cells.write[p_idx].albedo[0] += albedo_accum.r; + bake_cells.write[p_idx].albedo[1] += albedo_accum.g; + bake_cells.write[p_idx].albedo[2] += albedo_accum.b; + bake_cells.write[p_idx].emission[0] += emission_accum.r; + bake_cells.write[p_idx].emission[1] += emission_accum.g; + bake_cells.write[p_idx].emission[2] += emission_accum.b; + bake_cells.write[p_idx].normal[0] += normal_accum.x; + bake_cells.write[p_idx].normal[1] += normal_accum.y; + bake_cells.write[p_idx].normal[2] += normal_accum.z; + bake_cells.write[p_idx].alpha += alpha; } else { //go down @@ -465,9 +465,9 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p //sub cell must be created uint32_t child_idx = bake_cells.size(); - bake_cells[p_idx].children[i] = child_idx; + bake_cells.write[p_idx].children[i] = child_idx; bake_cells.resize(bake_cells.size() + 1); - bake_cells[child_idx].level = p_level + 1; + bake_cells.write[child_idx].level = p_level + 1; } _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); @@ -483,7 +483,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color ret.resize(bake_texture_size * bake_texture_size); for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { - ret[i] = p_color_add; + ret.write[i] = p_color_add; } return ret; @@ -509,7 +509,7 @@ Vector<Color> VoxelLightBaker::_get_bake_texture(Ref<Image> p_image, const Color c.a = r[i * 4 + 3] / 255.0; - ret[i] = c; + ret.write[i] = c; } return ret; @@ -686,13 +686,13 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent) { - bake_light[p_idx].x = p_x; - bake_light[p_idx].y = p_y; - bake_light[p_idx].z = p_z; + bake_light.write[p_idx].x = p_x; + bake_light.write[p_idx].y = p_y; + bake_light.write[p_idx].z = p_z; if (p_level == cell_subdiv - 1) { - bake_light[p_idx].next_leaf = first_leaf; + bake_light.write[p_idx].next_leaf = first_leaf; first_leaf = p_idx; } else { @@ -1197,33 +1197,33 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { leaf_voxel_count++; float alpha = bake_cells[p_idx].alpha; - bake_cells[p_idx].albedo[0] /= alpha; - bake_cells[p_idx].albedo[1] /= alpha; - bake_cells[p_idx].albedo[2] /= alpha; + bake_cells.write[p_idx].albedo[0] /= alpha; + bake_cells.write[p_idx].albedo[1] /= alpha; + bake_cells.write[p_idx].albedo[2] /= alpha; //transfer emission to light - bake_cells[p_idx].emission[0] /= alpha; - bake_cells[p_idx].emission[1] /= alpha; - bake_cells[p_idx].emission[2] /= alpha; + bake_cells.write[p_idx].emission[0] /= alpha; + bake_cells.write[p_idx].emission[1] /= alpha; + bake_cells.write[p_idx].emission[2] /= alpha; - bake_cells[p_idx].normal[0] /= alpha; - bake_cells[p_idx].normal[1] /= alpha; - bake_cells[p_idx].normal[2] /= alpha; + bake_cells.write[p_idx].normal[0] /= alpha; + bake_cells.write[p_idx].normal[1] /= alpha; + bake_cells.write[p_idx].normal[2] /= alpha; Vector3 n(bake_cells[p_idx].normal[0], bake_cells[p_idx].normal[1], bake_cells[p_idx].normal[2]); if (n.length() < 0.01) { //too much fight over normal, zero it - bake_cells[p_idx].normal[0] = 0; - bake_cells[p_idx].normal[1] = 0; - bake_cells[p_idx].normal[2] = 0; + bake_cells.write[p_idx].normal[0] = 0; + bake_cells.write[p_idx].normal[1] = 0; + bake_cells.write[p_idx].normal[2] = 0; } else { n.normalize(); - bake_cells[p_idx].normal[0] = n.x; - bake_cells[p_idx].normal[1] = n.y; - bake_cells[p_idx].normal[2] = n.z; + bake_cells.write[p_idx].normal[0] = n.x; + bake_cells.write[p_idx].normal[1] = n.y; + bake_cells.write[p_idx].normal[2] = n.z; } - bake_cells[p_idx].alpha = 1.0; + bake_cells.write[p_idx].alpha = 1.0; /*if (bake_light.size()) { for(int i=0;i<6;i++) { @@ -1235,20 +1235,20 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { //go down - bake_cells[p_idx].emission[0] = 0; - bake_cells[p_idx].emission[1] = 0; - bake_cells[p_idx].emission[2] = 0; - bake_cells[p_idx].normal[0] = 0; - bake_cells[p_idx].normal[1] = 0; - bake_cells[p_idx].normal[2] = 0; - bake_cells[p_idx].albedo[0] = 0; - bake_cells[p_idx].albedo[1] = 0; - bake_cells[p_idx].albedo[2] = 0; + bake_cells.write[p_idx].emission[0] = 0; + bake_cells.write[p_idx].emission[1] = 0; + bake_cells.write[p_idx].emission[2] = 0; + bake_cells.write[p_idx].normal[0] = 0; + bake_cells.write[p_idx].normal[1] = 0; + bake_cells.write[p_idx].normal[2] = 0; + bake_cells.write[p_idx].albedo[0] = 0; + bake_cells.write[p_idx].albedo[1] = 0; + bake_cells.write[p_idx].albedo[2] = 0; if (bake_light.size()) { for (int j = 0; j < 6; j++) { - bake_light[p_idx].accum[j][0] = 0; - bake_light[p_idx].accum[j][1] = 0; - bake_light[p_idx].accum[j][2] = 0; + bake_light.write[p_idx].accum[j][0] = 0; + bake_light.write[p_idx].accum[j][1] = 0; + bake_light.write[p_idx].accum[j][2] = 0; } } @@ -1267,29 +1267,29 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) { if (bake_light.size() > 0) { for (int j = 0; j < 6; j++) { - bake_light[p_idx].accum[j][0] += bake_light[child].accum[j][0]; - bake_light[p_idx].accum[j][1] += bake_light[child].accum[j][1]; - bake_light[p_idx].accum[j][2] += bake_light[child].accum[j][2]; + bake_light.write[p_idx].accum[j][0] += bake_light[child].accum[j][0]; + bake_light.write[p_idx].accum[j][1] += bake_light[child].accum[j][1]; + bake_light.write[p_idx].accum[j][2] += bake_light[child].accum[j][2]; } - bake_cells[p_idx].emission[0] += bake_cells[child].emission[0]; - bake_cells[p_idx].emission[1] += bake_cells[child].emission[1]; - bake_cells[p_idx].emission[2] += bake_cells[child].emission[2]; + bake_cells.write[p_idx].emission[0] += bake_cells[child].emission[0]; + bake_cells.write[p_idx].emission[1] += bake_cells[child].emission[1]; + bake_cells.write[p_idx].emission[2] += bake_cells[child].emission[2]; } children_found++; } - bake_cells[p_idx].alpha = alpha_average / 8.0; + bake_cells.write[p_idx].alpha = alpha_average / 8.0; if (bake_light.size() && children_found) { float divisor = Math::lerp(8, children_found, propagation); for (int j = 0; j < 6; j++) { - bake_light[p_idx].accum[j][0] /= divisor; - bake_light[p_idx].accum[j][1] /= divisor; - bake_light[p_idx].accum[j][2] /= divisor; + bake_light.write[p_idx].accum[j][0] /= divisor; + bake_light.write[p_idx].accum[j][1] /= divisor; + bake_light.write[p_idx].accum[j][2] /= divisor; } - bake_cells[p_idx].emission[0] /= divisor; - bake_cells[p_idx].emission[1] /= divisor; - bake_cells[p_idx].emission[2] /= divisor; + bake_cells.write[p_idx].emission[0] /= divisor; + bake_cells.write[p_idx].emission[1] /= divisor; + bake_cells.write[p_idx].emission[2] /= divisor; } } } @@ -2403,25 +2403,25 @@ PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) { new_size++; demap.push_back(i); } - remap[i] = c; + remap.write[i] = c; } Vector<VoxelLightBakerOctree> octree; octree.resize(new_size); for (int i = 0; i < new_size; i++) { - octree[i].alpha = bake_cells[demap[i]].alpha; + octree.write[i].alpha = bake_cells[demap[i]].alpha; for (int j = 0; j < 6; j++) { for (int k = 0; k < 3; k++) { float l = bake_light[demap[i]].accum[j][k]; //add anisotropic light l += bake_cells[demap[i]].emission[k]; //add emission - octree[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree + octree.write[i].light[j][k] = CLAMP(l * 1024, 0, 65535); //give two more bits to octree } } for (int j = 0; j < 8; j++) { uint32_t child = bake_cells[demap[i]].children[j]; - octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; + octree.write[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child]; } } diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index bba25d64d9..3c93a0c8ec 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -24,7 +24,7 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_ for (int i = 0; i < triangles.size(); i++) { for (int j = 0; j < 3; j++) { if (triangles[i].points[j] >= p_at_index) { - triangles[i].points[j]++; + triangles.write[i].points[j]++; } } } @@ -81,7 +81,7 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { erase = true; break; } else if (triangles[i].points[j] > p_point) { - triangles[i].points[j]--; + triangles.write[i].points[j]--; } } if (erase) { @@ -264,9 +264,9 @@ Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const { t.resize(triangles.size() * 3); for (int i = 0; i < triangles.size(); i++) { - t[i * 3 + 0] = triangles[i].points[0]; - t[i * 3 + 1] = triangles[i].points[1]; - t[i * 3 + 2] = triangles[i].points[2]; + t.write[i * 3 + 0] = triangles[i].points[0]; + t.write[i * 3 + 1] = triangles[i].points[1]; + t.write[i * 3 + 2] = triangles[i].points[2]; } return t; } @@ -284,7 +284,7 @@ void AnimationNodeBlendSpace2D::_update_triangles() { Vector<Vector2> points; points.resize(blend_points_used); for (int i = 0; i < blend_points_used; i++) { - points[i] = blend_points[i].position; + points.write[i] = blend_points[i].position; } Vector<Delaunay2D::Triangle> triangles = Delaunay2D::triangulate(points); diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index 949a0be3bc..756907c41c 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -43,7 +43,7 @@ void AnimationCache::_node_exit_tree(Node *p_node) { if (path_cache[i].node != p_node) continue; - path_cache[i].valid = false; //invalidate path cache + path_cache.write[i].valid = false; //invalidate path cache } } @@ -196,7 +196,7 @@ void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform ERR_FAIL_COND(!cache_valid); ERR_FAIL_INDEX(p_idx, path_cache.size()); - Path &p = path_cache[p_idx]; + Path &p = path_cache.write[p_idx]; if (!p.valid) return; @@ -217,7 +217,7 @@ void AnimationCache::set_track_value(int p_idx, const Variant &p_value) { ERR_FAIL_COND(!cache_valid); ERR_FAIL_INDEX(p_idx, path_cache.size()); - Path &p = path_cache[p_idx]; + Path &p = path_cache.write[p_idx]; if (!p.valid) return; @@ -232,7 +232,7 @@ void AnimationCache::call_track(int p_idx, const StringName &p_method, const Var ERR_FAIL_COND(!cache_valid); ERR_FAIL_INDEX(p_idx, path_cache.size()); - Path &p = path_cache[p_idx]; + Path &p = path_cache.write[p_idx]; if (!p.valid) return; @@ -297,11 +297,11 @@ void AnimationCache::set_all(float p_time, float p_delta) { call_track(i, name, NULL, 0, err); } else { - Vector<Variant *> argptrs; + Vector<const Variant *> argptrs; argptrs.resize(args.size()); for (int j = 0; j < args.size(); j++) { - argptrs[j] = &args[j]; + argptrs.write[j] = &args.write[j]; } call_track(i, name, (const Variant **)&argptrs[0], args.size(), err); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 36587a1e91..f478112a36 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -169,11 +169,11 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri for (int i = 0; i < transitions.size(); i++) { if (transitions[i].from == p_name) { - transitions[i].from = p_new_name; + transitions.write[i].from = p_new_name; } if (transitions[i].to == p_name) { - transitions[i].to = p_new_name; + transitions.write[i].to = p_new_name; } } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 111620dac1..2782354432 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -233,7 +233,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { for (int i = 0; i < a->get_track_count(); i++) { - p_anim->node_cache[i] = NULL; + p_anim->node_cache.write[i] = NULL; RES resource; Vector<StringName> leftover_path; Node *child = parent->get_node_and_resource(a->track_get_path(i), resource, leftover_path); @@ -265,12 +265,12 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { if (node_cache_map.has(key)) { - p_anim->node_cache[i] = &node_cache_map[key]; + p_anim->node_cache.write[i] = &node_cache_map[key]; } else { node_cache_map[key] = TrackNodeCache(); - p_anim->node_cache[i] = &node_cache_map[key]; + p_anim->node_cache.write[i] = &node_cache_map[key]; p_anim->node_cache[i]->path = a->track_get_path(i); p_anim->node_cache[i]->node = child; p_anim->node_cache[i]->resource = resource; @@ -331,11 +331,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { if (!p_anim->node_cache[i]->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) { TrackNodeCache::BezierAnim ba; - String path = leftover_path[leftover_path.size() - 1]; - Vector<String> index = path.split("."); - for (int j = 0; j < index.size(); j++) { - ba.bezier_property.push_back(index[j]); - } + ba.bezier_property = leftover_path; ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child; ba.owner = p_anim->node_cache[i]; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 4fa66e8ede..de9f82dadc 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -78,9 +78,9 @@ float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p return 0; } - inputs[p_input].last_pass = state->last_pass; + inputs.write[p_input].last_pass = state->last_pass; - return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs[p_input].activity); + return _blend_node(node, p_time, p_seek, p_blend, p_filter, p_optimize, &inputs.write[p_input].activity); } float AnimationNode::blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { @@ -221,7 +221,7 @@ StringName AnimationNode::get_input_connection(int p_input) { void AnimationNode::set_input_connection(int p_input, const StringName &p_connection) { ERR_FAIL_INDEX(p_input, inputs.size()); - inputs[p_input].connected_to = p_connection; + inputs.write[p_input].connected_to = p_connection; } String AnimationNode::get_caption() const { @@ -248,7 +248,7 @@ void AnimationNode::add_input(const String &p_name) { void AnimationNode::set_input_name(int p_input, const String &p_name) { ERR_FAIL_INDEX(p_input, inputs.size()); ERR_FAIL_COND(p_name.find(".") != -1 || p_name.find("/") != -1); - inputs[p_input].name = p_name; + inputs.write[p_input].name = p_name; emit_changed(); } diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 026215508b..179f5d9698 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -1152,7 +1152,7 @@ void AnimationTreePlayer::transition_node_set_input_auto_advance(const StringNam GET_NODE(NODE_TRANSITION, TransitionNode); ERR_FAIL_INDEX(p_input, n->input_data.size()); - n->input_data[p_input].auto_advance = p_auto_advance; + n->input_data.write[p_input].auto_advance = p_auto_advance; } void AnimationTreePlayer::transition_node_set_xfade_time(const StringName &p_node, float p_time) { @@ -1365,7 +1365,7 @@ void AnimationTreePlayer::remove_node(const StringName &p_node) { for (int i = 0; i < nb->inputs.size(); i++) { if (nb->inputs[i].node == p_node) - nb->inputs[i].node = StringName(); + nb->inputs.write[i].node = StringName(); } } @@ -1426,11 +1426,11 @@ Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const Str for (int i = 0; i < nb->inputs.size(); i++) { if (nb->inputs[i].node == p_src_node) - nb->inputs[i].node = StringName(); + nb->inputs.write[i].node = StringName(); } } - dst->inputs[p_dst_input].node = p_src_node; + dst->inputs.write[p_dst_input].node = p_src_node; _clear_cycle_test(); @@ -1463,7 +1463,7 @@ void AnimationTreePlayer::disconnect_nodes(const StringName &p_node, int p_input NodeBase *dst = node_map[p_node]; ERR_FAIL_INDEX(p_input, dst->inputs.size()); - dst->inputs[p_input].node = StringName(); + dst->inputs.write[p_input].node = StringName(); last_error = CONNECT_INCOMPLETE; dirty_caches = true; } @@ -1703,7 +1703,7 @@ Error AnimationTreePlayer::node_rename(const StringName &p_node, const StringNam for (int i = 0; i < nb->inputs.size(); i++) { if (nb->inputs[i].node == p_node) { - nb->inputs[i].node = p_new_name; + nb->inputs.write[i].node = p_new_name; } } } diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 9f7503577b..81fdc32788 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -150,7 +150,7 @@ void Tween::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { - if (!processing) { + if (!is_active()) { //make sure that a previous process state was not saved //only process if "processing" is set set_physics_process_internal(false); @@ -164,7 +164,7 @@ void Tween::_notification(int p_what) { if (tween_process_mode == TWEEN_PROCESS_PHYSICS) break; - if (processing) + if (is_active()) _tween_process(get_process_delta_time()); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -172,7 +172,7 @@ void Tween::_notification(int p_what) { if (tween_process_mode == TWEEN_PROCESS_IDLE) break; - if (processing) + if (is_active()) _tween_process(get_physics_process_delta_time()); } break; case NOTIFICATION_EXIT_TREE: { @@ -201,7 +201,6 @@ void Tween::_bind_methods() { ClassDB::bind_method(D_METHOD("reset_all"), &Tween::reset_all); ClassDB::bind_method(D_METHOD("stop", "object", "key"), &Tween::stop, DEFVAL("")); ClassDB::bind_method(D_METHOD("stop_all"), &Tween::stop_all); - ClassDB::bind_method(D_METHOD("is_stopped"), &Tween::is_stopped); ClassDB::bind_method(D_METHOD("resume", "object", "key"), &Tween::resume, DEFVAL("")); ClassDB::bind_method(D_METHOD("resume_all"), &Tween::resume_all); ClassDB::bind_method(D_METHOD("remove", "object", "key"), &Tween::remove, DEFVAL("")); @@ -522,8 +521,8 @@ void Tween::_tween_process(float p_delta) { pending_update++; // if repeat and all interpolates was finished then reset all interpolates + bool all_finished = true; if (repeat) { - bool all_finished = true; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -539,9 +538,12 @@ void Tween::_tween_process(float p_delta) { reset_all(); } + all_finished = true; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { InterpolateData &data = E->get(); + all_finished = all_finished && data.finish; + if (!data.active || data.finish) continue; @@ -555,8 +557,8 @@ void Tween::_tween_process(float p_delta) { continue; else if (prev_delaying) { - emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false)); _apply_tween_value(data, data.initial_val); + emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false)); } if (data.elapsed > (data.delay + data.duration)) { @@ -603,32 +605,29 @@ void Tween::_tween_process(float p_delta) { } } else { Variant result = _run_equation(data); - emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result); _apply_tween_value(data, result); + emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result); } if (data.finish) { _apply_tween_value(data, data.final_val); + data.elapsed = 0; emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false)); // not repeat mode, remove completed action if (!repeat) call_deferred("_remove", object, NodePath(Vector<StringName>(), data.key, false), true); - } + } else if (!repeat) + all_finished = all_finished && data.finish; } pending_update--; + + if (all_finished) + set_active(false); } void Tween::set_tween_process_mode(TweenProcessMode p_mode) { - if (tween_process_mode == p_mode) - return; - - bool pr = processing; - if (pr) - _set_process(false); tween_process_mode = p_mode; - if (pr) - _set_process(true); } Tween::TweenProcessMode Tween::get_tween_process_mode() const { @@ -636,32 +635,21 @@ Tween::TweenProcessMode Tween::get_tween_process_mode() const { return tween_process_mode; } -void Tween::_set_process(bool p_process, bool p_force) { - - if (processing == p_process && !p_force) - return; - - switch (tween_process_mode) { - - case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_process && active); break; - case TWEEN_PROCESS_IDLE: set_process_internal(p_process && active); break; - } - - processing = p_process; -} - bool Tween::is_active() const { - return active; + return is_processing_internal() || is_physics_processing_internal(); } void Tween::set_active(bool p_active) { - if (active == p_active) + if (is_active() == p_active) return; - active = p_active; - _set_process(processing, true); + switch (tween_process_mode) { + + case TWEEN_PROCESS_IDLE: set_process_internal(p_active); break; + case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_active); break; + } } bool Tween::is_repeat() const { @@ -687,7 +675,6 @@ float Tween::get_speed_scale() const { bool Tween::start() { set_active(true); - _set_process(true); return true; } @@ -744,14 +731,9 @@ bool Tween::stop(Object *p_object, StringName p_key) { return true; } -bool Tween::is_stopped() const { - return tell() >= get_runtime(); -} - bool Tween::stop_all() { set_active(false); - _set_process(false); pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -766,7 +748,6 @@ bool Tween::stop_all() { bool Tween::resume(Object *p_object, StringName p_key) { set_active(true); - _set_process(true); pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -785,7 +766,6 @@ bool Tween::resume(Object *p_object, StringName p_key) { bool Tween::resume_all() { set_active(true); - _set_process(true); pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -834,7 +814,6 @@ bool Tween::remove_all() { return true; } set_active(false); - _set_process(false); interpolates.clear(); return true; } @@ -1425,8 +1404,6 @@ Tween::Tween() { //String autoplay; tween_process_mode = TWEEN_PROCESS_IDLE; - processing = false; - active = false; repeat = false; speed_scale = 1; pending_update = 0; diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 36094bf294..9997349c64 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -104,8 +104,6 @@ private: String autoplay; TweenProcessMode tween_process_mode; - bool processing; - bool active; bool repeat; float speed_scale; mutable int pending_update; @@ -133,7 +131,6 @@ private: bool _apply_tween_value(InterpolateData &p_data, Variant &value); void _tween_process(float p_delta); - void _set_process(bool p_process, bool p_force = false); void _remove(Object *p_object, StringName p_key, bool first_only); protected: @@ -162,7 +159,6 @@ public: bool reset_all(); bool stop(Object *p_object, StringName p_key); bool stop_all(); - bool is_stopped() const; bool resume(Object *p_object, StringName p_key); bool resume_all(); bool remove(Object *p_object, StringName p_key); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 068af42260..12aeed1520 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2188,10 +2188,17 @@ void Control::set_tooltip(const String &p_tooltip) { data.tooltip = p_tooltip; } + String Control::get_tooltip(const Point2 &p_pos) const { return data.tooltip; } +Control *Control::make_custom_tooltip(const String &p_text) const { + if (get_script_instance()) { + return const_cast<Control *>(this)->call("_make_custom_tooltip", p_text); + } + return NULL; +} void Control::set_default_cursor_shape(CursorShape p_shape) { @@ -2820,6 +2827,7 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_drag_data", PropertyInfo(Variant::VECTOR2, "position"))); BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); + BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text"))); ADD_GROUP("Anchor", "anchor_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.01"), "_set_anchor", "get_anchor", MARGIN_LEFT); @@ -2964,7 +2972,6 @@ Control::Control() { data.SI = NULL; data.MI = NULL; data.RI = NULL; - data.modal = false; data.theme_owner = NULL; data.modal_exclusive = false; data.default_cursor = CURSOR_ARROW; diff --git a/scene/gui/control.h b/scene/gui/control.h index fa5274d854..6bea04345b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -182,7 +182,6 @@ private: Control *parent; ObjectID drag_owner; - bool modal; bool modal_exclusive; uint64_t modal_frame; //frame used to put something as modal Ref<Theme> theme; @@ -454,6 +453,7 @@ public: void set_tooltip(const String &p_tooltip); virtual String get_tooltip(const Point2 &p_pos) const; + virtual Control *make_custom_tooltip(const String &p_text) const; /* CURSOR */ diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index b5622604e2..749efe8364 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -256,7 +256,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) { if (!valid) return; - points[grabbed].offset = newofs; + points.write[grabbed].offset = newofs; points.sort(); for (int i = 0; i < points.size(); i++) { @@ -407,7 +407,7 @@ void GradientEdit::_color_changed(const Color &p_color) { if (grabbed == -1) return; - points[grabbed].color = p_color; + points.write[grabbed].color = p_color; update(); emit_signal("ramp_changed"); } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index e2c730a56e..d95ec9e495 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -268,6 +268,10 @@ void GraphEdit::remove_child_notify(Node *p_child) { void GraphEdit::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal"); + port_grab_distance_vertical = get_constant("port_grab_distance_vertical"); + } if (p_what == NOTIFICATION_READY) { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); @@ -343,8 +347,6 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { Ref<Texture> port = get_icon("port", "GraphNode"); - float grab_r_extend = 2.0; - float grab_r = port->get_width() * 0.5 * grab_r_extend; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); @@ -354,14 +356,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); - if (pos.distance_to(p_point) < grab_r) + if (create_hot_zone(pos).has_point(p_point)) return true; } for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); - if (pos.distance_to(p_point) < grab_r) { + if (create_hot_zone(pos).has_point(p_point)) { return true; } } @@ -372,13 +374,11 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { - float grab_r_extend = 2.0; Ref<InputEventMouseButton> mb = p_ev; if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { Ref<Texture> port = get_icon("port", "GraphNode"); Vector2 mpos(mb->get_position().x, mb->get_position().y); - float grab_r = port->get_width() * 0.5 * grab_r_extend; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); @@ -388,7 +388,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); - if (pos.distance_to(mpos) < grab_r) { + if (create_hot_zone(pos).has_point(mpos)) { if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { //check disconnect @@ -435,8 +435,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); - - if (pos.distance_to(mpos) < grab_r) { + if (create_hot_zone(pos).has_point(mpos)) { if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { //check disconnect @@ -492,7 +491,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Ref<Texture> port = get_icon("port", "GraphNode"); Vector2 mpos = mm->get_position(); - float grab_r = port->get_width() * 0.5 * grab_r_extend; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); @@ -504,7 +502,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); int type = gn->get_connection_output_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && pos.distance_to(mpos) < grab_r) { + if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) { connecting_target = true; connecting_to = pos; @@ -519,7 +517,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); int type = gn->get_connection_input_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && pos.distance_to(mpos) < grab_r) { + if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -559,6 +557,10 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } } +Rect2 GraphEdit::create_hot_zone(const Vector2 &pos) { + return Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2); +} + template <class Vector2> static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) { /* Formula from Wikipedia article on Bezier curves. */ diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 14789001e4..64ba18681e 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -81,6 +81,9 @@ private: HScrollBar *h_scroll; VScrollBar *v_scroll; + float port_grab_distance_horizontal; + float port_grab_distance_vertical; + bool connecting; String connecting_from; bool connecting_out; @@ -127,6 +130,9 @@ private: Control *connections_layer; GraphEditFilter *top_layer; void _top_layer_input(const Ref<InputEvent> &p_ev); + + Rect2 create_hot_zone(const Vector2 &pos); + void _top_layer_draw(); void _connections_layer_draw(); void _update_scroll_offset(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index aa52739b0a..5c79741682 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -72,7 +72,7 @@ void ItemList::set_item_text(int p_idx, const String &p_text) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].text = p_text; + items.write[p_idx].text = p_text; update(); shape_changed = true; } @@ -85,7 +85,7 @@ String ItemList::get_item_text(int p_idx) const { void ItemList::set_item_tooltip_enabled(int p_idx, const bool p_enabled) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].tooltip_enabled = p_enabled; + items.write[p_idx].tooltip_enabled = p_enabled; } bool ItemList::is_item_tooltip_enabled(int p_idx) const { @@ -97,7 +97,7 @@ void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].tooltip = p_tooltip; + items.write[p_idx].tooltip = p_tooltip; update(); shape_changed = true; } @@ -112,7 +112,7 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].icon = p_icon; + items.write[p_idx].icon = p_icon; update(); shape_changed = true; } @@ -128,7 +128,7 @@ void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].icon_region = p_region; + items.write[p_idx].icon_region = p_region; update(); shape_changed = true; } @@ -144,7 +144,7 @@ void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].icon_modulate = p_modulate; + items.write[p_idx].icon_modulate = p_modulate; update(); } @@ -159,7 +159,7 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].custom_bg = p_custom_bg_color; + items.write[p_idx].custom_bg = p_custom_bg_color; } Color ItemList::get_item_custom_bg_color(int p_idx) const { @@ -173,7 +173,7 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].custom_fg = p_custom_fg_color; + items.write[p_idx].custom_fg = p_custom_fg_color; } Color ItemList::get_item_custom_fg_color(int p_idx) const { @@ -187,7 +187,7 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture> &p_tag_icon) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].tag_icon = p_tag_icon; + items.write[p_idx].tag_icon = p_tag_icon; update(); shape_changed = true; } @@ -202,7 +202,7 @@ void ItemList::set_item_selectable(int p_idx, bool p_selectable) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].selectable = p_selectable; + items.write[p_idx].selectable = p_selectable; } bool ItemList::is_item_selectable(int p_idx) const { @@ -215,7 +215,7 @@ void ItemList::set_item_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].disabled = p_disabled; + items.write[p_idx].disabled = p_disabled; update(); } @@ -229,7 +229,7 @@ void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].metadata = p_metadata; + items.write[p_idx].metadata = p_metadata; update(); shape_changed = true; } @@ -250,7 +250,7 @@ void ItemList::select(int p_idx, bool p_single) { } for (int i = 0; i < items.size(); i++) { - items[i].selected = p_idx == i; + items.write[i].selected = p_idx == i; } current = p_idx; @@ -258,7 +258,7 @@ void ItemList::select(int p_idx, bool p_single) { } else { if (items[p_idx].selectable && !items[p_idx].disabled) { - items[p_idx].selected = true; + items.write[p_idx].selected = true; } } update(); @@ -268,10 +268,10 @@ void ItemList::unselect(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); if (select_mode != SELECT_MULTI) { - items[p_idx].selected = false; + items.write[p_idx].selected = false; current = -1; } else { - items[p_idx].selected = false; + items.write[p_idx].selected = false; } update(); } @@ -283,7 +283,7 @@ void ItemList::unselect_all() { for (int i = 0; i < items.size(); i++) { - items[i].selected = false; + items.write[i].selected = false; } current = -1; update(); @@ -869,8 +869,8 @@ void ItemList::_notification(int p_what) { // elements need to adapt to the selected size minsize.y += vseparation; minsize.x += hseparation; - items[i].rect_cache.size = minsize; - items[i].min_rect_cache.size = minsize; + items.write[i].rect_cache.size = minsize; + items.write[i].min_rect_cache.size = minsize; } int fit_size = size.x - bg->get_minimum_size().width - mw; @@ -897,8 +897,8 @@ void ItemList::_notification(int p_what) { } if (same_column_width) - items[i].rect_cache.size.x = max_column_width; - items[i].rect_cache.position = ofs; + items.write[i].rect_cache.size.x = max_column_width; + items.write[i].rect_cache.position = ofs; max_h = MAX(max_h, items[i].rect_cache.size.y); ofs.x += items[i].rect_cache.size.x + hseparation; col++; @@ -908,7 +908,7 @@ void ItemList::_notification(int p_what) { separators.push_back(ofs.y + max_h + vseparation / 2); for (int j = i; j >= 0 && col > 0; j--, col--) { - items[j].rect_cache.size.y = max_h; + items.write[j].rect_cache.size.y = max_h; } ofs.x = 0; @@ -919,7 +919,7 @@ void ItemList::_notification(int p_what) { } for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) { - items[j].rect_cache.size.y = max_h; + items.write[j].rect_cache.size.y = max_h; } if (all_fit) { @@ -1103,8 +1103,8 @@ void ItemList::_notification(int p_what) { int cs = j < ss ? font->get_char_size(items[i].text[j], items[i].text[j + 1]).x : 0; if (ofs + cs > max_len || j == ss) { - line_limit_cache[line] = j; - line_size_cache[line] = ofs; + line_limit_cache.write[line] = j; + line_size_cache.write[line] = ofs; line++; ofs = 0; if (line >= max_text_lines) diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 2356444ecb..0636accfee 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -43,7 +43,6 @@ class MenuButton : public Button { bool clicked; bool disable_shortcuts; PopupMenu *popup; - virtual void pressed(); void _unhandled_key_input(Ref<InputEvent> p_event); Array _get_items() const; @@ -55,6 +54,8 @@ protected: static void _bind_methods(); public: + virtual void pressed(); + PopupMenu *get_popup() const; void set_disable_shortcuts(bool p_disabled); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index ebec61ee6d..cd4ece0950 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -410,7 +410,7 @@ void PopupMenu::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { for (int i = 0; i < items.size(); i++) { - items[i].xl_text = tr(items[i].text); + items.write[i].xl_text = tr(items[i].text); } minimum_size_changed(); @@ -524,7 +524,7 @@ void PopupMenu::_notification(int p_what) { font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, i == mouse_over ? font_color_hover : font_color_accel); } - items[i]._ofs_cache = ofs.y; + items.write[i]._ofs_cache = ofs.y; ofs.y += h; } @@ -622,7 +622,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p_accel) { add_check_item(p_label, p_ID, p_accel); - items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } @@ -630,7 +630,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { add_icon_check_item(p_icon, p_label, p_ID, p_accel); - items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } @@ -702,7 +702,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { add_check_shortcut(p_shortcut, p_ID, p_global); - items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; + items.write[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); minimum_size_changed(); } @@ -724,8 +724,8 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int void PopupMenu::set_item_text(int p_idx, const String &p_text) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].text = p_text; - items[p_idx].xl_text = tr(p_text); + items.write[p_idx].text = p_text; + items.write[p_idx].xl_text = tr(p_text); update(); minimum_size_changed(); @@ -733,7 +733,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) { void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].icon = p_icon; + items.write[p_idx].icon = p_icon; update(); minimum_size_changed(); @@ -742,7 +742,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checked = p_checked; + items.write[p_idx].checked = p_checked; update(); minimum_size_changed(); @@ -750,7 +750,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { void PopupMenu::set_item_id(int p_idx, int p_ID) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].ID = p_ID; + items.write[p_idx].ID = p_ID; update(); minimum_size_changed(); @@ -759,7 +759,7 @@ void PopupMenu::set_item_id(int p_idx, int p_ID) { void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].accel = p_accel; + items.write[p_idx].accel = p_accel; update(); minimum_size_changed(); @@ -768,7 +768,7 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].metadata = p_meta; + items.write[p_idx].metadata = p_meta; update(); minimum_size_changed(); } @@ -776,7 +776,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].disabled = p_disabled; + items.write[p_idx].disabled = p_disabled; update(); minimum_size_changed(); } @@ -784,7 +784,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].submenu = p_submenu; + items.write[p_idx].submenu = p_submenu; update(); minimum_size_changed(); } @@ -792,7 +792,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { void PopupMenu::toggle_item_checked(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checked = !items[p_idx].checked; + items.write[p_idx].checked = !items[p_idx].checked; update(); minimum_size_changed(); } @@ -886,7 +886,7 @@ int PopupMenu::get_item_state(int p_idx) const { void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].separator = p_separator; + items.write[p_idx].separator = p_separator; update(); } @@ -898,21 +898,21 @@ bool PopupMenu::is_item_separator(int p_idx) const { void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; + items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; update(); } void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; + items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; update(); } void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].tooltip = p_tooltip; + items.write[p_idx].tooltip = p_tooltip; update(); } @@ -921,8 +921,8 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo if (items[p_idx].shortcut.is_valid()) { _unref_shortcut(items[p_idx].shortcut); } - items[p_idx].shortcut = p_shortcut; - items[p_idx].shortcut_is_global = p_global; + items.write[p_idx].shortcut = p_shortcut; + items.write[p_idx].shortcut_is_global = p_global; if (items[p_idx].shortcut.is_valid()) { _ref_shortcut(items[p_idx].shortcut); @@ -934,7 +934,7 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bo void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].h_ofs = p_offset; + items.write[p_idx].h_ofs = p_offset; update(); minimum_size_changed(); } @@ -942,14 +942,14 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { void PopupMenu::set_item_multistate(int p_idx, int p_state) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].state = p_state; + items.write[p_idx].state = p_state; update(); } void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); - items[p_idx].shortcut_is_disabled = p_disabled; + items.write[p_idx].shortcut_is_disabled = p_disabled; update(); } @@ -960,9 +960,9 @@ void PopupMenu::toggle_item_multistate(int p_idx) { return; } - ++items[p_idx].state; - if (items[p_idx].max_states <= items[p_idx].state) - items[p_idx].state = 0; + ++items.write[p_idx].state; + if (items.write[p_idx].max_states <= items[p_idx].state) + items.write[p_idx].state = 0; update(); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index ce2e3538da..a3748bf14c 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -149,7 +149,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & if (r_click_item) *r_click_item = NULL; } - Line &l = p_frame->lines[p_line]; + Line &l = p_frame->lines.write[p_line]; Item *it = l.from; int line_ofs = 0; @@ -535,9 +535,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int idx = 0; //set minimums to zero for (int i = 0; i < table->columns.size(); i++) { - table->columns[i].min_width = 0; - table->columns[i].max_width = 0; - table->columns[i].width = 0; + table->columns.write[i].min_width = 0; + table->columns.write[i].max_width = 0; + table->columns.write[i].width = 0; } //compute minimum width for each cell const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs; @@ -553,8 +553,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < frame->lines.size(); i++) { _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs); - table->columns[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); - table->columns[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width); + table->columns.write[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width); + table->columns.write[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width); } idx++; } @@ -568,16 +568,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & for (int i = 0; i < table->columns.size(); i++) { remaining_width -= table->columns[i].min_width; if (table->columns[i].max_width > table->columns[i].min_width) - table->columns[i].expand = true; + table->columns.write[i].expand = true; if (table->columns[i].expand) total_ratio += table->columns[i].expand_ratio; } //assign actual widths for (int i = 0; i < table->columns.size(); i++) { - table->columns[i].width = table->columns[i].min_width; + table->columns.write[i].width = table->columns[i].min_width; if (table->columns[i].expand) - table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; + table->columns.write[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; table->total_width += table->columns[i].width + hseparation; } @@ -592,7 +592,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int dif = table->columns[i].width - table->columns[i].max_width; if (dif > 0) { table_need_fit = true; - table->columns[i].width = table->columns[i].max_width; + table->columns.write[i].width = table->columns[i].max_width; table->total_width -= dif; total_ratio -= table->columns[i].expand_ratio; } @@ -606,7 +606,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & if (dif > 0) { int slice = table->columns[i].expand_ratio * remaining_width / total_ratio; int incr = MIN(dif, slice); - table->columns[i].width += incr; + table->columns.write[i].width += incr; table->total_width += incr; } } @@ -626,8 +626,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int ly = 0; _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs); - frame->lines[i].height_cache = ly; //actual height - frame->lines[i].height_accum_cache = ly; //actual height + frame->lines.write[i].height_cache = ly; //actual height + frame->lines.write[i].height_accum_cache = ly; //actual height } idx++; } @@ -669,7 +669,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & yofs += frame->lines[i].height_cache; if (p_mode == PROCESS_CACHE) { - frame->lines[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache; + frame->lines.write[i].height_accum_cache = offset.y + draw_ofs.y + frame->lines[i].height_cache; } } @@ -1253,6 +1253,9 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { //validate invalid lines Size2 size = get_size(); + if (fixed_width != -1) { + size.width = fixed_width; + } Rect2 text_rect = _get_text_rect(); Color font_color_shadow = get_color("font_color_shadow"); bool use_outline = get_constant("shadow_as_outline"); @@ -1264,11 +1267,11 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) { int y = 0; _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color(), font_color_shadow, use_outline, shadow_ofs); - p_frame->lines[i].height_cache = y; - p_frame->lines[i].height_accum_cache = y; + p_frame->lines.write[i].height_cache = y; + p_frame->lines.write[i].height_accum_cache = y; if (i > 0) - p_frame->lines[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache; + p_frame->lines.write[i].height_accum_cache += p_frame->lines[i - 1].height_accum_cache; } int total_height = 0; @@ -1343,7 +1346,7 @@ void RichTextLabel::add_text(const String &p_text) { _add_item(item, false); current_frame->lines.resize(current_frame->lines.size() + 1); if (item->type != ITEM_NEWLINE) - current_frame->lines[current_frame->lines.size() - 1].from = item; + current_frame->lines.write[current_frame->lines.size() - 1].from = item; _invalidate_current_line(current_frame); } @@ -1366,7 +1369,7 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) } if (current_frame->lines[current_frame->lines.size() - 1].from == NULL) { - current_frame->lines[current_frame->lines.size() - 1].from = p_item; + current_frame->lines.write[current_frame->lines.size() - 1].from = p_item; } p_item->line = current_frame->lines.size() - 1; @@ -1428,7 +1431,7 @@ bool RichTextLabel::remove_line(const int p_line) { _remove_item(current->subitems[lines], current->subitems[lines]->line, lines); if (p_line == 0) { - main->lines[0].from = main; + main->lines.write[0].from = main; } main->first_invalid_line = 0; @@ -1507,8 +1510,8 @@ void RichTextLabel::push_table(int p_columns) { item->columns.resize(p_columns); item->total_width = 0; for (int i = 0; i < item->columns.size(); i++) { - item->columns[i].expand = false; - item->columns[i].expand_ratio = 1; + item->columns.write[i].expand = false; + item->columns.write[i].expand_ratio = 1; } _add_item(item, true, true); } @@ -1518,8 +1521,8 @@ void RichTextLabel::set_table_column_expand(int p_column, bool p_expand, int p_r ERR_FAIL_COND(current->type != ITEM_TABLE); ItemTable *table = static_cast<ItemTable *>(current); ERR_FAIL_INDEX(p_column, table->columns.size()); - table->columns[p_column].expand = p_expand; - table->columns[p_column].expand_ratio = p_ratio; + table->columns.write[p_column].expand = p_expand; + table->columns.write[p_column].expand_ratio = p_ratio; } void RichTextLabel::push_cell() { @@ -1533,7 +1536,7 @@ void RichTextLabel::push_cell() { item->cell = true; item->parent_line = item->parent_frame->lines.size() - 1; item->lines.resize(1); - item->lines[0].from = NULL; + item->lines.write[0].from = NULL; item->first_invalid_line = 0; } @@ -2245,13 +2248,28 @@ int RichTextLabel::get_total_character_count() const { return tc; } +void RichTextLabel::set_fixed_size_to_width(int p_width) { + fixed_width = p_width; + minimum_size_changed(); +} + +Size2 RichTextLabel::get_minimum_size() const { + + if (fixed_width != -1) { + const_cast<RichTextLabel *>(this)->_validate_line_caches(main); + return Size2(fixed_width, const_cast<RichTextLabel *>(this)->get_content_height()); + } + + return Size2(); +} + RichTextLabel::RichTextLabel() { main = memnew(ItemFrame); main->index = 0; current = main; main->lines.resize(1); - main->lines[0].from = main; + main->lines.write[0].from = main; main->first_invalid_line = 0; current_frame = main; tab_size = 4; @@ -2287,6 +2305,7 @@ RichTextLabel::RichTextLabel() { percent_visible = 1; visible_line_count = 0; + fixed_width = -1; set_clip_contents(true); } diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index af368af46a..06e9b8efe3 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -293,6 +293,8 @@ private: void _update_all_lines(); + int fixed_width; + protected: void _notification(int p_what); @@ -368,6 +370,9 @@ public: void set_percent_visible(float p_percent); float get_percent_visible() const; + void set_fixed_size_to_width(int p_width); + virtual Size2 get_minimum_size() const; + RichTextLabel(); ~RichTextLabel(); }; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index b114264de1..50bd1d867c 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -286,7 +286,7 @@ void Tabs::_notification(int p_what) { for (int i = 0; i < tabs.size(); i++) { - tabs[i].ofs_cache = mw; + tabs.write[i].ofs_cache = mw; mw += get_tab_width(i); } @@ -314,7 +314,7 @@ void Tabs::_notification(int p_what) { if (i < offset) continue; - tabs[i].ofs_cache = w; + tabs.write[i].ofs_cache = w; int lsize = tabs[i].size_cache; @@ -379,7 +379,7 @@ void Tabs::_notification(int p_what) { rb->draw(ci, Point2i(w + style->get_margin(MARGIN_LEFT), rb_rect.position.y + style->get_margin(MARGIN_TOP))); w += rb->get_width(); - tabs[i].rb_rect = rb_rect; + tabs.write[i].rb_rect = rb_rect; } if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { @@ -403,7 +403,7 @@ void Tabs::_notification(int p_what) { cb->draw(ci, Point2i(w + style->get_margin(MARGIN_LEFT), cb_rect.position.y + style->get_margin(MARGIN_TOP))); w += cb->get_width(); - tabs[i].cb_rect = cb_rect; + tabs.write[i].cb_rect = cb_rect; } w += sb->get_margin(MARGIN_RIGHT); @@ -471,7 +471,7 @@ bool Tabs::get_offset_buttons_visible() const { void Tabs::set_tab_title(int p_tab, const String &p_title) { ERR_FAIL_INDEX(p_tab, tabs.size()); - tabs[p_tab].text = p_title; + tabs.write[p_tab].text = p_title; update(); minimum_size_changed(); } @@ -485,7 +485,7 @@ String Tabs::get_tab_title(int p_tab) const { void Tabs::set_tab_icon(int p_tab, const Ref<Texture> &p_icon) { ERR_FAIL_INDEX(p_tab, tabs.size()); - tabs[p_tab].icon = p_icon; + tabs.write[p_tab].icon = p_icon; update(); minimum_size_changed(); } @@ -499,7 +499,7 @@ Ref<Texture> Tabs::get_tab_icon(int p_tab) const { void Tabs::set_tab_disabled(int p_tab, bool p_disabled) { ERR_FAIL_INDEX(p_tab, tabs.size()); - tabs[p_tab].disabled = p_disabled; + tabs.write[p_tab].disabled = p_disabled; update(); } bool Tabs::get_tab_disabled(int p_tab) const { @@ -511,7 +511,7 @@ bool Tabs::get_tab_disabled(int p_tab) const { void Tabs::set_tab_right_button(int p_tab, const Ref<Texture> &p_right_button) { ERR_FAIL_INDEX(p_tab, tabs.size()); - tabs[p_tab].right_button = p_right_button; + tabs.write[p_tab].right_button = p_right_button; _update_cache(); update(); minimum_size_changed(); @@ -536,9 +536,9 @@ void Tabs::_update_cache() { int size_fixed = 0; int count_resize = 0; for (int i = 0; i < tabs.size(); i++) { - tabs[i].ofs_cache = mw; - tabs[i].size_cache = get_tab_width(i); - tabs[i].size_text = font->get_string_size(tabs[i].text).width; + tabs.write[i].ofs_cache = mw; + tabs.write[i].size_cache = get_tab_width(i); + tabs.write[i].size_text = font->get_string_size(tabs[i].text).width; mw += tabs[i].size_cache; if (tabs[i].size_cache <= min_width || i == current) { size_fixed += tabs[i].size_cache; @@ -579,9 +579,9 @@ void Tabs::_update_cache() { lsize = m_width; } } - tabs[i].ofs_cache = w; - tabs[i].size_cache = lsize; - tabs[i].size_text = slen; + tabs.write[i].ofs_cache = w; + tabs.write[i].size_cache = lsize; + tabs.write[i].size_text = slen; w += lsize; } } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 218b5060a1..8926c1ec00 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -127,13 +127,13 @@ void TextEdit::Text::_update_line_cache(int p_line) const { w += get_char_width(str[i], str[i + 1], w); } - text[p_line].width_cache = w; + text.write[p_line].width_cache = w; - text[p_line].wrap_amount_cache = -1; + text.write[p_line].wrap_amount_cache = -1; //update regions - text[p_line].region_info.clear(); + text.write[p_line].region_info.clear(); for (int i = 0; i < len; i++) { @@ -172,7 +172,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const { ColorRegionInfo cri; cri.end = false; cri.region = j; - text[p_line].region_info[i] = cri; + text.write[p_line].region_info[i] = cri; i += lr - 1; break; @@ -200,7 +200,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const { ColorRegionInfo cri; cri.end = true; cri.region = j; - text[p_line].region_info[i] = cri; + text.write[p_line].region_info[i] = cri; i += lr - 1; break; @@ -236,7 +236,7 @@ void TextEdit::Text::set_line_wrap_amount(int p_line, int p_wrap_amount) const { ERR_FAIL_INDEX(p_line, text.size()); - text[p_line].wrap_amount_cache = p_wrap_amount; + text.write[p_line].wrap_amount_cache = p_wrap_amount; } int TextEdit::Text::get_line_wrap_amount(int p_line) const { @@ -249,14 +249,14 @@ int TextEdit::Text::get_line_wrap_amount(int p_line) const { void TextEdit::Text::clear_width_cache() { for (int i = 0; i < text.size(); i++) { - text[i].width_cache = -1; + text.write[i].width_cache = -1; } } void TextEdit::Text::clear_wrap_cache() { for (int i = 0; i < text.size(); i++) { - text[i].wrap_amount_cache = -1; + text.write[i].wrap_amount_cache = -1; } } @@ -281,15 +281,16 @@ void TextEdit::Text::set(int p_line, const String &p_text) { ERR_FAIL_INDEX(p_line, text.size()); - text[p_line].width_cache = -1; - text[p_line].wrap_amount_cache = -1; - text[p_line].data = p_text; + text.write[p_line].width_cache = -1; + text.write[p_line].wrap_amount_cache = -1; + text.write[p_line].data = p_text; } void TextEdit::Text::insert(int p_at, const String &p_text) { Line line; line.marked = false; + line.safe = false; line.breakpoint = false; line.hidden = false; line.width_cache = -1; @@ -336,10 +337,6 @@ void TextEdit::_update_scrollbars() { int hscroll_rows = ((hmin.height - 1) / get_row_height()) + 1; int visible_rows = get_visible_rows(); - int first_vis_line = get_first_visible_line(); - int wi; - int num_rows = MAX(visible_rows, num_lines_from_rows(first_vis_line, cursor.wrap_ofs, visible_rows, wi)); - int total_rows = get_total_visible_rows(); if (scroll_past_end_of_file_enabled) { total_rows += visible_rows - 1; @@ -972,7 +969,7 @@ void TextEdit::_notification(int p_what) { fc = line_num_padding + fc; } - cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, cache.line_number_color); + cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, yofs + cache.font->get_ascent()), fc, text.is_safe(line) ? cache.safe_line_number_color : cache.line_number_color); } } @@ -1672,7 +1669,6 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co rows /= get_row_height(); rows += get_v_scroll_offset(); int first_vis_line = get_first_visible_line(); - int last_vis_line = get_last_visible_line(); int row = first_vis_line + Math::floor(rows); int wrap_index = 0; @@ -3799,7 +3795,6 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { } // line ends before hit wrap_at; add this word to the substring wrap_substring += word_str; - px += word_px; lines.push_back(wrap_substring); return lines; } @@ -4314,6 +4309,7 @@ void TextEdit::_update_caches() { cache.caret_color = get_color("caret_color"); cache.caret_background_color = get_color("caret_background_color"); cache.line_number_color = get_color("line_number_color"); + cache.safe_line_number_color = get_color("safe_line_number_color"); cache.font_color = get_color("font_color"); cache.font_selected_color = get_color("font_selected_color"); cache.keyword_color = get_color("keyword_color"); @@ -4885,6 +4881,17 @@ void TextEdit::set_line_as_marked(int p_line, bool p_marked) { update(); } +void TextEdit::set_line_as_safe(int p_line, bool p_safe) { + ERR_FAIL_INDEX(p_line, text.size()); + text.set_safe(p_line, p_safe); + update(); +} + +bool TextEdit::is_line_set_as_safe(int p_line) const { + ERR_FAIL_INDEX_V(p_line, text.size(), false); + return text.is_safe(p_line); +} + bool TextEdit::is_line_set_as_breakpoint(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), false); @@ -5506,9 +5513,8 @@ int TextEdit::get_last_visible_line() const { int TextEdit::get_last_visible_line_wrap_index() const { int first_vis_line = get_first_visible_line(); - int last_vis_line = 0; int wi; - last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1; + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi); return wi; } @@ -5723,7 +5729,7 @@ void TextEdit::_update_completion_candidates() { for (int i = 0; i < completion_strings.size(); i++) { if (single_quote && completion_strings[i].is_quoted()) { - completion_strings[i] = completion_strings[i].unquote().quote("'"); + completion_strings.write[i] = completion_strings[i].unquote().quote("'"); } if (s == completion_strings[i]) { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 586f4c8e93..19b5d574c6 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -76,6 +76,7 @@ public: bool marked : 1; bool breakpoint : 1; bool hidden : 1; + bool safe : 1; int wrap_amount_cache : 24; Map<int, ColorRegionInfo> region_info; String data; @@ -100,12 +101,14 @@ public: int get_line_wrap_amount(int p_line) const; const Map<int, ColorRegionInfo> &get_color_region_info(int p_line) const; void set(int p_line, const String &p_text); - void set_marked(int p_line, bool p_marked) { text[p_line].marked = p_marked; } + void set_marked(int p_line, bool p_marked) { text.write[p_line].marked = p_marked; } bool is_marked(int p_line) const { return text[p_line].marked; } - void set_breakpoint(int p_line, bool p_breakpoint) { text[p_line].breakpoint = p_breakpoint; } + void set_breakpoint(int p_line, bool p_breakpoint) { text.write[p_line].breakpoint = p_breakpoint; } bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; } - void set_hidden(int p_line, bool p_hidden) { text[p_line].hidden = p_hidden; } + void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; } bool is_hidden(int p_line) const { return text[p_line].hidden; } + void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; } + bool is_safe(int p_line) const { return text[p_line].safe; } void insert(int p_at, const String &p_text); void remove(int p_at); int size() const { return text.size(); } @@ -165,6 +168,7 @@ private: Color caret_color; Color caret_background_color; Color line_number_color; + Color safe_line_number_color; Color font_color; Color font_selected_color; Color keyword_color; @@ -472,6 +476,8 @@ public: void set_line_as_marked(int p_line, bool p_marked); void set_line_as_breakpoint(int p_line, bool p_breakpoint); bool is_line_set_as_breakpoint(int p_line) const; + void set_line_as_safe(int p_line, bool p_safe); + bool is_line_set_as_safe(int p_line) const; void get_breakpoints(List<int> *p_breakpoints) const; Array get_breakpoints_array() const; void remove_breakpoints(); diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp index 82d983184b..6e4fe88dbf 100644 --- a/scene/gui/texture_progress.cpp +++ b/scene/gui/texture_progress.cpp @@ -309,15 +309,23 @@ void TextureProgress::_notification(int p_what) { draw_texture_rect_region(progress, region, region, tint_progress); } break; case FILL_CLOCKWISE: - case FILL_COUNTER_CLOCKWISE: { + case FILL_COUNTER_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { Rect2 region = Rect2(Point2(), s); draw_texture_rect_region(progress, region, region, tint_progress); } else if (val != 0) { Array pts; - float direction = mode == FILL_CLOCKWISE ? 1 : -1; - float start = rad_init_angle / 360; + float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1; + float start; + + if (mode == FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE) { + start = rad_init_angle / 360 - val / 2; + } else { + start = rad_init_angle / 360; + } + float end = start + direction * val; pts.append(start); pts.append(end); @@ -351,6 +359,14 @@ void TextureProgress::_notification(int p_what) { draw_line(p - Point2(0, 8), p + Point2(0, 8), Color(0.9, 0.5, 0.5), 2); } } break; + case FILL_BILINEAR_LEFT_AND_RIGHT: { + Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y)); + draw_texture_rect_region(progress, region, region, tint_progress); + } break; + case FILL_BILINEAR_TOP_AND_BOTTOM: { + Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); + draw_texture_rect_region(progress, region, region, tint_progress); + } break; default: draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); } @@ -364,7 +380,7 @@ void TextureProgress::_notification(int p_what) { } void TextureProgress::set_fill_mode(int p_fill) { - ERR_FAIL_INDEX(p_fill, 6); + ERR_FAIL_INDEX(p_fill, 9); mode = (FillMode)p_fill; update(); } @@ -446,7 +462,7 @@ void TextureProgress::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_under_texture", "get_under_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_over_texture", "get_over_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_progress_texture", "get_progress_texture"); - ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise"), "set_fill_mode", "get_fill_mode"); + ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode"); ADD_GROUP("Tint", "tint_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_under", "get_tint_under"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_over", "get_tint_over"); @@ -468,6 +484,9 @@ void TextureProgress::_bind_methods() { BIND_ENUM_CONSTANT(FILL_BOTTOM_TO_TOP); BIND_ENUM_CONSTANT(FILL_CLOCKWISE); BIND_ENUM_CONSTANT(FILL_COUNTER_CLOCKWISE); + BIND_ENUM_CONSTANT(FILL_BILINEAR_LEFT_AND_RIGHT); + BIND_ENUM_CONSTANT(FILL_BILINEAR_TOP_AND_BOTTOM); + BIND_ENUM_CONSTANT(FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE); } TextureProgress::TextureProgress() { diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h index 34158b5db5..a11e55234a 100644 --- a/scene/gui/texture_progress.h +++ b/scene/gui/texture_progress.h @@ -52,7 +52,10 @@ public: FILL_TOP_TO_BOTTOM, FILL_BOTTOM_TO_TOP, FILL_CLOCKWISE, - FILL_COUNTER_CLOCKWISE + FILL_COUNTER_CLOCKWISE, + FILL_BILINEAR_LEFT_AND_RIGHT, + FILL_BILINEAR_TOP_AND_BOTTOM, + FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE }; void set_fill_mode(int p_fill); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 1d27612766..6f09488b64 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -121,7 +121,7 @@ void TreeItem::_cell_deselected(int p_cell) { void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) { ERR_FAIL_INDEX(p_column, cells.size()); - Cell &c = cells[p_column]; + Cell &c = cells.write[p_column]; c.mode = p_mode; c.min = 0; c.max = 100; @@ -144,7 +144,7 @@ TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const { void TreeItem::set_checked(int p_column, bool p_checked) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].checked = p_checked; + cells.write[p_column].checked = p_checked; _changed_notify(p_column); } @@ -157,22 +157,22 @@ bool TreeItem::is_checked(int p_column) const { void TreeItem::set_text(int p_column, String p_text) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].text = p_text; + cells.write[p_column].text = p_text; if (cells[p_column].mode == TreeItem::CELL_MODE_RANGE || cells[p_column].mode == TreeItem::CELL_MODE_RANGE_EXPRESSION) { Vector<String> strings = p_text.split(","); - cells[p_column].min = INT_MAX; - cells[p_column].max = INT_MIN; + cells.write[p_column].min = INT_MAX; + cells.write[p_column].max = INT_MIN; for (int i = 0; i < strings.size(); i++) { int value = i; if (!strings[i].get_slicec(':', 1).empty()) { value = strings[i].get_slicec(':', 1).to_int(); } - cells[p_column].min = MIN(cells[p_column].min, value); - cells[p_column].max = MAX(cells[p_column].max, value); + cells.write[p_column].min = MIN(cells[p_column].min, value); + cells.write[p_column].max = MAX(cells[p_column].max, value); } - cells[p_column].step = 0; + cells.write[p_column].step = 0; } _changed_notify(p_column); } @@ -186,7 +186,7 @@ String TreeItem::get_text(int p_column) const { void TreeItem::set_suffix(int p_column, String p_suffix) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].suffix = p_suffix; + cells.write[p_column].suffix = p_suffix; _changed_notify(p_column); } @@ -200,7 +200,7 @@ String TreeItem::get_suffix(int p_column) const { void TreeItem::set_icon(int p_column, const Ref<Texture> &p_icon) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].icon = p_icon; + cells.write[p_column].icon = p_icon; _changed_notify(p_column); } @@ -213,7 +213,7 @@ Ref<Texture> TreeItem::get_icon(int p_column) const { void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].icon_region = p_icon_region; + cells.write[p_column].icon_region = p_icon_region; _changed_notify(p_column); } @@ -226,7 +226,7 @@ Rect2 TreeItem::get_icon_region(int p_column) const { void TreeItem::set_icon_color(int p_column, const Color &p_icon_color) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].icon_color = p_icon_color; + cells.write[p_column].icon_color = p_icon_color; _changed_notify(p_column); } @@ -239,7 +239,7 @@ Color TreeItem::get_icon_color(int p_column) const { void TreeItem::set_icon_max_width(int p_column, int p_max) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].icon_max_w = p_max; + cells.write[p_column].icon_max_w = p_max; _changed_notify(p_column); } @@ -260,7 +260,7 @@ void TreeItem::set_range(int p_column, double p_value) { if (p_value > cells[p_column].max) p_value = cells[p_column].max; - cells[p_column].val = p_value; + cells.write[p_column].val = p_value; _changed_notify(p_column); } @@ -278,10 +278,10 @@ bool TreeItem::is_range_exponential(int p_column) const { void TreeItem::set_range_config(int p_column, double p_min, double p_max, double p_step, bool p_exp) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].min = p_min; - cells[p_column].max = p_max; - cells[p_column].step = p_step; - cells[p_column].expr = p_exp; + cells.write[p_column].min = p_min; + cells.write[p_column].max = p_max; + cells.write[p_column].step = p_step; + cells.write[p_column].expr = p_exp; _changed_notify(p_column); } @@ -296,7 +296,7 @@ void TreeItem::get_range_config(int p_column, double &r_min, double &r_max, doub void TreeItem::set_metadata(int p_column, const Variant &p_meta) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].meta = p_meta; + cells.write[p_column].meta = p_meta; } Variant TreeItem::get_metadata(int p_column) const { @@ -311,8 +311,8 @@ void TreeItem::set_custom_draw(int p_column, Object *p_object, const StringName ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_NULL(p_object); - cells[p_column].custom_draw_obj = p_object->get_instance_id(); - cells[p_column].custom_draw_callback = p_callback; + cells.write[p_column].custom_draw_obj = p_object->get_instance_id(); + cells.write[p_column].custom_draw_callback = p_callback; } void TreeItem::set_collapsed(bool p_collapsed) { @@ -467,7 +467,7 @@ void TreeItem::remove_child(TreeItem *p_item) { void TreeItem::set_selectable(int p_column, bool p_selectable) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].selectable = p_selectable; + cells.write[p_column].selectable = p_selectable; } bool TreeItem::is_selectable(int p_column) const { @@ -517,7 +517,7 @@ void TreeItem::add_button(int p_column, const Ref<Texture> &p_button, int p_id, button.id = p_id; button.disabled = p_disabled; button.tooltip = p_tooltip; - cells[p_column].buttons.push_back(button); + cells.write[p_column].buttons.push_back(button); _changed_notify(p_column); } @@ -540,7 +540,7 @@ void TreeItem::erase_button(int p_column, int p_idx) { ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); - cells[p_column].buttons.remove(p_idx); + cells.write[p_column].buttons.remove(p_idx); _changed_notify(p_column); } @@ -568,7 +568,7 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture> &p_button) ERR_FAIL_COND(p_button.is_null()); ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); - cells[p_column].buttons[p_idx].texture = p_button; + cells.write[p_column].buttons.write[p_idx].texture = p_button; _changed_notify(p_column); } @@ -576,14 +576,14 @@ void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) { ERR_FAIL_INDEX(p_column, cells.size()); ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); - cells[p_column].buttons[p_idx].color = p_color; + cells.write[p_column].buttons.write[p_idx].color = p_color; _changed_notify(p_column); } void TreeItem::set_editable(int p_column, bool p_editable) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].editable = p_editable; + cells.write[p_column].editable = p_editable; _changed_notify(p_column); } @@ -596,8 +596,8 @@ bool TreeItem::is_editable(int p_column) { void TreeItem::set_custom_color(int p_column, const Color &p_color) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].custom_color = true; - cells[p_column].color = p_color; + cells.write[p_column].custom_color = true; + cells.write[p_column].color = p_color; _changed_notify(p_column); } Color TreeItem::get_custom_color(int p_column) const { @@ -610,15 +610,15 @@ Color TreeItem::get_custom_color(int p_column) const { void TreeItem::clear_custom_color(int p_column) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].custom_color = false; - cells[p_column].color = Color(); + cells.write[p_column].custom_color = false; + cells.write[p_column].color = Color(); _changed_notify(p_column); } void TreeItem::set_tooltip(int p_column, const String &p_tooltip) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].tooltip = p_tooltip; + cells.write[p_column].tooltip = p_tooltip; } String TreeItem::get_tooltip(int p_column) const { @@ -630,17 +630,17 @@ String TreeItem::get_tooltip(int p_column) const { void TreeItem::set_custom_bg_color(int p_column, const Color &p_color, bool p_bg_outline) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].custom_bg_color = true; - cells[p_column].custom_bg_outline = p_bg_outline; - cells[p_column].bg_color = p_color; + cells.write[p_column].custom_bg_color = true; + cells.write[p_column].custom_bg_outline = p_bg_outline; + cells.write[p_column].bg_color = p_color; _changed_notify(p_column); } void TreeItem::clear_custom_bg_color(int p_column) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].custom_bg_color = false; - cells[p_column].bg_color = Color(); + cells.write[p_column].custom_bg_color = false; + cells.write[p_column].bg_color = Color(); _changed_notify(p_column); } @@ -655,7 +655,7 @@ Color TreeItem::get_custom_bg_color(int p_column) const { void TreeItem::set_custom_as_button(int p_column, bool p_button) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].custom_button = p_button; + cells.write[p_column].custom_button = p_button; } bool TreeItem::is_custom_set_as_button(int p_column) const { @@ -666,7 +666,7 @@ bool TreeItem::is_custom_set_as_button(int p_column) const { void TreeItem::set_text_align(int p_column, TextAlign p_align) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].text_align = p_align; + cells.write[p_column].text_align = p_align; _changed_notify(p_column); } @@ -678,7 +678,7 @@ TreeItem::TextAlign TreeItem::get_text_align(int p_column) const { void TreeItem::set_expand_right(int p_column, bool p_enable) { ERR_FAIL_INDEX(p_column, cells.size()); - cells[p_column].expand_right = p_enable; + cells.write[p_column].expand_right = p_enable; _changed_notify(p_column); } @@ -1486,7 +1486,7 @@ int Tree::_count_selected_items(TreeItem *p_from) const { } void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) { - TreeItem::Cell &selected_cell = p_selected->cells[p_col]; + TreeItem::Cell &selected_cell = p_selected->cells.write[p_col]; bool switched = false; if (r_in_range && !*r_in_range && (p_current == p_selected || p_current == p_prev)) { @@ -1498,7 +1498,7 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c for (int i = 0; i < columns.size(); i++) { - TreeItem::Cell &c = p_current->cells[i]; + TreeItem::Cell &c = p_current->cells.write[i]; if (!c.selectable) continue; @@ -1689,7 +1689,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool return -1; //collapse/uncollapse because nothing can be done with item } - TreeItem::Cell &c = p_item->cells[col]; + const TreeItem::Cell &c = p_item->cells[col]; bool already_selected = c.selected; bool already_cursor = (p_item == selected_item) && col == selected_col; @@ -1990,7 +1990,7 @@ void Tree::text_editor_enter(String p_text) { if (popup_edited_item_col < 0 || popup_edited_item_col > columns.size()) return; - TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col]; + TreeItem::Cell &c = popup_edited_item->cells.write[popup_edited_item_col]; switch (c.mode) { case TreeItem::CELL_MODE_STRING: { @@ -2041,7 +2041,7 @@ void Tree::value_editor_changed(double p_value) { return; } - TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col]; + TreeItem::Cell &c = popup_edited_item->cells.write[popup_edited_item_col]; c.val = p_value; item_edited(popup_edited_item_col, popup_edited_item); update(); @@ -2055,7 +2055,7 @@ void Tree::popup_select(int p_option) { if (popup_edited_item_col < 0 || popup_edited_item_col > columns.size()) return; - popup_edited_item->cells[popup_edited_item_col].val = p_option; + popup_edited_item->cells.write[popup_edited_item_col].val = p_option; //popup_edited_item->edited_signal.call( popup_edited_item_col ); update(); item_edited(popup_edited_item_col, popup_edited_item); @@ -2426,14 +2426,23 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { int col, h, section; TreeItem *it = _find_item_at_pos(root, mpos, col, h, section); - if ((drop_mode_flags && it != drop_mode_over) || section != drop_mode_section) { - drop_mode_over = it; - drop_mode_section = section; - update(); + if (drop_mode_flags) { + if (it != drop_mode_over) { + drop_mode_over = it; + update(); + } + if (it && section != drop_mode_section) { + drop_mode_section = section; + update(); + } } - if (it != cache.hover_item || col != cache.hover_cell) { + if (it != cache.hover_item) { cache.hover_item = it; + update(); + } + + if (it && col != cache.hover_cell) { cache.hover_cell = col; update(); } @@ -2458,7 +2467,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } else { - TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col]; + const TreeItem::Cell &c = popup_edited_item->cells[popup_edited_item_col]; float diff_y = -mm->get_relative().y; diff_y = Math::pow(ABS(diff_y), 1.8f) * SGN(diff_y); diff_y *= 0.1; @@ -2672,7 +2681,7 @@ bool Tree::edit_selected() { popup_edited_item = s; popup_edited_item_col = col; - TreeItem::Cell &c = s->cells[col]; + const TreeItem::Cell &c = s->cells[col]; if (c.mode == TreeItem::CELL_MODE_CHECK) { @@ -3063,7 +3072,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) { if (!p_item->cells[p_column].selectable) return; - p_item->cells[p_column].selected = true; + p_item->cells.write[p_column].selected = true; //emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select selected_col = p_column; @@ -3077,7 +3086,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) { void Tree::item_deselected(int p_column, TreeItem *p_item) { if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) { - p_item->cells[p_column].selected = false; + p_item->cells.write[p_column].selected = false; } update(); } @@ -3158,14 +3167,14 @@ void Tree::set_column_min_width(int p_column, int p_min_width) { if (p_min_width < 1) return; - columns[p_column].min_width = p_min_width; + columns.write[p_column].min_width = p_min_width; update(); } void Tree::set_column_expand(int p_column, bool p_expand) { ERR_FAIL_INDEX(p_column, columns.size()); - columns[p_column].expand = p_expand; + columns.write[p_column].expand = p_expand; update(); } @@ -3413,7 +3422,7 @@ bool Tree::are_column_titles_visible() const { void Tree::set_column_title(int p_column, const String &p_title) { ERR_FAIL_INDEX(p_column, columns.size()); - columns[p_column].title = p_title; + columns.write[p_column].title = p_title; update(); } @@ -3659,7 +3668,7 @@ String Tree::get_tooltip(const Point2 &p_pos) const { if (it) { - TreeItem::Cell &c = it->cells[col]; + const TreeItem::Cell &c = it->cells[col]; int col_width = get_column_width(col); for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture> b = c.buttons[j].texture; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e1333bcae2..b7b26d1c55 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -809,6 +809,22 @@ bool Node::is_processing_internal() const { return data.idle_process_internal; } +void Node::set_process_priority(int p_priority) { + data.process_priority = p_priority; + + if (is_processing()) + data.tree->make_group_changed("idle_process"); + + if (is_processing_internal()) + data.tree->make_group_changed("idle_process_internal"); + + if (is_physics_processing()) + data.tree->make_group_changed("physics_process"); + + if (is_physics_processing_internal()) + data.tree->make_group_changed("physics_process_internal"); +} + void Node::set_process_input(bool p_enable) { if (p_enable == data.input) @@ -1388,6 +1404,11 @@ bool Node::is_greater_than(const Node *p_node) const { return res; } +bool Node::has_priority_higher_than(const Node *p_node) const { + ERR_FAIL_NULL_V(p_node, false); + return data.process_priority > p_node->data.process_priority; +} + void Node::get_owned_by(Node *p_by, List<Node *> *p_owned) { if (data.owner == p_by) @@ -2608,6 +2629,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("is_physics_processing"), &Node::is_physics_processing); ClassDB::bind_method(D_METHOD("get_process_delta_time"), &Node::get_process_delta_time); ClassDB::bind_method(D_METHOD("set_process", "enable"), &Node::set_process); + ClassDB::bind_method(D_METHOD("set_process_priority", "priority"), &Node::set_process_priority); ClassDB::bind_method(D_METHOD("is_processing"), &Node::is_processing); ClassDB::bind_method(D_METHOD("set_process_input", "enable"), &Node::set_process_input); ClassDB::bind_method(D_METHOD("is_processing_input"), &Node::is_processing_input); @@ -2759,6 +2781,7 @@ Node::Node() { data.tree = NULL; data.physics_process = false; data.idle_process = false; + data.process_priority = 0; data.physics_process_internal = false; data.idle_process_internal = false; data.inside_tree = false; diff --git a/scene/main/node.h b/scene/main/node.h index 341349de79..4b8f584ba7 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -70,6 +70,11 @@ public: bool operator()(const Node *p_a, const Node *p_b) const { return p_b->is_greater_than(p_a); } }; + struct ComparatorWithPriority { + + bool operator()(const Node *p_a, const Node *p_b) const { return p_b->has_priority_higher_than(p_a) || p_b->is_greater_than(p_a); } + }; + private: struct GroupData { @@ -118,6 +123,7 @@ private: //should move all the stuff below to bits bool physics_process; bool idle_process; + int process_priority; bool physics_process_internal; bool idle_process_internal; @@ -259,6 +265,7 @@ public: bool is_a_parent_of(const Node *p_node) const; bool is_greater_than(const Node *p_node) const; + bool has_priority_higher_than(const Node *p_node) const; NodePath get_path() const; NodePath get_path_to(const Node *p_node) const; @@ -319,6 +326,8 @@ public: void set_process_internal(bool p_idle_process_internal); bool is_processing_internal() const; + void set_process_priority(int p_priority); + void set_process_input(bool p_enable); bool is_processing_input() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 6438616cf2..1b2e87dd99 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -132,6 +132,12 @@ void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) { group_map.erase(E); } +void SceneTree::make_group_changed(const StringName &p_group) { + Map<StringName, Group>::Element *E = group_map.find(p_group); + if (E) + E->get().changed = true; +} + void SceneTree::flush_transform_notifications() { SelfList<Node> *n = xform_change_list.first(); @@ -165,18 +171,23 @@ void SceneTree::_flush_ugc() { ugc_locked = false; } -void SceneTree::_update_group_order(Group &g) { +void SceneTree::_update_group_order(Group &g, bool p_use_priority) { if (!g.changed) return; if (g.nodes.empty()) return; - Node **nodes = &g.nodes[0]; + Node **nodes = g.nodes.ptrw(); int node_count = g.nodes.size(); - SortArray<Node *, Node::Comparator> node_sort; - node_sort.sort(nodes, node_count); + if (p_use_priority) { + SortArray<Node *, Node::ComparatorWithPriority> node_sort; + node_sort.sort(nodes, node_count); + } else { + SortArray<Node *, Node::Comparator> node_sort; + node_sort.sort(nodes, node_count); + } g.changed = false; } @@ -216,7 +227,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou _update_group_order(g); Vector<Node *> nodes_copy = g.nodes; - Node **nodes = &nodes_copy[0]; + Node **nodes = nodes_copy.ptrw(); int node_count = nodes_copy.size(); call_lock++; @@ -271,7 +282,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr _update_group_order(g); Vector<Node *> nodes_copy = g.nodes; - Node **nodes = &nodes_copy[0]; + Node **nodes = nodes_copy.ptrw(); int node_count = nodes_copy.size(); call_lock++; @@ -320,7 +331,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group _update_group_order(g); Vector<Node *> nodes_copy = g.nodes; - Node **nodes = &nodes_copy[0]; + Node **nodes = nodes_copy.ptrw(); int node_count = nodes_copy.size(); call_lock++; @@ -884,7 +895,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p Vector<Node *> nodes_copy = g.nodes; int node_count = nodes_copy.size(); - Node **nodes = &nodes_copy[0]; + Node **nodes = nodes_copy.ptrw(); Variant arg = p_input; const Variant *v[1] = { &arg }; @@ -921,14 +932,14 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio if (g.nodes.empty()) return; - _update_group_order(g); + _update_group_order(g, p_notification == Node::NOTIFICATION_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PROCESS || p_notification == Node::NOTIFICATION_PHYSICS_PROCESS || p_notification == Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); //copy, so copy on write happens in case something is removed from process while being called //performance is not lost because only if something is added/removed the vector is copied. Vector<Node *> nodes_copy = g.nodes; int node_count = nodes_copy.size(); - Node **nodes = &nodes_copy[0]; + Node **nodes = nodes_copy.ptrw(); call_lock++; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index aa8d78b1e1..11201097d4 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -161,7 +161,7 @@ private: bool ugc_locked; void _flush_ugc(); - _FORCE_INLINE_ void _update_group_order(Group &g); + _FORCE_INLINE_ void _update_group_order(Group &g, bool p_use_priority = false); void _update_listener(); Array _get_nodes_in_group(const StringName &p_group); @@ -204,6 +204,7 @@ private: Group *add_to_group(const StringName &p_group, Node *p_node); void remove_from_group(const StringName &p_group, Node *p_node); + void make_group_changed(const StringName &p_group); void _notify_group_pause(const StringName &p_group, int p_notification); void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 01302d4214..573c401290 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -41,7 +41,10 @@ #include "scene/3d/spatial.h" #include "scene/gui/control.h" #include "scene/gui/label.h" +#include "scene/gui/menu_button.h" #include "scene/gui/panel.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/popup_menu.h" #include "scene/main/timer.h" #include "scene/resources/mesh.h" #include "scene/scene_string_names.h" @@ -166,9 +169,9 @@ ViewportTexture::~ViewportTexture() { ///////////////////////////////////// -class TooltipPanel : public Panel { +class TooltipPanel : public PanelContainer { - GDCLASS(TooltipPanel, Panel) + GDCLASS(TooltipPanel, PanelContainer) public: TooltipPanel(){}; }; @@ -1305,10 +1308,11 @@ void Viewport::_gui_cancel_tooltip() { if (gui.tooltip_popup) { gui.tooltip_popup->queue_delete(); gui.tooltip_popup = NULL; + gui.tooltip_label = NULL; } } -String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos) { +String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) { Vector2 pos = p_pos; String tooltip; @@ -1317,6 +1321,10 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos) { tooltip = p_control->get_tooltip(pos); + if (r_which) { + *r_which = p_control; + } + if (tooltip != String()) break; pos = p_control->get_transform().xform(pos); @@ -1338,41 +1346,49 @@ void Viewport::_gui_show_tooltip() { return; } - String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos)); + Control *which = NULL; + String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which); if (tooltip.length() == 0) return; // bye if (gui.tooltip_popup) { memdelete(gui.tooltip_popup); gui.tooltip_popup = NULL; + gui.tooltip_label = NULL; } - if (!gui.tooltip) { + if (!which) { return; } - Control *rp = gui.tooltip->get_root_parent_control(); + Control *rp = which; //->get_root_parent_control(); if (!rp) return; - gui.tooltip_popup = memnew(TooltipPanel); + gui.tooltip_popup = which->make_custom_tooltip(tooltip); + + if (!gui.tooltip_popup) { + gui.tooltip_popup = memnew(TooltipPanel); + + gui.tooltip_label = memnew(TooltipLabel); + gui.tooltip_popup->add_child(gui.tooltip_label); + + Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel"); + + gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT)); + gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP)); + gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT)); + gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM)); + gui.tooltip_label->set_text(tooltip.strip_edges()); + } rp->add_child(gui.tooltip_popup); gui.tooltip_popup->force_parent_owned(); - gui.tooltip_label = memnew(TooltipLabel); - gui.tooltip_popup->add_child(gui.tooltip_label); gui.tooltip_popup->set_as_toplevel(true); - gui.tooltip_popup->hide(); + //gui.tooltip_popup->hide(); - Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel"); - - gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT)); - gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP)); - gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT)); - gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM)); - gui.tooltip_label->set_text(tooltip.strip_edges()); - Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_minimum_size() + ttp->get_minimum_size()); - Rect2 vr = gui.tooltip_label->get_viewport_rect(); + Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_popup->get_minimum_size()); + Rect2 vr = gui.tooltip_popup->get_viewport_rect(); if (r.size.x + r.position.x > vr.size.x) r.position.x = vr.size.x - r.size.x; else if (r.position.x < 0) @@ -1840,8 +1856,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) { Control *top = gui.modal_stack.back()->get(); + if (over != top && !top->is_a_parent_of(over)) { - over = NULL; //nothing can be found outside the modal stack + + PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top); + MenuButton *popup_menu_parent; + MenuButton *menu_button = Object::cast_to<MenuButton>(over); + + if (popup_menu) + popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent()); + + // If the mouse is over a menu button, this menu will open automatically + // if there is already a pop-up menu open at the same hierarchical level. + if (popup_menu_parent && menu_button && + popup_menu_parent->get_icon().is_null() && + menu_button->get_icon().is_null() && + (popup_menu->get_parent()->get_parent()->is_a_parent_of(menu_button) || + menu_button->get_parent()->is_a_parent_of(popup_menu))) { + + popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE); + popup_menu->_modal_stack_remove(); + popup_menu->hide(); + + menu_button->pressed(); + } else { + over = NULL; //nothing can be found outside the modal stack + } } } @@ -1891,13 +1931,18 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { bool is_tooltip_shown = false; if (gui.tooltip_popup) { - if (can_tooltip) { + if (can_tooltip && gui.tooltip) { String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos)); if (tooltip.length() == 0) _gui_cancel_tooltip(); - else if (tooltip == gui.tooltip_label->get_text()) + else if (gui.tooltip_label) { + if (tooltip == gui.tooltip_label->get_text()) { + is_tooltip_shown = true; + } + } else if (tooltip == String(gui.tooltip_popup->call("get_tooltip_text"))) { is_tooltip_shown = true; + } } else _gui_cancel_tooltip(); } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 3000398540..e717d27069 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -255,7 +255,7 @@ private: Control *key_focus; Control *mouse_over; Control *tooltip; - Panel *tooltip_popup; + Control *tooltip_popup; Label *tooltip_label; Point2 tooltip_pos; Point2 last_mouse_pos; @@ -312,7 +312,7 @@ private: void _gui_remove_root_control(List<Control *>::Element *RI); void _gui_remove_subwindow_control(List<Control *>::Element *SI); - String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos); + String _gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which = NULL); void _gui_cancel_tooltip(); void _gui_show_tooltip(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 8f78e137b4..a4fd35304a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -156,6 +156,7 @@ #include "scene/resources/sky_box.h" #include "scene/resources/sphere_shape.h" #include "scene/resources/surface_tool.h" +#include "scene/resources/text_file.h" #include "scene/resources/texture.h" #include "scene/resources/tile_set.h" #include "scene/resources/video_stream.h" @@ -199,10 +200,12 @@ #include "scene/3d/remote_transform.h" #include "scene/3d/room_instance.h" #include "scene/3d/skeleton.h" +#include "scene/3d/soft_body.h" #include "scene/3d/sprite_3d.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/visibility_notifier.h" #include "scene/resources/environment.h" +#include "scene/resources/physics_material.h" #endif static ResourceFormatLoaderTheme *resource_loader_theme = NULL; @@ -312,21 +315,19 @@ void register_scene_types() { ClassDB::register_class<CenterContainer>(); ClassDB::register_class<ScrollContainer>(); ClassDB::register_class<PanelContainer>(); - ClassDB::register_virtual_class<SplitContainer>(); - ClassDB::register_class<HSplitContainer>(); - ClassDB::register_class<VSplitContainer>(); - ClassDB::register_class<GraphNode>(); - ClassDB::register_class<GraphEdit>(); OS::get_singleton()->yield(); //may take time to init ClassDB::register_class<TextureProgress>(); ClassDB::register_class<ItemList>(); + ClassDB::register_class<LineEdit>(); + ClassDB::register_class<VideoPlayer>(); + #ifndef ADVANCED_GUI_DISABLED ClassDB::register_class<FileDialog>(); - ClassDB::register_class<LineEdit>(); + ClassDB::register_class<PopupMenu>(); ClassDB::register_class<Tree>(); @@ -343,9 +344,13 @@ void register_scene_types() { ClassDB::register_class<WindowDialog>(); ClassDB::register_class<AcceptDialog>(); ClassDB::register_class<ConfirmationDialog>(); - ClassDB::register_class<VideoPlayer>(); ClassDB::register_class<MarginContainer>(); ClassDB::register_class<ViewportContainer>(); + ClassDB::register_virtual_class<SplitContainer>(); + ClassDB::register_class<HSplitContainer>(); + ClassDB::register_class<VSplitContainer>(); + ClassDB::register_class<GraphNode>(); + ClassDB::register_class<GraphEdit>(); OS::get_singleton()->yield(); //may take time to init @@ -425,6 +430,7 @@ void register_scene_types() { ClassDB::register_class<KinematicCollision>(); ClassDB::register_class<KinematicBody>(); ClassDB::register_class<PhysicalBone>(); + ClassDB::register_class<SoftBody>(); ClassDB::register_class<VehicleBody>(); ClassDB::register_class<VehicleWheel>(); @@ -588,6 +594,8 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init ClassDB::register_class<SpatialVelocityTracker>(); + + ClassDB::register_class<PhysicsMaterial>(); #endif ClassDB::register_class<World>(); ClassDB::register_class<Environment>(); @@ -610,6 +618,8 @@ void register_scene_types() { ClassDB::register_class<BitmapFont>(); ClassDB::register_class<Curve>(); + ClassDB::register_class<TextFile>(); + ClassDB::register_class<DynamicFontData>(); ClassDB::register_class<DynamicFont>(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 8acfdc482a..7041b62487 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -100,7 +100,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { for (int i = 0; i < (vcount / 12); i++) { - TKey<TransformKey> &tk = tt->transforms[i]; + TKey<TransformKey> &tk = tt->transforms.write[i]; const float *ofs = &r[i * 12]; tk.time = ofs[0]; tk.transition = ofs[1]; @@ -154,8 +154,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { for (int i = 0; i < valcount; i++) { - vt->values[i].time = rt[i]; - vt->values[i].value = values[i]; + vt->values.write[i].time = rt[i]; + vt->values.write[i].value = values[i]; } if (d.has("transitions")) { @@ -167,7 +167,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { for (int i = 0; i < valcount; i++) { - vt->values[i].transition = rtr[i]; + vt->values.write[i].transition = rtr[i]; } } } @@ -235,13 +235,13 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { for (int i = 0; i < valcount; i++) { - bt->values[i].time = rt[i]; - bt->values[i].transition = 0; //unused in bezier - bt->values[i].value.value = rv[i * 5 + 0]; - bt->values[i].value.in_handle.x = rv[i * 5 + 1]; - bt->values[i].value.in_handle.y = rv[i * 5 + 2]; - bt->values[i].value.out_handle.x = rv[i * 5 + 3]; - bt->values[i].value.out_handle.y = rv[i * 5 + 4]; + bt->values.write[i].time = rt[i]; + bt->values.write[i].transition = 0; //unused in bezier + bt->values.write[i].value.value = rv[i * 5 + 0]; + bt->values.write[i].value.in_handle.x = rv[i * 5 + 1]; + bt->values.write[i].value.in_handle.y = rv[i * 5 + 2]; + bt->values.write[i].value.out_handle.x = rv[i * 5 + 3]; + bt->values.write[i].value.out_handle.y = rv[i * 5 + 4]; } } @@ -313,7 +313,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { TKey<StringName> ak; ak.time = rt[i]; ak.value = rc[i]; - an->values[i] = ak; + an->values.write[i] = ak; } } @@ -822,7 +822,7 @@ int Animation::_insert(float p_time, T &p_keys, const V &p_value) { } else if (p_keys[idx - 1].time == p_time) { // condition for replacing. - p_keys[idx - 1] = p_value; + p_keys.write[idx - 1] = p_value; return idx - 1; } @@ -1349,18 +1349,18 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); Dictionary d = p_value; if (d.has("location")) - tt->transforms[p_key_idx].value.loc = d["location"]; + tt->transforms.write[p_key_idx].value.loc = d["location"]; if (d.has("rotation")) - tt->transforms[p_key_idx].value.rot = d["rotation"]; + tt->transforms.write[p_key_idx].value.rot = d["rotation"]; if (d.has("scale")) - tt->transforms[p_key_idx].value.scale = d["scale"]; + tt->transforms.write[p_key_idx].value.scale = d["scale"]; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_key_idx, vt->values.size()); - vt->values[p_key_idx].value = p_value; + vt->values.write[p_key_idx].value = p_value; } break; case TYPE_METHOD: { @@ -1369,9 +1369,9 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p ERR_FAIL_INDEX(p_key_idx, mt->methods.size()); Dictionary d = p_value; if (d.has("method")) - mt->methods[p_key_idx].method = d["method"]; + mt->methods.write[p_key_idx].method = d["method"]; if (d.has("args")) - mt->methods[p_key_idx].params = d["args"]; + mt->methods.write[p_key_idx].params = d["args"]; } break; case TYPE_BEZIER: { @@ -1381,11 +1381,11 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p Array arr = p_value; ERR_FAIL_COND(arr.size() != 5); - bt->values[p_key_idx].value.value = arr[0]; - bt->values[p_key_idx].value.in_handle.x = arr[1]; - bt->values[p_key_idx].value.in_handle.y = arr[2]; - bt->values[p_key_idx].value.out_handle.x = arr[3]; - bt->values[p_key_idx].value.out_handle.y = arr[4]; + bt->values.write[p_key_idx].value.value = arr[0]; + bt->values.write[p_key_idx].value.in_handle.x = arr[1]; + bt->values.write[p_key_idx].value.in_handle.y = arr[2]; + bt->values.write[p_key_idx].value.out_handle.x = arr[3]; + bt->values.write[p_key_idx].value.out_handle.y = arr[4]; } break; case TYPE_AUDIO: { @@ -1397,16 +1397,16 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p ERR_FAIL_COND(!k.has("end_offset")); ERR_FAIL_COND(!k.has("stream")); - at->values[p_key_idx].value.start_offset = k["start_offset"]; - at->values[p_key_idx].value.end_offset = k["end_offset"]; - at->values[p_key_idx].value.stream = k["stream"]; + at->values.write[p_key_idx].value.start_offset = k["start_offset"]; + at->values.write[p_key_idx].value.end_offset = k["end_offset"]; + at->values.write[p_key_idx].value.stream = k["stream"]; } break; case TYPE_ANIMATION: { AnimationTrack *at = static_cast<AnimationTrack *>(t); - at->values[p_key_idx].value = p_value; + at->values.write[p_key_idx].value = p_value; } break; } @@ -1423,20 +1423,20 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); - tt->transforms[p_key_idx].transition = p_transition; + tt->transforms.write[p_key_idx].transition = p_transition; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); ERR_FAIL_INDEX(p_key_idx, vt->values.size()); - vt->values[p_key_idx].transition = p_transition; + vt->values.write[p_key_idx].transition = p_transition; } break; case TYPE_METHOD: { MethodTrack *mt = static_cast<MethodTrack *>(t); ERR_FAIL_INDEX(p_key_idx, mt->methods.size()); - mt->methods[p_key_idx].transition = p_transition; + mt->methods.write[p_key_idx].transition = p_transition; } break; case TYPE_BEZIER: @@ -2210,7 +2210,7 @@ void Animation::bezier_track_set_key_value(int p_track, int p_index, float p_val ERR_FAIL_INDEX(p_index, bt->values.size()); - bt->values[p_index].value.value = p_value; + bt->values.write[p_index].value.value = p_value; emit_changed(); } @@ -2224,9 +2224,9 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V ERR_FAIL_INDEX(p_index, bt->values.size()); - bt->values[p_index].value.in_handle = p_handle; + bt->values.write[p_index].value.in_handle = p_handle; if (bt->values[p_index].value.in_handle.x > 0) { - bt->values[p_index].value.in_handle.x = 0; + bt->values.write[p_index].value.in_handle.x = 0; } emit_changed(); } @@ -2240,9 +2240,9 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const ERR_FAIL_INDEX(p_index, bt->values.size()); - bt->values[p_index].value.out_handle = p_handle; + bt->values.write[p_index].value.out_handle = p_handle; if (bt->values[p_index].value.out_handle.x < 0) { - bt->values[p_index].value.out_handle.x = 0; + bt->values.write[p_index].value.out_handle.x = 0; } emit_changed(); } @@ -2396,7 +2396,7 @@ void Animation::audio_track_set_key_stream(int p_track, int p_key, const RES &p_ ERR_FAIL_INDEX(p_key, at->values.size()); - at->values[p_key].value.stream = p_stream; + at->values.write[p_key].value.stream = p_stream; emit_changed(); } @@ -2414,7 +2414,7 @@ void Animation::audio_track_set_key_start_offset(int p_track, int p_key, float p if (p_offset < 0) p_offset = 0; - at->values[p_key].value.start_offset = p_offset; + at->values.write[p_key].value.start_offset = p_offset; emit_changed(); } @@ -2432,7 +2432,7 @@ void Animation::audio_track_set_key_end_offset(int p_track, int p_key, float p_o if (p_offset < 0) p_offset = 0; - at->values[p_key].value.end_offset = p_offset; + at->values.write[p_key].value.end_offset = p_offset; emit_changed(); } @@ -2505,7 +2505,7 @@ void Animation::animation_track_set_key_animation(int p_track, int p_key, const ERR_FAIL_INDEX(p_key, at->values.size()); - at->values[p_key].value = p_animation; + at->values.write[p_key].value = p_animation; emit_changed(); } @@ -2550,7 +2550,7 @@ void Animation::track_move_up(int p_track) { if (p_track >= 0 && p_track < (tracks.size() - 1)) { - SWAP(tracks[p_track], tracks[p_track + 1]); + SWAP(tracks.write[p_track], tracks.write[p_track + 1]); } emit_changed(); @@ -2585,7 +2585,7 @@ void Animation::track_move_down(int p_track) { if (p_track > 0 && p_track < tracks.size()) { - SWAP(tracks[p_track], tracks[p_track - 1]); + SWAP(tracks.write[p_track], tracks.write[p_track - 1]); } emit_changed(); } @@ -2596,7 +2596,7 @@ void Animation::track_swap(int p_track, int p_with_track) { ERR_FAIL_INDEX(p_with_track, tracks.size()); if (p_track == p_with_track) return; - SWAP(tracks[p_track], tracks[p_with_track]); + SWAP(tracks.write[p_track], tracks.write[p_with_track]); emit_changed(); } @@ -2927,9 +2927,9 @@ void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err, for (int i = 1; i < tt->transforms.size() - 1; i++) { - TKey<TransformKey> &t0 = tt->transforms[i - 1]; - TKey<TransformKey> &t1 = tt->transforms[i]; - TKey<TransformKey> &t2 = tt->transforms[i + 1]; + TKey<TransformKey> &t0 = tt->transforms.write[i - 1]; + TKey<TransformKey> &t1 = tt->transforms.write[i]; + TKey<TransformKey> &t2 = tt->transforms.write[i + 1]; bool erase = _transform_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle, norm); if (erase && !prev_erased) { diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index 29ffefd9d6..85e36abf4e 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -130,7 +130,7 @@ void BitMap::set_bit(const Point2 &p_pos, bool p_value) { else b &= ~(1 << bbit); - bitmask[bbyte] = b; + bitmask.write[bbyte] = b; } bool BitMap::get_bit(const Point2 &p_pos) const { @@ -322,8 +322,8 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) curx += stepx; cury += stepy; if (stepx == prevx && stepy == prevy) { - _points[_points.size() - 1].x = (float)(curx - rect.position.x); - _points[_points.size() - 1].y = (float)(cury + rect.position.y); + _points.write[_points.size() - 1].x = (float)(curx - rect.position.x); + _points.write[_points.size() - 1].y = (float)(cury + rect.position.y); } else { _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y))); } @@ -373,11 +373,11 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) { Vector<Vector2> left, right; left.resize(index); for (int i = 0; i < index; i++) { - left[i] = v[i]; + left.write[i] = v[i]; } right.resize(v.size() - index); for (int i = 0; i < right.size(); i++) { - right[i] = v[index + i]; + right.write[i] = v[index + i]; } Vector<Vector2> r1 = rdp(left, optimization); Vector<Vector2> r2 = rdp(right, optimization); @@ -385,7 +385,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) { int middle = r1.size(); r1.resize(r1.size() + r2.size()); for (int i = 0; i < r2.size(); i++) { - r1[middle + i] = r2[i]; + r1.write[middle + i] = r2[i]; } return r1; } else { @@ -412,7 +412,7 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, Vector2 last = result[result.size() - 1]; if (last.y > result[0].y && last.distance_to(result[0]) < ep * 0.5f) { - result[0].y = last.y; + result.write[0].y = last.y; result.resize(result.size() - 1); } return result; diff --git a/scene/resources/color_ramp.cpp b/scene/resources/color_ramp.cpp index b2f586d02d..4a43303d84 100644 --- a/scene/resources/color_ramp.cpp +++ b/scene/resources/color_ramp.cpp @@ -40,10 +40,10 @@ Gradient::Gradient() { //Set initial color ramp transition from black to white points.resize(2); - points[0].color = Color(0, 0, 0, 1); - points[0].offset = 0; - points[1].color = Color(1, 1, 1, 1); - points[1].offset = 1; + points.write[0].color = Color(0, 0, 0, 1); + points.write[0].offset = 0; + points.write[1].color = Color(1, 1, 1, 1); + points.write[1].offset = 1; is_sorted = true; } @@ -79,7 +79,7 @@ Vector<float> Gradient::get_offsets() const { Vector<float> offsets; offsets.resize(points.size()); for (int i = 0; i < points.size(); i++) { - offsets[i] = points[i].offset; + offsets.write[i] = points[i].offset; } return offsets; } @@ -88,7 +88,7 @@ Vector<Color> Gradient::get_colors() const { Vector<Color> colors; colors.resize(points.size()); for (int i = 0; i < points.size(); i++) { - colors[i] = points[i].color; + colors.write[i] = points[i].color; } return colors; } @@ -96,7 +96,7 @@ Vector<Color> Gradient::get_colors() const { void Gradient::set_offsets(const Vector<float> &p_offsets) { points.resize(p_offsets.size()); for (int i = 0; i < points.size(); i++) { - points[i].offset = p_offsets[i]; + points.write[i].offset = p_offsets[i]; } is_sorted = false; emit_signal(CoreStringNames::get_singleton()->changed); @@ -107,7 +107,7 @@ void Gradient::set_colors(const Vector<Color> &p_colors) { is_sorted = false; points.resize(p_colors.size()); for (int i = 0; i < points.size(); i++) { - points[i].color = p_colors[i]; + points.write[i].color = p_colors[i]; } emit_signal(CoreStringNames::get_singleton()->changed); } @@ -144,7 +144,7 @@ void Gradient::set_points(Vector<Gradient::Point> &p_points) { void Gradient::set_offset(int pos, const float offset) { if (points.size() <= pos) points.resize(pos + 1); - points[pos].offset = offset; + points.write[pos].offset = offset; is_sorted = false; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -160,7 +160,7 @@ void Gradient::set_color(int pos, const Color &color) { points.resize(pos + 1); is_sorted = false; } - points[pos].color = color; + points.write[pos].color = color; emit_signal(CoreStringNames::get_singleton()->changed); } diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h index c042a0d3d0..070ad7f0d3 100644 --- a/scene/resources/color_ramp.h +++ b/scene/resources/color_ramp.h @@ -98,7 +98,7 @@ public: while (low <= high) { middle = (low + high) / 2; - Point &point = points[middle]; + const Point &point = points[middle]; if (point.offset > p_offset) { high = middle - 1; //search low end of array } else if (point.offset < p_offset) { @@ -118,8 +118,8 @@ public: return points[points.size() - 1].color; if (first < 0) return points[0].color; - Point &pointFirst = points[first]; - Point &pointSecond = points[second]; + const Point &pointFirst = points[first]; + const Point &pointSecond = points[second]; return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); } diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp index 935f041837..bc9e2848b3 100644 --- a/scene/resources/concave_polygon_shape.cpp +++ b/scene/resources/concave_polygon_shape.cpp @@ -56,8 +56,8 @@ Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() { int idx = 0; for (Set<DrawEdge>::Element *E = edges.front(); E; E = E->next()) { - points[idx + 0] = E->get().a; - points[idx + 1] = E->get().b; + points.write[idx + 0] = E->get().a; + points.write[idx + 1] = E->get().b; idx += 2; } diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp index a2e0996996..fa9369d3bc 100644 --- a/scene/resources/convex_polygon_shape.cpp +++ b/scene/resources/convex_polygon_shape.cpp @@ -46,8 +46,8 @@ Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() { Vector<Vector3> lines; lines.resize(md.edges.size() * 2); for (int i = 0; i < md.edges.size(); i++) { - lines[i * 2 + 0] = md.vertices[md.edges[i].a]; - lines[i * 2 + 1] = md.vertices[md.edges[i].b]; + lines.write[i * 2 + 0] = md.vertices[md.edges[i].a]; + lines.write[i * 2 + 1] = md.vertices[md.edges[i].b]; } return lines; } diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index f2fd919f20..d8989bf062 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -153,25 +153,25 @@ void Curve::clean_dupes() { void Curve::set_point_left_tangent(int i, real_t tangent) { ERR_FAIL_INDEX(i, _points.size()); - _points[i].left_tangent = tangent; - _points[i].left_mode = TANGENT_FREE; + _points.write[i].left_tangent = tangent; + _points.write[i].left_mode = TANGENT_FREE; mark_dirty(); } void Curve::set_point_right_tangent(int i, real_t tangent) { ERR_FAIL_INDEX(i, _points.size()); - _points[i].right_tangent = tangent; - _points[i].right_mode = TANGENT_FREE; + _points.write[i].right_tangent = tangent; + _points.write[i].right_mode = TANGENT_FREE; mark_dirty(); } void Curve::set_point_left_mode(int i, TangentMode p_mode) { ERR_FAIL_INDEX(i, _points.size()); - _points[i].left_mode = p_mode; + _points.write[i].left_mode = p_mode; if (i > 0) { if (p_mode == TANGENT_LINEAR) { Vector2 v = (_points[i - 1].pos - _points[i].pos).normalized(); - _points[i].left_tangent = v.y / v.x; + _points.write[i].left_tangent = v.y / v.x; } } mark_dirty(); @@ -179,11 +179,11 @@ void Curve::set_point_left_mode(int i, TangentMode p_mode) { void Curve::set_point_right_mode(int i, TangentMode p_mode) { ERR_FAIL_INDEX(i, _points.size()); - _points[i].right_mode = p_mode; + _points.write[i].right_mode = p_mode; if (i + 1 < _points.size()) { if (p_mode == TANGENT_LINEAR) { Vector2 v = (_points[i + 1].pos - _points[i].pos).normalized(); - _points[i].right_tangent = v.y / v.x; + _points.write[i].right_tangent = v.y / v.x; } } mark_dirty(); @@ -222,7 +222,7 @@ void Curve::clear_points() { void Curve::set_point_value(int p_index, real_t pos) { ERR_FAIL_INDEX(p_index, _points.size()); - _points[p_index].pos.y = pos; + _points.write[p_index].pos.y = pos; update_auto_tangents(p_index); mark_dirty(); } @@ -232,10 +232,10 @@ int Curve::set_point_offset(int p_index, float offset) { Point p = _points[p_index]; remove_point(p_index); int i = add_point(Vector2(offset, p.pos.y)); - _points[i].left_tangent = p.left_tangent; - _points[i].right_tangent = p.right_tangent; - _points[i].left_mode = p.left_mode; - _points[i].right_mode = p.right_mode; + _points.write[i].left_tangent = p.left_tangent; + _points.write[i].right_tangent = p.right_tangent; + _points.write[i].left_mode = p.left_mode; + _points.write[i].right_mode = p.right_mode; if (p_index != i) update_auto_tangents(p_index); update_auto_tangents(i); @@ -254,7 +254,7 @@ Curve::Point Curve::get_point(int p_index) const { void Curve::update_auto_tangents(int i) { - Point &p = _points[i]; + Point &p = _points.write[i]; if (i > 0) { if (p.left_mode == TANGENT_LINEAR) { @@ -263,7 +263,7 @@ void Curve::update_auto_tangents(int i) { } if (_points[i - 1].right_mode == TANGENT_LINEAR) { Vector2 v = (_points[i - 1].pos - p.pos).normalized(); - _points[i - 1].right_tangent = v.y / v.x; + _points.write[i - 1].right_tangent = v.y / v.x; } } @@ -274,7 +274,7 @@ void Curve::update_auto_tangents(int i) { } if (_points[i + 1].left_mode == TANGENT_LINEAR) { Vector2 v = (_points[i + 1].pos - p.pos).normalized(); - _points[i + 1].left_tangent = v.y / v.x; + _points.write[i + 1].left_tangent = v.y / v.x; } } } @@ -402,7 +402,7 @@ void Curve::set_data(Array input) { for (int j = 0; j < _points.size(); ++j) { - Point &p = _points[j]; + Point &p = _points.write[j]; int i = j * ELEMS; p.pos = input[i]; @@ -426,12 +426,12 @@ void Curve::bake() { for (int i = 1; i < _bake_resolution - 1; ++i) { real_t x = i / static_cast<real_t>(_bake_resolution); real_t y = interpolate(x); - _baked_cache[i] = y; + _baked_cache.write[i] = y; } if (_points.size() != 0) { - _baked_cache[0] = _points[0].pos.y; - _baked_cache[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y; + _baked_cache.write[0] = _points[0].pos.y; + _baked_cache.write[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y; } _baked_cache_dirty = false; @@ -553,7 +553,7 @@ void Curve2D::set_point_position(int p_index, const Vector2 &p_pos) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].pos = p_pos; + points.write[p_index].pos = p_pos; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -567,7 +567,7 @@ void Curve2D::set_point_in(int p_index, const Vector2 &p_in) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].in = p_in; + points.write[p_index].in = p_in; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -581,7 +581,7 @@ void Curve2D::set_point_out(int p_index, const Vector2 &p_out) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].out = p_out; + points.write[p_index].out = p_out; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -930,9 +930,9 @@ void Curve2D::_set_data(const Dictionary &p_data) { for (int i = 0; i < points.size(); i++) { - points[i].in = r[i * 3 + 0]; - points[i].out = r[i * 3 + 1]; - points[i].pos = r[i * 3 + 2]; + points.write[i].in = r[i * 3 + 0]; + points.write[i].out = r[i * 3 + 1]; + points.write[i].pos = r[i * 3 + 2]; } baked_cache_dirty = true; @@ -952,7 +952,7 @@ PoolVector2Array Curve2D::tessellate(int p_max_stages, float p_tolerance) const int pc = 1; for (int i = 0; i < points.size() - 1; i++) { - _bake_segment2d(midpoints[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance); + _bake_segment2d(midpoints.write[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance); pc++; pc += midpoints[i].size(); } @@ -1049,7 +1049,7 @@ void Curve3D::set_point_position(int p_index, const Vector3 &p_pos) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].pos = p_pos; + points.write[p_index].pos = p_pos; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -1063,7 +1063,7 @@ void Curve3D::set_point_tilt(int p_index, float p_tilt) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].tilt = p_tilt; + points.write[p_index].tilt = p_tilt; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -1077,7 +1077,7 @@ void Curve3D::set_point_in(int p_index, const Vector3 &p_in) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].in = p_in; + points.write[p_index].in = p_in; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -1091,7 +1091,7 @@ void Curve3D::set_point_out(int p_index, const Vector3 &p_out) { ERR_FAIL_INDEX(p_index, points.size()); - points[p_index].out = p_out; + points.write[p_index].out = p_out; baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); } @@ -1621,10 +1621,10 @@ void Curve3D::_set_data(const Dictionary &p_data) { for (int i = 0; i < points.size(); i++) { - points[i].in = r[i * 3 + 0]; - points[i].out = r[i * 3 + 1]; - points[i].pos = r[i * 3 + 2]; - points[i].tilt = rt[i]; + points.write[i].in = r[i * 3 + 0]; + points.write[i].out = r[i * 3 + 1]; + points.write[i].pos = r[i * 3 + 2]; + points.write[i].tilt = rt[i]; } baked_cache_dirty = true; @@ -1644,7 +1644,7 @@ PoolVector3Array Curve3D::tessellate(int p_max_stages, float p_tolerance) const int pc = 1; for (int i = 0; i < points.size() - 1; i++) { - _bake_segment3d(midpoints[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance); + _bake_segment3d(midpoints.write[i], 0, 1, points[i].pos, points[i].out, points[i + 1].pos, points[i + 1].in, 0, p_max_stages, p_tolerance); pc++; pc += midpoints[i].size(); } diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index d4432b969f..601f6fb558 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -476,6 +476,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("symbol_color", "TextEdit", control_font_color_hover); theme->set_color("brace_mismatch_color", "TextEdit", Color(1, 0.2, 0.2)); theme->set_color("line_number_color", "TextEdit", Color::html("66aaaaaa")); + theme->set_color("safe_line_number_color", "TextEdit", Color::html("99aac8aa")); theme->set_color("function_color", "TextEdit", Color::html("66a2ce")); theme->set_color("member_variable_color", "TextEdit", Color::html("e64e59")); theme->set_color("number_color", "TextEdit", Color::html("EB9532")); @@ -882,6 +883,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("logo", "Icons", make_icon(logo_png)); + // Visual Node Ports + theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale); + theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale); + // Theme default_icon = make_icon(error_icon_png); diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index e5d463d391..2f2abd4e08 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -211,9 +211,9 @@ Error DynamicFontAtSize::_load() { scale_color_font = float(id.size) / face->available_sizes[i].width; } } - error = FT_Select_Size(face, best_match); + FT_Select_Size(face, best_match); } else { - error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling); + FT_Set_Pixel_Sizes(face, 0, id.size * oversampling); } ascent = (face->size->metrics.ascender / 64.0) / oversampling * scale_color_font; @@ -314,7 +314,7 @@ void DynamicFontAtSize::set_texture_flags(uint32_t p_flags) { texture_flags = p_flags; for (int i = 0; i < textures.size(); i++) { - Ref<ImageTexture> &tex = textures[i].texture; + Ref<ImageTexture> &tex = textures.write[i].texture; if (!tex.is_null()) tex->set_flags(p_flags); } @@ -400,7 +400,7 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp for (int i = 0; i < textures.size(); i++) { - CharTexture &ct = textures[i]; + const CharTexture &ct = textures[i]; if (ct.texture->get_format() != p_image_format) continue; @@ -466,7 +466,7 @@ DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyp } tex.offsets.resize(texsize); for (int i = 0; i < texsize; i++) //zero offsets - tex.offsets[i] = 0; + tex.offsets.write[i] = 0; textures.push_back(tex); ret.index = textures.size() - 1; @@ -493,7 +493,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b //fit character in char texture - CharTexture &tex = textures[tex_pos.index]; + CharTexture &tex = textures.write[tex_pos.index]; { PoolVector<uint8_t>::Write wr = tex.imgdata.write(); @@ -547,7 +547,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b // update height array for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - tex.offsets[k] = tex_pos.y + mh; + tex.offsets.write[k] = tex_pos.y + mh; } Character chr; @@ -698,9 +698,9 @@ void DynamicFont::_reload_cache() { } for (int i = 0; i < fallbacks.size(); i++) { - fallback_data_at_size[i] = fallbacks[i]->_get_dynamic_font_at_size(cache_id); + fallback_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(cache_id); if (outline_cache_id.outline_size > 0) - fallback_outline_data_at_size[i] = fallbacks[i]->_get_dynamic_font_at_size(outline_cache_id); + fallback_outline_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(outline_cache_id); } emit_changed(); @@ -895,17 +895,17 @@ void DynamicFont::set_fallback(int p_idx, const Ref<DynamicFontData> &p_data) { ERR_FAIL_COND(p_data.is_null()); ERR_FAIL_INDEX(p_idx, fallbacks.size()); - fallbacks[p_idx] = p_data; - fallback_data_at_size[p_idx] = fallbacks[p_idx]->_get_dynamic_font_at_size(cache_id); + fallbacks.write[p_idx] = p_data; + fallback_data_at_size.write[p_idx] = fallbacks.write[p_idx]->_get_dynamic_font_at_size(cache_id); } void DynamicFont::add_fallback(const Ref<DynamicFontData> &p_data) { ERR_FAIL_COND(p_data.is_null()); fallbacks.push_back(p_data); - fallback_data_at_size.push_back(fallbacks[fallbacks.size() - 1]->_get_dynamic_font_at_size(cache_id)); //const.. + fallback_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(cache_id)); //const.. if (outline_cache_id.outline_size > 0) - fallback_outline_data_at_size.push_back(fallbacks[fallbacks.size() - 1]->_get_dynamic_font_at_size(outline_cache_id)); + fallback_outline_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(outline_cache_id)); _change_notify(); emit_changed(); @@ -1092,7 +1092,7 @@ void DynamicFont::update_oversampling() { dynamic_font_mutex->unlock(); for (int i = 0; i < changed.size(); i++) { - changed[i]->emit_changed(); + changed.write[i]->emit_changed(); } } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 0bae9d9b2d..3dfde01320 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -386,7 +386,7 @@ Vector<CharType> BitmapFont::get_char_keys() const { int count = 0; while ((ct = char_map.next(ct))) { - chars[count++] = *ct; + chars.write[count++] = *ct; }; return chars; @@ -438,7 +438,7 @@ Vector<BitmapFont::KerningPairKey> BitmapFont::get_kerning_pair_keys() const { int i = 0; for (Map<KerningPairKey, int>::Element *E = kerning_map.front(); E; E = E->next()) { - ret[i++] = E->key(); + ret.write[i++] = E->key(); } return ret; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 56b3ee70bb..df5bbe9e6c 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -554,9 +554,20 @@ void SpatialMaterial::_update_shader() { case BILLBOARD_ENABLED: { code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],CAMERA_MATRIX[1],CAMERA_MATRIX[2],WORLD_MATRIX[3]);\n"; + + if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n"; + } } break; case BILLBOARD_FIXED_Y: { + code += "\tMODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0],WORLD_MATRIX[1],vec4(normalize(cross(CAMERA_MATRIX[0].xyz,WORLD_MATRIX[1].xyz)),0.0),WORLD_MATRIX[3]);\n"; + + if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(WORLD_MATRIX[0].xyz),0,0,0),vec4(0,1,0,0),vec4(0,0,length(WORLD_MATRIX[2].xyz),0),vec4(0,0,0,1));\n"; + } else { + code += "\tMODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(1,0,0,0),vec4(0,1.0/length(WORLD_MATRIX[1].xyz),0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n"; + } } break; case BILLBOARD_PARTICLES: { @@ -573,8 +584,6 @@ void SpatialMaterial::_update_shader() { code += "\tif (particles_anim_loop) particle_frame=clamp(particle_frame,0,particle_total_frames-1); else particle_frame=abs(particle_frame)%particle_total_frames;\n"; code += "\tUV /= vec2(float(particles_anim_h_frames),float(particles_anim_v_frames));\n"; code += "\tUV += vec2(float(particle_frame % particles_anim_h_frames) / float(particles_anim_h_frames),float(particle_frame / particles_anim_h_frames) / float(particles_anim_v_frames));\n"; - //handle rotation - // code += "\tmat4 rotation = mat4(" } break; } @@ -1883,7 +1892,8 @@ void SpatialMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "params_depth_draw_mode", PROPERTY_HINT_ENUM, "Opaque Only,Always,Never,Opaque Pre-Pass"), "set_depth_draw_mode", "get_depth_draw_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_line_width", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_line_width", "get_line_width"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_point_size", "get_point_size"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "params_billboard_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particle Billboard"), "set_billboard_mode", "get_billboard_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "params_billboard_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particle Billboard1"), "set_billboard_mode", "get_billboard_mode"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_billboard_keep_scale"), "set_flag", "get_flag", FLAG_BILLBOARD_KEEP_SCALE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "params_grow"), "set_grow_enabled", "is_grow_enabled"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "params_grow_amount", PROPERTY_HINT_RANGE, "-16,10,0.01"), "set_grow", "get_grow"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "params_use_alpha_scissor"), "set_flag", "get_flag", FLAG_USE_ALPHA_SCISSOR); @@ -2053,6 +2063,7 @@ void SpatialMaterial::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_SRGB_VERTEX_COLOR); BIND_ENUM_CONSTANT(FLAG_USE_POINT_SIZE); BIND_ENUM_CONSTANT(FLAG_FIXED_SIZE); + BIND_ENUM_CONSTANT(FLAG_BILLBOARD_KEEP_SCALE); BIND_ENUM_CONSTANT(FLAG_UV1_USE_TRIPLANAR); BIND_ENUM_CONSTANT(FLAG_UV2_USE_TRIPLANAR); BIND_ENUM_CONSTANT(FLAG_AO_ON_UV2); diff --git a/scene/resources/material.h b/scene/resources/material.h index 84f1005b03..7a1a4acfbf 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -183,6 +183,7 @@ public: FLAG_SRGB_VERTEX_COLOR, FLAG_USE_POINT_SIZE, FLAG_FIXED_SIZE, + FLAG_BILLBOARD_KEEP_SCALE, FLAG_UV1_USE_TRIPLANAR, FLAG_UV2_USE_TRIPLANAR, FLAG_TRIPLANAR_USE_WORLD, @@ -241,7 +242,7 @@ private: uint64_t blend_mode : 2; uint64_t depth_draw_mode : 2; uint64_t cull_mode : 2; - uint64_t flags : 17; + uint64_t flags : 18; uint64_t detail_blend_mode : 2; uint64_t diffuse_mode : 3; uint64_t specular_mode : 2; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index b0620d3363..e74ad2e55b 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -40,7 +40,6 @@ void Mesh::_clear_triangle_mesh() const { triangle_mesh.unref(); - ; } Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { @@ -110,6 +109,54 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { return triangle_mesh; } +void Mesh::generate_debug_mesh_lines(Vector<Vector3> &r_lines) { + + Ref<TriangleMesh> tm = generate_triangle_mesh(); + if (tm.is_null()) + return; + + PoolVector<int> triangle_indices; + tm->get_indices(&triangle_indices); + const int triangles_num = tm->get_triangles().size(); + PoolVector<Vector3> vertices = tm->get_vertices(); + + r_lines.resize(tm->get_triangles().size() * 6); // 3 lines x 2 points each line + + PoolVector<int>::Read ind_r = triangle_indices.read(); + PoolVector<Vector3>::Read ver_r = vertices.read(); + for (int j = 0, x = 0, i = 0; i < triangles_num; j += 6, x += 3, ++i) { + // Triangle line 1 + r_lines.write[j + 0] = ver_r[ind_r[x + 0]]; + r_lines.write[j + 1] = ver_r[ind_r[x + 1]]; + + // Triangle line 2 + r_lines.write[j + 2] = ver_r[ind_r[x + 1]]; + r_lines.write[j + 3] = ver_r[ind_r[x + 2]]; + + // Triangle line 3 + r_lines.write[j + 4] = ver_r[ind_r[x + 2]]; + r_lines.write[j + 5] = ver_r[ind_r[x + 0]]; + } +} +void Mesh::generate_debug_mesh_indices(Vector<Vector3> &r_points) { + Ref<TriangleMesh> tm = generate_triangle_mesh(); + if (tm.is_null()) + return; + + PoolVector<Vector3> vertices = tm->get_vertices(); + + int vertices_size = vertices.size(); + r_points.resize(vertices_size); + for (int i = 0; i < vertices_size; ++i) { + r_points.write[i] = vertices[i]; + } +} + +bool Mesh::surface_is_softbody_friendly(int p_idx) const { + const uint32_t surface_format = surface_get_format(p_idx); + return (surface_format & Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE && (!(surface_format & Mesh::ARRAY_COMPRESS_VERTEX)) && (!(surface_format & Mesh::ARRAY_COMPRESS_NORMAL))); +} + PoolVector<Face3> Mesh::get_faces() const { Ref<TriangleMesh> tm = generate_triangle_mesh(); @@ -484,6 +531,10 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_MAX); } +void Mesh::clear_cache() { + _clear_triangle_mesh(); +} + Mesh::Mesh() { } @@ -616,7 +667,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { bone_aabb.resize(baabb.size()); for (int i = 0; i < baabb.size(); i++) { - bone_aabb[i] = baabb[i]; + bone_aabb.write[i] = baabb[i]; } } @@ -788,8 +839,8 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & aabb.expand_to(vtx[i]); } - surfaces[surfaces.size() - 1].aabb = aabb; - surfaces[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; + surfaces.write[surfaces.size() - 1].aabb = aabb; + surfaces.write[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; _recompute_aabb(); } @@ -908,7 +959,7 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) ERR_FAIL_INDEX(p_idx, surfaces.size()); if (surfaces[p_idx].material == p_material) return; - surfaces[p_idx].material = p_material; + surfaces.write[p_idx].material = p_material; VisualServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid()); _change_notify("material"); @@ -919,7 +970,7 @@ void ArrayMesh::surface_set_name(int p_idx, const String &p_name) { ERR_FAIL_INDEX(p_idx, surfaces.size()); - surfaces[p_idx].name = p_name; + surfaces.write[p_idx].name = p_name; emit_changed(); } @@ -939,7 +990,7 @@ void ArrayMesh::surface_update_region(int p_surface, int p_offset, const PoolVec void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) { ERR_FAIL_INDEX(p_idx, surfaces.size()); - surfaces[p_idx].aabb = p_aabb; + surfaces.write[p_idx].aabb = p_aabb; // set custom aabb too? emit_changed(); } @@ -1042,8 +1093,8 @@ void ArrayMesh::regen_normalmaps() { for (int i = 0; i < surfs.size(); i++) { - surfs[i]->generate_tangents(); - surfs[i]->commit(Ref<ArrayMesh>(this)); + surfs.write[i]->generate_tangents(); + surfs.write[i]->commit(Ref<ArrayMesh>(this)); } } @@ -1108,13 +1159,13 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe Vector3 v = p_base_transform.xform(r[j]); Vector3 n = p_base_transform.basis.xform(rn[j]).normalized(); - vertices[(j + vertex_ofs) * 3 + 0] = v.x; - vertices[(j + vertex_ofs) * 3 + 1] = v.y; - vertices[(j + vertex_ofs) * 3 + 2] = v.z; - normals[(j + vertex_ofs) * 3 + 0] = n.x; - normals[(j + vertex_ofs) * 3 + 1] = n.y; - normals[(j + vertex_ofs) * 3 + 2] = n.z; - uv_index[j + vertex_ofs] = Pair<int, int>(i, j); + vertices.write[(j + vertex_ofs) * 3 + 0] = v.x; + vertices.write[(j + vertex_ofs) * 3 + 1] = v.y; + vertices.write[(j + vertex_ofs) * 3 + 2] = v.z; + normals.write[(j + vertex_ofs) * 3 + 0] = n.x; + normals.write[(j + vertex_ofs) * 3 + 1] = n.y; + normals.write[(j + vertex_ofs) * 3 + 2] = n.z; + uv_index.write[j + vertex_ofs] = Pair<int, int>(i, j); } PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX]; @@ -1197,31 +1248,31 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second]; if (surfaces[surface].format & ARRAY_FORMAT_COLOR) { - surfaces_tools[surface]->add_color(v.color); + surfaces_tools.write[surface]->add_color(v.color); } if (surfaces[surface].format & ARRAY_FORMAT_TEX_UV) { - surfaces_tools[surface]->add_uv(v.uv); + surfaces_tools.write[surface]->add_uv(v.uv); } if (surfaces[surface].format & ARRAY_FORMAT_NORMAL) { - surfaces_tools[surface]->add_normal(v.normal); + surfaces_tools.write[surface]->add_normal(v.normal); } if (surfaces[surface].format & ARRAY_FORMAT_TANGENT) { Plane t; t.normal = v.tangent; t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1; - surfaces_tools[surface]->add_tangent(t); + surfaces_tools.write[surface]->add_tangent(t); } if (surfaces[surface].format & ARRAY_FORMAT_BONES) { - surfaces_tools[surface]->add_bones(v.bones); + surfaces_tools.write[surface]->add_bones(v.bones); } if (surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) { - surfaces_tools[surface]->add_weights(v.weights); + surfaces_tools.write[surface]->add_weights(v.weights); } Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); - surfaces_tools[surface]->add_uv2(uv2); + surfaces_tools.write[surface]->add_uv2(uv2); - surfaces_tools[surface]->add_vertex(v.vertex); + surfaces_tools.write[surface]->add_vertex(v.vertex); } } @@ -1233,8 +1284,8 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe //generate surfaces for (int i = 0; i < surfaces_tools.size(); i++) { - surfaces_tools[i]->index(); - surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format); + surfaces_tools.write[i]->index(); + surfaces_tools.write[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format); } set_lightmap_size_hint(Size2(size_x, size_y)); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index a3fb068569..2127eaae4c 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -123,6 +123,7 @@ public: virtual int get_surface_count() const = 0; virtual int surface_get_array_len(int p_idx) const = 0; virtual int surface_get_array_index_len(int p_idx) const = 0; + virtual bool surface_is_softbody_friendly(int p_idx) const; virtual Array surface_get_arrays(int p_surface) const = 0; virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0; virtual uint32_t surface_get_format(int p_idx) const = 0; @@ -133,6 +134,8 @@ public: PoolVector<Face3> get_faces() const; Ref<TriangleMesh> generate_triangle_mesh() const; + void generate_debug_mesh_lines(Vector<Vector3> &r_lines); + void generate_debug_mesh_indices(Vector<Vector3> &r_points); Ref<Shape> create_trimesh_shape() const; Ref<Shape> create_convex_shape() const; @@ -143,6 +146,7 @@ public: void set_lightmap_size_hint(const Vector2 &p_size); Size2 get_lightmap_size_hint() const; + void clear_cache(); Mesh(); }; diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index 8639b325c3..6732303925 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -120,7 +120,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf v.bones.push_back(bo[i * 4 + 3]); } - vertices[i] = v; + vertices.write[i] = v; } PoolVector<int> indices; @@ -143,7 +143,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf for (int i = 0; i < icount; i += 3) { - Vertex *v[3] = { &vertices[r[i + 0]], &vertices[r[i + 1]], &vertices[r[i + 2]] }; + Vertex *v[3] = { &vertices.write[r[i + 0]], &vertices.write[r[i + 1]], &vertices.write[r[i + 2]] }; int fidx = faces.size(); Face face; @@ -169,7 +169,7 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf edges.push_back(e); } - edges[face.edges[j]].faces.push_back(fidx); + edges.write[face.edges[j]].faces.push_back(fidx); v[j]->faces.push_back(fidx); v[j]->edges.push_back(face.edges[j]); } @@ -247,7 +247,7 @@ Error MeshDataTool::commit_to_surface(const Ref<ArrayMesh> &p_mesh) { for (int i = 0; i < vcount; i++) { - Vertex &vtx = vertices[i]; + const Vertex &vtx = vertices[i]; vr[i] = vtx.vertex; if (nr.ptr()) @@ -344,7 +344,7 @@ Vector3 MeshDataTool::get_vertex(int p_idx) const { void MeshDataTool::set_vertex(int p_idx, const Vector3 &p_vertex) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].vertex = p_vertex; + vertices.write[p_idx].vertex = p_vertex; } Vector3 MeshDataTool::get_vertex_normal(int p_idx) const { @@ -355,7 +355,7 @@ Vector3 MeshDataTool::get_vertex_normal(int p_idx) const { void MeshDataTool::set_vertex_normal(int p_idx, const Vector3 &p_normal) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].normal = p_normal; + vertices.write[p_idx].normal = p_normal; format |= Mesh::ARRAY_FORMAT_NORMAL; } @@ -367,7 +367,7 @@ Plane MeshDataTool::get_vertex_tangent(int p_idx) const { void MeshDataTool::set_vertex_tangent(int p_idx, const Plane &p_tangent) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].tangent = p_tangent; + vertices.write[p_idx].tangent = p_tangent; format |= Mesh::ARRAY_FORMAT_TANGENT; } @@ -379,7 +379,7 @@ Vector2 MeshDataTool::get_vertex_uv(int p_idx) const { void MeshDataTool::set_vertex_uv(int p_idx, const Vector2 &p_uv) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].uv = p_uv; + vertices.write[p_idx].uv = p_uv; format |= Mesh::ARRAY_FORMAT_TEX_UV; } @@ -391,7 +391,7 @@ Vector2 MeshDataTool::get_vertex_uv2(int p_idx) const { void MeshDataTool::set_vertex_uv2(int p_idx, const Vector2 &p_uv2) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].uv2 = p_uv2; + vertices.write[p_idx].uv2 = p_uv2; format |= Mesh::ARRAY_FORMAT_TEX_UV2; } @@ -403,7 +403,7 @@ Color MeshDataTool::get_vertex_color(int p_idx) const { void MeshDataTool::set_vertex_color(int p_idx, const Color &p_color) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].color = p_color; + vertices.write[p_idx].color = p_color; format |= Mesh::ARRAY_FORMAT_COLOR; } @@ -415,7 +415,7 @@ Vector<int> MeshDataTool::get_vertex_bones(int p_idx) const { void MeshDataTool::set_vertex_bones(int p_idx, const Vector<int> &p_bones) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].bones = p_bones; + vertices.write[p_idx].bones = p_bones; format |= Mesh::ARRAY_FORMAT_BONES; } @@ -426,7 +426,7 @@ Vector<float> MeshDataTool::get_vertex_weights(int p_idx) const { } void MeshDataTool::set_vertex_weights(int p_idx, const Vector<float> &p_weights) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].weights = p_weights; + vertices.write[p_idx].weights = p_weights; format |= Mesh::ARRAY_FORMAT_WEIGHTS; } @@ -439,7 +439,7 @@ Variant MeshDataTool::get_vertex_meta(int p_idx) const { void MeshDataTool::set_vertex_meta(int p_idx, const Variant &p_meta) { ERR_FAIL_INDEX(p_idx, vertices.size()); - vertices[p_idx].meta = p_meta; + vertices.write[p_idx].meta = p_meta; } Vector<int> MeshDataTool::get_vertex_edges(int p_idx) const { @@ -472,7 +472,7 @@ Variant MeshDataTool::get_edge_meta(int p_idx) const { void MeshDataTool::set_edge_meta(int p_idx, const Variant &p_meta) { ERR_FAIL_INDEX(p_idx, edges.size()); - edges[p_idx].meta = p_meta; + edges.write[p_idx].meta = p_meta; } int MeshDataTool::get_face_vertex(int p_face, int p_vertex) const { @@ -495,7 +495,7 @@ Variant MeshDataTool::get_face_meta(int p_face) const { void MeshDataTool::set_face_meta(int p_face, const Variant &p_meta) { ERR_FAIL_INDEX(p_face, faces.size()); - faces[p_face].meta = p_meta; + faces.write[p_face].meta = p_meta; } Vector3 MeshDataTool::get_face_normal(int p_face) const { diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index e1d3540fd1..a1d3e0ba1e 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -209,7 +209,7 @@ Vector<int> MeshLibrary::get_item_list() const { int idx = 0; for (Map<int, Item>::Element *E = item_map.front(); E; E = E->next()) { - ret[idx++] = E->key(); + ret.write[idx++] = E->key(); } return ret; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 846f6e356e..b95e0495d9 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -325,7 +325,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { if (c.binds.size()) { binds.resize(c.binds.size()); for (int j = 0; j < c.binds.size(); j++) - binds[j] = props[c.binds[j]]; + binds.write[j] = props[c.binds[j]]; } cfrom->connect(snames[c.signal], cto, snames[c.method], binds, CONNECT_PERSIST | c.flags); @@ -875,7 +875,7 @@ Error SceneState::pack(Node *p_scene) { for (Map<StringName, int>::Element *E = name_map.front(); E; E = E->next()) { - names[E->get()] = E->key(); + names.write[E->get()] = E->key(); } variants.resize(variant_map.size()); @@ -883,13 +883,13 @@ Error SceneState::pack(Node *p_scene) { while ((K = variant_map.next(K))) { int idx = variant_map[*K]; - variants[idx] = *K; + variants.write[idx] = *K; } node_paths.resize(nodepath_map.size()); for (Map<Node *, int>::Element *E = nodepath_map.front(); E; E = E->next()) { - node_paths[E->get()] = scene->get_path_to(E->key()); + node_paths.write[E->get()] = scene->get_path_to(E->key()); } return OK; @@ -1090,7 +1090,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { names.resize(namecount); PoolVector<String>::Read r = snames.read(); for (int i = 0; i < names.size(); i++) - names[i] = r[i]; + names.write[i] = r[i]; } Array svariants = p_dictionary["variants"]; @@ -1100,7 +1100,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { variants.resize(varcount); for (int i = 0; i < varcount; i++) { - variants[i] = svariants[i]; + variants.write[i] = svariants[i]; } } else { @@ -1114,7 +1114,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { PoolVector<int>::Read r = snodes.read(); int idx = 0; for (int i = 0; i < nc; i++) { - NodeData &nd = nodes[i]; + NodeData &nd = nodes.write[i]; nd.parent = r[idx++]; nd.owner = r[idx++]; nd.type = r[idx++]; @@ -1126,13 +1126,13 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { nd.properties.resize(r[idx++]); for (int j = 0; j < nd.properties.size(); j++) { - nd.properties[j].name = r[idx++]; - nd.properties[j].value = r[idx++]; + nd.properties.write[j].name = r[idx++]; + nd.properties.write[j].value = r[idx++]; } nd.groups.resize(r[idx++]); for (int j = 0; j < nd.groups.size(); j++) { - nd.groups[j] = r[idx++]; + nd.groups.write[j] = r[idx++]; } } } @@ -1146,7 +1146,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { PoolVector<int>::Read r = sconns.read(); int idx = 0; for (int i = 0; i < cc; i++) { - ConnectionData &cd = connections[i]; + ConnectionData &cd = connections.write[i]; cd.from = r[idx++]; cd.to = r[idx++]; cd.signal = r[idx++]; @@ -1156,7 +1156,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { for (int j = 0; j < cd.binds.size(); j++) { - cd.binds[j] = r[idx++]; + cd.binds.write[j] = r[idx++]; } } } @@ -1167,7 +1167,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { } node_paths.resize(np.size()); for (int i = 0; i < np.size(); i++) { - node_paths[i] = np[i]; + node_paths.write[i] = np[i]; } Array ei; @@ -1181,7 +1181,7 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { editable_instances.resize(ei.size()); for (int i = 0; i < editable_instances.size(); i++) { - editable_instances[i] = ei[i]; + editable_instances.write[i] = ei[i]; } //path=p_dictionary["path"]; @@ -1563,13 +1563,13 @@ void SceneState::add_node_property(int p_node, int p_name, int p_value) { NodeData::Property prop; prop.name = p_name; prop.value = p_value; - nodes[p_node].properties.push_back(prop); + nodes.write[p_node].properties.push_back(prop); } void SceneState::add_node_group(int p_node, int p_group) { ERR_FAIL_INDEX(p_node, nodes.size()); ERR_FAIL_INDEX(p_group, names.size()); - nodes[p_node].groups.push_back(p_group); + nodes.write[p_node].groups.push_back(p_group); } void SceneState::set_base_scene(int p_idx) { diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp new file mode 100644 index 0000000000..de3cfd1371 --- /dev/null +++ b/scene/resources/physics_material.cpp @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* physics_material.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://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 "physics_material.h" + +bool PhysicsMaterial::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "bounce") { + set_bounce(p_value); + } else if (p_name == "bounce_combine_mode") { + set_bounce_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value))); + } else if (p_name == "friction") { + set_friction(p_value); + } else if (p_name == "friction_combine_mode") { + set_friction_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value))); + } else { + return false; + } + + emit_changed(); + return true; +} + +bool PhysicsMaterial::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "bounce") { + r_ret = bounce; + } else if (p_name == "bounce_combine_mode") { + r_ret = int(bounce_combine_mode); + } else if (p_name == "friction") { + r_ret = friction; + } else if (p_name == "friction_combine_mode") { + r_ret = int(friction_combine_mode); + } else { + return false; + } + + return true; +} + +void PhysicsMaterial::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::REAL, "bounce")); + p_list->push_back(PropertyInfo(Variant::INT, "bounce_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average")); + p_list->push_back(PropertyInfo(Variant::REAL, "friction")); + p_list->push_back(PropertyInfo(Variant::INT, "friction_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average")); +} + +void PhysicsMaterial::_bind_methods() {} + +void PhysicsMaterial::set_bounce(real_t p_val) { + bounce = p_val; +} + +void PhysicsMaterial::set_bounce_combine_mode(PhysicsServer::CombineMode p_val) { + bounce_combine_mode = p_val; +} + +void PhysicsMaterial::set_friction(real_t p_val) { + friction = p_val; +} + +void PhysicsMaterial::set_friction_combine_mode(PhysicsServer::CombineMode p_val) { + friction_combine_mode = p_val; +} + +PhysicsMaterial::PhysicsMaterial() : + bounce(0), + bounce_combine_mode(PhysicsServer::COMBINE_MODE_MAX), + friction(0), + friction_combine_mode(PhysicsServer::COMBINE_MODE_MULTIPLY) {} diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h new file mode 100644 index 0000000000..a6cb8c288e --- /dev/null +++ b/scene/resources/physics_material.h @@ -0,0 +1,70 @@ +/*************************************************************************/ +/* physics_material.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://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 physics_material_override_H +#define physics_material_override_H + +#include "resource.h" +#include "servers/physics_server.h" + +class PhysicsMaterial : public Resource { + + GDCLASS(PhysicsMaterial, Resource); + OBJ_SAVE_TYPE(PhysicsMaterial); + RES_BASE_EXTENSION("PhyMat"); + + real_t bounce; + PhysicsServer::CombineMode bounce_combine_mode; + real_t friction; + PhysicsServer::CombineMode friction_combine_mode; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + void set_bounce(real_t p_val); + _FORCE_INLINE_ real_t get_bounce() const { return bounce; } + + void set_bounce_combine_mode(PhysicsServer::CombineMode p_val); + _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } + + void set_friction(real_t p_val); + _FORCE_INLINE_ real_t get_friction() const { return friction; } + + void set_friction_combine_mode(PhysicsServer::CombineMode p_val); + _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } + + PhysicsMaterial(); +}; + +#endif // physics_material_override_H diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index 6fea2e1a8e..44f9ebaf33 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -65,8 +65,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> for (int i = 0; i < p_points.size(); i++) { - points[i].pos = p_points[i]; - points[i].penalty = 0; + points.write[i].pos = p_points[i]; + points.write[i].penalty = 0; outside_point.x = i == 0 ? p_points[0].x : (MAX(p_points[i].x, outside_point.x)); outside_point.y = i == 0 ? p_points[0].y : (MAX(p_points[i].y, outside_point.y)); @@ -88,8 +88,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> Edge e(p_connections[i], p_connections[i + 1]); ERR_FAIL_INDEX(e.points[0], point_count); ERR_FAIL_INDEX(e.points[1], point_count); - points[p_connections[i]].connections.insert(p_connections[i + 1]); - points[p_connections[i + 1]].connections.insert(p_connections[i]); + points.write[p_connections[i]].connections.insert(p_connections[i + 1]); + points.write[p_connections[i + 1]].connections.insert(p_connections[i]); edges.insert(e); } @@ -126,8 +126,8 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> } if (valid) { - points[i].connections.insert(j); - points[j].connections.insert(i); + points.write[i].connections.insert(j); + points.write[j].connections.insert(i); } } } @@ -227,21 +227,21 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector int aidx = points.size() - 2; int bidx = points.size() - 1; - points[aidx].pos = from; - points[bidx].pos = to; - points[aidx].distance = 0; - points[bidx].distance = 0; - points[aidx].prev = -1; - points[bidx].prev = -1; - points[aidx].penalty = 0; - points[bidx].penalty = 0; + points.write[aidx].pos = from; + points.write[bidx].pos = to; + points.write[aidx].distance = 0; + points.write[bidx].distance = 0; + points.write[aidx].prev = -1; + points.write[bidx].prev = -1; + points.write[aidx].penalty = 0; + points.write[bidx].penalty = 0; for (int i = 0; i < points.size() - 2; i++) { bool valid_a = true; bool valid_b = true; - points[i].prev = -1; - points[i].distance = 0; + points.write[i].prev = -1; + points.write[i].distance = 0; if (!_is_point_inside(from * 0.5 + points[i].pos * 0.5)) { valid_a = false; @@ -292,26 +292,26 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector } if (valid_a) { - points[i].connections.insert(aidx); - points[aidx].connections.insert(i); + points.write[i].connections.insert(aidx); + points.write[aidx].connections.insert(i); } if (valid_b) { - points[i].connections.insert(bidx); - points[bidx].connections.insert(i); + points.write[i].connections.insert(bidx); + points.write[bidx].connections.insert(i); } } //solve graph Set<int> open_list; - points[aidx].distance = 0; - points[aidx].prev = aidx; + points.write[aidx].distance = 0; + points.write[aidx].prev = aidx; for (Set<int>::Element *E = points[aidx].connections.front(); E; E = E->next()) { open_list.insert(E->get()); - points[E->get()].distance = from.distance_to(points[E->get()].pos); - points[E->get()].prev = aidx; + points.write[E->get()].distance = from.distance_to(points[E->get()].pos); + points.write[E->get()].prev = aidx; } bool found_route = false; @@ -342,12 +342,12 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector } } - Point &np = points[least_cost_point]; + const Point &np = points[least_cost_point]; //open the neighbours for search for (Set<int>::Element *E = np.connections.front(); E; E = E->next()) { - Point &p = points[E->get()]; + Point &p = points.write[E->get()]; float distance = np.pos.distance_to(p.pos) + np.distance; if (p.prev != -1) { @@ -392,18 +392,18 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector for (int i = 0; i < points.size() - 2; i++) { - points[i].connections.erase(aidx); - points[i].connections.erase(bidx); - points[i].prev = -1; - points[i].distance = 0; + points.write[i].connections.erase(aidx); + points.write[i].connections.erase(bidx); + points.write[i].prev = -1; + points.write[i].distance = 0; } - points[aidx].connections.clear(); - points[aidx].prev = -1; - points[aidx].distance = 0; - points[bidx].connections.clear(); - points[bidx].prev = -1; - points[bidx].distance = 0; + points.write[aidx].connections.clear(); + points.write[aidx].prev = -1; + points.write[aidx].distance = 0; + points.write[bidx].connections.clear(); + points.write[bidx].prev = -1; + points.write[bidx].distance = 0; return path; } @@ -427,13 +427,13 @@ void PolygonPathFinder::_set_data(const Dictionary &p_data) { PoolVector<Vector2>::Read pr = p.read(); for (int i = 0; i < pc; i++) { - points[i].pos = pr[i]; + points.write[i].pos = pr[i]; PoolVector<int> con = c[i]; PoolVector<int>::Read cr = con.read(); int cc = con.size(); for (int j = 0; j < cc; j++) { - points[i].connections.insert(cr[j]); + points.write[i].connections.insert(cr[j]); } } @@ -443,7 +443,7 @@ void PolygonPathFinder::_set_data(const Dictionary &p_data) { if (penalties.size() == pc) { PoolVector<float>::Read pr = penalties.read(); for (int i = 0; i < pc; i++) { - points[i].penalty = pr[i]; + points.write[i].penalty = pr[i]; } } } @@ -566,7 +566,7 @@ Rect2 PolygonPathFinder::get_bounds() const { void PolygonPathFinder::set_point_penalty(int p_point, float p_penalty) { ERR_FAIL_INDEX(p_point, points.size() - 2); - points[p_point].penalty = p_penalty; + points.write[p_point].penalty = p_penalty; } float PolygonPathFinder::get_point_penalty(int p_point) const { diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index 9df117d09c..fd9989fe72 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -1523,7 +1523,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) { - sorted_er[E->get()] = E->key(); + sorted_er.write[E->get()] = E->key(); } for (int i = 0; i < sorted_er.size(); i++) { diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 5a42873d79..ec489e5c5b 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -421,6 +421,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_ Array a = commit_to_arrays(); mesh->add_surface_from_arrays(primitive, a, Array(), p_flags); + if (material.is_valid()) mesh->surface_set_material(surface, material); @@ -465,7 +466,7 @@ void SurfaceTool::deindex() { int idx = 0; for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - varr[idx++] = E->get(); + varr.write[idx++] = E->get(); } vertex_array.clear(); for (List<int>::Element *E = index_array.front(); E; E = E->next()) { @@ -569,19 +570,19 @@ Vector<SurfaceTool::Vertex> SurfaceTool::create_vertex_array_from_triangle_array if (lformat & VS::ARRAY_FORMAT_BONES) { Vector<int> b; b.resize(4); - b[0] = barr[i * 4 + 0]; - b[1] = barr[i * 4 + 1]; - b[2] = barr[i * 4 + 2]; - b[3] = barr[i * 4 + 3]; + b.write[0] = barr[i * 4 + 0]; + b.write[1] = barr[i * 4 + 1]; + b.write[2] = barr[i * 4 + 2]; + b.write[3] = barr[i * 4 + 3]; v.bones = b; } if (lformat & VS::ARRAY_FORMAT_WEIGHTS) { Vector<float> w; w.resize(4); - w[0] = warr[i * 4 + 0]; - w[1] = warr[i * 4 + 1]; - w[2] = warr[i * 4 + 2]; - w[3] = warr[i * 4 + 3]; + w.write[0] = warr[i * 4 + 0]; + w.write[1] = warr[i * 4 + 1]; + w.write[2] = warr[i * 4 + 2]; + w.write[3] = warr[i * 4 + 3]; v.weights = w; } @@ -674,19 +675,19 @@ void SurfaceTool::_create_list_from_arrays(Array arr, List<Vertex> *r_vertex, Li if (lformat & VS::ARRAY_FORMAT_BONES) { Vector<int> b; b.resize(4); - b[0] = barr[i * 4 + 0]; - b[1] = barr[i * 4 + 1]; - b[2] = barr[i * 4 + 2]; - b[3] = barr[i * 4 + 3]; + b.write[0] = barr[i * 4 + 0]; + b.write[1] = barr[i * 4 + 1]; + b.write[2] = barr[i * 4 + 2]; + b.write[3] = barr[i * 4 + 3]; v.bones = b; } if (lformat & VS::ARRAY_FORMAT_WEIGHTS) { Vector<float> w; w.resize(4); - w[0] = warr[i * 4 + 0]; - w[1] = warr[i * 4 + 1]; - w[2] = warr[i * 4 + 2]; - w[3] = warr[i * 4 + 3]; + w.write[0] = warr[i * 4 + 0]; + w.write[1] = warr[i * 4 + 1]; + w.write[2] = warr[i * 4 + 2]; + w.write[3] = warr[i * 4 + 3]; v.weights = w; } @@ -845,7 +846,7 @@ void SurfaceTool::generate_tangents() { vtx.resize(vertex_array.size()); int idx = 0; for (List<Vertex>::Element *E = vertex_array.front(); E; E = E->next()) { - vtx[idx++] = E; + vtx.write[idx++] = E; E->get().binormal = Vector3(); E->get().tangent = Vector3(); } diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp new file mode 100644 index 0000000000..e2fe0adfc5 --- /dev/null +++ b/scene/resources/text_file.cpp @@ -0,0 +1,77 @@ +/*************************************************************************/ +/* text_file.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "text_file.h" + +#include "os/file_access.h" + +bool TextFile::has_text() const { + return text != ""; +} + +String TextFile::get_text() const { + return text; +} + +void TextFile::set_text(const String &p_code) { + text = p_code; +} + +void TextFile::reload_from_file() { + load_text(path); +} + +Error TextFile::load_text(const String &p_path) { + + PoolVector<uint8_t> sourcef; + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + if (err) { + ERR_FAIL_COND_V(err, err); + } + + int len = f->get_len(); + sourcef.resize(len + 1); + PoolVector<uint8_t>::Write w = sourcef.write(); + int r = f->get_buffer(w.ptr(), len); + f->close(); + memdelete(f); + ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w.ptr())) { + ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode."); + ERR_FAIL_V(ERR_INVALID_DATA); + } + text = s; + path = p_path; + return OK; +} diff --git a/scene/resources/text_file.h b/scene/resources/text_file.h new file mode 100644 index 0000000000..40b648eebb --- /dev/null +++ b/scene/resources/text_file.h @@ -0,0 +1,55 @@ +/*************************************************************************/ +/* text_file.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 TEXTFILE_H +#define TEXTFILE_H + +#include "io/resource_loader.h" +#include "io/resource_saver.h" + +class TextFile : public Resource { + + GDCLASS(TextFile, Resource) + +private: + String text; + String path; + +public: + virtual bool has_text() const; + virtual String get_text() const; + virtual void set_text(const String &p_code); + virtual void reload_from_file(); + + void set_file_path(const String &p_path) { path = p_path; } + Error load_text(const String &p_path); +}; + +#endif // TEXTFILE_H diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 2baad555c0..c8d12b88fc 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -235,6 +235,8 @@ Error ImageTexture::load(const String &p_path) { void ImageTexture::set_data(const Ref<Image> &p_image) { + ERR_FAIL_COND(p_image.is_null()); + VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); @@ -1037,7 +1039,7 @@ bool LargeTexture::has_alpha() const { void LargeTexture::set_flags(uint32_t p_flags) { for (int i = 0; i < pieces.size(); i++) { - pieces[i].texture->set_flags(p_flags); + pieces.write[i].texture->set_flags(p_flags); } } @@ -1063,13 +1065,13 @@ int LargeTexture::add_piece(const Point2 &p_offset, const Ref<Texture> &p_textur void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) { ERR_FAIL_INDEX(p_idx, pieces.size()); - pieces[p_idx].offset = p_offset; + pieces.write[p_idx].offset = p_offset; }; void LargeTexture::set_piece_texture(int p_idx, const Ref<Texture> &p_texture) { ERR_FAIL_INDEX(p_idx, pieces.size()); - pieces[p_idx].texture = p_texture; + pieces.write[p_idx].texture = p_texture; }; void LargeTexture::set_size(const Size2 &p_size) { diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 58057cda0c..dd50671fa0 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -576,7 +576,7 @@ void TileSet::tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_sha ERR_FAIL_COND(!tile_map.has(p_id)); if (tile_map[p_id].shapes_data.size() <= p_shape_id) tile_map[p_id].shapes_data.resize(p_shape_id + 1); - tile_map[p_id].shapes_data[p_shape_id].shape = p_shape; + tile_map[p_id].shapes_data.write[p_shape_id].shape = p_shape; emit_changed(); } @@ -594,7 +594,7 @@ void TileSet::tile_set_shape_transform(int p_id, int p_shape_id, const Transform ERR_FAIL_COND(!tile_map.has(p_id)); if (tile_map[p_id].shapes_data.size() <= p_shape_id) tile_map[p_id].shapes_data.resize(p_shape_id + 1); - tile_map[p_id].shapes_data[p_shape_id].shape_transform = p_offset; + tile_map[p_id].shapes_data.write[p_shape_id].shape_transform = p_offset; emit_changed(); } @@ -622,7 +622,7 @@ void TileSet::tile_set_shape_one_way(int p_id, int p_shape_id, const bool p_one_ ERR_FAIL_COND(!tile_map.has(p_id)); if (tile_map[p_id].shapes_data.size() <= p_shape_id) tile_map[p_id].shapes_data.resize(p_shape_id + 1); - tile_map[p_id].shapes_data[p_shape_id].one_way_collision = p_one_way; + tile_map[p_id].shapes_data.write[p_shape_id].one_way_collision = p_one_way; emit_changed(); } @@ -923,6 +923,8 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("tile_get_normal_map", "id"), &TileSet::tile_get_normal_map); ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material); ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material); + ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate); + ClassDB::bind_method(D_METHOD("tile_get_modulate", "id"), &TileSet::tile_get_modulate); ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset); ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset); ClassDB::bind_method(D_METHOD("tile_set_region", "id", "region"), &TileSet::tile_set_region); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index b7b7802d1b..d8fc3677fb 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -949,8 +949,8 @@ void VisualShader::_bind_methods() { ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node); ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position); + ClassDB::bind_method(D_METHOD("get_node", "type", "id"), &VisualShader::get_node); ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position); - ClassDB::bind_method(D_METHOD("get_node", "type"), &VisualShader::get_node); ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list); ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id); diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h index 0b922c5892..910b401db9 100644 --- a/servers/arvr/arvr_interface.h +++ b/servers/arvr/arvr_interface.h @@ -88,7 +88,7 @@ public: bool is_primary(); void set_is_primary(bool p_is_primary); - virtual bool is_initialized() = 0; /* returns true if we've initialized this interface */ + virtual bool is_initialized() const = 0; /* returns true if we've initialized this interface */ void set_is_initialized(bool p_initialized); /* helper function, will call initialize or uninitialize */ virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */ virtual void uninitialize() = 0; /* deinitialize this interface */ diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp index f48bedbdac..0d1aad0dff 100644 --- a/servers/arvr_server.cpp +++ b/servers/arvr_server.cpp @@ -353,7 +353,7 @@ void ARVRServer::_process() { if (!interfaces[i].is_valid()) { // ignore, not a valid reference } else if (interfaces[i]->is_initialized()) { - interfaces[i]->process(); + interfaces.write[i]->process(); }; }; }; diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 9faa4056c3..3414351681 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -100,6 +100,8 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i if (C == 6) { + // FIXME: Lot of unused assignments here, but it seems like intermediate calculations + // should be done as for C == 2 (C == 4 also has some unused assignments). float v0 = rb[(pos * 6) + 0]; float v1 = rb[(pos * 6) + 1]; float v2 = rb[(pos * 6) + 2]; diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp index f2f554a09b..fd9e3311e7 100644 --- a/servers/audio/effects/audio_effect_chorus.cpp +++ b/servers/audio/effects/audio_effect_chorus.cpp @@ -53,7 +53,7 @@ void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames, A //fill ringbuffer for (int i = 0; i < p_frame_count; i++) { - audio_buffer[(buffer_pos + i) & buffer_mask] = p_src_frames[i]; + audio_buffer.write[(buffer_pos + i) & buffer_mask] = p_src_frames[i]; p_dst_frames[i] = p_src_frames[i] * base->dry; } @@ -175,7 +175,7 @@ Ref<AudioEffectInstance> AudioEffectChorus::instance() { ins->buffer_pos = 0; ins->audio_buffer.resize(ringbuff_size); for (int i = 0; i < ringbuff_size; i++) { - ins->audio_buffer[i] = AudioFrame(0, 0); + ins->audio_buffer.write[i] = AudioFrame(0, 0); } return ins; diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp index a30fca4e8d..cf8f7d3e16 100644 --- a/servers/audio/effects/audio_effect_eq.cpp +++ b/servers/audio/effects/audio_effect_eq.cpp @@ -70,7 +70,7 @@ Ref<AudioEffectInstance> AudioEffectEQ::instance() { for (int i = 0; i < 2; i++) { ins->bands[i].resize(eq.get_band_count()); for (int j = 0; j < ins->bands[i].size(); j++) { - ins->bands[i][j] = eq.get_band_processor(j); + ins->bands[i].write[j] = eq.get_band_processor(j); } } @@ -79,7 +79,7 @@ Ref<AudioEffectInstance> AudioEffectEQ::instance() { void AudioEffectEQ::set_band_gain_db(int p_band, float p_volume) { ERR_FAIL_INDEX(p_band, gain.size()); - gain[p_band] = p_volume; + gain.write[p_band] = p_volume; } float AudioEffectEQ::get_band_gain_db(int p_band) const { @@ -134,7 +134,7 @@ AudioEffectEQ::AudioEffectEQ(EQ::Preset p_preset) { eq.set_preset_band_mode(p_preset); gain.resize(eq.get_band_count()); for (int i = 0; i < gain.size(); i++) { - gain[i] = 0.0; + gain.write[i] = 0.0; String name = "band_db/" + itos(eq.get_band_frequency(i)) + "_hz"; prop_band_map[name] = i; band_names.push_back(name); diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp index 9ef41191f5..b15fc7ecf4 100644 --- a/servers/audio/effects/eq.cpp +++ b/servers/audio/effects/eq.cpp @@ -108,9 +108,9 @@ void EQ::recalculate_band_coefficients() { ERR_CONTINUE(roots == 0); - band[i].c1 = 2.0 * ((0.5 - r1) / 2.0); - band[i].c2 = 2.0 * r1; - band[i].c3 = 2.0 * (0.5 + r1) * cos(th); + band.write[i].c1 = 2.0 * ((0.5 - r1) / 2.0); + band.write[i].c2 = 2.0 * r1; + band.write[i].c3 = 2.0 * (0.5 + r1) * cos(th); //printf("band %i, coefs = %f,%f,%f\n",i,(float)bands[i].c1,(float)bands[i].c2,(float)bands[i].c3); } } @@ -180,7 +180,7 @@ void EQ::set_bands(const Vector<float> &p_bands) { band.resize(p_bands.size()); for (int i = 0; i < p_bands.size(); i++) { - band[i].freq = p_bands[i]; + band.write[i].freq = p_bands[i]; } recalculate_band_coefficients(); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index a26983d3d1..2eaa2ce8e7 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -264,7 +264,7 @@ void AudioServer::_mix_step() { bus->index_cache = i; //might be moved around by editor, so.. for (int k = 0; k < bus->channels.size(); k++) { - bus->channels[k].used = false; + bus->channels.write[k].used = false; } if (bus->solo) { @@ -310,7 +310,7 @@ void AudioServer::_mix_step() { if (bus->channels[k].active && !bus->channels[k].used) { //buffer was not used, but it's still active, so it must be cleaned - AudioFrame *buf = bus->channels[k].buffer.ptrw(); + AudioFrame *buf = bus->channels.write[k].buffer.ptrw(); for (uint32_t j = 0; j < buffer_size; j++) { @@ -334,7 +334,7 @@ void AudioServer::_mix_step() { if (!(bus->channels[k].active || bus->channels[k].effect_instances[j]->process_silence())) continue; - bus->channels[k].effect_instances[j]->process(bus->channels[k].buffer.ptr(), temp_buffer[k].ptrw(), buffer_size); + bus->channels.write[k].effect_instances.write[j]->process(bus->channels[k].buffer.ptr(), temp_buffer.write[k].ptrw(), buffer_size); } //swap buffers, so internal buffer always has the right data @@ -342,11 +342,11 @@ void AudioServer::_mix_step() { if (!(buses[i]->channels[k].active || bus->channels[k].effect_instances[j]->process_silence())) continue; - SWAP(bus->channels[k].buffer, temp_buffer[k]); + SWAP(bus->channels.write[k].buffer, temp_buffer.write[k]); } #ifdef DEBUG_ENABLED - bus->effects[j].prof_time += OS::get_singleton()->get_ticks_usec() - ticks; + bus->effects.write[j].prof_time += OS::get_singleton()->get_ticks_usec() - ticks; #endif } } @@ -372,7 +372,7 @@ void AudioServer::_mix_step() { if (!bus->channels[k].active) continue; - AudioFrame *buf = bus->channels[k].buffer.ptrw(); + AudioFrame *buf = bus->channels.write[k].buffer.ptrw(); AudioFrame peak = AudioFrame(0, 0); @@ -403,15 +403,15 @@ void AudioServer::_mix_step() { } } - bus->channels[k].peak_volume = AudioFrame(Math::linear2db(peak.l + 0.0000000001), Math::linear2db(peak.r + 0.0000000001)); + bus->channels.write[k].peak_volume = AudioFrame(Math::linear2db(peak.l + 0.0000000001), Math::linear2db(peak.r + 0.0000000001)); if (!bus->channels[k].used) { //see if any audio is contained, because channel was not used if (MAX(peak.r, peak.l) > Math::db2linear(channel_disable_threshold_db)) { - bus->channels[k].last_mix_with_audio = mix_frames; + bus->channels.write[k].last_mix_with_audio = mix_frames; } else if (mix_frames - bus->channels[k].last_mix_with_audio > channel_disable_frames) { - bus->channels[k].active = false; + bus->channels.write[k].active = false; continue; //went inactive, don't mix. } } @@ -436,12 +436,12 @@ AudioFrame *AudioServer::thread_get_channel_mix_buffer(int p_bus, int p_buffer) ERR_FAIL_INDEX_V(p_bus, buses.size(), NULL); ERR_FAIL_INDEX_V(p_buffer, buses[p_bus]->channels.size(), NULL); - AudioFrame *data = buses[p_bus]->channels[p_buffer].buffer.ptrw(); + AudioFrame *data = buses.write[p_bus]->channels.write[p_buffer].buffer.ptrw(); if (!buses[p_bus]->channels[p_buffer].used) { - buses[p_bus]->channels[p_buffer].used = true; - buses[p_bus]->channels[p_buffer].active = true; - buses[p_bus]->channels[p_buffer].last_mix_with_audio = mix_frames; + buses.write[p_bus]->channels.write[p_buffer].used = true; + buses.write[p_bus]->channels.write[p_buffer].active = true; + buses.write[p_bus]->channels.write[p_buffer].last_mix_with_audio = mix_frames; for (uint32_t i = 0; i < buffer_size; i++) { data[i] = AudioFrame(0, 0); } @@ -506,10 +506,10 @@ void AudioServer::set_bus_count(int p_count) { } } - buses[i] = memnew(Bus); - buses[i]->channels.resize(channel_count); + buses.write[i] = memnew(Bus); + buses.write[i]->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - buses[i]->channels[j].buffer.resize(buffer_size); + buses.write[i]->channels.write[j].buffer.resize(buffer_size); } buses[i]->name = attempt; buses[i]->solo = false; @@ -581,7 +581,7 @@ void AudioServer::add_bus(int p_at_pos) { Bus *bus = memnew(Bus); bus->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - bus->channels[j].buffer.resize(buffer_size); + bus->channels.write[j].buffer.resize(buffer_size); } bus->name = attempt; bus->solo = false; @@ -764,13 +764,13 @@ bool AudioServer::is_bus_bypassing_effects(int p_bus) const { void AudioServer::_update_bus_effects(int p_bus) { for (int i = 0; i < buses[p_bus]->channels.size(); i++) { - buses[p_bus]->channels[i].effect_instances.resize(buses[p_bus]->effects.size()); + buses.write[p_bus]->channels.write[i].effect_instances.resize(buses[p_bus]->effects.size()); for (int j = 0; j < buses[p_bus]->effects.size(); j++) { - Ref<AudioEffectInstance> fx = buses[p_bus]->effects[j].effect->instance(); + Ref<AudioEffectInstance> fx = buses.write[p_bus]->effects.write[j].effect->instance(); if (Object::cast_to<AudioEffectCompressorInstance>(*fx)) { Object::cast_to<AudioEffectCompressorInstance>(*fx)->set_current_channel(i); } - buses[p_bus]->channels[i].effect_instances[j] = fx; + buses.write[p_bus]->channels.write[i].effect_instances.write[j] = fx; } } } @@ -841,7 +841,7 @@ void AudioServer::swap_bus_effects(int p_bus, int p_effect, int p_by_effect) { MARK_EDITED lock(); - SWAP(buses[p_bus]->effects[p_effect], buses[p_bus]->effects[p_by_effect]); + SWAP(buses.write[p_bus]->effects.write[p_effect], buses.write[p_bus]->effects.write[p_by_effect]); _update_bus_effects(p_bus); unlock(); } @@ -853,7 +853,7 @@ void AudioServer::set_bus_effect_enabled(int p_bus, int p_effect, bool p_enabled MARK_EDITED - buses[p_bus]->effects[p_effect].enabled = p_enabled; + buses.write[p_bus]->effects.write[p_effect].enabled = p_enabled; } bool AudioServer::is_bus_effect_enabled(int p_bus, int p_effect) const { @@ -890,13 +890,13 @@ void AudioServer::init_channels_and_buffers() { temp_buffer.resize(channel_count); for (int i = 0; i < temp_buffer.size(); i++) { - temp_buffer[i].resize(buffer_size); + temp_buffer.write[i].resize(buffer_size); } for (int i = 0; i < buses.size(); i++) { buses[i]->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - buses[i]->channels[j].buffer.resize(buffer_size); + buses.write[i]->channels.write[j].buffer.resize(buffer_size); } } } @@ -976,7 +976,7 @@ void AudioServer::update() { if (!bus->effects[j].enabled) continue; - bus->effects[j].prof_time = 0; + bus->effects.write[j].prof_time = 0; } } @@ -1146,11 +1146,11 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { } bus_map[bus->name] = bus; - buses[i] = bus; + buses.write[i] = bus; buses[i]->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - buses[i]->channels[j].buffer.resize(buffer_size); + buses.write[i]->channels.write[j].buffer.resize(buffer_size); } _update_bus_effects(i); } @@ -1169,17 +1169,17 @@ Ref<AudioBusLayout> AudioServer::generate_bus_layout() const { for (int i = 0; i < buses.size(); i++) { - state->buses[i].name = buses[i]->name; - state->buses[i].send = buses[i]->send; - state->buses[i].mute = buses[i]->mute; - state->buses[i].solo = buses[i]->solo; - state->buses[i].bypass = buses[i]->bypass; - state->buses[i].volume_db = buses[i]->volume_db; + state->buses.write[i].name = buses[i]->name; + state->buses.write[i].send = buses[i]->send; + state->buses.write[i].mute = buses[i]->mute; + state->buses.write[i].solo = buses[i]->solo; + state->buses.write[i].bypass = buses[i]->bypass; + state->buses.write[i].volume_db = buses[i]->volume_db; for (int j = 0; j < buses[i]->effects.size(); j++) { AudioBusLayout::Bus::Effect fx; fx.effect = buses[i]->effects[j].effect; fx.enabled = buses[i]->effects[j].enabled; - state->buses[i].effects.push_back(fx); + state->buses.write[i].effects.push_back(fx); } } @@ -1294,7 +1294,7 @@ bool AudioBusLayout::_set(const StringName &p_name, const Variant &p_value) { buses.resize(index + 1); } - Bus &bus = buses[index]; + Bus &bus = buses.write[index]; String what = s.get_slice("/", 2); @@ -1316,7 +1316,7 @@ bool AudioBusLayout::_set(const StringName &p_name, const Variant &p_value) { bus.effects.resize(which + 1); } - Bus::Effect &fx = bus.effects[which]; + Bus::Effect &fx = bus.effects.write[which]; String fxwhat = s.get_slice("/", 4); if (fxwhat == "effect") { @@ -1410,5 +1410,5 @@ void AudioBusLayout::_get_property_list(List<PropertyInfo> *p_list) const { AudioBusLayout::AudioBusLayout() { buses.resize(1); - buses[0].name = "Master"; + buses.write[0].name = "Master"; } diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp index 2a6a9e08ae..5a41b621eb 100644 --- a/servers/physics/body_pair_sw.cpp +++ b/servers/physics/body_pair_sw.cpp @@ -211,6 +211,44 @@ bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Tran return true; } +real_t combine_bounce(BodySW *A, BodySW *B) { + const PhysicsServer::CombineMode cm = A->get_bounce_combine_mode(); + + switch (cm) { + case PhysicsServer::COMBINE_MODE_INHERIT: + if (B->get_bounce_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) + return combine_bounce(B, A); + // else use MAX [This is used when the two bodies doesn't use physical material] + case PhysicsServer::COMBINE_MODE_MAX: + return MAX(A->get_bounce(), B->get_bounce()); + case PhysicsServer::COMBINE_MODE_MIN: + return MIN(A->get_bounce(), B->get_bounce()); + case PhysicsServer::COMBINE_MODE_MULTIPLY: + return A->get_bounce() * B->get_bounce(); + default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: + return (A->get_bounce() + B->get_bounce()) / 2; + } +} + +real_t combine_friction(BodySW *A, BodySW *B) { + const PhysicsServer::CombineMode cm = A->get_friction_combine_mode(); + + switch (cm) { + case PhysicsServer::COMBINE_MODE_INHERIT: + if (B->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) + return combine_friction(B, A); + // else use Multiply [This is used when the two bodies doesn't use physical material] + case PhysicsServer::COMBINE_MODE_MULTIPLY: + return A->get_friction() * B->get_friction(); + case PhysicsServer::COMBINE_MODE_MAX: + return MAX(A->get_friction(), B->get_friction()); + case PhysicsServer::COMBINE_MODE_MIN: + return MIN(A->get_friction(), B->get_friction()); + default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: + return (A->get_friction() + B->get_friction()) / 2; + } +} + bool BodyPairSW::setup(real_t p_step) { //cannot collide @@ -331,7 +369,7 @@ bool BodyPairSW::setup(real_t p_step) { c.acc_bias_impulse = 0; c.acc_bias_impulse_center_of_mass = 0; - c.bounce = MAX(A->get_bounce(), B->get_bounce()); + c.bounce = combine_bounce(A, B); if (c.bounce) { Vector3 crA = A->get_angular_velocity().cross(c.rA); @@ -421,7 +459,7 @@ void BodyPairSW::solve(real_t p_step) { //friction impulse - real_t friction = A->get_friction() * B->get_friction(); + real_t friction = combine_friction(A, B); Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA); Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB); diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index cc9681193c..59f987fc17 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -423,6 +423,22 @@ void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) { area_angular_damp += p_area->get_angular_damp(); } +void BodySW::set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode) { + if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { + bounce_combine_mode = p_mode; + } else { + friction_combine_mode = p_mode; + } +} + +PhysicsServer::CombineMode BodySW::get_combine_mode(PhysicsServer::BodyParameter p_param) const { + if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { + return bounce_combine_mode; + } else { + return friction_combine_mode; + } +} + void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) { if (lock) { locked_axis |= p_axis; diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index fd2ab16b84..5df270f679 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -49,6 +49,8 @@ class BodySW : public CollisionObjectSW { real_t mass; real_t bounce; real_t friction; + PhysicsServer::CombineMode bounce_combine_mode; + PhysicsServer::CombineMode friction_combine_mode; real_t linear_damp; real_t angular_damp; @@ -157,7 +159,7 @@ public: _FORCE_INLINE_ void add_area(AreaSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount += 1; + areas.write[index].refCount += 1; } else { areas.ordered_insert(AreaCMP(p_area)); } @@ -166,7 +168,7 @@ public: _FORCE_INLINE_ void remove_area(AreaSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount -= 1; + areas.write[index].refCount -= 1; if (areas[index].refCount < 1) areas.remove(index); } @@ -217,6 +219,10 @@ public: _FORCE_INLINE_ const Vector3 &get_biased_linear_velocity() const { return biased_linear_velocity; } _FORCE_INLINE_ const Vector3 &get_biased_angular_velocity() const { return biased_angular_velocity; } + _FORCE_INLINE_ void apply_central_impulse(const Vector3 &p_j) { + linear_velocity += p_j * _inv_mass; + } + _FORCE_INLINE_ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { linear_velocity += p_j * _inv_mass; @@ -298,6 +304,12 @@ public: _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; } _FORCE_INLINE_ real_t get_bounce() const { return bounce; } + void set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode); + PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const; + + _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } + _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } + void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock); bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const; @@ -344,7 +356,7 @@ void BodySW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_norm if (c_max == 0) return; - Contact *c = &contacts[0]; + Contact *c = contacts.ptrw(); int idx = -1; @@ -413,6 +425,7 @@ public: virtual void add_central_force(const Vector3 &p_force) { body->add_central_force(p_force); } virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) { body->add_force(p_force, p_pos); } virtual void add_torque(const Vector3 &p_torque) { body->add_torque(p_torque); } + virtual void apply_central_impulse(const Vector3 &p_j) { body->apply_central_impulse(p_j); } virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { body->apply_impulse(p_pos, p_j); } virtual void apply_torque_impulse(const Vector3 &p_j) { body->apply_torque_impulse(p_j); } @@ -429,6 +442,9 @@ public: ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].local_normal; } + virtual float get_contact_impulse(int p_contact_idx) const { + return 0.0f; // Only implemented for bullet + } virtual int get_contact_local_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1); return body->contacts[p_contact_idx].local_shape; diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp index f7a58a9cf2..09f72ff39b 100644 --- a/servers/physics/collision_object_sw.cpp +++ b/servers/physics/collision_object_sw.cpp @@ -53,7 +53,7 @@ void CollisionObjectSW::set_shape(int p_index, ShapeSW *p_shape) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes[p_index].shape->remove_owner(this); - shapes[p_index].shape = p_shape; + shapes.write[p_index].shape = p_shape; p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { @@ -66,8 +66,8 @@ void CollisionObjectSW::set_shape_transform(int p_index, const Transform &p_tran ERR_FAIL_INDEX(p_index, shapes.size()); - shapes[p_index].xform = p_transform; - shapes[p_index].xform_inv = p_transform.affine_inverse(); + shapes.write[p_index].xform = p_transform; + shapes.write[p_index].xform_inv = p_transform.affine_inverse(); if (!pending_shape_update_list.in_list()) { PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); } @@ -97,7 +97,7 @@ void CollisionObjectSW::remove_shape(int p_index) { continue; //should never get here with a null owner space->get_broadphase()->remove(shapes[i].bpid); - shapes[i].bpid = 0; + shapes.write[i].bpid = 0; } shapes[p_index].shape->remove_owner(this); shapes.remove(p_index); @@ -117,7 +117,7 @@ void CollisionObjectSW::_set_static(bool p_static) { if (!space) return; for (int i = 0; i < get_shape_count(); i++) { - Shape &s = shapes[i]; + const Shape &s = shapes[i]; if (s.bpid > 0) { space->get_broadphase()->set_static(s.bpid, _static); } @@ -128,7 +128,7 @@ void CollisionObjectSW::_unregister_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid > 0) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; @@ -143,7 +143,7 @@ void CollisionObjectSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid == 0) { s.bpid = space->get_broadphase()->create(this, i); space->get_broadphase()->set_static(s.bpid, _static); @@ -170,7 +170,7 @@ void CollisionObjectSW::_update_shapes_with_motion(const Vector3 &p_motion) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid == 0) { s.bpid = space->get_broadphase()->create(this, i); space->get_broadphase()->set_static(s.bpid, _static); @@ -195,7 +195,7 @@ void CollisionObjectSW::_set_space(SpaceSW *p_space) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index dee28bb6df..b6430b38dc 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -135,7 +135,7 @@ public: _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } - _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_enable) { shapes[p_idx].disabled = p_enable; } + _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_enable) { shapes.write[p_idx].disabled = p_enable; } _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { return shapes[p_idx].disabled; } _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; } diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp index e587485fcb..44b7c9ac34 100644 --- a/servers/physics/collision_solver_sat.cpp +++ b/servers/physics/collision_solver_sat.cpp @@ -217,8 +217,6 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ // generate contacts //Plane plane_A(p_points_A[0],p_points_A[1],p_points_A[2]); - int added = 0; - for (int i = 0; i < clipbuf_len; i++) { real_t d = plane_B.distance_to(clipbuf_src[i]); @@ -233,7 +231,6 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ continue; p_callback->call(clipbuf_src[i], closest_B); - added++; } } diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 6c25ad43f9..a06942cb2a 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -701,6 +701,20 @@ real_t PhysicsServerSW::body_get_param(RID p_body, BodyParameter p_param) const return body->get_param(p_param); }; +void PhysicsServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_combine_mode(p_param, p_mode); +} + +PhysicsServer::CombineMode PhysicsServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); + + return body->get_combine_mode(p_param); +} + void PhysicsServerSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { BodySW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); @@ -763,6 +777,40 @@ Vector3 PhysicsServerSW::body_get_applied_torque(RID p_body) const { return body->get_applied_torque(); }; +void PhysicsServerSW::body_add_central_force(RID p_body, const Vector3 &p_force) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_central_force(p_force); + body->wakeup(); +} + +void PhysicsServerSW::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_force(p_force, p_pos); + body->wakeup(); +}; + +void PhysicsServerSW::body_add_torque(RID p_body, const Vector3 &p_torque) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_torque(p_torque); + body->wakeup(); +}; + +void PhysicsServerSW::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_central_impulse(p_impulse); + body->wakeup(); +} + void PhysicsServerSW::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) { BodySW *body = body_owner.get(p_body); @@ -1367,6 +1415,8 @@ void PhysicsServerSW::init() { void PhysicsServerSW::step(real_t p_step) { +#ifndef _3D_DISABLED + if (!active) return; @@ -1387,6 +1437,7 @@ void PhysicsServerSW::step(real_t p_step) { active_objects += E->get()->get_active_objects(); collision_pairs += E->get()->get_collision_pairs(); } +#endif } void PhysicsServerSW::sync(){ @@ -1395,6 +1446,8 @@ void PhysicsServerSW::sync(){ void PhysicsServerSW::flush_queries() { +#ifndef _3D_DISABLED + if (!active) return; @@ -1441,6 +1494,7 @@ void PhysicsServerSW::flush_queries() { ScriptDebugger::get_singleton()->add_profiling_frame_data("physics", values); } +#endif }; void PhysicsServerSW::finish() { diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 3f56ba26d0..57037fb325 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -188,6 +188,10 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value); virtual real_t body_get_param(RID p_body, BodyParameter p_param) const; + /// p_param accept only Bounce and Friction + virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); + virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; + virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin); virtual real_t body_get_kinematic_safe_margin(RID p_body) const; @@ -200,6 +204,11 @@ public: virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque); virtual Vector3 body_get_applied_torque(RID p_body) const; + virtual void body_add_central_force(RID p_body, const Vector3 &p_force); + virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos); + virtual void body_add_torque(RID p_body, const Vector3 &p_torque); + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse); virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); @@ -230,6 +239,72 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); + /* SOFT BODY */ + + virtual RID soft_body_create(bool p_init_sleeping = false) { return RID(); } + + virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) {} + + virtual void soft_body_set_space(RID p_body, RID p_space) {} + virtual RID soft_body_get_space(RID p_body) const { return RID(); } + + virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {} + virtual uint32_t soft_body_get_collision_layer(RID p_body) const { return 0; } + + virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {} + virtual uint32_t soft_body_get_collision_mask(RID p_body) const { return 0; } + + virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) {} + virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) {} + virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {} + + virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {} + virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const { return Variant(); } + + virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) {} + virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const { return Vector3(); } + + virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) {} + virtual bool soft_body_is_ray_pickable(RID p_body) const { return false; } + + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {} + virtual int soft_body_get_simulation_precision(RID p_body) { return 0; } + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) {} + virtual real_t soft_body_get_total_mass(RID p_body) { return 0.; } + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {} + virtual real_t soft_body_get_linear_stiffness(RID p_body) { return 0.; } + + virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) {} + virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) { return 0.; } + + virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {} + virtual real_t soft_body_get_volume_stiffness(RID p_body) { return 0.; } + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {} + virtual real_t soft_body_get_pressure_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {} + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {} + virtual real_t soft_body_get_damping_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {} + virtual real_t soft_body_get_drag_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) {} + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {} + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) { return Vector3(); } + + virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const { return Vector3(); } + + virtual void soft_body_remove_all_pinned_points(RID p_body) {} + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {} + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) { return 0; } + /* JOINT API */ virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B); diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index 2452d6a187..4d864e9a51 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -186,7 +186,7 @@ public: void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { - if (contact_debug_count < contact_debug.size()) contact_debug[contact_debug_count++] = p_contact; + if (contact_debug_count < contact_debug.size()) contact_debug.write[contact_debug_count++] = p_contact; } _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contact_debug; } _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; } diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index aa063d6c1e..fcd2a65ee7 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -405,6 +405,22 @@ void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) { area_angular_damp += p_area->get_angular_damp(); } +void Body2DSW::set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode) { + if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) { + bounce_combine_mode = p_mode; + } else { + friction_combine_mode = p_mode; + } +} + +Physics2DServer::CombineMode Body2DSW::get_combine_mode(Physics2DServer::BodyParameter p_param) const { + if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) { + return bounce_combine_mode; + } else { + return friction_combine_mode; + } +} + void Body2DSW::integrate_forces(real_t p_step) { if (mode == Physics2DServer::BODY_MODE_STATIC) diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 782adf3416..fef233a72b 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -54,6 +54,8 @@ class Body2DSW : public CollisionObject2DSW { real_t mass; real_t bounce; real_t friction; + Physics2DServer::CombineMode bounce_combine_mode; + Physics2DServer::CombineMode friction_combine_mode; real_t _inv_mass; real_t _inv_inertia; @@ -139,7 +141,7 @@ public: _FORCE_INLINE_ void add_area(Area2DSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount += 1; + areas.write[index].refCount += 1; } else { areas.ordered_insert(AreaCMP(p_area)); } @@ -148,7 +150,7 @@ public: _FORCE_INLINE_ void remove_area(Area2DSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount -= 1; + areas.write[index].refCount -= 1; if (areas[index].refCount < 1) areas.remove(index); } @@ -199,12 +201,20 @@ public: _FORCE_INLINE_ void set_biased_angular_velocity(real_t p_velocity) { biased_angular_velocity = p_velocity; } _FORCE_INLINE_ real_t get_biased_angular_velocity() const { return biased_angular_velocity; } + _FORCE_INLINE_ void apply_central_impulse(const Vector2 &p_impulse) { + linear_velocity += p_impulse * _inv_mass; + } + _FORCE_INLINE_ void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) { linear_velocity += p_impulse * _inv_mass; angular_velocity += _inv_inertia * p_offset.cross(p_impulse); } + _FORCE_INLINE_ void apply_torque_impulse(real_t p_torque) { + angular_velocity += _inv_inertia * p_torque; + } + _FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_pos, const Vector2 &p_j) { biased_linear_velocity += p_j * _inv_mass; @@ -235,12 +245,20 @@ public: void set_applied_torque(real_t p_torque) { applied_torque = p_torque; } real_t get_applied_torque() const { return applied_torque; } - _FORCE_INLINE_ void add_force(const Vector2 &p_force, const Vector2 &p_offset) { + _FORCE_INLINE_ void add_central_force(const Vector2 &p_force) { + applied_force += p_force; + } + + _FORCE_INLINE_ void add_force(const Vector2 &p_offset, const Vector2 &p_force) { applied_force += p_force; applied_torque += p_offset.cross(p_force); } + _FORCE_INLINE_ void add_torque(real_t p_torque) { + applied_torque += p_torque; + } + _FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode = p_mode; } _FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; } @@ -256,6 +274,12 @@ public: _FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; } _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; } + void set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode); + Physics2DServer::CombineMode get_combine_mode(Physics2DServer::BodyParameter p_param) const; + + _FORCE_INLINE_ Physics2DServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } + _FORCE_INLINE_ Physics2DServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } + void integrate_forces(real_t p_step); void integrate_velocities(real_t p_step); @@ -287,7 +311,7 @@ void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_no if (c_max == 0) return; - Contact *c = &contacts[0]; + Contact *c = contacts.ptrw(); int idx = -1; @@ -349,6 +373,13 @@ public: virtual void set_transform(const Transform2D &p_transform) { body->set_state(Physics2DServer::BODY_STATE_TRANSFORM, p_transform); } virtual Transform2D get_transform() const { return body->get_transform(); } + virtual void add_central_force(const Vector2 &p_force) { body->add_central_force(p_force); } + virtual void add_force(const Vector2 &p_offset, const Vector2 &p_force) { body->add_force(p_offset, p_force); } + virtual void add_torque(real_t p_torque) { body->add_torque(p_torque); } + virtual void apply_central_impulse(const Vector2 &p_impulse) { body->apply_central_impulse(p_impulse); } + virtual void apply_impulse(const Vector2 &p_offset, const Vector2 &p_force) { body->apply_impulse(p_offset, p_force); } + virtual void apply_torque_impulse(real_t p_torque) { body->apply_torque_impulse(p_torque); } + virtual void set_sleep_state(bool p_enable) { body->set_active(!p_enable); } virtual bool is_sleeping() const { return !body->is_active(); } diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index 61c0e0063f..be8dcf6fa8 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -219,6 +219,44 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const return true; } +real_t combine_bounce(Body2DSW *A, Body2DSW *B) { + const Physics2DServer::CombineMode cm = A->get_bounce_combine_mode(); + + switch (cm) { + case Physics2DServer::COMBINE_MODE_INHERIT: + if (B->get_bounce_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT) + return combine_bounce(B, A); + // else use MAX [This is used when the two bodies doesn't use physical material] + case Physics2DServer::COMBINE_MODE_MAX: + return MAX(A->get_bounce(), B->get_bounce()); + case Physics2DServer::COMBINE_MODE_MIN: + return MIN(A->get_bounce(), B->get_bounce()); + case Physics2DServer::COMBINE_MODE_MULTIPLY: + return A->get_bounce() * B->get_bounce(); + default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE: + return (A->get_bounce() + B->get_bounce()) / 2; + } +} + +real_t combine_friction(Body2DSW *A, Body2DSW *B) { + const Physics2DServer::CombineMode cm = A->get_friction_combine_mode(); + + switch (cm) { + case Physics2DServer::COMBINE_MODE_INHERIT: + if (B->get_friction_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT) + return combine_friction(B, A); + // else use Multiply [This is used when the two bodies doesn't use physical material] + case Physics2DServer::COMBINE_MODE_MULTIPLY: + return A->get_friction() * B->get_friction(); + case Physics2DServer::COMBINE_MODE_MAX: + return MAX(A->get_friction(), B->get_friction()); + case Physics2DServer::COMBINE_MODE_MIN: + return MIN(A->get_friction(), B->get_friction()); + default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE: + return (A->get_friction() + B->get_friction()) / 2; + } +} + bool BodyPair2DSW::setup(real_t p_step) { //cannot collide @@ -432,7 +470,7 @@ bool BodyPair2DSW::setup(real_t p_step) { #endif - c.bounce = MAX(A->get_bounce(), B->get_bounce()); + c.bounce = combine_bounce(A, B); if (c.bounce) { Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x); @@ -488,7 +526,7 @@ void BodyPair2DSW::solve(real_t p_step) { real_t jnOld = c.acc_normal_impulse; c.acc_normal_impulse = MAX(jnOld + jn, 0.0f); - real_t friction = A->get_friction() * B->get_friction(); + real_t friction = combine_friction(A, B); real_t jtMax = friction * c.acc_normal_impulse; real_t jt = -vt * c.mass_tangent; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 23084a4241..4dd5b2040f 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -50,7 +50,7 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes[p_index].shape->remove_owner(this); - shapes[p_index].shape = p_shape; + shapes.write[p_index].shape = p_shape; p_shape->add_owner(this); _update_shapes(); @@ -60,15 +60,15 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { void CollisionObject2DSW::set_shape_metadata(int p_index, const Variant &p_metadata) { ERR_FAIL_INDEX(p_index, shapes.size()); - shapes[p_index].metadata = p_metadata; + shapes.write[p_index].metadata = p_metadata; } void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_transform) { ERR_FAIL_INDEX(p_index, shapes.size()); - shapes[p_index].xform = p_transform; - shapes[p_index].xform_inv = p_transform.affine_inverse(); + shapes.write[p_index].xform = p_transform; + shapes.write[p_index].xform_inv = p_transform.affine_inverse(); _update_shapes(); _shapes_changed(); } @@ -76,7 +76,7 @@ void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_ void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, shapes.size()); - CollisionObject2DSW::Shape &shape = shapes[p_idx]; + CollisionObject2DSW::Shape &shape = shapes.write[p_idx]; if (shape.disabled == p_disabled) return; @@ -116,7 +116,7 @@ void CollisionObject2DSW::remove_shape(int p_index) { continue; //should never get here with a null owner space->get_broadphase()->remove(shapes[i].bpid); - shapes[i].bpid = 0; + shapes.write[i].bpid = 0; } shapes[p_index].shape->remove_owner(this); shapes.remove(p_index); @@ -133,7 +133,7 @@ void CollisionObject2DSW::_set_static(bool p_static) { if (!space) return; for (int i = 0; i < get_shape_count(); i++) { - Shape &s = shapes[i]; + const Shape &s = shapes[i]; if (s.bpid > 0) { space->get_broadphase()->set_static(s.bpid, _static); } @@ -144,7 +144,7 @@ void CollisionObject2DSW::_unregister_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid > 0) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; @@ -159,7 +159,7 @@ void CollisionObject2DSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.disabled) continue; @@ -187,7 +187,7 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.disabled) continue; @@ -215,7 +215,7 @@ void CollisionObject2DSW::_set_space(Space2DSW *p_space) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index ab3e219ac0..393c4a6ed7 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -144,7 +144,7 @@ public: _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision) { ERR_FAIL_INDEX(p_idx, shapes.size()); - shapes[p_idx].one_way_collision = p_one_way_collision; + shapes.write[p_idx].one_way_collision = p_one_way_collision; } _FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, shapes.size(), false); diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index a473e0beb2..ba87969eea 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -789,6 +789,22 @@ real_t Physics2DServerSW::body_get_param(RID p_body, BodyParameter p_param) cons return body->get_param(p_param); }; +void Physics2DServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { + + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->set_combine_mode(p_param, p_mode); +} + +Physics2DServer::CombineMode Physics2DServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const { + + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); + + return body->get_combine_mode(p_param); +} + void Physics2DServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { Body2DSW *body = body_owner.get(p_body); @@ -838,6 +854,21 @@ real_t Physics2DServerSW::body_get_applied_torque(RID p_body) const { return body->get_applied_torque(); }; +void Physics2DServerSW::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_impulse(p_impulse); + body->wakeup(); +} + +void Physics2DServerSW::body_apply_torque_impulse(RID p_body, real_t p_torque) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_torque_impulse(p_torque); +} + void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse) { Body2DSW *body = body_owner.get(p_body); @@ -847,12 +878,28 @@ void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, con body->wakeup(); }; +void Physics2DServerSW::body_add_central_force(RID p_body, const Vector2 &p_force) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_central_force(p_force); + body->wakeup(); +}; + void Physics2DServerSW::body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - body->add_force(p_force, p_offset); + body->add_force(p_offset, p_force); + body->wakeup(); +}; + +void Physics2DServerSW::body_add_torque(RID p_body, real_t p_torque) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_torque(p_torque); body->wakeup(); }; diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index e5961b9011..0b8d3f2a31 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -200,6 +200,10 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value); virtual real_t body_get_param(RID p_body, BodyParameter p_param) const; + /// p_param accept only Bounce and Friction + virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); + virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; + virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant); virtual Variant body_get_state(RID p_body, BodyState p_state) const; @@ -209,8 +213,12 @@ public: virtual void body_set_applied_torque(RID p_body, real_t p_torque); virtual real_t body_get_applied_torque(RID p_body) const; + virtual void body_add_central_force(RID p_body, const Vector2 &p_force); virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force); + virtual void body_add_torque(RID p_body, real_t p_torque); + virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse); + virtual void body_apply_torque_impulse(RID p_body, real_t p_torque); virtual void body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index 3119b930d7..b9b0f80805 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -211,6 +211,9 @@ public: FUNC3(body_set_param, RID, BodyParameter, real_t); FUNC2RC(real_t, body_get_param, RID, BodyParameter); + FUNC3(body_set_combine_mode, RID, BodyParameter, CombineMode); + FUNC2RC(CombineMode, body_get_combine_mode, RID, BodyParameter); + FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); @@ -220,7 +223,11 @@ public: FUNC2(body_set_applied_torque, RID, real_t); FUNC1RC(real_t, body_get_applied_torque, RID); + FUNC2(body_add_central_force, RID, const Vector2 &); FUNC3(body_add_force, RID, const Vector2 &, const Vector2 &); + FUNC2(body_add_torque, RID, real_t); + FUNC2(body_apply_central_impulse, RID, const Vector2 &); + FUNC2(body_apply_torque_impulse, RID, real_t); FUNC3(body_apply_impulse, RID, const Vector2 &, const Vector2 &); FUNC2(body_set_axis_velocity, RID, const Vector2 &); diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 2b0eab5999..dc8ec23e69 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -891,8 +891,8 @@ int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) { int l = _generate_bvh(p_bvh, median, p_depth + 1); int r = _generate_bvh(&p_bvh[median], p_len - median, p_depth + 1); - bvh[node_idx].left = l; - bvh[node_idx].right = r; + bvh.write[node_idx].left = l; + bvh.write[node_idx].right = r; return node_idx; } @@ -953,20 +953,20 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) { for (Map<Point2, int>::Element *E = pointmap.front(); E; E = E->next()) { aabb.expand_to(E->key()); - points[E->get()] = E->key(); + points.write[E->get()] = E->key(); } Vector<BVH> main_vbh; main_vbh.resize(segments.size()); for (int i = 0; i < main_vbh.size(); i++) { - main_vbh[i].aabb.position = points[segments[i].points[0]]; - main_vbh[i].aabb.expand_to(points[segments[i].points[1]]); - main_vbh[i].left = -1; - main_vbh[i].right = i; + main_vbh.write[i].aabb.position = points[segments[i].points[0]]; + main_vbh.write[i].aabb.expand_to(points[segments[i].points[1]]); + main_vbh.write[i].left = -1; + main_vbh.write[i].right = i; } - _generate_bvh(&main_vbh[0], main_vbh.size(), 1); + _generate_bvh(main_vbh.ptrw(), main_vbh.size(), 1); } else { //dictionary with arrays diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 959e15e12d..1247317b03 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -188,7 +188,7 @@ public: void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) { - if (contact_debug_count < contact_debug.size()) contact_debug[contact_debug_count++] = p_contact; + if (contact_debug_count < contact_debug.size()) contact_debug.write[contact_debug_count++] = p_contact; } _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; } _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; } diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index cb7669ec24..37c4bc83ad 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -91,6 +91,13 @@ void Physics2DDirectBodyState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform", "transform"), &Physics2DDirectBodyState::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &Physics2DDirectBodyState::get_transform); + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &Physics2DDirectBodyState::add_central_force); + ClassDB::bind_method(D_METHOD("add_force", "offset", "force"), &Physics2DDirectBodyState::add_force); + ClassDB::bind_method(D_METHOD("add_torque", "torque"), &Physics2DDirectBodyState::add_torque); + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &Physics2DDirectBodyState::apply_central_impulse); + ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &Physics2DDirectBodyState::apply_torque_impulse); + ClassDB::bind_method(D_METHOD("apply_impulse", "offset", "impulse"), &Physics2DDirectBodyState::apply_impulse); + ClassDB::bind_method(D_METHOD("set_sleep_state", "enabled"), &Physics2DDirectBodyState::set_sleep_state); ClassDB::bind_method(D_METHOD("is_sleeping"), &Physics2DDirectBodyState::is_sleeping); @@ -191,7 +198,7 @@ Vector<RID> Physics2DShapeQueryParameters::get_exclude() const { ret.resize(exclude.size()); int idx = 0; for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) { - ret[idx] = E->get(); + ret.write[idx] = E->get(); } return ret; } @@ -585,8 +592,12 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &Physics2DServer::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &Physics2DServer::body_get_state); + ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &Physics2DServer::body_apply_central_impulse); + ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &Physics2DServer::body_apply_torque_impulse); ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &Physics2DServer::body_apply_impulse); + ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &Physics2DServer::body_add_central_force); ClassDB::bind_method(D_METHOD("body_add_force", "body", "offset", "force"), &Physics2DServer::body_add_force); + ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &Physics2DServer::body_add_torque); ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &Physics2DServer::body_set_axis_velocity); ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &Physics2DServer::body_add_collision_exception); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 1d04fbc5c6..796eec1e8e 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -61,6 +61,13 @@ public: virtual void set_transform(const Transform2D &p_transform) = 0; virtual Transform2D get_transform() const = 0; + virtual void add_central_force(const Vector2 &p_force) = 0; + virtual void add_force(const Vector2 &p_offset, const Vector2 &p_force) = 0; + virtual void add_torque(real_t p_torque) = 0; + virtual void apply_central_impulse(const Vector2 &p_impulse) = 0; + virtual void apply_torque_impulse(real_t p_torque) = 0; + virtual void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) = 0; + virtual void set_sleep_state(bool p_enable) = 0; virtual bool is_sleeping() const = 0; @@ -416,6 +423,19 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0; virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0; + enum CombineMode { + COMBINE_MODE_MAX, + COMBINE_MODE_MIN, + COMBINE_MODE_MULTIPLY, + COMBINE_MODE_AVERAGE, + + COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction) + }; + + /// p_param accept only Bounce and Friction + virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0; + virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0; + //state enum BodyState { BODY_STATE_TRANSFORM, @@ -435,8 +455,12 @@ public: virtual void body_set_applied_torque(RID p_body, float p_torque) = 0; virtual float body_get_applied_torque(RID p_body) const = 0; + virtual void body_add_central_force(RID p_body, const Vector2 &p_force) = 0; virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) = 0; + virtual void body_add_torque(RID p_body, float p_torque) = 0; + virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) = 0; + virtual void body_apply_torque_impulse(RID p_body, float p_torque) = 0; virtual void body_apply_impulse(RID p_body, const Vector2 &p_offset, const Vector2 &p_impulse) = 0; virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) = 0; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index de173491b2..cda3856ecc 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -95,6 +95,7 @@ void PhysicsDirectBodyState::_bind_methods() { ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState::add_central_force); ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState::add_force); ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState::add_torque); + ClassDB::bind_method(D_METHOD("apply_central_impulse", "j"), &PhysicsDirectBodyState::apply_central_impulse); ClassDB::bind_method(D_METHOD("apply_impulse", "position", "j"), &PhysicsDirectBodyState::apply_impulse); ClassDB::bind_method(D_METHOD("apply_torque_impulse", "j"), &PhysicsDirectBodyState::apply_torque_impulse); @@ -105,6 +106,7 @@ void PhysicsDirectBodyState::_bind_methods() { ClassDB::bind_method(D_METHOD("get_contact_local_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_position); ClassDB::bind_method(D_METHOD("get_contact_local_normal", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_normal); + ClassDB::bind_method(D_METHOD("get_contact_impulse", "contact_idx"), &PhysicsDirectBodyState::get_contact_impulse); ClassDB::bind_method(D_METHOD("get_contact_local_shape", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_shape); ClassDB::bind_method(D_METHOD("get_contact_collider", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider); ClassDB::bind_method(D_METHOD("get_contact_collider_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_position); @@ -191,7 +193,7 @@ Vector<RID> PhysicsShapeQueryParameters::get_exclude() const { ret.resize(exclude.size()); int idx = 0; for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) { - ret[idx] = E->get(); + ret.write[idx] = E->get(); } return ret; } @@ -400,6 +402,8 @@ void PhysicsShapeQueryResult::_bind_methods() { void PhysicsServer::_bind_methods() { +#ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("shape_create", "type"), &PhysicsServer::shape_create); ClassDB::bind_method(D_METHOD("shape_set_data", "shape", "data"), &PhysicsServer::shape_set_data); @@ -493,6 +497,11 @@ void PhysicsServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer::body_get_state); + ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &PhysicsServer::body_add_central_force); + ClassDB::bind_method(D_METHOD("body_add_force", "body", "force", "position"), &PhysicsServer::body_add_force); + ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &PhysicsServer::body_add_torque); + + ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &PhysicsServer::body_apply_central_impulse); ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &PhysicsServer::body_apply_impulse); ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &PhysicsServer::body_apply_torque_impulse); ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &PhysicsServer::body_set_axis_velocity); @@ -737,6 +746,8 @@ void PhysicsServer::_bind_methods() { BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_X); BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Y); BIND_ENUM_CONSTANT(BODY_AXIS_ANGULAR_Z); + +#endif } PhysicsServer::PhysicsServer() { diff --git a/servers/physics_server.h b/servers/physics_server.h index 8ecf17c0e6..294c6b6674 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -66,6 +66,7 @@ public: virtual void add_central_force(const Vector3 &p_force) = 0; virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) = 0; virtual void add_torque(const Vector3 &p_torque) = 0; + virtual void apply_central_impulse(const Vector3 &p_j) = 0; virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) = 0; virtual void apply_torque_impulse(const Vector3 &p_j) = 0; @@ -76,6 +77,7 @@ public: virtual Vector3 get_contact_local_position(int p_contact_idx) const = 0; virtual Vector3 get_contact_local_normal(int p_contact_idx) const = 0; + virtual float get_contact_impulse(int p_contact_idx) const = 0; virtual int get_contact_local_shape(int p_contact_idx) const = 0; virtual RID get_contact_collider(int p_contact_idx) const = 0; @@ -399,6 +401,19 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0; virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0; + enum CombineMode { + COMBINE_MODE_MAX, + COMBINE_MODE_MIN, + COMBINE_MODE_MULTIPLY, + COMBINE_MODE_AVERAGE, + + COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction) + }; + + /// p_param accept only Bounce and Friction + virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0; + virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0; + virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0; virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0; @@ -421,6 +436,11 @@ public: virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque) = 0; virtual Vector3 body_get_applied_torque(RID p_body) const = 0; + virtual void body_add_central_force(RID p_body, const Vector3 &p_force) = 0; + virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) = 0; + virtual void body_add_torque(RID p_body, const Vector3 &p_torque) = 0; + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) = 0; virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) = 0; virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) = 0; virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) = 0; @@ -477,6 +497,72 @@ public: virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL) = 0; + /* SOFT BODY */ + + virtual RID soft_body_create(bool p_init_sleeping = false) = 0; + + virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) = 0; + + virtual void soft_body_set_space(RID p_body, RID p_space) = 0; + virtual RID soft_body_get_space(RID p_body) const = 0; + + virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) = 0; + + virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) = 0; + virtual uint32_t soft_body_get_collision_layer(RID p_body) const = 0; + + virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; + virtual uint32_t soft_body_get_collision_mask(RID p_body) const = 0; + + virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) = 0; + virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) = 0; + virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0; + + virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0; + virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const = 0; + + virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) = 0; + virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const = 0; + + virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0; + virtual bool soft_body_is_ray_pickable(RID p_body) const = 0; + + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) = 0; + virtual int soft_body_get_simulation_precision(RID p_body) = 0; + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) = 0; + virtual real_t soft_body_get_total_mass(RID p_body) = 0; + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_linear_stiffness(RID p_body) = 0; + + virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) = 0; + + virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_volume_stiffness(RID p_body) = 0; + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) = 0; + virtual real_t soft_body_get_pressure_coefficient(RID p_body) = 0; + + virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) = 0; + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) = 0; + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) = 0; + virtual real_t soft_body_get_damping_coefficient(RID p_body) = 0; + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) = 0; + virtual real_t soft_body_get_drag_coefficient(RID p_body) = 0; + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0; + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) = 0; + + virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const = 0; + + virtual void soft_body_remove_all_pinned_points(RID p_body) = 0; + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0; + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) = 0; + /* JOINT API */ enum JointType { diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0b37d266e7..5ce4f2b62d 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -104,10 +104,12 @@ public: VS::ShadowCastingSetting cast_shadows; + //fit in 32 bits bool mirror : 8; bool receive_shadows : 8; bool visible : 8; - bool baked_light : 8; //this flag is only to know if it actually did use baked light + bool baked_light : 4; //this flag is only to know if it actually did use baked light + bool redraw_if_visible : 4; float depth; //used for sorting @@ -131,6 +133,7 @@ public: depth_layer = 0; layer_mask = 1; baked_light = false; + redraw_if_visible = false; lightmap_capture = NULL; } }; @@ -277,6 +280,7 @@ public: virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const = 0; + virtual void mesh_clear(RID p_mesh) = 0; /* MULTIMESH API */ @@ -1074,7 +1078,7 @@ public: virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) = 0; virtual void initialize() = 0; - virtual void begin_frame() = 0; + virtual void begin_frame(double frame_step) = 0; virtual void set_current_render_target(RID p_render_target) = 0; virtual void restore_render_target() = 0; virtual void clear_render_target(const Color &p_color) = 0; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index fd1eb77143..1783ef4525 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -612,6 +612,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } ERR_PRINT("BUG"); return Token(); + +#undef GETCHAR } String ShaderLanguage::token_debug(const String &p_code) { @@ -1376,6 +1378,15 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID } }, { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID } }, + //conversion between matrixes + + { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID } }, + { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID } }, + { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID } }, + { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID } }, + { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID } }, + { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID } }, + //builtins - trigonometry { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } }, @@ -2460,7 +2471,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons //add to current function as dependency for (int j = 0; j < shader->functions.size(); j++) { if (shader->functions[j].name == current_function) { - shader->functions[j].uses_function.insert(name); + shader->functions.write[j].uses_function.insert(name); break; } } @@ -3010,8 +3021,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } op->arguments.push_back(expression[i + 1].node); - expression[i].is_op = false; - expression[i].node = op; + expression.write[i].is_op = false; + expression.write[i].node = op; if (!_validate_operator(op, &op->return_cache)) { @@ -3045,8 +3056,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->arguments.push_back(expression[next_op + 1].node); op->arguments.push_back(expression[next_op + 3].node); - expression[next_op - 1].is_op = false; - expression[next_op - 1].node = op; + expression.write[next_op - 1].is_op = false; + expression.write[next_op - 1].node = op; if (!_validate_operator(op, &op->return_cache)) { String at; @@ -3096,7 +3107,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->arguments.push_back(expression[next_op - 1].node); //expression goes as left op->arguments.push_back(expression[next_op + 1].node); //next expression goes as right - expression[next_op - 1].node = op; + expression.write[next_op - 1].node = op; //replace all 3 nodes by this operator and make it an expression @@ -3138,7 +3149,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha for (int i = 1; i < op->arguments.size(); i++) { - op->arguments[i] = _reduce_expression(p_block, op->arguments[i]); + op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]); if (op->arguments[i]->type == Node::TYPE_CONSTANT) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i]); @@ -3178,7 +3189,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha return cn; } else if (op->op == OP_NEGATE) { - op->arguments[0] = _reduce_expression(p_block, op->arguments[0]); + op->arguments.write[0] = _reduce_expression(p_block, op->arguments[0]); if (op->arguments[0]->type == Node::TYPE_CONSTANT) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[0]); @@ -4064,13 +4075,58 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return OK; } +// skips over whitespace and /* */ and // comments +static int _get_first_ident_pos(const String &p_code) { + + int idx = 0; + +#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0)) + + while (true) { + if (GETCHAR(0) == '/' && GETCHAR(1) == '/') { + idx += 2; + while (true) { + if (GETCHAR(0) == 0) return 0; + if (GETCHAR(0) == '\n') { + idx++; + break; // loop + } + idx++; + } + } else if (GETCHAR(0) == '/' && GETCHAR(1) == '*') { + idx += 2; + while (true) { + if (GETCHAR(0) == 0) return 0; + if (GETCHAR(0) == '*' && GETCHAR(1) == '/') { + idx += 2; + break; // loop + } + idx++; + } + } else { + switch (GETCHAR(0)) { + case ' ': + case '\t': + case '\r': + case '\n': { + idx++; + } break; // switch + default: + return idx; + } + } + } + +#undef GETCHAR +} + String ShaderLanguage::get_shader_type(const String &p_code) { bool reading_type = false; String cur_identifier; - for (int i = 0; i < p_code.length(); i++) { + for (int i = _get_first_ident_pos(p_code); i < p_code.length(); i++) { if (p_code[i] == ';') { break; diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 6439ba8509..a1c6e83296 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -220,7 +220,7 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr for (int i = 0; i < l; i++) { - Canvas::ChildItem &ci = p_canvas->child_items[i]; + const Canvas::ChildItem &ci = p_canvas->child_items[i]; _render_canvas_item_tree(ci.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); //mirroring (useful for scrolling backgrounds) @@ -263,7 +263,7 @@ void VisualServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, con int idx = canvas->find_item(canvas_item); ERR_FAIL_COND(idx == -1); - canvas->child_items[idx].mirror = p_mirroring; + canvas->child_items.write[idx].mirror = p_mirroring; } void VisualServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) { @@ -468,21 +468,21 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; if (p_antialiased) { - pline->lines[i] = p_points[i] + tangent; - pline->lines[p_points.size() * 2 - i - 1] = p_points[i] - tangent; + pline->lines.write[i] = p_points[i] + tangent; + pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent; if (pline->line_colors.size() > 1) { - pline->line_colors[i] = p_colors[i]; - pline->line_colors[p_points.size() * 2 - i - 1] = p_colors[i]; + pline->line_colors.write[i] = p_colors[i]; + pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i]; } } - pline->triangles[i * 2 + 0] = p_points[i] + tangent; - pline->triangles[i * 2 + 1] = p_points[i] - tangent; + pline->triangles.write[i * 2 + 0] = p_points[i] + tangent; + pline->triangles.write[i * 2 + 1] = p_points[i] - tangent; if (pline->triangle_colors.size() > 1) { - pline->triangle_colors[i * 2 + 0] = p_colors[i]; - pline->triangle_colors[i * 2 + 1] = p_colors[i]; + pline->triangle_colors.write[i * 2 + 0] = p_colors[i]; + pline->triangle_colors.write[i * 2 + 1] = p_colors[i]; } prev_t = t; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 5f207b1d3f..6bf3670e5a 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -93,14 +93,14 @@ void VisualServerRaster::request_frame_drawn_callback(Object *p_where, const Str frame_drawn_callbacks.push_back(fdc); } -void VisualServerRaster::draw(bool p_swap_buffers) { +void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { //needs to be done before changes is reset to 0, to not force the editor to redraw VS::get_singleton()->emit_signal("frame_pre_draw"); changes = 0; - VSG::rasterizer->begin_frame(); + VSG::rasterizer->begin_frame(frame_step); VSG::scene->update_dirty_instances(); //update scene stuff diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index ec0d02ed2a..d58be21858 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -660,7 +660,7 @@ public: virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata); - virtual void draw(bool p_swap_buffers); + virtual void draw(bool p_swap_buffers, double frame_step); virtual void sync(); virtual bool has_changed() const; virtual void init(); diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 697c890c9a..73d18e61b6 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -589,7 +589,7 @@ void VisualServerScene::instance_set_blend_shape_weight(RID p_instance, int p_sh } ERR_FAIL_INDEX(p_shape, instance->blend_values.size()); - instance->blend_values[p_shape] = p_weight; + instance->blend_values.write[p_shape] = p_weight; } void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { @@ -606,7 +606,7 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf if (instance->materials[p_surface].is_valid()) { VSG::storage->material_remove_instance_owner(instance->materials[p_surface], instance); } - instance->materials[p_surface] = p_material; + instance->materials.write[p_surface] = p_material; instance->base_material_changed(); if (instance->materials[p_surface].is_valid()) { @@ -820,6 +820,11 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF instance->baked_light = p_enabled; } break; + case VS::INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE: { + + instance->redraw_if_visible = p_enabled; + + } break; } } void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) { @@ -1248,7 +1253,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) Vector3 dir = to_cell_xform.basis.xform(cone_traces[i]).normalized(); Color capture = _light_capture_voxel_cone_trace(octree_r.ptr(), pos, dir, cone_aperture, cell_subdiv); - p_instance->lightmap_capture_data[i] += capture; + p_instance->lightmap_capture_data.write[i] += capture; } } } @@ -1459,14 +1464,14 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons light_frustum_planes.resize(6); //right/left - light_frustum_planes[0] = Plane(x_vec, x_max); - light_frustum_planes[1] = Plane(-x_vec, -x_min); + light_frustum_planes.write[0] = Plane(x_vec, x_max); + light_frustum_planes.write[1] = Plane(-x_vec, -x_min); //top/bottom - light_frustum_planes[2] = Plane(y_vec, y_max); - light_frustum_planes[3] = Plane(-y_vec, -y_min); + light_frustum_planes.write[2] = Plane(y_vec, y_max); + light_frustum_planes.write[3] = Plane(-y_vec, -y_min); //near/far - light_frustum_planes[4] = Plane(z_vec, z_max + 1e6); - light_frustum_planes[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed + light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6); + light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK); @@ -1527,11 +1532,11 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons float z = i == 0 ? -1 : 1; Vector<Plane> planes; planes.resize(5); - planes[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); - planes[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); - planes[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); - planes[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); - planes[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); + planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); + planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); + planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); + planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); + planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK); Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); @@ -1644,7 +1649,8 @@ 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 +// render to mono camera +#ifndef _3D_DISABLED Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); @@ -1679,6 +1685,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view _prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); _render_scene(camera->transform, camera_matrix, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1); +#endif } 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) { @@ -1871,6 +1878,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data); + if (ins->redraw_if_visible) { + VisualServerRaster::redraw_request(); + } + if (ins->base_type == VS::INSTANCE_PARTICLES) { //particles visible? process them VSG::storage->particles_request_process(ins->base); @@ -1887,7 +1898,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - ins->light_instances[l++] = light->instance; + ins->light_instances.write[l++] = light->instance; } geom->lighting_dirty = false; @@ -1902,7 +1913,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); - ins->reflection_probe_instances[l++] = reflection_probe->instance; + ins->reflection_probe_instances.write[l++] = reflection_probe->instance; } geom->reflection_dirty = false; @@ -1917,7 +1928,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); - ins->gi_probe_instances[l++] = gi_probe->probe_instance; + ins->gi_probe_instances.write[l++] = gi_probe->probe_instance; } geom->gi_probes_dirty = false; @@ -2102,6 +2113,8 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform, const Cam void VisualServerScene::render_empty_scene(RID p_scenario, RID p_shadow_atlas) { +#ifndef _3D_DISABLED + Scenario *scenario = scenario_owner.getornull(p_scenario); RID environment; @@ -2110,6 +2123,7 @@ void VisualServerScene::render_empty_scene(RID p_scenario, RID p_shadow_atlas) { else environment = scenario->fallback_environment; VSG::scene_render->render_scene(Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0); +#endif } bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int p_step) { @@ -2358,7 +2372,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { uint32_t key = blockz * blockw * blockh + blocky * blockw + blockx; - Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> &cmap = comp_blocks[mipmap]; + Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> &cmap = comp_blocks.write[mipmap]; if (!cmap.has(key)) { @@ -2378,8 +2392,8 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { for (int i = 0; i < mipmap_count; i++) { print_line("S3TC level: " + itos(i) + " blocks: " + itos(comp_blocks[i].size())); - probe->dynamic.mipmaps_s3tc[i].resize(comp_blocks[i].size()); - PoolVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc[i].write(); + probe->dynamic.mipmaps_s3tc.write[i].resize(comp_blocks[i].size()); + PoolVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc.write[i].write(); int block_idx = 0; for (Map<uint32_t, InstanceGIProbeData::CompBlockS3TC>::Element *E = comp_blocks[i].front(); E; E = E->next()) { @@ -2847,7 +2861,7 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { 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(); - PoolVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d[stage].write(); + PoolVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d.write[stage].write(); uint8_t *mipmapw = lw.ptr(); uint32_t sizes[3] = { header->width >> stage, header->height >> stage, header->depth >> stage }; @@ -2876,7 +2890,7 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { for (int mmi = 0; mmi < mipmap_count; mmi++) { - PoolVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d[mmi].write(); + PoolVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d.write[mmi].write(); int block_count = probe_data->dynamic.mipmaps_s3tc[mmi].size(); PoolVector<InstanceGIProbeData::CompBlockS3TC>::Read mmr = probe_data->dynamic.mipmaps_s3tc[mmi].read(); @@ -3209,7 +3223,7 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (new_blend_shape_count != p_instance->blend_values.size()) { p_instance->blend_values.resize(new_blend_shape_count); for (int i = 0; i < new_blend_shape_count; i++) { - p_instance->blend_values[i] = 0; + p_instance->blend_values.write[i] = 0; } } } diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index 094e2794ed..93f3792bdc 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -37,11 +37,11 @@ void VisualServerWrapMT::thread_exit() { exit = true; } -void VisualServerWrapMT::thread_draw() { +void VisualServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) { if (!atomic_decrement(&draw_pending)) { - visual_server->draw(); + visual_server->draw(p_swap_buffers, frame_step); } } @@ -91,15 +91,15 @@ void VisualServerWrapMT::sync() { } } -void VisualServerWrapMT::draw(bool p_swap_buffers) { +void VisualServerWrapMT::draw(bool p_swap_buffers, double frame_step) { if (create_thread) { atomic_increment(&draw_pending); - command_queue.push(this, &VisualServerWrapMT::thread_draw); + command_queue.push(this, &VisualServerWrapMT::thread_draw, p_swap_buffers, frame_step); } else { - visual_server->draw(p_swap_buffers); + visual_server->draw(p_swap_buffers, frame_step); } } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 48f0ec46f3..c6af960d9f 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -55,7 +55,7 @@ class VisualServerWrapMT : public VisualServer { bool create_thread; uint64_t draw_pending; - void thread_draw(); + void thread_draw(bool p_swap_buffers, double frame_step); void thread_flush(); void thread_exit(); @@ -578,7 +578,7 @@ public: virtual void init(); virtual void finish(); - virtual void draw(bool p_swap_buffers); + virtual void draw(bool p_swap_buffers, double frame_step); virtual void sync(); FUNC0RC(bool, has_changed) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index dffaccc0d4..cca74302e6 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -187,16 +187,14 @@ RID VisualServer::_make_test_cube() { PoolVector<float> tangents; PoolVector<Vector3> uvs; - int vtx_idx = 0; -#define ADD_VTX(m_idx) \ - vertices.push_back(face_points[m_idx]); \ - normals.push_back(normal_points[m_idx]); \ - tangents.push_back(normal_points[m_idx][1]); \ - tangents.push_back(normal_points[m_idx][2]); \ - tangents.push_back(normal_points[m_idx][0]); \ - tangents.push_back(1.0); \ - uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0)); \ - vtx_idx++; +#define ADD_VTX(m_idx) \ + vertices.push_back(face_points[m_idx]); \ + normals.push_back(normal_points[m_idx]); \ + tangents.push_back(normal_points[m_idx][1]); \ + tangents.push_back(normal_points[m_idx][2]); \ + tangents.push_back(normal_points[m_idx][0]); \ + tangents.push_back(1.0); \ + uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0)); for (int i = 0; i < 6; i++) { @@ -746,7 +744,7 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ if (first) { for (int i = 0; i < total_bones; i++) { - r_bone_aabb[i].size = Vector3(-1, -1, -1); //negative means unused + r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused } } @@ -795,6 +793,140 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ return OK; } +uint32_t VisualServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const { + uint32_t offsets[ARRAY_MAX]; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); + return offsets[p_array_index]; +} + +uint32_t VisualServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const { + uint32_t offsets[ARRAY_MAX]; + return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); +} + +uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const { + + int total_elem_size = 0; + + for (int i = 0; i < VS::ARRAY_MAX; i++) { + + r_offsets[i] = 0; //reset + + if (!(p_format & (1 << i))) // no array + continue; + + int elem_size = 0; + + switch (i) { + + case VS::ARRAY_VERTEX: { + + if (p_format & ARRAY_FLAG_USE_2D_VERTICES) { + elem_size = 2; + } else { + elem_size = 3; + } + + if (p_format & ARRAY_COMPRESS_VERTEX) { + elem_size *= sizeof(int16_t); + } else { + elem_size *= sizeof(float); + } + + if (elem_size == 6) { + elem_size = 8; + } + + } break; + case VS::ARRAY_NORMAL: { + + if (p_format & ARRAY_COMPRESS_NORMAL) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 3; + } + + } break; + + case VS::ARRAY_TANGENT: { + if (p_format & ARRAY_COMPRESS_TANGENT) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 4; + } + + } break; + case VS::ARRAY_COLOR: { + + if (p_format & ARRAY_COMPRESS_COLOR) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 4; + } + } break; + case VS::ARRAY_TEX_UV: { + if (p_format & ARRAY_COMPRESS_TEX_UV) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 2; + } + + } break; + + case VS::ARRAY_TEX_UV2: { + if (p_format & ARRAY_COMPRESS_TEX_UV2) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 2; + } + + } break; + case VS::ARRAY_WEIGHTS: { + + if (p_format & ARRAY_COMPRESS_WEIGHTS) { + elem_size = sizeof(uint16_t) * 4; + } else { + elem_size = sizeof(float) * 4; + } + + } break; + case VS::ARRAY_BONES: { + + if (p_format & ARRAY_FLAG_USE_16_BIT_BONES) { + elem_size = sizeof(uint16_t) * 4; + } else { + elem_size = sizeof(uint32_t); + } + + } break; + case VS::ARRAY_INDEX: { + + if (p_index_len <= 0) { + ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); + break; + } + /* determine whether using 16 or 32 bits indices */ + if (p_vertex_len >= (1 << 16)) { + + elem_size = 4; + + } else { + elem_size = 2; + } + r_offsets[i] = elem_size; + continue; + } break; + default: { + ERR_FAIL_V(0); + } + } + + r_offsets[i] = total_elem_size; + total_elem_size += elem_size; + } + return total_elem_size; +} + void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format) { ERR_FAIL_INDEX(p_primitive, VS::PRIMITIVE_MAX); @@ -1516,13 +1648,13 @@ Array VisualServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surfa void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("force_sync"), &VisualServer::sync); - ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers"), &VisualServer::draw, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &VisualServer::draw, DEFVAL(true), DEFVAL(0.0)); // "draw" and "sync" are deprecated duplicates of "force_draw" and "force_sync" // FIXME: Add deprecation messages using GH-4397 once available, and retire // once the warnings have been enabled for a full release cycle ClassDB::bind_method(D_METHOD("sync"), &VisualServer::sync); - ClassDB::bind_method(D_METHOD("draw", "swap_buffers"), &VisualServer::draw, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("draw", "swap_buffers", "frame_step"), &VisualServer::draw, DEFVAL(true), DEFVAL(0.0)); ClassDB::bind_method(D_METHOD("texture_create"), &VisualServer::texture_create); ClassDB::bind_method(D_METHOD("texture_create_from_image", "image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); @@ -1543,10 +1675,10 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_debug_usage"), &VisualServer::_texture_debug_usage_bind); ClassDB::bind_method(D_METHOD("textures_keep_original", "enable"), &VisualServer::textures_keep_original); - +#ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("sky_create"), &VisualServer::sky_create); ClassDB::bind_method(D_METHOD("sky_set_texture", "sky", "cube_map", "radiance_size"), &VisualServer::sky_set_texture); - +#endif ClassDB::bind_method(D_METHOD("shader_create"), &VisualServer::shader_create); ClassDB::bind_method(D_METHOD("shader_set_code", "shader", "code"), &VisualServer::shader_set_code); ClassDB::bind_method(D_METHOD("shader_get_code", "shader"), &VisualServer::shader_get_code); @@ -1564,11 +1696,14 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &VisualServer::material_set_next_pass); ClassDB::bind_method(D_METHOD("mesh_create"), &VisualServer::mesh_create); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &VisualServer::mesh_surface_get_format_offset); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &VisualServer::mesh_surface_get_format_stride); ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primtive", "arrays", "blend_shapes", "compress_format"), &VisualServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_count", "mesh", "amount"), &VisualServer::mesh_set_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &VisualServer::mesh_get_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &VisualServer::mesh_set_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &VisualServer::mesh_get_blend_shape_mode); + ClassDB::bind_method(D_METHOD("mesh_surface_update_region", "mesh", "surface", "offset", "data"), &VisualServer::mesh_surface_update_region); ClassDB::bind_method(D_METHOD("mesh_surface_set_material", "mesh", "surface", "material"), &VisualServer::mesh_surface_set_material); ClassDB::bind_method(D_METHOD("mesh_surface_get_material", "mesh", "surface"), &VisualServer::mesh_surface_get_material); ClassDB::bind_method(D_METHOD("mesh_surface_get_array_len", "mesh", "surface"), &VisualServer::mesh_surface_get_array_len); @@ -1603,7 +1738,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("multimesh_set_visible_instances", "multimesh", "visible"), &VisualServer::multimesh_set_visible_instances); ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &VisualServer::multimesh_get_visible_instances); ClassDB::bind_method(D_METHOD("multimesh_set_as_bulk_array", "multimesh", "array"), &VisualServer::multimesh_set_as_bulk_array); - +#ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("immediate_create"), &VisualServer::immediate_create); ClassDB::bind_method(D_METHOD("immediate_begin", "immediate", "primitive", "texture"), &VisualServer::immediate_begin, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("immediate_vertex", "immediate", "vertex"), &VisualServer::immediate_vertex); @@ -1617,6 +1752,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("immediate_clear", "immediate"), &VisualServer::immediate_clear); ClassDB::bind_method(D_METHOD("immediate_set_material", "immediate", "material"), &VisualServer::immediate_set_material); ClassDB::bind_method(D_METHOD("immediate_get_material", "immediate"), &VisualServer::immediate_get_material); +#endif ClassDB::bind_method(D_METHOD("skeleton_create"), &VisualServer::skeleton_create); ClassDB::bind_method(D_METHOD("skeleton_allocate", "skeleton", "bones", "is_2d_skeleton"), &VisualServer::skeleton_allocate, DEFVAL(false)); @@ -1626,6 +1762,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform_2d", "skeleton", "bone", "transform"), &VisualServer::skeleton_bone_set_transform_2d); ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform_2d", "skeleton", "bone"), &VisualServer::skeleton_bone_get_transform_2d); +#ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("directional_light_create"), &VisualServer::directional_light_create); ClassDB::bind_method(D_METHOD("omni_light_create"), &VisualServer::omni_light_create); ClassDB::bind_method(D_METHOD("spot_light_create"), &VisualServer::spot_light_create); @@ -1695,7 +1832,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &VisualServer::lightmap_capture_get_octree); ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &VisualServer::lightmap_capture_set_energy); ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &VisualServer::lightmap_capture_get_energy); - +#endif ClassDB::bind_method(D_METHOD("particles_create"), &VisualServer::particles_create); ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &VisualServer::particles_set_emitting); ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &VisualServer::particles_get_emitting); @@ -1771,7 +1908,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &VisualServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &VisualServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance", "roughness"), &VisualServer::environment_set_ssr); - ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "radius2", "intensity2", "bias", "light_affect", "color", "quality", "blur", "bilateral_sharpness"), &VisualServer::environment_set_ssao); + ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "radius2", "intensity2", "bias", "light_affect", "ao_channel_affect", "color", "quality", "blur", "bilateral_sharpness"), &VisualServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "color", "sun_color", "sun_amount"), &VisualServer::environment_set_fog); ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "enable", "depth_begin", "depth_curve", "transmit", "transmit_curve"), &VisualServer::environment_set_fog_depth); ClassDB::bind_method(D_METHOD("environment_set_fog_height", "env", "enable", "min_height", "max_height", "height_curve"), &VisualServer::environment_set_fog_height); @@ -1782,6 +1919,8 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("scenario_set_reflection_atlas_size", "scenario", "p_size", "subdiv"), &VisualServer::scenario_set_reflection_atlas_size); ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &VisualServer::scenario_set_fallback_environment); +#ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("instance_create2", "base", "scenario"), &VisualServer::instance_create2); ClassDB::bind_method(D_METHOD("instance_create"), &VisualServer::instance_create); ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &VisualServer::instance_set_base); @@ -1806,7 +1945,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &VisualServer::_instances_cull_aabb_bind, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &VisualServer::_instances_cull_ray_bind, DEFVAL(RID())); ClassDB::bind_method(D_METHOD("instances_cull_convex", "convex", "scenario"), &VisualServer::_instances_cull_convex_bind, DEFVAL(RID())); - +#endif ClassDB::bind_method(D_METHOD("canvas_create"), &VisualServer::canvas_create); ClassDB::bind_method(D_METHOD("canvas_set_item_mirroring", "canvas", "item", "mirroring"), &VisualServer::canvas_set_item_mirroring); ClassDB::bind_method(D_METHOD("canvas_set_modulate", "canvas", "color"), &VisualServer::canvas_set_modulate); @@ -1889,13 +2028,14 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("init"), &VisualServer::init); ClassDB::bind_method(D_METHOD("finish"), &VisualServer::finish); ClassDB::bind_method(D_METHOD("get_render_info", "info"), &VisualServer::get_render_info); +#ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &VisualServer::make_sphere_mesh); ClassDB::bind_method(D_METHOD("get_test_cube"), &VisualServer::get_test_cube); +#endif ClassDB::bind_method(D_METHOD("get_test_texture"), &VisualServer::get_test_texture); ClassDB::bind_method(D_METHOD("get_white_texture"), &VisualServer::get_white_texture); - ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &VisualServer::make_sphere_mesh); - ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale"), &VisualServer::set_boot_image); ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &VisualServer::set_default_clear_color); @@ -2061,6 +2201,7 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK); BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT); + BIND_ENUM_CONSTANT(INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE); BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF); diff --git a/servers/visual_server.h b/servers/visual_server.h index 968cb852ed..8a4a4e2d36 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -251,6 +251,10 @@ public: virtual RID mesh_create() = 0; + virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const; + virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const; + /// Returns stride + virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const; virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes = Vector<PoolVector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()) = 0; @@ -805,6 +809,7 @@ public: enum InstanceFlags { INSTANCE_FLAG_USE_BAKED_LIGHT, + INSTANCE_FLAG_REDRAW_FRAME_IF_VISIBLE, INSTANCE_FLAG_MAX }; @@ -950,7 +955,7 @@ public: /* EVENT QUEUING */ - virtual void draw(bool p_swap_buffers = true) = 0; + virtual void draw(bool p_swap_buffers = true, double frame_step = 0.0) = 0; virtual void sync() = 0; virtual bool has_changed() const = 0; virtual void init() = 0; |