diff options
65 files changed, 1604 insertions, 893 deletions
diff --git a/LICENSE.txt b/LICENSE.txt index 0b5b0c341f..bcce1a3a33 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -18,5 +18,3 @@ 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. - --- Godot Engine <https://godotengine.org> @@ -26,6 +26,8 @@ Before being open sourced in February 2014, Godot had been developed by Juan Linietsky and Ariel Manzur (both still maintaining the project) for several years as an in-house engine, used to publish several work-for-hire titles. + + ### Getting the engine #### Binary downloads diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index b47e611a51..12b892d873 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -413,6 +413,7 @@ String _OS::get_latin_keyboard_variant() const { case OS::LATIN_KEYBOARD_QZERTY: return "QZERTY"; case OS::LATIN_KEYBOARD_DVORAK: return "DVORAK"; case OS::LATIN_KEYBOARD_NEO: return "NEO"; + case OS::LATIN_KEYBOARD_COLEMAK: return "COLEMAK"; default: return "ERROR"; } } diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 6fb688f16b..64e01e5841 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -176,3 +176,18 @@ float Math::random(float from, float to) { float ret = (float)r / (float)RANDOM_MAX; return (ret) * (to - from) + from; } + +int Math::wrapi(int value, int min, int max) { + --max; + int rng = max - min + 1; + value = ((value - min) % rng); + if (value < 0) + return max + 1 + value; + else + return min + value; +} + +float Math::wrapf(float value, float min, float max) { + float rng = max - min; + return min + (value - min) - (rng * floor((value - min) / rng)); +} diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 65b2ffb0df..7715e5d6e5 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -207,6 +207,9 @@ public: static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } + static int wrapi(int value, int min, int max); + static float wrapf(float value, float min, float max); + // double only, as these functions are mainly used by the editor and not performance-critical, static double ease(double p_x, double p_c); static int step_decimals(double p_step); @@ -268,7 +271,7 @@ public: #elif defined(_MSC_VER) && _MSC_VER < 1800 __asm fld a __asm fistp b -/*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) + /*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) // use AT&T inline assembly style, document that // we use memory as output (=m) and input (m) __asm__ __volatile__ ( diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index 85421c074b..ab3bca79ae 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -279,7 +279,7 @@ Vector3 Basis::get_signed_scale() const { // Decomposes a Basis into a rotation-reflection matrix (an element of the group O(3)) and a positive scaling matrix as B = O.S. // Returns the rotation-reflection matrix via reference argument, and scaling information is returned as a Vector3. -// This (internal) function is too specıfıc and named too ugly to expose to users, and probably there's no need to do so. +// This (internal) function is too specific and named too ugly to expose to users, and probably there's no need to do so. Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const { #ifdef MATH_CHECKS ERR_FAIL_COND_V(determinant() == 0, Vector3()); @@ -371,31 +371,30 @@ Vector3 Basis::get_euler_xyz() const { #ifdef MATH_CHECKS ERR_FAIL_COND_V(is_rotation() == false, euler); #endif - euler.y = Math::asin(elements[0][2]); - if (euler.y < Math_PI * 0.5) { - if (euler.y > -Math_PI * 0.5) { + real_t sy = elements[0][2]; + if (sy < 1.0) { + if (sy > -1.0) { // is this a pure Y rotation? if (elements[1][0] == 0.0 && elements[0][1] == 0.0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) { - // return the simplest form + // return the simplest form (human friendlier in editor and scripts) euler.x = 0; euler.y = atan2(elements[0][2], elements[0][0]); euler.z = 0; } else { euler.x = Math::atan2(-elements[1][2], elements[2][2]); + euler.y = Math::asin(sy); euler.z = Math::atan2(-elements[0][1], elements[0][0]); } - } else { - real_t r = Math::atan2(elements[1][0], elements[1][1]); + euler.x = -Math::atan2(elements[0][1], elements[1][1]); + euler.y = -Math_PI / 2.0; euler.z = 0.0; - euler.x = euler.z - r; } } else { - real_t r = Math::atan2(elements[0][1], elements[1][1]); - euler.z = 0; - euler.x = r - euler.z; + euler.x = Math::atan2(elements[0][1], elements[1][1]); + euler.y = Math_PI / 2.0; + euler.z = 0.0; } - return euler; } @@ -445,7 +444,7 @@ Vector3 Basis::get_euler_yxz() const { if (m12 > -1) { // is this a pure X rotation? if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) { - // return the simplest form + // return the simplest form (human friendlier in editor and scripts) euler.x = atan2(-m12, elements[1][1]); euler.y = 0; euler.z = 0; diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 30e7d5e791..edf4f3e2f9 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -505,6 +505,27 @@ static const _KeyCodeReplace _keycode_replace_neo[] = { { 0, 0 } }; +static const _KeyCodeReplace _keycode_replace_colemak[] = { + { KEY_E, KEY_F }, + { KEY_R, KEY_P }, + { KEY_T, KEY_G }, + { KEY_Y, KEY_J }, + { KEY_U, KEY_L }, + { KEY_I, KEY_U }, + { KEY_O, KEY_Y }, + { KEY_P, KEY_SEMICOLON }, + { KEY_S, KEY_R }, + { KEY_D, KEY_S }, + { KEY_F, KEY_T }, + { KEY_G, KEY_D }, + { KEY_J, KEY_N }, + { KEY_K, KEY_E }, + { KEY_L, KEY_I }, + { KEY_SEMICOLON, KEY_O }, + { KEY_N, KEY_K }, + { 0, 0 } +}; + int keycode_get_count() { const _KeyCodeText *kct = &_keycodes[0]; @@ -537,6 +558,7 @@ int latin_keyboard_keycode_convert(int p_keycode) { case OS::LATIN_KEYBOARD_QZERTY: kcr = _keycode_replace_qzerty; break; case OS::LATIN_KEYBOARD_DVORAK: kcr = _keycode_replace_dvorak; break; case OS::LATIN_KEYBOARD_NEO: kcr = _keycode_replace_neo; break; + case OS::LATIN_KEYBOARD_COLEMAK: kcr = _keycode_replace_colemak; break; default: return p_keycode; } diff --git a/core/os/os.h b/core/os/os.h index 48effe99da..f5e479ac0b 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -409,6 +409,7 @@ public: LATIN_KEYBOARD_QZERTY, LATIN_KEYBOARD_DVORAK, LATIN_KEYBOARD_NEO, + LATIN_KEYBOARD_COLEMAK, }; virtual LatinKeyboardVariant get_latin_keyboard_variant() const; diff --git a/core/ustring.cpp b/core/ustring.cpp index b85996e3d1..415494ddc8 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -2476,6 +2476,11 @@ bool String::begins_with(const char *p_string) const { return *p_string == 0; } +bool String::is_enclosed_in(const String &p_string) const { + + return begins_with(p_string) && ends_with(p_string); +} + bool String::is_subsequence_of(const String &p_string) const { return _base_is_subsequence_of(p_string, false); @@ -2486,6 +2491,11 @@ bool String::is_subsequence_ofi(const String &p_string) const { return _base_is_subsequence_of(p_string, true); } +bool String::is_quoted() const { + + return is_enclosed_in("\"") || is_enclosed_in("'"); +} + bool String::_base_is_subsequence_of(const String &p_string, bool case_insensitive) const { int len = length(); @@ -2747,6 +2757,48 @@ CharType String::ord_at(int p_idx) const { return operator[](p_idx); } +String String::dedent() const { + + String new_string; + String indent; + bool has_indent = false; + bool has_text = false; + int line_start = 0; + int indent_stop = -1; + + for (int i = 0; i < length(); i++) { + + CharType c = operator[](i); + if (c == '\n') { + if (has_text) + new_string += substr(indent_stop, i - indent_stop); + new_string += "\n"; + has_text = false; + line_start = i + 1; + indent_stop = -1; + } else if (!has_text) { + if (c > 32) { + has_text = true; + if (!has_indent) { + has_indent = true; + indent = substr(line_start, i - line_start); + indent_stop = i; + } + } + if (has_indent && indent_stop < 0) { + int j = i - line_start; + if (j >= indent.length() || c != indent[j]) + indent_stop = i; + } + } + } + + if (has_text) + new_string += substr(indent_stop, length() - indent_stop); + + return new_string; +} + String String::strip_edges(bool left, bool right) const { int len = length(); @@ -3906,6 +3958,18 @@ String String::sprintf(const Array &values, bool *error) const { return formatted; } +String String::quote(String quotechar) const { + return quotechar + *this + quotechar; +} + +String String::unquote() const { + if (!is_quoted()) { + return *this; + } + + return substr(1, length() - 2); +} + #include "translation.h" #ifdef TOOLS_ENABLED diff --git a/core/ustring.h b/core/ustring.h index ab4e325f2c..353c8e6c1d 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -118,8 +118,10 @@ public: bool begins_with(const String &p_string) const; bool begins_with(const char *p_string) const; bool ends_with(const String &p_string) const; + bool is_enclosed_in(const String &p_string) const; bool is_subsequence_of(const String &p_string) const; bool is_subsequence_ofi(const String &p_string) const; + bool is_quoted() const; Vector<String> bigrams() const; float similarity(const String &p_string) const; String format(const Variant &values, String placeholder = "{_}") const; @@ -132,6 +134,8 @@ public: String lpad(int min_length, const String &character = " ") const; String rpad(int min_length, const String &character = " ") const; String sprintf(const Array &values, bool *error) const; + String quote(String quotechar = "\"") const; + String unquote() const; static String num(double p_num, int p_decimals = -1); static String num_scientific(double p_num); static String num_real(double p_num); @@ -172,6 +176,7 @@ public: String left(int p_pos) const; String right(int p_pos) const; + String dedent() const; String strip_edges(bool left = true, bool right = true) const; String strip_escapes() const; String get_extension() const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index d141621fbb..1a29b92810 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -54,9 +54,8 @@ struct _VariantCall { Variant::Type return_type; bool _const; -#ifdef DEBUG_ENABLED bool returns; -#endif + VariantFunc func; _FORCE_INLINE_ bool verify_arguments(const Variant **p_args, Variant::CallError &r_error) { @@ -146,7 +145,7 @@ struct _VariantCall { #endif } - static void addfunc(bool p_const, Variant::Type p_type, Variant::Type p_return, const StringName &p_name, VariantFunc p_func, const Vector<Variant> &p_defaultarg, const Arg &p_argtype1 = Arg(), const Arg &p_argtype2 = Arg(), const Arg &p_argtype3 = Arg(), const Arg &p_argtype4 = Arg(), const Arg &p_argtype5 = Arg()) { + static void addfunc(bool p_const, Variant::Type p_type, Variant::Type p_return, bool p_has_return, const StringName &p_name, VariantFunc p_func, const Vector<Variant> &p_defaultarg, const Arg &p_argtype1 = Arg(), const Arg &p_argtype2 = Arg(), const Arg &p_argtype3 = Arg(), const Arg &p_argtype4 = Arg(), const Arg &p_argtype5 = Arg()) { FuncData funcdata; funcdata.func = p_func; @@ -154,7 +153,7 @@ struct _VariantCall { funcdata._const = p_const; #ifdef DEBUG_ENABLED funcdata.return_type = p_return; - funcdata.returns = p_return != Variant::NIL; + funcdata.returns = p_has_return; #endif if (p_argtype1.name) { @@ -261,6 +260,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(String, to_lower); VCALL_LOCALMEM1R(String, left); VCALL_LOCALMEM1R(String, right); + VCALL_LOCALMEM0R(String, dedent); VCALL_LOCALMEM2R(String, strip_edges); VCALL_LOCALMEM0R(String, get_extension); VCALL_LOCALMEM0R(String, get_basename); @@ -1051,7 +1051,6 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return String(); // math types - case VECTOR2: return Vector2(); // 5 case RECT2: return Rect2(); @@ -1234,7 +1233,7 @@ Variant::Type Variant::get_method_return_type(Variant::Type p_type, const String return Variant::NIL; if (r_has_return) - *r_has_return = E->get().return_type; + *r_has_return = E->get().returns; return E->get().return_type; } @@ -1376,215 +1375,238 @@ void register_variant_methods() { _VariantCall::construct_funcs = memnew_arr(_VariantCall::ConstructFunc, Variant::VARIANT_MAX); _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX); +#define ADDFUNC0R(m_vtype, m_ret, m_class, m_method, m_defarg) \ + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg); +#define ADDFUNC1R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \ + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1))); +#define ADDFUNC2R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \ + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2))); +#define ADDFUNC3R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \ + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3))); +#define ADDFUNC4R(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \ + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4))); + +#define ADDFUNC0RNC(m_vtype, m_ret, m_class, m_method, m_defarg) \ + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg); +#define ADDFUNC1RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \ + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1))); +#define ADDFUNC2RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \ + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2))); +#define ADDFUNC3RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \ + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3))); +#define ADDFUNC4RNC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \ + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, true, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4))); + #define ADDFUNC0(m_vtype, m_ret, m_class, m_method, m_defarg) \ - _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg); + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg); #define ADDFUNC1(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \ - _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1))); + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1))); #define ADDFUNC2(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \ - _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2))); + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2))); #define ADDFUNC3(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \ - _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3))); + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3))); #define ADDFUNC4(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \ - _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4))); + _VariantCall::addfunc(true, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4))); #define ADDFUNC0NC(m_vtype, m_ret, m_class, m_method, m_defarg) \ - _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg); + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg); #define ADDFUNC1NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_defarg) \ - _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1))); + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1))); #define ADDFUNC2NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_defarg) \ - _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2))); + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2))); #define ADDFUNC3NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_defarg) \ - _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3))); + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3))); #define ADDFUNC4NC(m_vtype, m_ret, m_class, m_method, m_arg1, m_argname1, m_arg2, m_argname2, m_arg3, m_argname3, m_arg4, m_argname4, m_defarg) \ - _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4))); + _VariantCall::addfunc(false, Variant::m_vtype, Variant::m_ret, false, _scs_create(#m_method), VCALL(m_class, m_method), m_defarg, _VariantCall::Arg(Variant::m_arg1, _scs_create(m_argname1)), _VariantCall::Arg(Variant::m_arg2, _scs_create(m_argname2)), _VariantCall::Arg(Variant::m_arg3, _scs_create(m_argname3)), _VariantCall::Arg(Variant::m_arg4, _scs_create(m_argname4))); /* STRING */ - ADDFUNC1(STRING, INT, String, casecmp_to, STRING, "to", varray()); - ADDFUNC1(STRING, INT, String, nocasecmp_to, STRING, "to", varray()); - ADDFUNC0(STRING, INT, String, length, varray()); - ADDFUNC2(STRING, STRING, String, substr, INT, "from", INT, "len", varray()); - - ADDFUNC2(STRING, INT, String, find, STRING, "what", INT, "from", varray(0)); - - ADDFUNC1(STRING, INT, String, find_last, STRING, "what", varray()); - ADDFUNC2(STRING, INT, String, findn, STRING, "what", INT, "from", varray(0)); - ADDFUNC2(STRING, INT, String, rfind, STRING, "what", INT, "from", varray(-1)); - ADDFUNC2(STRING, INT, String, rfindn, STRING, "what", INT, "from", varray(-1)); - ADDFUNC1(STRING, BOOL, String, match, STRING, "expr", varray()); - ADDFUNC1(STRING, BOOL, String, matchn, STRING, "expr", varray()); - ADDFUNC1(STRING, BOOL, String, begins_with, STRING, "text", varray()); - ADDFUNC1(STRING, BOOL, String, ends_with, STRING, "text", varray()); - ADDFUNC1(STRING, BOOL, String, is_subsequence_of, STRING, "text", varray()); - ADDFUNC1(STRING, BOOL, String, is_subsequence_ofi, STRING, "text", varray()); - ADDFUNC0(STRING, POOL_STRING_ARRAY, String, bigrams, varray()); - ADDFUNC1(STRING, REAL, String, similarity, STRING, "text", varray()); - - ADDFUNC2(STRING, STRING, String, format, NIL, "values", STRING, "placeholder", varray("{_}")); - ADDFUNC2(STRING, STRING, String, replace, STRING, "what", STRING, "forwhat", varray()); - ADDFUNC2(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray()); - ADDFUNC2(STRING, STRING, String, insert, INT, "position", STRING, "what", varray()); - ADDFUNC0(STRING, STRING, String, capitalize, varray()); - ADDFUNC2(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", varray(true)); - ADDFUNC2(STRING, POOL_REAL_ARRAY, String, split_floats, STRING, "divisor", BOOL, "allow_empty", varray(true)); - - ADDFUNC0(STRING, STRING, String, to_upper, varray()); - ADDFUNC0(STRING, STRING, String, to_lower, varray()); - - ADDFUNC1(STRING, STRING, String, left, INT, "position", varray()); - ADDFUNC1(STRING, STRING, String, right, INT, "position", varray()); - ADDFUNC2(STRING, STRING, String, strip_edges, BOOL, "left", BOOL, "right", varray(true, true)); - ADDFUNC0(STRING, STRING, String, get_extension, varray()); - ADDFUNC0(STRING, STRING, String, get_basename, varray()); - ADDFUNC1(STRING, STRING, String, plus_file, STRING, "file", varray()); - ADDFUNC1(STRING, INT, String, ord_at, INT, "at", varray()); + ADDFUNC1R(STRING, INT, String, casecmp_to, STRING, "to", varray()); + ADDFUNC1R(STRING, INT, String, nocasecmp_to, STRING, "to", varray()); + ADDFUNC0R(STRING, INT, String, length, varray()); + ADDFUNC2R(STRING, STRING, String, substr, INT, "from", INT, "len", varray()); + + ADDFUNC2R(STRING, INT, String, find, STRING, "what", INT, "from", varray(0)); + + ADDFUNC1R(STRING, INT, String, find_last, STRING, "what", varray()); + ADDFUNC2R(STRING, INT, String, findn, STRING, "what", INT, "from", varray(0)); + ADDFUNC2R(STRING, INT, String, rfind, STRING, "what", INT, "from", varray(-1)); + ADDFUNC2R(STRING, INT, String, rfindn, STRING, "what", INT, "from", varray(-1)); + ADDFUNC1R(STRING, BOOL, String, match, STRING, "expr", varray()); + ADDFUNC1R(STRING, BOOL, String, matchn, STRING, "expr", varray()); + ADDFUNC1R(STRING, BOOL, String, begins_with, STRING, "text", varray()); + ADDFUNC1R(STRING, BOOL, String, ends_with, STRING, "text", varray()); + ADDFUNC1R(STRING, BOOL, String, is_subsequence_of, STRING, "text", varray()); + ADDFUNC1R(STRING, BOOL, String, is_subsequence_ofi, STRING, "text", varray()); + ADDFUNC0R(STRING, POOL_STRING_ARRAY, String, bigrams, varray()); + ADDFUNC1R(STRING, REAL, String, similarity, STRING, "text", varray()); + + ADDFUNC2R(STRING, STRING, String, format, NIL, "values", STRING, "placeholder", varray("{_}")); + ADDFUNC2R(STRING, STRING, String, replace, STRING, "what", STRING, "forwhat", varray()); + ADDFUNC2R(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray()); + ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray()); + ADDFUNC0R(STRING, STRING, String, capitalize, varray()); + ADDFUNC2R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", varray(true)); + ADDFUNC2R(STRING, POOL_REAL_ARRAY, String, split_floats, STRING, "divisor", BOOL, "allow_empty", varray(true)); + + ADDFUNC0R(STRING, STRING, String, to_upper, varray()); + ADDFUNC0R(STRING, STRING, String, to_lower, varray()); + + ADDFUNC1R(STRING, STRING, String, left, INT, "position", varray()); + ADDFUNC1R(STRING, STRING, String, right, INT, "position", varray()); + ADDFUNC2R(STRING, STRING, String, strip_edges, BOOL, "left", BOOL, "right", varray(true, true)); + ADDFUNC0R(STRING, STRING, String, get_extension, varray()); + ADDFUNC0R(STRING, STRING, String, get_basename, varray()); + ADDFUNC1R(STRING, STRING, String, plus_file, STRING, "file", varray()); + ADDFUNC1R(STRING, INT, String, ord_at, INT, "at", varray()); + ADDFUNC0(STRING, STRING, String, dedent, varray()); ADDFUNC2(STRING, NIL, String, erase, INT, "position", INT, "chars", varray()); - ADDFUNC0(STRING, INT, String, hash, varray()); - ADDFUNC0(STRING, STRING, String, md5_text, varray()); - ADDFUNC0(STRING, STRING, String, sha256_text, varray()); - ADDFUNC0(STRING, POOL_BYTE_ARRAY, String, md5_buffer, varray()); - ADDFUNC0(STRING, POOL_BYTE_ARRAY, String, sha256_buffer, varray()); - ADDFUNC0(STRING, BOOL, String, empty, varray()); - ADDFUNC0(STRING, BOOL, String, is_abs_path, varray()); - ADDFUNC0(STRING, BOOL, String, is_rel_path, varray()); - ADDFUNC0(STRING, STRING, String, get_base_dir, varray()); - ADDFUNC0(STRING, STRING, String, get_file, varray()); - ADDFUNC0(STRING, STRING, String, xml_escape, varray()); - ADDFUNC0(STRING, STRING, String, xml_unescape, varray()); - ADDFUNC0(STRING, STRING, String, c_escape, varray()); - ADDFUNC0(STRING, STRING, String, c_unescape, varray()); - ADDFUNC0(STRING, STRING, String, json_escape, varray()); - ADDFUNC0(STRING, STRING, String, percent_encode, varray()); - ADDFUNC0(STRING, STRING, String, percent_decode, varray()); - ADDFUNC0(STRING, BOOL, String, is_valid_identifier, varray()); - ADDFUNC0(STRING, BOOL, String, is_valid_integer, varray()); - ADDFUNC0(STRING, BOOL, String, is_valid_float, varray()); - ADDFUNC0(STRING, BOOL, String, is_valid_html_color, varray()); - ADDFUNC0(STRING, BOOL, String, is_valid_ip_address, varray()); - ADDFUNC0(STRING, INT, String, to_int, varray()); - ADDFUNC0(STRING, REAL, String, to_float, varray()); - ADDFUNC0(STRING, INT, String, hex_to_int, varray()); - ADDFUNC1(STRING, STRING, String, pad_decimals, INT, "digits", varray()); - ADDFUNC1(STRING, STRING, String, pad_zeros, INT, "digits", varray()); - - ADDFUNC0(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray()); - ADDFUNC0(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray()); - - ADDFUNC0(VECTOR2, VECTOR2, Vector2, normalized, varray()); - ADDFUNC0(VECTOR2, REAL, Vector2, length, varray()); - ADDFUNC0(VECTOR2, REAL, Vector2, angle, varray()); - ADDFUNC0(VECTOR2, REAL, Vector2, length_squared, varray()); - ADDFUNC0(VECTOR2, BOOL, Vector2, is_normalized, varray()); - ADDFUNC1(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray()); - ADDFUNC1(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray()); - ADDFUNC1(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); - ADDFUNC1(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray()); - ADDFUNC2(VECTOR2, VECTOR2, Vector2, linear_interpolate, VECTOR2, "b", REAL, "t", varray()); - ADDFUNC4(VECTOR2, VECTOR2, Vector2, cubic_interpolate, VECTOR2, "b", VECTOR2, "pre_a", VECTOR2, "post_b", REAL, "t", varray()); - ADDFUNC1(VECTOR2, VECTOR2, Vector2, rotated, REAL, "phi", varray()); - ADDFUNC0(VECTOR2, VECTOR2, Vector2, tangent, varray()); - ADDFUNC0(VECTOR2, VECTOR2, Vector2, floor, varray()); - ADDFUNC1(VECTOR2, VECTOR2, Vector2, snapped, VECTOR2, "by", varray()); - ADDFUNC0(VECTOR2, REAL, Vector2, aspect, varray()); - ADDFUNC1(VECTOR2, REAL, Vector2, dot, VECTOR2, "with", varray()); - ADDFUNC1(VECTOR2, VECTOR2, Vector2, slide, VECTOR2, "n", varray()); - ADDFUNC1(VECTOR2, VECTOR2, Vector2, bounce, VECTOR2, "n", varray()); - ADDFUNC1(VECTOR2, VECTOR2, Vector2, reflect, VECTOR2, "n", varray()); - //ADDFUNC1(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray()); - ADDFUNC0(VECTOR2, VECTOR2, Vector2, abs, varray()); - ADDFUNC1(VECTOR2, VECTOR2, Vector2, clamped, REAL, "length", varray()); - - ADDFUNC0(RECT2, REAL, Rect2, get_area, varray()); - ADDFUNC1(RECT2, BOOL, Rect2, intersects, RECT2, "b", varray()); - ADDFUNC1(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray()); - ADDFUNC0(RECT2, BOOL, Rect2, has_no_area, varray()); - ADDFUNC1(RECT2, RECT2, Rect2, clip, RECT2, "b", varray()); - ADDFUNC1(RECT2, RECT2, Rect2, merge, RECT2, "b", varray()); - ADDFUNC1(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray()); - ADDFUNC1(RECT2, RECT2, Rect2, grow, REAL, "by", varray()); - ADDFUNC2(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray()); - ADDFUNC4(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray()); - ADDFUNC1(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); - - ADDFUNC0(VECTOR3, INT, Vector3, min_axis, varray()); - ADDFUNC0(VECTOR3, INT, Vector3, max_axis, varray()); - ADDFUNC0(VECTOR3, REAL, Vector3, length, varray()); - ADDFUNC0(VECTOR3, REAL, Vector3, length_squared, varray()); - ADDFUNC0(VECTOR3, BOOL, Vector3, is_normalized, varray()); - ADDFUNC0(VECTOR3, VECTOR3, Vector3, normalized, varray()); - ADDFUNC0(VECTOR3, VECTOR3, Vector3, inverse, varray()); - ADDFUNC1(VECTOR3, VECTOR3, Vector3, snapped, REAL, "by", varray()); - ADDFUNC2(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", REAL, "phi", varray()); - ADDFUNC2(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray()); - ADDFUNC4(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray()); - ADDFUNC1(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray()); - ADDFUNC1(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray()); - ADDFUNC1(VECTOR3, BASIS, Vector3, outer, VECTOR3, "b", varray()); - ADDFUNC0(VECTOR3, BASIS, Vector3, to_diagonal_matrix, varray()); - ADDFUNC0(VECTOR3, VECTOR3, Vector3, abs, varray()); - ADDFUNC0(VECTOR3, VECTOR3, Vector3, floor, varray()); - ADDFUNC0(VECTOR3, VECTOR3, Vector3, ceil, varray()); - ADDFUNC1(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); - ADDFUNC1(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); - ADDFUNC1(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); - ADDFUNC1(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray()); - ADDFUNC1(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray()); - ADDFUNC1(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray()); - - ADDFUNC0(PLANE, PLANE, Plane, normalized, varray()); - ADDFUNC0(PLANE, VECTOR3, Plane, center, varray()); - ADDFUNC0(PLANE, VECTOR3, Plane, get_any_point, varray()); - ADDFUNC1(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray()); - ADDFUNC1(PLANE, REAL, Plane, distance_to, VECTOR3, "point", varray()); - ADDFUNC2(PLANE, BOOL, Plane, has_point, VECTOR3, "point", REAL, "epsilon", varray(CMP_EPSILON)); - ADDFUNC1(PLANE, VECTOR3, Plane, project, VECTOR3, "point", varray()); - ADDFUNC2(PLANE, VECTOR3, Plane, intersect_3, PLANE, "b", PLANE, "c", varray()); - ADDFUNC2(PLANE, VECTOR3, Plane, intersects_ray, VECTOR3, "from", VECTOR3, "dir", varray()); - ADDFUNC2(PLANE, VECTOR3, Plane, intersects_segment, VECTOR3, "begin", VECTOR3, "end", varray()); - - ADDFUNC0(QUAT, REAL, Quat, length, varray()); - ADDFUNC0(QUAT, REAL, Quat, length_squared, varray()); - ADDFUNC0(QUAT, QUAT, Quat, normalized, varray()); - ADDFUNC0(QUAT, BOOL, Quat, is_normalized, varray()); - ADDFUNC0(QUAT, QUAT, Quat, inverse, varray()); - ADDFUNC1(QUAT, REAL, Quat, dot, QUAT, "b", varray()); - ADDFUNC1(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray()); - ADDFUNC2(QUAT, QUAT, Quat, slerp, QUAT, "b", REAL, "t", varray()); - ADDFUNC2(QUAT, QUAT, Quat, slerpni, QUAT, "b", REAL, "t", varray()); - ADDFUNC4(QUAT, QUAT, Quat, cubic_slerp, QUAT, "b", QUAT, "pre_a", QUAT, "post_b", REAL, "t", varray()); - - ADDFUNC0(COLOR, INT, Color, to_rgba32, varray()); - ADDFUNC0(COLOR, INT, Color, to_argb32, varray()); - ADDFUNC0(COLOR, REAL, Color, gray, varray()); - ADDFUNC0(COLOR, COLOR, Color, inverted, varray()); - ADDFUNC0(COLOR, COLOR, Color, contrasted, varray()); - ADDFUNC2(COLOR, COLOR, Color, linear_interpolate, COLOR, "b", REAL, "t", varray()); - ADDFUNC1(COLOR, COLOR, Color, blend, COLOR, "over", varray()); - ADDFUNC1(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true)); - - ADDFUNC0(_RID, INT, RID, get_id, varray()); - - ADDFUNC0(NODE_PATH, BOOL, NodePath, is_absolute, varray()); - ADDFUNC0(NODE_PATH, INT, NodePath, get_name_count, varray()); - ADDFUNC1(NODE_PATH, STRING, NodePath, get_name, INT, "idx", varray()); - ADDFUNC0(NODE_PATH, INT, NodePath, get_subname_count, varray()); - ADDFUNC1(NODE_PATH, STRING, NodePath, get_subname, INT, "idx", varray()); - ADDFUNC0(NODE_PATH, STRING, NodePath, get_property, varray()); - ADDFUNC0(NODE_PATH, BOOL, NodePath, is_empty, varray()); - - ADDFUNC0(DICTIONARY, INT, Dictionary, size, varray()); - ADDFUNC0(DICTIONARY, BOOL, Dictionary, empty, varray()); + ADDFUNC0R(STRING, INT, String, hash, varray()); + ADDFUNC0R(STRING, STRING, String, md5_text, varray()); + ADDFUNC0R(STRING, STRING, String, sha256_text, varray()); + ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, md5_buffer, varray()); + ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, sha256_buffer, varray()); + ADDFUNC0R(STRING, BOOL, String, empty, varray()); + ADDFUNC0R(STRING, BOOL, String, is_abs_path, varray()); + ADDFUNC0R(STRING, BOOL, String, is_rel_path, varray()); + ADDFUNC0R(STRING, STRING, String, get_base_dir, varray()); + ADDFUNC0R(STRING, STRING, String, get_file, varray()); + ADDFUNC0R(STRING, STRING, String, xml_escape, varray()); + ADDFUNC0R(STRING, STRING, String, xml_unescape, varray()); + ADDFUNC0R(STRING, STRING, String, c_escape, varray()); + ADDFUNC0R(STRING, STRING, String, c_unescape, varray()); + ADDFUNC0R(STRING, STRING, String, json_escape, varray()); + ADDFUNC0R(STRING, STRING, String, percent_encode, varray()); + ADDFUNC0R(STRING, STRING, String, percent_decode, varray()); + ADDFUNC0R(STRING, BOOL, String, is_valid_identifier, varray()); + ADDFUNC0R(STRING, BOOL, String, is_valid_integer, varray()); + ADDFUNC0R(STRING, BOOL, String, is_valid_float, varray()); + ADDFUNC0R(STRING, BOOL, String, is_valid_html_color, varray()); + ADDFUNC0R(STRING, BOOL, String, is_valid_ip_address, varray()); + ADDFUNC0R(STRING, INT, String, to_int, varray()); + ADDFUNC0R(STRING, REAL, String, to_float, varray()); + ADDFUNC0R(STRING, INT, String, hex_to_int, varray()); + ADDFUNC1R(STRING, STRING, String, pad_decimals, INT, "digits", varray()); + ADDFUNC1R(STRING, STRING, String, pad_zeros, INT, "digits", varray()); + + ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray()); + ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray()); + + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, normalized, varray()); + ADDFUNC0R(VECTOR2, REAL, Vector2, length, varray()); + ADDFUNC0R(VECTOR2, REAL, Vector2, angle, varray()); + ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray()); + ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray()); + ADDFUNC2R(VECTOR2, VECTOR2, Vector2, linear_interpolate, VECTOR2, "b", REAL, "t", varray()); + ADDFUNC4R(VECTOR2, VECTOR2, Vector2, cubic_interpolate, VECTOR2, "b", VECTOR2, "pre_a", VECTOR2, "post_b", REAL, "t", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, rotated, REAL, "phi", varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, tangent, varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, floor, varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, snapped, VECTOR2, "by", varray()); + ADDFUNC0R(VECTOR2, REAL, Vector2, aspect, varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, dot, VECTOR2, "with", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, slide, VECTOR2, "n", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, bounce, VECTOR2, "n", varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, reflect, VECTOR2, "n", varray()); + //ADDFUNC1R(VECTOR2,REAL,Vector2,cross,VECTOR2,"with",varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, abs, varray()); + ADDFUNC1R(VECTOR2, VECTOR2, Vector2, clamped, REAL, "length", varray()); + + ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray()); + ADDFUNC1R(RECT2, BOOL, Rect2, intersects, RECT2, "b", varray()); + ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray()); + ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray()); + ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, grow, REAL, "by", varray()); + ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray()); + ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); + + ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray()); + ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray()); + ADDFUNC0R(VECTOR3, REAL, Vector3, length, varray()); + ADDFUNC0R(VECTOR3, REAL, Vector3, length_squared, varray()); + ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, normalized, varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, inverse, varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, REAL, "by", varray()); + ADDFUNC2R(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", REAL, "phi", varray()); + ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray()); + ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, BASIS, Vector3, outer, VECTOR3, "b", varray()); + ADDFUNC0R(VECTOR3, BASIS, Vector3, to_diagonal_matrix, varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, abs, varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray()); + ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray()); + + ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray()); + ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray()); + ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray()); + ADDFUNC1R(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray()); + ADDFUNC1R(PLANE, REAL, Plane, distance_to, VECTOR3, "point", varray()); + ADDFUNC2R(PLANE, BOOL, Plane, has_point, VECTOR3, "point", REAL, "epsilon", varray(CMP_EPSILON)); + ADDFUNC1R(PLANE, VECTOR3, Plane, project, VECTOR3, "point", varray()); + ADDFUNC2R(PLANE, VECTOR3, Plane, intersect_3, PLANE, "b", PLANE, "c", varray()); + ADDFUNC2R(PLANE, VECTOR3, Plane, intersects_ray, VECTOR3, "from", VECTOR3, "dir", varray()); + ADDFUNC2R(PLANE, VECTOR3, Plane, intersects_segment, VECTOR3, "begin", VECTOR3, "end", varray()); + + ADDFUNC0R(QUAT, REAL, Quat, length, varray()); + ADDFUNC0R(QUAT, REAL, Quat, length_squared, varray()); + ADDFUNC0R(QUAT, QUAT, Quat, normalized, varray()); + ADDFUNC0R(QUAT, BOOL, Quat, is_normalized, varray()); + ADDFUNC0R(QUAT, QUAT, Quat, inverse, varray()); + ADDFUNC1R(QUAT, REAL, Quat, dot, QUAT, "b", varray()); + ADDFUNC1R(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray()); + ADDFUNC2R(QUAT, QUAT, Quat, slerp, QUAT, "b", REAL, "t", varray()); + ADDFUNC2R(QUAT, QUAT, Quat, slerpni, QUAT, "b", REAL, "t", varray()); + ADDFUNC4R(QUAT, QUAT, Quat, cubic_slerp, QUAT, "b", QUAT, "pre_a", QUAT, "post_b", REAL, "t", varray()); + + ADDFUNC0R(COLOR, INT, Color, to_rgba32, varray()); + ADDFUNC0R(COLOR, INT, Color, to_argb32, varray()); + ADDFUNC0R(COLOR, REAL, Color, gray, varray()); + ADDFUNC0R(COLOR, COLOR, Color, inverted, varray()); + ADDFUNC0R(COLOR, COLOR, Color, contrasted, varray()); + ADDFUNC2R(COLOR, COLOR, Color, linear_interpolate, COLOR, "b", REAL, "t", varray()); + ADDFUNC1R(COLOR, COLOR, Color, blend, COLOR, "over", varray()); + ADDFUNC1R(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true)); + + ADDFUNC0R(_RID, INT, RID, get_id, varray()); + + ADDFUNC0R(NODE_PATH, BOOL, NodePath, is_absolute, varray()); + ADDFUNC0R(NODE_PATH, INT, NodePath, get_name_count, varray()); + ADDFUNC1R(NODE_PATH, STRING, NodePath, get_name, INT, "idx", varray()); + ADDFUNC0R(NODE_PATH, INT, NodePath, get_subname_count, varray()); + ADDFUNC1R(NODE_PATH, STRING, NodePath, get_subname, INT, "idx", varray()); + ADDFUNC0R(NODE_PATH, STRING, NodePath, get_property, varray()); + ADDFUNC0R(NODE_PATH, BOOL, NodePath, is_empty, varray()); + + ADDFUNC0R(DICTIONARY, INT, Dictionary, size, varray()); + ADDFUNC0R(DICTIONARY, BOOL, Dictionary, empty, varray()); ADDFUNC0NC(DICTIONARY, NIL, Dictionary, clear, varray()); - ADDFUNC1(DICTIONARY, BOOL, Dictionary, has, NIL, "key", varray()); - ADDFUNC1(DICTIONARY, BOOL, Dictionary, has_all, ARRAY, "keys", varray()); + ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has, NIL, "key", varray()); + ADDFUNC1R(DICTIONARY, BOOL, Dictionary, has_all, ARRAY, "keys", varray()); ADDFUNC1(DICTIONARY, NIL, Dictionary, erase, NIL, "key", varray()); - ADDFUNC0(DICTIONARY, INT, Dictionary, hash, varray()); - ADDFUNC0(DICTIONARY, ARRAY, Dictionary, keys, varray()); - ADDFUNC0(DICTIONARY, ARRAY, Dictionary, values, varray()); + ADDFUNC0R(DICTIONARY, INT, Dictionary, hash, varray()); + ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray()); + ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray()); - ADDFUNC0(ARRAY, INT, Array, size, varray()); - ADDFUNC0(ARRAY, BOOL, Array, empty, varray()); + ADDFUNC0R(ARRAY, INT, Array, size, varray()); + ADDFUNC0R(ARRAY, BOOL, Array, empty, varray()); ADDFUNC0NC(ARRAY, NIL, Array, clear, varray()); - ADDFUNC0(ARRAY, INT, Array, hash, varray()); + ADDFUNC0R(ARRAY, INT, Array, hash, varray()); ADDFUNC1NC(ARRAY, NIL, Array, push_back, NIL, "value", varray()); ADDFUNC1NC(ARRAY, NIL, Array, push_front, NIL, "value", varray()); ADDFUNC1NC(ARRAY, NIL, Array, append, NIL, "value", varray()); @@ -1592,165 +1614,160 @@ void register_variant_methods() { ADDFUNC2NC(ARRAY, NIL, Array, insert, INT, "position", NIL, "value", varray()); ADDFUNC1NC(ARRAY, NIL, Array, remove, INT, "position", varray()); ADDFUNC1NC(ARRAY, NIL, Array, erase, NIL, "value", varray()); - ADDFUNC0(ARRAY, NIL, Array, front, varray()); - ADDFUNC0(ARRAY, NIL, Array, back, varray()); - ADDFUNC2(ARRAY, INT, Array, find, NIL, "what", INT, "from", varray(0)); - ADDFUNC2(ARRAY, INT, Array, rfind, NIL, "what", INT, "from", varray(-1)); - ADDFUNC1(ARRAY, INT, Array, find_last, NIL, "value", varray()); - ADDFUNC1(ARRAY, INT, Array, count, NIL, "value", varray()); - ADDFUNC1(ARRAY, BOOL, Array, has, NIL, "value", varray()); - ADDFUNC0NC(ARRAY, NIL, Array, pop_back, varray()); - ADDFUNC0NC(ARRAY, NIL, Array, pop_front, varray()); + ADDFUNC0R(ARRAY, NIL, Array, front, varray()); + ADDFUNC0R(ARRAY, NIL, Array, back, varray()); + ADDFUNC2R(ARRAY, INT, Array, find, NIL, "what", INT, "from", varray(0)); + ADDFUNC2R(ARRAY, INT, Array, rfind, NIL, "what", INT, "from", varray(-1)); + ADDFUNC1R(ARRAY, INT, Array, find_last, NIL, "value", varray()); + ADDFUNC1R(ARRAY, INT, Array, count, NIL, "value", varray()); + ADDFUNC1R(ARRAY, BOOL, Array, has, NIL, "value", varray()); + ADDFUNC0RNC(ARRAY, NIL, Array, pop_back, varray()); + ADDFUNC0RNC(ARRAY, NIL, Array, pop_front, varray()); ADDFUNC0NC(ARRAY, NIL, Array, sort, varray()); ADDFUNC2NC(ARRAY, NIL, Array, sort_custom, OBJECT, "obj", STRING, "func", varray()); ADDFUNC0NC(ARRAY, NIL, Array, invert, varray()); - ADDFUNC0NC(ARRAY, ARRAY, Array, duplicate, varray()); + ADDFUNC0RNC(ARRAY, ARRAY, Array, duplicate, varray()); - ADDFUNC0(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray()); + ADDFUNC0R(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray()); ADDFUNC2(POOL_BYTE_ARRAY, NIL, PoolByteArray, set, INT, "idx", INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, push_back, INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, append, INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, append_array, POOL_BYTE_ARRAY, "array", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, remove, INT, "idx", varray()); - ADDFUNC2(POOL_BYTE_ARRAY, INT, PoolByteArray, insert, INT, "idx", INT, "byte", varray()); + ADDFUNC2R(POOL_BYTE_ARRAY, INT, PoolByteArray, insert, INT, "idx", INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, resize, INT, "idx", varray()); ADDFUNC0(POOL_BYTE_ARRAY, NIL, PoolByteArray, invert, varray()); - ADDFUNC2(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, subarray, INT, "from", INT, "to", varray()); + ADDFUNC2R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, subarray, INT, "from", INT, "to", varray()); - ADDFUNC0(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_ascii, varray()); - ADDFUNC0(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_utf8, varray()); - ADDFUNC1(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, compress, INT, "compression_mode", varray(0)); - ADDFUNC2(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0)); + ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_ascii, varray()); + ADDFUNC0R(POOL_BYTE_ARRAY, STRING, PoolByteArray, get_string_from_utf8, varray()); + ADDFUNC1R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, compress, INT, "compression_mode", varray(0)); + ADDFUNC2R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0)); - ADDFUNC0(POOL_INT_ARRAY, INT, PoolIntArray, size, varray()); + ADDFUNC0R(POOL_INT_ARRAY, INT, PoolIntArray, size, varray()); ADDFUNC2(POOL_INT_ARRAY, NIL, PoolIntArray, set, INT, "idx", INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, push_back, INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, append, INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, append_array, POOL_INT_ARRAY, "array", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, remove, INT, "idx", varray()); - ADDFUNC2(POOL_INT_ARRAY, INT, PoolIntArray, insert, INT, "idx", INT, "integer", varray()); + ADDFUNC2R(POOL_INT_ARRAY, INT, PoolIntArray, insert, INT, "idx", INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, resize, INT, "idx", varray()); ADDFUNC0(POOL_INT_ARRAY, NIL, PoolIntArray, invert, varray()); - ADDFUNC0(POOL_REAL_ARRAY, INT, PoolRealArray, size, varray()); + ADDFUNC0R(POOL_REAL_ARRAY, INT, PoolRealArray, size, varray()); ADDFUNC2(POOL_REAL_ARRAY, NIL, PoolRealArray, set, INT, "idx", REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, push_back, REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, append, REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, append_array, POOL_REAL_ARRAY, "array", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, remove, INT, "idx", varray()); - ADDFUNC2(POOL_REAL_ARRAY, INT, PoolRealArray, insert, INT, "idx", REAL, "value", varray()); + ADDFUNC2R(POOL_REAL_ARRAY, INT, PoolRealArray, insert, INT, "idx", REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, resize, INT, "idx", varray()); ADDFUNC0(POOL_REAL_ARRAY, NIL, PoolRealArray, invert, varray()); - ADDFUNC0(POOL_STRING_ARRAY, INT, PoolStringArray, size, varray()); + ADDFUNC0R(POOL_STRING_ARRAY, INT, PoolStringArray, size, varray()); ADDFUNC2(POOL_STRING_ARRAY, NIL, PoolStringArray, set, INT, "idx", STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, push_back, STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, append, STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, append_array, POOL_STRING_ARRAY, "array", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, remove, INT, "idx", varray()); - ADDFUNC2(POOL_STRING_ARRAY, INT, PoolStringArray, insert, INT, "idx", STRING, "string", varray()); + ADDFUNC2R(POOL_STRING_ARRAY, INT, PoolStringArray, insert, INT, "idx", STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, resize, INT, "idx", varray()); ADDFUNC0(POOL_STRING_ARRAY, NIL, PoolStringArray, invert, varray()); ADDFUNC1(POOL_STRING_ARRAY, STRING, PoolStringArray, join, STRING, "delimiter", varray()); - ADDFUNC0(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, size, varray()); + ADDFUNC0R(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, size, varray()); ADDFUNC2(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, set, INT, "idx", VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, push_back, VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, append, VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, append_array, POOL_VECTOR2_ARRAY, "array", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, remove, INT, "idx", varray()); - ADDFUNC2(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, insert, INT, "idx", VECTOR2, "vector2", varray()); + ADDFUNC2R(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, insert, INT, "idx", VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, resize, INT, "idx", varray()); ADDFUNC0(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, invert, varray()); - ADDFUNC0(POOL_VECTOR3_ARRAY, INT, PoolVector3Array, size, varray()); + ADDFUNC0R(POOL_VECTOR3_ARRAY, INT, PoolVector3Array, size, varray()); ADDFUNC2(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, set, INT, "idx", VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, push_back, VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, append, VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, append_array, POOL_VECTOR3_ARRAY, "array", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, remove, INT, "idx", varray()); - ADDFUNC2(POOL_VECTOR3_ARRAY, INT, PoolVector3Array, insert, INT, "idx", VECTOR3, "vector3", varray()); + ADDFUNC2R(POOL_VECTOR3_ARRAY, INT, PoolVector3Array, insert, INT, "idx", VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, resize, INT, "idx", varray()); ADDFUNC0(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, invert, varray()); - ADDFUNC0(POOL_COLOR_ARRAY, INT, PoolColorArray, size, varray()); + ADDFUNC0R(POOL_COLOR_ARRAY, INT, PoolColorArray, size, varray()); ADDFUNC2(POOL_COLOR_ARRAY, NIL, PoolColorArray, set, INT, "idx", COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, push_back, COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, append, COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, append_array, POOL_COLOR_ARRAY, "array", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, remove, INT, "idx", varray()); - ADDFUNC2(POOL_COLOR_ARRAY, INT, PoolColorArray, insert, INT, "idx", COLOR, "color", varray()); + ADDFUNC2R(POOL_COLOR_ARRAY, INT, PoolColorArray, insert, INT, "idx", COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, resize, INT, "idx", varray()); ADDFUNC0(POOL_COLOR_ARRAY, NIL, PoolColorArray, invert, varray()); //pointerbased - ADDFUNC0(RECT3, REAL, Rect3, get_area, varray()); - ADDFUNC0(RECT3, BOOL, Rect3, has_no_area, varray()); - ADDFUNC0(RECT3, BOOL, Rect3, has_no_surface, varray()); - ADDFUNC1(RECT3, BOOL, Rect3, intersects, RECT3, "with", varray()); - ADDFUNC1(RECT3, BOOL, Rect3, encloses, RECT3, "with", varray()); - ADDFUNC1(RECT3, RECT3, Rect3, merge, RECT3, "with", varray()); - ADDFUNC1(RECT3, RECT3, Rect3, intersection, RECT3, "with", varray()); - ADDFUNC1(RECT3, BOOL, Rect3, intersects_plane, PLANE, "plane", varray()); - ADDFUNC2(RECT3, BOOL, Rect3, intersects_segment, VECTOR3, "from", VECTOR3, "to", varray()); - ADDFUNC1(RECT3, BOOL, Rect3, has_point, VECTOR3, "point", varray()); - ADDFUNC1(RECT3, VECTOR3, Rect3, get_support, VECTOR3, "dir", varray()); - ADDFUNC0(RECT3, VECTOR3, Rect3, get_longest_axis, varray()); - ADDFUNC0(RECT3, INT, Rect3, get_longest_axis_index, varray()); - ADDFUNC0(RECT3, REAL, Rect3, get_longest_axis_size, varray()); - ADDFUNC0(RECT3, VECTOR3, Rect3, get_shortest_axis, varray()); - ADDFUNC0(RECT3, INT, Rect3, get_shortest_axis_index, varray()); - ADDFUNC0(RECT3, REAL, Rect3, get_shortest_axis_size, varray()); - ADDFUNC1(RECT3, RECT3, Rect3, expand, VECTOR3, "to_point", varray()); - ADDFUNC1(RECT3, RECT3, Rect3, grow, REAL, "by", varray()); - ADDFUNC1(RECT3, VECTOR3, Rect3, get_endpoint, INT, "idx", varray()); - - ADDFUNC0(TRANSFORM2D, TRANSFORM2D, Transform2D, inverse, varray()); - ADDFUNC0(TRANSFORM2D, TRANSFORM2D, Transform2D, affine_inverse, varray()); - ADDFUNC0(TRANSFORM2D, REAL, Transform2D, get_rotation, varray()); - ADDFUNC0(TRANSFORM2D, VECTOR2, Transform2D, get_origin, varray()); - ADDFUNC0(TRANSFORM2D, VECTOR2, Transform2D, get_scale, varray()); - ADDFUNC0(TRANSFORM2D, TRANSFORM2D, Transform2D, orthonormalized, varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, rotated, REAL, "phi", varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, scaled, VECTOR2, "scale", varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, translated, VECTOR2, "offset", varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, xform, NIL, "v", varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, xform_inv, NIL, "v", varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, basis_xform, NIL, "v", varray()); - ADDFUNC1(TRANSFORM2D, TRANSFORM2D, Transform2D, basis_xform_inv, NIL, "v", varray()); - ADDFUNC2(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", REAL, "weight", varray()); - - ADDFUNC0(BASIS, BASIS, Basis, inverse, varray()); - ADDFUNC0(BASIS, BASIS, Basis, transposed, varray()); - ADDFUNC0(BASIS, BASIS, Basis, orthonormalized, varray()); - ADDFUNC0(BASIS, REAL, Basis, determinant, varray()); - ADDFUNC2(BASIS, BASIS, Basis, rotated, VECTOR3, "axis", REAL, "phi", varray()); - ADDFUNC1(BASIS, BASIS, Basis, scaled, VECTOR3, "scale", varray()); - ADDFUNC0(BASIS, VECTOR3, Basis, get_scale, varray()); - ADDFUNC0(BASIS, VECTOR3, Basis, get_euler, varray()); - ADDFUNC1(BASIS, REAL, Basis, tdotx, VECTOR3, "with", varray()); - ADDFUNC1(BASIS, REAL, Basis, tdoty, VECTOR3, "with", varray()); - ADDFUNC1(BASIS, REAL, Basis, tdotz, VECTOR3, "with", varray()); - ADDFUNC1(BASIS, VECTOR3, Basis, xform, VECTOR3, "v", varray()); - ADDFUNC1(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray()); - ADDFUNC0(BASIS, INT, Basis, get_orthogonal_index, varray()); - - ADDFUNC0(TRANSFORM, TRANSFORM, Transform, inverse, varray()); - ADDFUNC0(TRANSFORM, TRANSFORM, Transform, affine_inverse, varray()); - ADDFUNC0(TRANSFORM, TRANSFORM, Transform, orthonormalized, varray()); - ADDFUNC2(TRANSFORM, TRANSFORM, Transform, rotated, VECTOR3, "axis", REAL, "phi", varray()); - ADDFUNC1(TRANSFORM, TRANSFORM, Transform, scaled, VECTOR3, "scale", varray()); - ADDFUNC1(TRANSFORM, TRANSFORM, Transform, translated, VECTOR3, "ofs", varray()); - ADDFUNC2(TRANSFORM, TRANSFORM, Transform, looking_at, VECTOR3, "target", VECTOR3, "up", varray()); - ADDFUNC2(TRANSFORM, TRANSFORM, Transform, interpolate_with, TRANSFORM, "transform", REAL, "weight", varray()); - ADDFUNC1(TRANSFORM, NIL, Transform, xform, NIL, "v", varray()); - ADDFUNC1(TRANSFORM, NIL, Transform, xform_inv, NIL, "v", varray()); - -#ifdef DEBUG_ENABLED - _VariantCall::type_funcs[Variant::TRANSFORM].functions["xform"].returns = true; - _VariantCall::type_funcs[Variant::TRANSFORM].functions["xform_inv"].returns = true; -#endif + ADDFUNC0R(RECT3, REAL, Rect3, get_area, varray()); + ADDFUNC0R(RECT3, BOOL, Rect3, has_no_area, varray()); + ADDFUNC0R(RECT3, BOOL, Rect3, has_no_surface, varray()); + ADDFUNC1R(RECT3, BOOL, Rect3, intersects, RECT3, "with", varray()); + ADDFUNC1R(RECT3, BOOL, Rect3, encloses, RECT3, "with", varray()); + ADDFUNC1R(RECT3, RECT3, Rect3, merge, RECT3, "with", varray()); + ADDFUNC1R(RECT3, RECT3, Rect3, intersection, RECT3, "with", varray()); + ADDFUNC1R(RECT3, BOOL, Rect3, intersects_plane, PLANE, "plane", varray()); + ADDFUNC2R(RECT3, BOOL, Rect3, intersects_segment, VECTOR3, "from", VECTOR3, "to", varray()); + ADDFUNC1R(RECT3, BOOL, Rect3, has_point, VECTOR3, "point", varray()); + ADDFUNC1R(RECT3, VECTOR3, Rect3, get_support, VECTOR3, "dir", varray()); + ADDFUNC0R(RECT3, VECTOR3, Rect3, get_longest_axis, varray()); + ADDFUNC0R(RECT3, INT, Rect3, get_longest_axis_index, varray()); + ADDFUNC0R(RECT3, REAL, Rect3, get_longest_axis_size, varray()); + ADDFUNC0R(RECT3, VECTOR3, Rect3, get_shortest_axis, varray()); + ADDFUNC0R(RECT3, INT, Rect3, get_shortest_axis_index, varray()); + ADDFUNC0R(RECT3, REAL, Rect3, get_shortest_axis_size, varray()); + ADDFUNC1R(RECT3, RECT3, Rect3, expand, VECTOR3, "to_point", varray()); + ADDFUNC1R(RECT3, RECT3, Rect3, grow, REAL, "by", varray()); + ADDFUNC1R(RECT3, VECTOR3, Rect3, get_endpoint, INT, "idx", varray()); + + ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, inverse, varray()); + ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, affine_inverse, varray()); + ADDFUNC0R(TRANSFORM2D, REAL, Transform2D, get_rotation, varray()); + ADDFUNC0R(TRANSFORM2D, VECTOR2, Transform2D, get_origin, varray()); + ADDFUNC0R(TRANSFORM2D, VECTOR2, Transform2D, get_scale, varray()); + ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, orthonormalized, varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, rotated, REAL, "phi", varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, scaled, VECTOR2, "scale", varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, translated, VECTOR2, "offset", varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, xform, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, xform_inv, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, basis_xform, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM2D, TRANSFORM2D, Transform2D, basis_xform_inv, NIL, "v", varray()); + ADDFUNC2R(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", REAL, "weight", varray()); + + ADDFUNC0R(BASIS, BASIS, Basis, inverse, varray()); + ADDFUNC0R(BASIS, BASIS, Basis, transposed, varray()); + ADDFUNC0R(BASIS, BASIS, Basis, orthonormalized, varray()); + ADDFUNC0R(BASIS, REAL, Basis, determinant, varray()); + ADDFUNC2R(BASIS, BASIS, Basis, rotated, VECTOR3, "axis", REAL, "phi", varray()); + ADDFUNC1R(BASIS, BASIS, Basis, scaled, VECTOR3, "scale", varray()); + ADDFUNC0R(BASIS, VECTOR3, Basis, get_scale, varray()); + ADDFUNC0R(BASIS, VECTOR3, Basis, get_euler, varray()); + ADDFUNC1R(BASIS, REAL, Basis, tdotx, VECTOR3, "with", varray()); + ADDFUNC1R(BASIS, REAL, Basis, tdoty, VECTOR3, "with", varray()); + ADDFUNC1R(BASIS, REAL, Basis, tdotz, VECTOR3, "with", varray()); + ADDFUNC1R(BASIS, VECTOR3, Basis, xform, VECTOR3, "v", varray()); + ADDFUNC1R(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray()); + ADDFUNC0R(BASIS, INT, Basis, get_orthogonal_index, varray()); + + ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray()); + ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, affine_inverse, varray()); + ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, orthonormalized, varray()); + ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, rotated, VECTOR3, "axis", REAL, "phi", varray()); + ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, scaled, VECTOR3, "scale", varray()); + ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, translated, VECTOR3, "ofs", varray()); + ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, looking_at, VECTOR3, "target", VECTOR3, "up", varray()); + ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, interpolate_with, TRANSFORM, "transform", REAL, "weight", varray()); + ADDFUNC1R(TRANSFORM, NIL, Transform, xform, NIL, "v", varray()); + ADDFUNC1R(TRANSFORM, NIL, Transform, xform_inv, NIL, "v", varray()); /* REGISTER CONSTRUCTORS */ diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 70b880eb43..82eb291f27 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -381,7 +381,7 @@ </signals> <constants> <constant name="ANIMATION_PROCESS_PHYSICS" value="0"> - Process animation during the physics process. This is specially useful when animating physics bodies. + Process animation during the physics process. This is especially useful when animating physics bodies. </constant> <constant name="ANIMATION_PROCESS_IDLE" value="1"> Process animation during the idle process. diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 73b424eb12..2629e6740d 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -196,7 +196,7 @@ </return> <description> Returns the current latin keyboard variant as a String. - Possible return values are: "QWERTY", "AZERTY", "QZERTY", "DVORAK", "NEO" or "ERROR" + Possible return values are: "QWERTY", "AZERTY", "QZERTY", "DVORAK", "NEO", "COLEMAK" or "ERROR". </description> </method> <method name="get_locale" qualifiers="const"> diff --git a/doc/classes/OccluderPolygon2D.xml b/doc/classes/OccluderPolygon2D.xml index 99c1536ddf..7bc1f74762 100644 --- a/doc/classes/OccluderPolygon2D.xml +++ b/doc/classes/OccluderPolygon2D.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="OccluderPolygon2D" inherits="Resource" category="Core" version="3.0.alpha.custom_build"> <brief_description> + Defines a 2D polygon for LightOccluder2D. </brief_description> <description> + Editor facility that helps you draw a 2D polygon used as resource for [LightOccluder2D]. </description> <tutorials> </tutorials> @@ -54,18 +56,24 @@ </methods> <members> <member name="closed" type="bool" setter="set_closed" getter="is_closed"> + If [code]true[/code] closes the polygon. A closed OccluderPolygon2D occludes the light coming from any direction. An opened OccluderPolygon2D occludes the light only at its outline's direction. Default value [code]true[/code]. </member> <member name="cull_mode" type="int" setter="set_cull_mode" getter="get_cull_mode" enum="OccluderPolygon2D.CullMode"> + Set the direction of the occlusion culling when not [code]CULL_DISABLED[/code]. Default value [code]DISABLED[/code]. </member> <member name="polygon" type="PoolVector2Array" setter="set_polygon" getter="get_polygon"> + A [Vector2] array with the index for polygon's vertices positions. </member> </members> <constants> <constant name="CULL_DISABLED" value="0"> + Culling mode for the occlusion. Disabled means no culling. See [member cull_mode]. </constant> <constant name="CULL_CLOCKWISE" value="1"> + Culling mode for the occlusion. Sets the culling to be in clockwise direction. See [member cull_mode]. </constant> <constant name="CULL_COUNTER_CLOCKWISE" value="2"> + Culling mode for the occlusion. Sets the culling to be in counter clockwise direction. See [member cull_mode]. </constant> </constants> </class> diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index ddcb04fa7d..8ec988bec1 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1134,9 +1134,9 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m state.current_depth_draw = p_material->shader->spatial.depth_draw_mode; } -//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); -/* + /* if (p_material->flags[VS::MATERIAL_FLAG_WIREFRAME]) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); else @@ -4023,6 +4023,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.ubo_data.shadow_dual_paraboloid_render_side = 0; state.ubo_data.shadow_dual_paraboloid_render_zfar = 0; + p_cam_projection.get_viewport_size(state.ubo_data.viewport_size[0], state.ubo_data.viewport_size[1]); + if (storage->frame.current_rt) { state.ubo_data.screen_pixel_size[0] = 1.0 / storage->frame.current_rt->width; state.ubo_data.screen_pixel_size[1] = 1.0 / storage->frame.current_rt->height; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index ff691ddcec..69b43c7813 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -124,6 +124,7 @@ public: float z_slope_scale; float shadow_dual_paraboloid_render_zfar; float shadow_dual_paraboloid_render_side; + float viewport_size[2]; float screen_pixel_size[2]; float shadow_atlas_pixel_size[2]; float shadow_directional_pixel_size[2]; @@ -143,7 +144,7 @@ public: float fog_height_min; float fog_height_max; float fog_height_curve; - uint8_t padding[8]; + // make sure this struct is padded to be a multiple of 16 bytes for webgl } ubo_data; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index f39342b680..ad08c59de8 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -766,7 +766,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { //builtins actions[VS::SHADER_SPATIAL].renames["TIME"] = "time"; - //actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"]=ShaderLanguage::TYPE_VEC2; + actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index e4d76753cb..9880663143 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -80,6 +80,7 @@ layout(std140) uniform SceneData { //ubo:0 highp float shadow_dual_paraboloid_render_zfar; highp float shadow_dual_paraboloid_render_side; + highp vec2 viewport_size; highp vec2 screen_pixel_size; highp vec2 shadow_atlas_pixel_size; highp vec2 directional_shadow_pixel_size; @@ -566,6 +567,7 @@ in vec3 normal_interp; uniform bool no_ambient_light; + #ifdef USE_RADIANCE_MAP @@ -663,6 +665,7 @@ layout(std140) uniform SceneData { highp float shadow_dual_paraboloid_render_zfar; highp float shadow_dual_paraboloid_render_side; + highp vec2 viewport_size; highp vec2 screen_pixel_size; highp vec2 shadow_atlas_pixel_size; highp vec2 directional_shadow_pixel_size; diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index eb86491dec..0671ee408e 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -39,7 +39,7 @@ const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); -Error AudioDriverWASAPI::init_device() { +Error AudioDriverWASAPI::init_device(bool reinit) { WAVEFORMATEX *pwfex; IMMDeviceEnumerator *enumerator = NULL; @@ -51,10 +51,24 @@ Error AudioDriverWASAPI::init_device() { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); - ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + if (reinit) { + // In case we're trying to re-initialize the device prevent throwing this error on the console, + // otherwise if there is currently no devie available this will spam the console. + if (hr != S_OK) { + return ERR_CANT_OPEN; + } + } else { + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + } hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client); - ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + if (reinit) { + if (hr != S_OK) { + return ERR_CANT_OPEN; + } + } else { + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + } hr = audio_client->GetMixFormat(&pwfex); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); @@ -152,7 +166,9 @@ Error AudioDriverWASAPI::finish_device() { Error AudioDriverWASAPI::init() { Error err = init_device(); - ERR_FAIL_COND_V(err != OK, err); + if (err != OK) { + ERR_PRINT("WASAPI: init_device error"); + } active = false; exit_thread = false; @@ -209,7 +225,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { unsigned int left_frames = ad->buffer_frames; unsigned int buffer_idx = 0; - while (left_frames > 0) { + while (left_frames > 0 && ad->audio_client) { WaitForSingleObject(ad->event, 1000); UINT32 cur_frames; @@ -271,9 +287,9 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { // Device is not valid anymore, reopen it - Error err = ad->reopen(); + Error err = ad->finish_device(); if (err != OK) { - ad->exit_thread = true; + ERR_PRINT("WASAPI: finish_device error"); } else { // We reopened the device and samples_in may have resized, so invalidate the current left_frames left_frames = 0; @@ -285,9 +301,9 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { // Device is not valid anymore, reopen it - Error err = ad->reopen(); + Error err = ad->finish_device(); if (err != OK) { - ad->exit_thread = true; + ERR_PRINT("WASAPI: finish_device error"); } else { // We reopened the device and samples_in may have resized, so invalidate the current left_frames left_frames = 0; @@ -296,6 +312,13 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ERR_PRINT("WASAPI: GetCurrentPadding error"); } } + + if (!ad->audio_client) { + Error err = ad->init_device(true); + if (err == OK) { + ad->start(); + } + } } ad->thread_exited = true; @@ -303,11 +326,13 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { void AudioDriverWASAPI::start() { - HRESULT hr = audio_client->Start(); - if (hr != S_OK) { - ERR_PRINT("WASAPI: Start failed"); - } else { - active = true; + if (audio_client) { + HRESULT hr = audio_client->Start(); + if (hr != S_OK) { + ERR_PRINT("WASAPI: Start failed"); + } else { + active = true; + } } } diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index fab8ab3250..87a2db724c 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -64,7 +64,7 @@ class AudioDriverWASAPI : public AudioDriver { static void thread_func(void *p_udata); - Error init_device(); + Error init_device(bool reinit = false); Error finish_device(); Error reopen(); diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index d35dc53ae1..057b2d827d 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -615,6 +615,11 @@ void DocData::generate(bool p_basic_types) { } } +static String _format_description(const String &string) { + + return string.dedent().strip_edges().replace("\n", "\n\n"); +} + static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &methods) { String section = parser->get_node_name(); @@ -661,7 +666,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) - method.description = parser->get_node_data().strip_edges(); + method.description = _format_description(parser->get_node_data()); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == element) @@ -776,12 +781,12 @@ Error DocData::_load(Ref<XMLParser> parser) { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) - c.brief_description = parser->get_node_data().strip_edges(); + c.brief_description = _format_description(parser->get_node_data()); } else if (name == "description") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) - c.description = parser->get_node_data().strip_edges(); + c.description = _format_description(parser->get_node_data()); } else if (name == "tutorials") { parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) @@ -823,7 +828,7 @@ Error DocData::_load(Ref<XMLParser> parser) { prop.enumeration = parser->get_attribute_value("enum"); parser->read(); if (parser->get_node_type() == XMLParser::NODE_TEXT) - prop.description = parser->get_node_data().strip_edges(); + prop.description = _format_description(parser->get_node_data()); c.properties.push_back(prop); } else { ERR_EXPLAIN("Invalid tag in doc file: " + name); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index dfd35fdd96..62d77f56bc 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -38,16 +38,12 @@ #include "project_settings.h" #include "scene/main/viewport.h" -bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir) { +bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths) { TreeItem *item = tree->create_item(p_parent); String dname = p_dir->get_name(); if (dname == "") dname = "res://"; - else { - // collapse every tree item but the root folder - item->set_collapsed(true); - } item->set_text(0, dname); item->set_icon(0, get_icon("Folder", "EditorIcons")); @@ -61,38 +57,78 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory item->select(0); } + if ((path.begins_with(lpath) && path != lpath)) { + item->set_collapsed(false); + } else { + bool is_collapsed = true; + for (int i = 0; i < uncollapsed_paths.size(); i++) { + if (lpath == uncollapsed_paths[i]) { + is_collapsed = false; + break; + } + } + item->set_collapsed(is_collapsed); + } + for (int i = 0; i < p_dir->get_subdir_count(); i++) - _create_tree(item, p_dir->get_subdir(i)); + _create_tree(item, p_dir->get_subdir(i), uncollapsed_paths); return true; } -void FileSystemDock::_update_tree() { +void FileSystemDock::_update_tree(bool keep_collapse_state) { + + Vector<String> uncollapsed_paths; + if (keep_collapse_state) { + TreeItem *root = tree->get_root(); + if (root) { + TreeItem *resTree = root->get_children()->get_next(); + + Vector<TreeItem *> needs_check; + needs_check.push_back(resTree); + + while (needs_check.size()) { + if (!needs_check[0]->is_collapsed()) { + uncollapsed_paths.push_back(needs_check[0]->get_metadata(0)); + TreeItem *child = needs_check[0]->get_children(); + while (child) { + needs_check.push_back(child); + child = child->get_next(); + } + } + needs_check.remove(0); + } + } + } tree->clear(); updating_tree = true; + TreeItem *root = tree->create_item(); TreeItem *favorites = tree->create_item(root); favorites->set_icon(0, get_icon("Favorites", "EditorIcons")); favorites->set_text(0, TTR("Favorites:")); favorites->set_selectable(0, false); - Vector<String> faves = EditorSettings::get_singleton()->get_favorite_dirs(); - for (int i = 0; i < faves.size(); i++) { - if (!faves[i].begins_with("res://")) + + Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorite_dirs(); + String res_path = "res://"; + Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons"); + for (int i = 0; i < favorite_paths.size(); i++) { + String fave = favorite_paths[i]; + if (!fave.begins_with(res_path)) continue; TreeItem *ti = tree->create_item(favorites); - String fv = faves[i]; - if (fv == "res://") + if (fave == res_path) ti->set_text(0, "/"); else - ti->set_text(0, faves[i].get_file()); - ti->set_icon(0, get_icon("Folder", "EditorIcons")); + ti->set_text(0, fave.get_file()); + ti->set_icon(0, folder_icon); ti->set_selectable(0, true); - ti->set_metadata(0, faves[i]); + ti->set_metadata(0, fave); } - _create_tree(root, EditorFileSystem::get_singleton()->get_filesystem()); + _create_tree(root, EditorFileSystem::get_singleton()->get_filesystem(), uncollapsed_paths); updating_tree = false; } @@ -104,26 +140,28 @@ void FileSystemDock::_notification(int p_what) { bool new_mode = get_size().height < get_viewport_rect().size.height / 2; - if (new_mode != split_mode) { + if (new_mode != low_height_mode) { - split_mode = new_mode; + low_height_mode = new_mode; - //print_line("SPLIT MODE? "+itos(split_mode)); - if (split_mode) { + if (low_height_mode) { file_list_vb->hide(); - tree->set_custom_minimum_size(Size2(0, 0)); tree->set_v_size_flags(SIZE_EXPAND_FILL); - button_back->show(); + button_tree->show(); } else { - tree->show(); - file_list_vb->show(); - tree->set_custom_minimum_size(Size2(0, 200) * EDSCALE); tree->set_v_size_flags(SIZE_FILL); - button_back->hide(); - if (!EditorFileSystem::get_singleton()->is_scanning()) { - _fs_changed(); + if (!tree->is_visible()) { + tree->show(); + button_favorite->show(); + _update_tree(true); + } + + if (!file_list_vb->is_visible()) { + file_list_vb->show(); + button_tree->hide(); + _update_files(true); } } } @@ -138,30 +176,32 @@ void FileSystemDock::_notification(int p_what) { EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_fs_changed"); EditorResourcePreview::get_singleton()->connect("preview_invalidated", this, "_preview_invalidated"); - button_reload->set_icon(get_icon("Reload", "EditorIcons")); - button_favorite->set_icon(get_icon("Favorites", "EditorIcons")); - //button_instance->set_icon( get_icon("Add","EditorIcons")); - //button_open->set_icon( get_icon("Folder","EditorIcons")); - button_back->set_icon(get_icon("Filesystem", "EditorIcons")); + String ei = "EditorIcons"; + button_reload->set_icon(get_icon("Reload", ei)); + button_favorite->set_icon(get_icon("Favorites", ei)); + //button_instance->set_icon(get_icon("Add", ei)); + //button_open->set_icon(get_icon("Folder", ei)); + button_tree->set_icon(get_icon("Filesystem", ei)); _update_file_display_toggle_button(); button_display_mode->connect("pressed", this, "_change_file_display"); - //file_options->set_icon( get_icon("Tools","EditorIcons")); + //file_options->set_icon( get_icon("Tools","ei")); files->connect("item_activated", this, "_select_file"); button_hist_next->connect("pressed", this, "_fw_history"); button_hist_prev->connect("pressed", this, "_bw_history"); - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->add_icon_override("right_icon", get_icon("Search", ei)); - button_hist_next->set_icon(get_icon("Forward", "EditorIcons")); - button_hist_prev->set_icon(get_icon("Back", "EditorIcons")); + button_hist_next->set_icon(get_icon("Forward", ei)); + button_hist_prev->set_icon(get_icon("Back", ei)); file_options->connect("id_pressed", this, "_file_option"); folder_options->connect("id_pressed", this, "_folder_option"); - button_back->connect("pressed", this, "_go_to_tree", varray(), CONNECT_DEFERRED); - current_path->connect("text_entered", this, "_go_to_dir"); - _update_tree(); //maybe it finished already + button_tree->connect("pressed", this, "_go_to_tree", varray(), CONNECT_DEFERRED); + current_path->connect("text_entered", this, "navigate_to_path"); if (EditorFileSystem::get_singleton()->is_scanning()) { _set_scanning_mode(); + } else { + _update_tree(false); } } break; @@ -179,8 +219,7 @@ void FileSystemDock::_notification(int p_what) { if (tree->is_visible_in_tree() && dd.has("type")) { if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs") || (String(dd["type"]) == "resource")) { tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); - } - if ((String(dd["type"]) == "favorite")) { + } else if ((String(dd["type"]) == "favorite")) { tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN); } } @@ -193,52 +232,54 @@ void FileSystemDock::_notification(int p_what) { } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + String ei = "EditorIcons"; int new_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")); //_update_icons - button_reload->set_icon(get_icon("Reload", "EditorIcons")); - button_favorite->set_icon(get_icon("Favorites", "EditorIcons")); - button_back->set_icon(get_icon("Filesystem", "EditorIcons")); - _update_file_display_toggle_button(); - - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + button_reload->set_icon(get_icon("Reload", ei)); + button_favorite->set_icon(get_icon("Favorites", ei)); + button_tree->set_icon(get_icon("Filesystem", ei)); + button_hist_next->set_icon(get_icon("Forward", ei)); + button_hist_prev->set_icon(get_icon("Back", ei)); - button_hist_next->set_icon(get_icon("Forward", "EditorIcons")); - button_hist_prev->set_icon(get_icon("Back", "EditorIcons")); + search_box->add_icon_override("right_icon", get_icon("Search", ei)); if (new_mode != display_mode) { set_display_mode(new_mode); } else { + _update_file_display_toggle_button(); _update_files(true); } - _update_tree(); - + _update_tree(true); } break; } } void FileSystemDock::_dir_selected() { - TreeItem *ti = tree->get_selected(); - if (!ti) + TreeItem *sel = tree->get_selected(); + if (!sel) return; - String dir = ti->get_metadata(0); + path = sel->get_metadata(0); + bool found = false; Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); for (int i = 0; i < favorites.size(); i++) { - if (favorites[i] == dir) { + if (favorites[i] == path) { found = true; break; } } button_favorite->set_pressed(found); + current_path->set_text(path); + _push_to_history(); - if (!split_mode) { - _open_pressed(); //go directly to dir + if (!low_height_mode) { + _update_files(false); } } @@ -247,27 +288,25 @@ void FileSystemDock::_favorites_pressed() { TreeItem *sel = tree->get_selected(); if (!sel) return; - String dir = sel->get_metadata(0); + path = sel->get_metadata(0); int idx = -1; Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); for (int i = 0; i < favorites.size(); i++) { - if (favorites[i] == dir) { + if (favorites[i] == path) { idx = i; break; } } - if (button_favorite->is_pressed() && idx == -1) { - favorites.push_back(dir); - EditorSettings::get_singleton()->set_favorite_dirs(favorites); - _update_tree(); - } else if (!button_favorite->is_pressed() && idx != -1) { + if (idx == -1) { + favorites.push_back(path); + } else { favorites.remove(idx); - EditorSettings::get_singleton()->set_favorite_dirs(favorites); - _update_tree(); } + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(true); } String FileSystemDock::get_selected_path() const { @@ -275,8 +314,8 @@ String FileSystemDock::get_selected_path() const { TreeItem *sel = tree->get_selected(); if (!sel) return ""; - String path = sel->get_metadata(0); - return "res://" + path; + + return sel->get_metadata(0); } String FileSystemDock::get_current_path() const { @@ -286,27 +325,33 @@ String FileSystemDock::get_current_path() const { void FileSystemDock::navigate_to_path(const String &p_path) { // If the path is a file, do not only go to the directory in the tree, also select the file in the file list. - String dir_path = ""; String file_name = ""; DirAccess *dirAccess = DirAccess::open("res://"); if (dirAccess->file_exists(p_path)) { - dir_path = p_path.get_base_dir(); + path = p_path.get_base_dir(); file_name = p_path.get_file(); } else if (dirAccess->dir_exists(p_path)) { - dir_path = p_path; + path = p_path; } else { ERR_EXPLAIN(TTR("Cannot navigate to '" + p_path + "' as it has not been found in the file system!")); ERR_FAIL(); } - path = dir_path; - _update_tree(); - tree->ensure_cursor_is_visible(); + current_path->set_text(path); + _push_to_history(); - if (!file_name.empty()) { - _open_pressed(); // Seems to be the only way to get into the file view. This also pushes to history. + if (!low_height_mode) { + _update_tree(true); + _update_files(false); + } else { + if (file_name.empty()) { + _go_to_tree(); + } else { + _go_to_file_list(); + } + } - // Focus the given file. + if (!file_name.empty()) { for (int i = 0; i < files->get_item_count(); i++) { if (files->get_item_text(i) == file_name) { files->select(i, true); @@ -319,27 +364,13 @@ void FileSystemDock::navigate_to_path(const String &p_path) { void FileSystemDock::_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata) { - bool valid = false; - - if (search_box->is_visible()) { - valid = true; - } else { - valid = (path == p_path.get_base_dir()); - } - - if (p_preview.is_valid() && valid) { + if ((file_list_vb->is_visible_in_tree() || path == p_path.get_base_dir()) && p_preview.is_valid()) { Array uarr = p_udata; int idx = uarr[0]; String file = uarr[1]; - if (idx >= files->get_item_count()) - return; - if (files->get_item_text(idx) != file) - return; - String fpath = files->get_item_metadata(idx); - if (fpath != p_path) - return; - files->set_item_icon(idx, p_preview); + if (idx < files->get_item_count() && files->get_item_text(idx) == file && files->get_item_metadata(idx) == p_path) + files->set_item_icon(idx, p_preview); } } @@ -416,6 +447,7 @@ void FileSystemDock::_update_files(bool p_keep_selection) { if (!efd) return; + String ei = "EditorIcons"; int thumbnail_size = EditorSettings::get_singleton()->get("docks/filesystem/thumbnail_size"); thumbnail_size *= EDSCALE; Ref<Texture> folder_thumbnail; @@ -425,9 +457,9 @@ void FileSystemDock::_update_files(bool p_keep_selection) { bool always_show_folders = EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"); bool use_thumbnails = (display_mode == DISPLAY_THUMBNAILS); - bool use_folders = search_box->get_text().length() == 0 && (split_mode || always_show_folders); + bool use_folders = search_box->get_text().length() == 0 && (low_height_mode || always_show_folders); - if (use_thumbnails) { //thumbnails + if (use_thumbnails) { files->set_max_columns(0); files->set_icon_mode(ItemList::ICON_MODE_TOP); @@ -436,13 +468,13 @@ void FileSystemDock::_update_files(bool p_keep_selection) { files->set_fixed_icon_size(Size2(thumbnail_size, thumbnail_size)); if (thumbnail_size < 64) { - folder_thumbnail = get_icon("FolderMediumThumb", "EditorIcons"); - file_thumbnail = get_icon("FileMediumThumb", "EditorIcons"); - file_thumbnail_broken = get_icon("FileDeadMediumThumb", "EditorIcons"); + folder_thumbnail = get_icon("FolderMediumThumb", ei); + file_thumbnail = get_icon("FileMediumThumb", ei); + file_thumbnail_broken = get_icon("FileDeadMediumThumb", ei); } else { - folder_thumbnail = get_icon("FolderBigThumb", "EditorIcons"); - file_thumbnail = get_icon("FileBigThumb", "EditorIcons"); - file_thumbnail_broken = get_icon("FileDeadBigThumb", "EditorIcons"); + folder_thumbnail = get_icon("FolderBigThumb", ei); + file_thumbnail = get_icon("FileBigThumb", ei); + file_thumbnail_broken = get_icon("FileDeadBigThumb", ei); } } else { @@ -454,14 +486,10 @@ void FileSystemDock::_update_files(bool p_keep_selection) { } if (use_folders) { + Ref<Texture> folderIcon = (use_thumbnails) ? folder_thumbnail : get_icon("folder", "FileDialog"); if (path != "res://") { - - if (use_thumbnails) { - files->add_item("..", folder_thumbnail, false); - } else { - files->add_item("..", get_icon("folder", "FileDialog"), false); - } + files->add_item("..", folderIcon, false); String bd = path.get_base_dir(); if (bd != "res://" && !bd.ends_with("/")) @@ -474,12 +502,7 @@ void FileSystemDock::_update_files(bool p_keep_selection) { String dname = efd->get_subdir(i)->get_name(); - if (use_thumbnails) { - files->add_item(dname, folder_thumbnail, true); - } else { - files->add_item(dname, get_icon("folder", "FileDialog"), true); - } - + files->add_item(dname, folderIcon, true); files->set_item_metadata(files->get_item_count() - 1, path.plus_file(dname) + "/"); if (cselection.has(dname)) @@ -489,12 +512,9 @@ void FileSystemDock::_update_files(bool p_keep_selection) { List<FileInfo> filelist; - if (search_box->get_text().length()) { - - if (search_box->get_text().length() > 1) { - _search(EditorFileSystem::get_singleton()->get_filesystem(), &filelist, 128); - } + if (search_box->get_text().length() > 0) { + _search(EditorFileSystem::get_singleton()->get_filesystem(), &filelist, 128); filelist.sort(); } else { @@ -511,68 +531,66 @@ void FileSystemDock::_update_files(bool p_keep_selection) { } } - StringName ei = "EditorIcons"; //make it faster.. - StringName oi = "Object"; + String oi = "Object"; for (List<FileInfo>::Element *E = filelist.front(); E; E = E->next()) { - String fname = E->get().name; - String fp = E->get().path; - StringName type = E->get().type; + FileInfo *finfo = &(E->get()); + String fname = finfo->name; + String fpath = finfo->path; + String ftype = finfo->type; Ref<Texture> type_icon; - Ref<Texture> big_icon = file_thumbnail; + Ref<Texture> big_icon; String tooltip = fname; - if (!E->get().import_broken) { - - if (has_icon(type, ei)) { - type_icon = get_icon(type, ei); - } else { - type_icon = get_icon(oi, ei); - } + if (!finfo->import_broken) { + type_icon = (has_icon(ftype, ei)) ? get_icon(ftype, ei) : get_icon(oi, ei); + big_icon = file_thumbnail; } else { - type_icon = get_icon("ImportFail", "EditorIcons"); + type_icon = get_icon("ImportFail", ei); big_icon = file_thumbnail_broken; tooltip += TTR("\nStatus: Import of file failed. Please fix file and reimport manually."); } - if (E->get().sources.size()) { - for (int i = 0; i < E->get().sources.size(); i++) { - tooltip += TTR("\nSource: ") + E->get().sources[i]; - } - } - + int item_index; if (use_thumbnails) { files->add_item(fname, big_icon, true); - files->set_item_metadata(files->get_item_count() - 1, fp); - files->set_item_tag_icon(files->get_item_count() - 1, type_icon); - Array udata; - udata.resize(2); - udata[0] = files->get_item_count() - 1; - udata[1] = fname; - if (!E->get().import_broken) { - EditorResourcePreview::get_singleton()->queue_resource_preview(fp, this, "_thumbnail_done", udata); + item_index = files->get_item_count() - 1; + files->set_item_metadata(item_index, fpath); + files->set_item_tag_icon(item_index, type_icon); + if (!finfo->import_broken) { + Array udata; + udata.resize(2); + udata[0] = item_index; + udata[1] = fname; + EditorResourcePreview::get_singleton()->queue_resource_preview(fpath, this, "_thumbnail_done", udata); } } else { files->add_item(fname, type_icon, true); - files->set_item_metadata(files->get_item_count() - 1, fp); + item_index = files->get_item_count() - 1; + files->set_item_metadata(item_index, fpath); } if (cselection.has(fname)) - files->select(files->get_item_count() - 1, false); + files->select(item_index, false); - files->set_item_tooltip(files->get_item_count() - 1, tooltip); + if (finfo->sources.size()) { + for (int j = 0; j < finfo->sources.size(); j++) { + tooltip += "\nSource: " + finfo->sources[j]; + } + } + files->set_item_tooltip(item_index, tooltip); } } void FileSystemDock::_select_file(int p_idx) { - String path = files->get_item_metadata(p_idx); - if (path.ends_with("/")) { - if (path != "res://") { - path = path.substr(0, path.length() - 1); + String fpath = files->get_item_metadata(p_idx); + if (fpath.ends_with("/")) { + if (fpath != "res://") { + fpath = fpath.substr(0, fpath.length() - 1); } - this->path = path; + path = fpath; _update_files(false); current_path->set_text(path); _push_to_history(); @@ -587,27 +605,19 @@ void FileSystemDock::_select_file(int p_idx) { void FileSystemDock::_go_to_tree() { - tree->show(); - file_list_vb->hide(); - _update_tree(); + if (low_height_mode) { + tree->show(); + button_favorite->show(); + file_list_vb->hide(); + } + + _update_tree(true); tree->grab_focus(); tree->ensure_cursor_is_visible(); - button_favorite->show(); //button_open->hide(); //file_options->hide(); } -void FileSystemDock::_go_to_dir(const String &p_dir) { - - DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (da->change_dir(p_dir) == OK) { - path = da->get_current_dir(); - _update_files(false); - } - current_path->set_text(path); - memdelete(da); -} - void FileSystemDock::_preview_invalidated(const String &p_path) { if (display_mode == DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && search_box->get_text() == String() && file_list_vb->is_visible_in_tree()) { @@ -630,17 +640,15 @@ void FileSystemDock::_preview_invalidated(const String &p_path) { void FileSystemDock::_fs_changed() { button_hist_prev->set_disabled(history_pos == 0); - button_hist_next->set_disabled(history_pos + 1 == history.size()); + button_hist_next->set_disabled(history_pos == history.size() - 1); scanning_vb->hide(); split_box->show(); if (tree->is_visible()) { - button_favorite->show(); - _update_tree(); + _update_tree(true); } if (file_list_vb->is_visible()) { - _update_files(true); } @@ -649,9 +657,9 @@ void FileSystemDock::_fs_changed() { void FileSystemDock::_set_scanning_mode() { - split_box->hide(); button_hist_prev->set_disabled(true); button_hist_next->set_disabled(true); + split_box->hide(); scanning_vb->show(); set_process(true); if (EditorFileSystem::get_singleton()->is_scanning()) { @@ -666,55 +674,48 @@ void FileSystemDock::_fw_history() { if (history_pos < history.size() - 1) history_pos++; - path = history[history_pos]; - - if (tree->is_visible()) { - _update_tree(); - tree->grab_focus(); - tree->ensure_cursor_is_visible(); - } - - if (file_list_vb->is_visible()) { - _update_files(false); - current_path->set_text(path); - } - - button_hist_prev->set_disabled(history_pos == 0); - button_hist_next->set_disabled(history_pos + 1 == history.size()); + _update_history(); } void FileSystemDock::_bw_history() { - if (history_pos > 0) history_pos--; + _update_history(); +} + +void FileSystemDock::_update_history() { path = history[history_pos]; + current_path->set_text(path); if (tree->is_visible()) { - _update_tree(); + _update_tree(true); tree->grab_focus(); tree->ensure_cursor_is_visible(); } if (file_list_vb->is_visible()) { _update_files(false); - current_path->set_text(path); } button_hist_prev->set_disabled(history_pos == 0); - button_hist_next->set_disabled(history_pos + 1 == history.size()); + button_hist_next->set_disabled(history_pos == history.size() - 1); } void FileSystemDock::_push_to_history() { - - history.resize(history_pos + 1); if (history[history_pos] != path) { + history.resize(history_pos + 1); history.push_back(path); history_pos++; + + if (history.size() > history_max_size) { + history.remove(0); + history_pos = history_max_size - 1; + } } button_hist_prev->set_disabled(history_pos == 0); - button_hist_next->set_disabled(history_pos + 1 == history.size()); + button_hist_next->set_disabled(history_pos == history.size() - 1); } void FileSystemDock::_get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const { @@ -903,9 +904,9 @@ void FileSystemDock::_file_option(int p_option) { for (int i = 0; i < files->get_item_count(); i++) { if (!files->is_selected(i)) continue; - String path = files->get_item_metadata(i); - if (EditorFileSystem::get_singleton()->get_file_type(path) == "PackedScene") { - paths.push_back(path); + String fpath = files->get_item_metadata(i); + if (EditorFileSystem::get_singleton()->get_file_type(fpath) == "PackedScene") { + paths.push_back(fpath); } } @@ -918,16 +919,16 @@ void FileSystemDock::_file_option(int p_option) { int idx = files->get_current(); if (idx < 0 || idx >= files->get_item_count()) break; - String path = files->get_item_metadata(idx); - deps_editor->edit(path); + String fpath = files->get_item_metadata(idx); + deps_editor->edit(fpath); } break; case FILE_OWNERS: { int idx = files->get_current(); if (idx < 0 || idx >= files->get_item_count()) break; - String path = files->get_item_metadata(idx); - owners_editor->show(path); + String fpath = files->get_item_metadata(idx); + owners_editor->show(fpath); } break; case FILE_MOVE: { to_move.clear(); @@ -935,8 +936,8 @@ void FileSystemDock::_file_option(int p_option) { if (!files->is_selected(i)) continue; - String path = files->get_item_metadata(i); - to_move.push_back(FileOrFolder(path, !path.ends_with("/"))); + String fpath = files->get_item_metadata(i); + to_move.push_back(FileOrFolder(fpath, !fpath.ends_with("/"))); } if (to_move.size() > 0) { move_dialog->popup_centered_ratio(); @@ -968,12 +969,12 @@ void FileSystemDock::_file_option(int p_option) { Vector<String> remove_folders; for (int i = 0; i < files->get_item_count(); i++) { - String path = files->get_item_metadata(i); - if (files->is_selected(i) && path != "res://") { - if (path.ends_with("/")) { - remove_folders.push_back(path); + String fpath = files->get_item_metadata(i); + if (files->is_selected(i) && fpath != "res://") { + if (fpath.ends_with("/")) { + remove_folders.push_back(fpath); } else { - remove_files.push_back(path); + remove_files.push_back(fpath); } } } @@ -995,8 +996,8 @@ void FileSystemDock::_file_option(int p_option) { if (!files->is_selected(i)) continue; - String path = files->get_item_metadata(i); - reimport.push_back(path); + String fpath = files->get_item_metadata(i); + reimport.push_back(fpath); } ERR_FAIL_COND(reimport.size() == 0); @@ -1030,34 +1031,38 @@ void FileSystemDock::_file_option(int p_option) { int idx = files->get_current(); if (idx < 0 || idx >= files->get_item_count()) break; - String path = files->get_item_metadata(idx); - OS::get_singleton()->set_clipboard(path); + String fpath = files->get_item_metadata(idx); + OS::get_singleton()->set_clipboard(fpath); } break; } } void FileSystemDock::_folder_option(int p_option) { - TreeItem *item = tree->get_selected(); - TreeItem *child = item->get_children(); + TreeItem *selected = tree->get_selected(); switch (p_option) { - case FOLDER_EXPAND_ALL: { - item->set_collapsed(false); - while (child) { - child->set_collapsed(false); - child = child->get_next(); - } - } break; + case FOLDER_EXPAND_ALL: case FOLDER_COLLAPSE_ALL: { - while (child) { - child->set_collapsed(true); - child = child->get_next(); + bool is_collapsed = (p_option == FOLDER_COLLAPSE_ALL); + Vector<TreeItem *> needs_check; + needs_check.push_back(selected); + + while (needs_check.size()) { + needs_check[0]->set_collapsed(is_collapsed); + + TreeItem *child = needs_check[0]->get_children(); + while (child) { + needs_check.push_back(child); + child = child->get_next(); + } + + needs_check.remove(0); } } break; case FOLDER_MOVE: { to_move.clear(); - String fpath = item->get_metadata(tree->get_selected_column()); + String fpath = selected->get_metadata(tree->get_selected_column()); if (fpath != "res://") { fpath = fpath.ends_with("/") ? fpath.substr(0, fpath.length() - 1) : fpath; to_move.push_back(FileOrFolder(fpath, false)); @@ -1065,7 +1070,7 @@ void FileSystemDock::_folder_option(int p_option) { } } break; case FOLDER_RENAME: { - to_rename.path = item->get_metadata(tree->get_selected_column()); + to_rename.path = selected->get_metadata(tree->get_selected_column()); to_rename.is_file = false; if (to_rename.path != "res://") { String name = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1).get_file() : to_rename.path.get_file(); @@ -1079,9 +1084,9 @@ void FileSystemDock::_folder_option(int p_option) { case FOLDER_REMOVE: { Vector<String> remove_folders; Vector<String> remove_files; - String path = item->get_metadata(tree->get_selected_column()); - if (path != "res://") { - remove_folders.push_back(path); + String fpath = selected->get_metadata(tree->get_selected_column()); + if (fpath != "res://") { + remove_folders.push_back(fpath); remove_dialog->show(remove_folders, remove_files); } } break; @@ -1092,31 +1097,20 @@ void FileSystemDock::_folder_option(int p_option) { make_dir_dialog_text->grab_focus(); } break; case FOLDER_COPY_PATH: { - String path = item->get_metadata(tree->get_selected_column()); - OS::get_singleton()->set_clipboard(path); + String fpath = selected->get_metadata(tree->get_selected_column()); + OS::get_singleton()->set_clipboard(fpath); } break; case FOLDER_SHOW_IN_EXPLORER: { - String path = item->get_metadata(tree->get_selected_column()); - String dir = ProjectSettings::get_singleton()->globalize_path(path); + String fpath = selected->get_metadata(tree->get_selected_column()); + String dir = ProjectSettings::get_singleton()->globalize_path(fpath); OS::get_singleton()->shell_open(String("file://") + dir); } break; } } -void FileSystemDock::_open_pressed() { - - TreeItem *sel = tree->get_selected(); - if (!sel) { - return; - } - path = sel->get_metadata(0); - /*if (path!="res://" && path.ends_with("/")) { - path=path.substr(0,path.length()-1); - }*/ - - //tree_mode=false; +void FileSystemDock::_go_to_file_list() { - if (split_mode) { + if (low_height_mode) { tree->hide(); file_list_vb->show(); button_favorite->hide(); @@ -1125,8 +1119,6 @@ void FileSystemDock::_open_pressed() { //file_options->show(); _update_files(false); - current_path->set_text(path); - _push_to_history(); //emit_signal("open",path); } @@ -1158,10 +1150,8 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { void FileSystemDock::_search_changed(const String &p_text) { - if (!search_box->is_visible_in_tree()) - return; //wtf - - _update_files(false); + if (file_list_vb->is_visible()) + _update_files(false); } void FileSystemDock::_rescan() { @@ -1176,7 +1166,7 @@ void FileSystemDock::fix_dependencies(const String &p_for_file) { void FileSystemDock::focus_on_filter() { - if (!search_box->is_visible_in_tree()) { + if (low_height_mode && tree->is_visible()) { // Tree mode, switch to files list with search box tree->hide(); file_list_vb->show(); @@ -1203,13 +1193,13 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from) if (!selected) return Variant(); - String path = selected->get_metadata(0); - if (path == String()) + String fpath = selected->get_metadata(0); + if (fpath == String()) return Variant(); - if (!path.ends_with("/")) - path = path + "/"; + if (!fpath.ends_with("/")) + fpath = fpath + "/"; Vector<String> paths; - paths.push_back(path); + paths.push_back(fpath); Dictionary d = EditorNode::get_singleton()->drag_files(paths, p_from); if (selected->get_parent() && tree->get_root()->get_children() == selected->get_parent()) { @@ -1227,8 +1217,8 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from) for (int i = 0; i < files->get_item_count(); i++) { if (files->is_selected(i)) { - String path = files->get_item_metadata(i); - if (path.ends_with("/")) + String fpath = files->get_item_metadata(i); + if (fpath.ends_with("/")) seldirs.push_back(i); else selfiles.push_back(i); @@ -1249,22 +1239,20 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from) } }*/ - if (selfiles.size() > 0 && seldirs.size() == 0) { - Vector<String> fnames; - for (List<int>::Element *E = selfiles.front(); E; E = E->next()) { - fnames.push_back(files->get_item_metadata(E->get())); - } - return EditorNode::get_singleton()->drag_files(fnames, p_from); - } - + Vector<String> fnames; if (selfiles.size() > 0 || seldirs.size() > 0) { - Vector<String> fnames; - for (List<int>::Element *E = selfiles.front(); E; E = E->next()) { - fnames.push_back(files->get_item_metadata(E->get())); + if (selfiles.size() > 0) { + for (List<int>::Element *E = selfiles.front(); E; E = E->next()) { + fnames.push_back(files->get_item_metadata(E->get())); + } + if (seldirs.size() == 0) + return EditorNode::get_singleton()->drag_files(fnames, p_from); } + for (List<int>::Element *E = seldirs.front(); E; E = E->next()) { fnames.push_back(files->get_item_metadata(E->get())); } + return EditorNode::get_singleton()->drag_files_and_dirs(fnames, p_from); } } @@ -1323,9 +1311,9 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da TreeItem *ti = tree->get_item_at_position(p_point); if (!ti) return false; - String path = ti->get_metadata(0); - if (path == String()) + String fpath = ti->get_metadata(0); + if (fpath == String()) return false; return true; @@ -1399,7 +1387,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, } EditorSettings::get_singleton()->set_favorite_dirs(dirs); - _update_tree(); + _update_tree(true); return; } @@ -1415,12 +1403,12 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, TreeItem *ti = tree->get_item_at_position(p_point); if (!ti) return; - String path = ti->get_metadata(0); - if (path == String()) + String fpath = ti->get_metadata(0); + if (fpath == String()) return; - EditorNode::get_singleton()->save_resource_as(res, path); + EditorNode::get_singleton()->save_resource_as(res, fpath); return; } @@ -1495,14 +1483,14 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { continue; } - String path = files->get_item_metadata(i); - if (path.ends_with("/")) { - foldernames.push_back(path); + String fpath = files->get_item_metadata(i); + if (fpath.ends_with("/")) { + foldernames.push_back(fpath); all_files = false; } else { - filenames.push_back(path); + filenames.push_back(fpath); all_folders = false; - all_files_scenes &= (EditorFileSystem::get_singleton()->get_file_type(path) == "PackedScene"); + all_files_scenes &= (EditorFileSystem::get_singleton()->get_file_type(fpath) == "PackedScene"); } } @@ -1513,18 +1501,18 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (all_files_scenes) { file_options->add_item(TTR("Instance"), FILE_INSTANCE); } - file_options->add_separator(); if (filenames.size() == 1) { + file_options->add_separator(); file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES); file_options->add_item(TTR("View Owners.."), FILE_OWNERS); - file_options->add_separator(); } } else if (all_folders && foldernames.size() > 0) { file_options->add_item(TTR("Open"), FILE_OPEN); - file_options->add_separator(); } + file_options->add_separator(); + int num_items = filenames.size() + foldernames.size(); if (num_items >= 1) { if (num_items == 1) { @@ -1545,14 +1533,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { void FileSystemDock::select_file(const String &p_file) { - _go_to_dir(p_file.get_base_dir()); - for (int i = 0; i < files->get_item_count(); i++) { - if (files->get_item_metadata(i) == p_file) { - files->select(i); - files->ensure_current_is_visible(); - break; - } - } + navigate_to_path(p_file); } void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) { @@ -1570,14 +1551,14 @@ void FileSystemDock::_file_selected() { if (!files->is_selected(i)) continue; - String p = files->get_item_metadata(i); - if (!FileAccess::exists(p + ".import")) { + String fpath = files->get_item_metadata(i); + if (!FileAccess::exists(fpath + ".import")) { imports.clear(); break; } Ref<ConfigFile> cf; cf.instance(); - Error err = cf->load(p + ".import"); + Error err = cf->load(fpath + ".import"); if (err != OK) { imports.clear(); break; @@ -1591,7 +1572,7 @@ void FileSystemDock::_file_selected() { imports.clear(); break; } - imports.push_back(p); + imports.push_back(fpath); } if (imports.size() == 0) { @@ -1609,13 +1590,13 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_rescan"), &FileSystemDock::_rescan); ClassDB::bind_method(D_METHOD("_favorites_pressed"), &FileSystemDock::_favorites_pressed); //ClassDB::bind_method(D_METHOD("_instance_pressed"),&ScenesDock::_instance_pressed); - ClassDB::bind_method(D_METHOD("_open_pressed"), &FileSystemDock::_open_pressed); + ClassDB::bind_method(D_METHOD("_go_to_file_list"), &FileSystemDock::_go_to_file_list); ClassDB::bind_method(D_METHOD("_dir_rmb_pressed"), &FileSystemDock::_dir_rmb_pressed); ClassDB::bind_method(D_METHOD("_thumbnail_done"), &FileSystemDock::_thumbnail_done); ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file); ClassDB::bind_method(D_METHOD("_go_to_tree"), &FileSystemDock::_go_to_tree); - ClassDB::bind_method(D_METHOD("_go_to_dir"), &FileSystemDock::_go_to_dir); + ClassDB::bind_method(D_METHOD("navigate_to_path"), &FileSystemDock::navigate_to_path); ClassDB::bind_method(D_METHOD("_change_file_display"), &FileSystemDock::_change_file_display); ClassDB::bind_method(D_METHOD("_fw_history"), &FileSystemDock::_fw_history); ClassDB::bind_method(D_METHOD("_bw_history"), &FileSystemDock::_bw_history); @@ -1645,21 +1626,22 @@ void FileSystemDock::_bind_methods() { FileSystemDock::FileSystemDock(EditorNode *p_editor) { editor = p_editor; + path = "res://"; HBoxContainer *toolbar_hbc = memnew(HBoxContainer); add_child(toolbar_hbc); button_hist_prev = memnew(ToolButton); - toolbar_hbc->add_child(button_hist_prev); button_hist_prev->set_disabled(true); + button_hist_prev->set_focus_mode(FOCUS_NONE); button_hist_prev->set_tooltip(TTR("Previous Directory")); + toolbar_hbc->add_child(button_hist_prev); button_hist_next = memnew(ToolButton); - toolbar_hbc->add_child(button_hist_next); button_hist_next->set_disabled(true); - button_hist_prev->set_focus_mode(FOCUS_NONE); button_hist_next->set_focus_mode(FOCUS_NONE); button_hist_next->set_tooltip(TTR("Next Directory")); + toolbar_hbc->add_child(button_hist_next); current_path = memnew(LineEdit); current_path->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1668,10 +1650,10 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { button_reload = memnew(Button); button_reload->set_flat(true); button_reload->connect("pressed", this, "_rescan"); - toolbar_hbc->add_child(button_reload); button_reload->set_focus_mode(FOCUS_NONE); button_reload->set_tooltip(TTR("Re-Scan Filesystem")); button_reload->hide(); + toolbar_hbc->add_child(button_reload); //toolbar_hbc->add_spacer(); @@ -1679,17 +1661,16 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { button_favorite->set_flat(true); button_favorite->set_toggle_mode(true); button_favorite->connect("pressed", this, "_favorites_pressed"); - toolbar_hbc->add_child(button_favorite); button_favorite->set_tooltip(TTR("Toggle folder status as Favorite")); - button_favorite->set_focus_mode(FOCUS_NONE); + toolbar_hbc->add_child(button_favorite); //Control *spacer = memnew( Control); /* button_open = memnew( Button ); button_open->set_flat(true); - button_open->connect("pressed",this,"_open_pressed"); + button_open->connect("pressed",this,"_go_to_file_list"); toolbar_hbc->add_child(button_open); button_open->hide(); button_open->set_focus_mode(FOCUS_NONE); @@ -1712,62 +1693,63 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { add_child(folder_options); split_box = memnew(VSplitContainer); - add_child(split_box); split_box->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(split_box); tree = memnew(Tree); tree->set_hide_root(true); - split_box->add_child(tree); tree->set_drag_forwarding(this); tree->set_allow_rmb_select(true); + tree->set_custom_minimum_size(Size2(0, 200 * EDSCALE)); + split_box->add_child(tree); - //tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->connect("item_edited", this, "_favorite_toggled"); - tree->connect("item_activated", this, "_open_pressed"); + tree->connect("item_activated", this, "_go_to_file_list"); tree->connect("cell_selected", this, "_dir_selected"); tree->connect("item_rmb_selected", this, "_dir_rmb_pressed"); - files = memnew(ItemList); - files->set_v_size_flags(SIZE_EXPAND_FILL); - files->set_select_mode(ItemList::SELECT_MULTI); - files->set_drag_forwarding(this); - files->connect("item_rmb_selected", this, "_files_list_rmb_select"); - files->connect("item_selected", this, "_file_selected"); - files->connect("multi_selected", this, "_file_multi_selected"); - files->set_allow_rmb_select(true); - file_list_vb = memnew(VBoxContainer); - split_box->add_child(file_list_vb); file_list_vb->set_v_size_flags(SIZE_EXPAND_FILL); + split_box->add_child(file_list_vb); path_hb = memnew(HBoxContainer); file_list_vb->add_child(path_hb); - button_back = memnew(ToolButton); - path_hb->add_child(button_back); - button_back->hide(); + button_tree = memnew(ToolButton); + button_tree->hide(); + path_hb->add_child(button_tree); search_box = memnew(LineEdit); search_box->set_h_size_flags(SIZE_EXPAND_FILL); - path_hb->add_child(search_box); search_box->connect("text_changed", this, "_search_changed"); + path_hb->add_child(search_box); button_display_mode = memnew(ToolButton); - path_hb->add_child(button_display_mode); button_display_mode->set_toggle_mode(true); + path_hb->add_child(button_display_mode); + files = memnew(ItemList); + files->set_v_size_flags(SIZE_EXPAND_FILL); + files->set_select_mode(ItemList::SELECT_MULTI); + files->set_drag_forwarding(this); + files->connect("item_rmb_selected", this, "_files_list_rmb_select"); + files->connect("item_selected", this, "_file_selected"); + files->connect("multi_selected", this, "_file_multi_selected"); + files->set_allow_rmb_select(true); file_list_vb->add_child(files); scanning_vb = memnew(VBoxContainer); + scanning_vb->hide(); + add_child(scanning_vb); + Label *slabel = memnew(Label); slabel->set_text(TTR("Scanning Files,\nPlease Wait..")); slabel->set_align(Label::ALIGN_CENTER); scanning_vb->add_child(slabel); + scanning_progress = memnew(ProgressBar); scanning_vb->add_child(scanning_progress); - add_child(scanning_vb); - scanning_vb->hide(); deps_editor = memnew(DependencyEditor); add_child(deps_editor); @@ -1779,9 +1761,9 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { add_child(remove_dialog); move_dialog = memnew(EditorDirDialog); + move_dialog->get_ok()->set_text(TTR("Move")); add_child(move_dialog); move_dialog->connect("dir_selected", this, "_move_operation_confirm"); - move_dialog->get_ok()->set_text(TTR("Move")); rename_dialog = memnew(ConfirmationDialog); VBoxContainer *rename_dialog_vb = memnew(VBoxContainer); @@ -1808,13 +1790,12 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { updating_tree = false; initialized = false; - history.push_back("res://"); history_pos = 0; + history_max_size = 20; + history.push_back("res://"); - split_mode = false; + low_height_mode = false; display_mode = DISPLAY_THUMBNAILS; - - path = "res://"; } FileSystemDock::~FileSystemDock() { diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 89b250e295..2cb0573a3d 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -98,7 +98,7 @@ private: Button *button_reload; Button *button_favorite; - Button *button_back; + Button *button_tree; Button *button_display_mode; Button *button_hist_next; Button *button_hist_prev; @@ -107,7 +107,7 @@ private: TextureRect *search_icon; HBoxContainer *path_hb; - bool split_mode; + bool low_height_mode; DisplayMode display_mode; PopupMenu *file_options; @@ -138,6 +138,7 @@ private: Vector<String> history; int history_pos; + int history_max_size; String path; @@ -147,15 +148,22 @@ private: Tree *tree; //directories ItemList *files; - void _file_multi_selected(int p_index, bool p_selected); - void _file_selected(); + bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths); + void _update_tree(bool keep_collapse_state); + + void _update_files(bool p_keep_selection); + void _update_file_display_toggle_button(); + void _change_file_display(); + void _fs_changed(); void _go_to_tree(); - void _go_to_dir(const String &p_dir); + void _go_to_file_list(); + void _select_file(int p_idx); + void _file_multi_selected(int p_index, bool p_selected); - bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir); - void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata); + void _file_selected(); + void _dir_selected(); void _get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const; void _find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const; @@ -168,25 +176,19 @@ private: void _file_option(int p_option); void _folder_option(int p_option); - void _update_files(bool p_keep_selection); - void _update_file_display_toggle_button(); - void _change_file_display(); - void _fs_changed(); void _fw_history(); void _bw_history(); + void _update_history(); void _push_to_history(); - void _dir_selected(); - void _update_tree(); - void _rescan(); void _set_scanning_mode(); + void _rescan(); void _favorites_pressed(); - void _open_pressed(); - void _dir_rmb_pressed(const Vector2 &p_pos); void _search_changed(const String &p_text); + void _dir_rmb_pressed(const Vector2 &p_pos); void _files_list_rmb_select(int p_item, const Vector2 &p_pos); struct FileInfo { @@ -209,6 +211,7 @@ private: void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); void _preview_invalidated(const String &p_path); + void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata); protected: void _notification(int p_what); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 22c81a3b61..34c0a3d439 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -222,41 +222,38 @@ void CanvasItemEditor::_edit_set_pivot(const Vector2 &mouse_pos) { undo_redo->commit_action(); } -void CanvasItemEditor::_snap_if_closer(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation, float p_radius) { +void CanvasItemEditor::_snap_if_closer_float(float p_value, float p_target_snap, float &r_current_snap, bool &r_snapped, float p_radius) { float radius = p_radius / zoom; - float dist; + float dist = Math::abs(p_value - p_target_snap); + if (p_radius < 0 || dist < radius && (!r_snapped || dist < Math::abs(r_current_snap - p_value))) { + r_current_snap = p_target_snap; + r_snapped = true; + } +} +void CanvasItemEditor::_snap_if_closer_point(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation, float p_radius) { Transform2D rot_trans = Transform2D(rotation, Point2()); p_value = rot_trans.inverse().xform(p_value); p_target_snap = rot_trans.inverse().xform(p_target_snap); r_current_snap = rot_trans.inverse().xform(r_current_snap); - dist = Math::abs(p_value.x - p_target_snap.x); - if (p_radius < 0 || dist < radius && (!r_snapped[0] || dist < Math::abs(r_current_snap.x - p_value.x))) { - r_current_snap.x = p_target_snap.x; - r_snapped[0] = true; - } - - dist = Math::abs(p_value.y - p_target_snap.y); - if (p_radius < 0 || dist < radius && (!r_snapped[1] || dist < Math::abs(r_current_snap.y - p_value.y))) { - r_current_snap.y = p_target_snap.y; - r_snapped[1] = true; - } + _snap_if_closer_float(p_value.x, p_target_snap.x, r_current_snap.x, r_snapped[0], p_radius); + _snap_if_closer_float(p_value.y, p_target_snap.y, r_current_snap.y, r_snapped[1], p_radius); r_current_snap = rot_trans.xform(r_current_snap); } void CanvasItemEditor::_snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap) { const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_current); - if (canvas_item && p_current != p_to_snap) { + if (canvas_item && (!p_to_snap || p_current != p_to_snap)) { Transform2D ci_transform = canvas_item->get_global_transform_with_canvas(); - Transform2D to_snap_transform = p_to_snap->get_global_transform_with_canvas(); - if (ci_transform.get_rotation() == to_snap_transform.get_rotation()) { + Transform2D to_snap_transform = p_to_snap ? p_to_snap->get_global_transform_with_canvas() : Transform2D(); + if (fmod(ci_transform.get_rotation() - to_snap_transform.get_rotation(), 360.0) == 0.0) { Point2 begin = ci_transform.xform(canvas_item->get_item_rect().get_position()); Point2 end = ci_transform.xform(canvas_item->get_item_rect().get_position() + canvas_item->get_item_rect().get_size()); - _snap_if_closer(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation()); - _snap_if_closer(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation()); + _snap_if_closer_point(p_value, begin, r_current_snap, r_snapped, ci_transform.get_rotation()); + _snap_if_closer_point(p_value, end, r_current_snap, r_snapped, ci_transform.get_rotation()); } } for (int i = 0; i < p_current->get_child_count(); i++) { @@ -291,9 +288,9 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const } if (can_snap) { - _snap_if_closer(p_target, begin, output, snapped, rotation); - _snap_if_closer(p_target, (begin + end) / 2.0, output, snapped, rotation); - _snap_if_closer(p_target, end, output, snapped, rotation); + _snap_if_closer_point(p_target, begin, output, snapped, rotation); + _snap_if_closer_point(p_target, (begin + end) / 2.0, output, snapped, rotation); + _snap_if_closer_point(p_target, end, output, snapped, rotation); } } @@ -302,8 +299,8 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const if (const Control *c = Object::cast_to<Control>(p_canvas_item)) { begin = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_LEFT), c->get_anchor(MARGIN_TOP)))); end = p_canvas_item->get_global_transform_with_canvas().xform(_anchor_to_position(c, Point2(c->get_anchor(MARGIN_RIGHT), c->get_anchor(MARGIN_BOTTOM)))); - _snap_if_closer(p_target, begin, output, snapped, rotation); - _snap_if_closer(p_target, end, output, snapped, rotation); + _snap_if_closer_point(p_target, begin, output, snapped, rotation); + _snap_if_closer_point(p_target, end, output, snapped, rotation); } } @@ -311,17 +308,34 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const if ((snap_active && snap_node_sides && (p_modes & SNAP_NODE_SIDES)) || (p_forced_modes & SNAP_NODE_SIDES)) { begin = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position()); end = p_canvas_item->get_global_transform_with_canvas().xform(p_canvas_item->get_item_rect().get_position() + p_canvas_item->get_item_rect().get_size()); - _snap_if_closer(p_target, begin, output, snapped, rotation); - _snap_if_closer(p_target, end, output, snapped, rotation); + _snap_if_closer_point(p_target, begin, output, snapped, rotation); + _snap_if_closer_point(p_target, end, output, snapped, rotation); + } + } + + // Other nodes sides + if ((snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) { + _snap_other_nodes(p_target, output, snapped, get_tree()->get_edited_scene_root(), p_canvas_item); + } + + if (((snap_active && snap_guides && (p_modes & SNAP_GUIDES)) || (p_forced_modes & SNAP_GUIDES)) && fmod(rotation, 360.0) == 0.0) { + // Guides + if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { + Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_"); + for (int i = 0; i < vguides.size(); i++) { + _snap_if_closer_float(p_target.x, vguides[i], output.x, snapped[0]); + } } - // Other nodes sides - if ((snap_active && snap_other_nodes && (p_modes & SNAP_OTHER_NODES)) || (p_forced_modes & SNAP_OTHER_NODES)) { - _snap_other_nodes(p_target, output, snapped, get_tree()->get_edited_scene_root(), p_canvas_item); + if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) { + Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_"); + for (int i = 0; i < hguides.size(); i++) { + _snap_if_closer_float(p_target.y, hguides[i], output.y, snapped[1]); + } } } - if (((snap_active && snap_grid && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && rotation == 0.0) { + if (((snap_active && snap_grid && (p_modes & SNAP_GRID)) || (p_forced_modes & SNAP_GRID)) && fmod(rotation, 360.0) == 0.0) { // Grid Point2 offset = grid_offset; if (snap_relative) { @@ -335,7 +349,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, const Point2 grid_output; grid_output.x = Math::stepify(p_target.x - offset.x, grid_step.x * Math::pow(2.0, grid_step_multiplier)) + offset.x; grid_output.y = Math::stepify(p_target.y - offset.y, grid_step.y * Math::pow(2.0, grid_step_multiplier)) + offset.y; - _snap_if_closer(p_target, grid_output, output, snapped, 0.0, -1.0); + _snap_if_closer_point(p_target, grid_output, output, snapped, 0.0, -1.0); } if (((snap_pixel && (p_modes & SNAP_PIXEL)) || (p_forced_modes & SNAP_PIXEL)) && rotation == 0.0) { @@ -429,8 +443,10 @@ Dictionary CanvasItemEditor::get_state() const { state["snap_node_sides"] = snap_node_sides; state["snap_other_nodes"] = snap_other_nodes; state["snap_grid"] = snap_grid; + state["snap_guides"] = snap_guides; state["show_grid"] = show_grid; state["show_rulers"] = show_rulers; + state["show_guides"] = show_guides; state["show_helpers"] = show_helpers; state["snap_rotation"] = snap_rotation; state["snap_relative"] = snap_relative; @@ -497,6 +513,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { smartsnap_config_popup->set_item_checked(idx, snap_other_nodes); } + if (state.has("snap_guides")) { + snap_guides = state["snap_guides"]; + int idx = smartsnap_config_popup->get_item_index(SNAP_USE_GUIDES); + smartsnap_config_popup->set_item_checked(idx, snap_guides); + } + if (state.has("snap_grid")) { snap_grid = state["snap_grid"]; int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_GRID); @@ -515,6 +537,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { view_menu->get_popup()->set_item_checked(idx, show_rulers); } + if (state.has("show_guides")) { + show_guides = state["show_guides"]; + int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES); + view_menu->get_popup()->set_item_checked(idx, show_guides); + } + if (state.has("show_helpers")) { show_helpers = state["show_helpers"]; int idx = view_menu->get_popup()->get_item_index(SHOW_HELPERS); @@ -1200,10 +1228,176 @@ void CanvasItemEditor::_update_cursor() { void CanvasItemEditor::_gui_input_viewport_base(const Ref<InputEvent> &p_event) { + Ref<InputEventMouseButton> b = p_event; + if (b.is_valid()) { + if (b->get_button_index() == BUTTON_LEFT && b->is_pressed()) { + if (show_guides && show_rulers && EditorNode::get_singleton()->get_edited_scene()) { + Transform2D xform = viewport_scrollable->get_transform() * transform; + // Retreive the guide lists + Array vguides; + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { + vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_"); + } + Array hguides; + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) { + hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_"); + } + + // Press button + if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) { + // Drag a new double guide + drag = DRAG_DOUBLE_GUIDE; + edited_guide_index = -1; + } else if (b->get_position().x < RULER_WIDTH) { + // Check if we drag an existing horizontal guide + float minimum = 1e20; + edited_guide_index = -1; + for (int i = 0; i < hguides.size(); i++) { + if (ABS(xform.xform(Point2(0, hguides[i])).y - b->get_position().y) < MIN(minimum, 8)) { + edited_guide_index = i; + } + } + + if (edited_guide_index >= 0) { + // Drag an existing horizontal guide + drag = DRAG_H_GUIDE; + } else { + // Drag a new vertical guide + drag = DRAG_V_GUIDE; + } + } else if (b->get_position().y < RULER_WIDTH) { + // Check if we drag an existing vertical guide + float minimum = 1e20; + edited_guide_index = -1; + for (int i = 0; i < vguides.size(); i++) { + if (ABS(xform.xform(Point2(vguides[i], 0)).x - b->get_position().x) < MIN(minimum, 8)) { + edited_guide_index = i; + } + } + + if (edited_guide_index >= 0) { + // Drag an existing vertical guide + drag = DRAG_V_GUIDE; + } else { + // Drag a new vertical guide + drag = DRAG_H_GUIDE; + } + } + } + } + + if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { + // Release button + if (show_guides && EditorNode::get_singleton()->get_edited_scene()) { + Transform2D xform = viewport_scrollable->get_transform() * transform; + + // Retreive the guide lists + Array vguides; + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { + vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_"); + } + Array hguides; + if (EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) { + hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_"); + } + + Point2 edited = snap_point(xform.affine_inverse().xform(b->get_position()), SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES); + if (drag == DRAG_V_GUIDE) { + Array prev_vguides = vguides.duplicate(); + if (b->get_position().x > RULER_WIDTH) { + // Adds a new vertical guide + if (edited_guide_index >= 0) { + vguides[edited_guide_index] = edited.x; + undo_redo->create_action(TTR("Move vertical guide")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } else { + vguides.push_back(edited.x); + undo_redo->create_action(TTR("Create new vertical guide")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } + } else { + if (edited_guide_index >= 0) { + vguides.remove(edited_guide_index); + undo_redo->create_action(TTR("Remove vertical guide")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } + } + } else if (drag == DRAG_H_GUIDE) { + Array prev_hguides = hguides.duplicate(); + if (b->get_position().y > RULER_WIDTH) { + // Adds a new horizontal guide + if (edited_guide_index >= 0) { + hguides[edited_guide_index] = edited.y; + undo_redo->create_action(TTR("Move horizontal guide")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } else { + hguides.push_back(edited.y); + undo_redo->create_action(TTR("Create new horizontal guide")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } + } else { + if (edited_guide_index >= 0) { + hguides.remove(edited_guide_index); + undo_redo->create_action(TTR("Remove horizontal guide")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } + } + } else if (drag == DRAG_DOUBLE_GUIDE) { + Array prev_hguides = hguides.duplicate(); + Array prev_vguides = vguides.duplicate(); + if (b->get_position().x > RULER_WIDTH && b->get_position().y > RULER_WIDTH) { + // Adds a new horizontal guide a new vertical guide + vguides.push_back(edited.x); + hguides.push_back(edited.y); + undo_redo->create_action(TTR("Create new horizontal and vertical guides")); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", vguides); + undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", hguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_vertical_guides_", prev_vguides); + undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_meta", "_edit_horizontal_guides_", prev_hguides); + undo_redo->add_undo_method(viewport_base, "update"); + undo_redo->commit_action(); + } + } + } + if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_V_GUIDE || drag == DRAG_H_GUIDE) { + drag = DRAG_NONE; + viewport_base->update(); + } + } + } + Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { - if (!viewport_base->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) + if (!viewport_base->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field())) { viewport_base->call_deferred("grab_focus"); + } + if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_H_GUIDE || drag == DRAG_V_GUIDE) { + Transform2D xform = viewport_scrollable->get_transform() * transform; + Point2 mouse_pos = m->get_position(); + mouse_pos = xform.affine_inverse().xform(mouse_pos); + mouse_pos = xform.xform(snap_point(mouse_pos, SNAP_GRID | SNAP_PIXEL | SNAP_OTHER_NODES)); + + edited_guide_pos = mouse_pos; + viewport_base->update(); + } } Ref<InputEventKey> k = p_event; @@ -1767,7 +1961,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { Vector2 anchor = c_trans_rev.xform(dto - drag_from + drag_point_from); anchor = _position_to_anchor(control, anchor); - Vector2 anchor_snapped = c_trans_rev.xform(snap_point(dto - drag_from + drag_point_from, SNAP_GRID | SNAP_OTHER_NODES, _get_single_item(), SNAP_NODE_PARENT | SNAP_NODE_SIDES)); + Vector2 anchor_snapped = c_trans_rev.xform(snap_point(dto - drag_from + drag_point_from, SNAP_GRID | SNAP_GUIDES | SNAP_OTHER_NODES, _get_single_item(), SNAP_NODE_PARENT | SNAP_NODE_SIDES)); anchor_snapped = _position_to_anchor(control, anchor_snapped).snapped(Vector2(0.00001, 0.00001)); bool use_y = Math::abs(drag_vector.y) > Math::abs(drag_vector.x); @@ -1803,7 +1997,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { } dfrom = drag_point_from; - dto = snap_point(dto, SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, _get_single_item()); + dto = snap_point(dto, SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL, _get_single_item()); drag_vector = canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) - @@ -2065,6 +2259,58 @@ void CanvasItemEditor::_draw_percentage_at_position(float p_value, Point2 p_posi } } +void CanvasItemEditor::_draw_focus() { + // Draw the focus around the base viewport + if (viewport_base->has_focus()) { + get_stylebox("Focus", "EditorStyles")->draw(viewport_base->get_canvas_item(), Rect2(Point2(), viewport_base->get_size())); + } +} + +void CanvasItemEditor::_draw_guides() { + + Color guide_color = Color(0.6, 0.0, 0.8); + Transform2D xform = viewport_scrollable->get_transform() * transform; + + // Guides already there + if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_vertical_guides_")) { + Array vguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_vertical_guides_"); + for (int i = 0; i < vguides.size(); i++) { + if (drag == DRAG_V_GUIDE && i == edited_guide_index) + continue; + float x = xform.xform(Point2(vguides[i], 0)).x; + viewport_base->draw_line(Point2(x, 0), Point2(x, viewport_base->get_size().y), guide_color); + } + } + + if (EditorNode::get_singleton()->get_edited_scene() && EditorNode::get_singleton()->get_edited_scene()->has_meta("_edit_horizontal_guides_")) { + Array hguides = EditorNode::get_singleton()->get_edited_scene()->get_meta("_edit_horizontal_guides_"); + for (int i = 0; i < hguides.size(); i++) { + if (drag == DRAG_H_GUIDE && i == edited_guide_index) + continue; + float y = xform.xform(Point2(0, hguides[i])).y; + viewport_base->draw_line(Point2(0, y), Point2(viewport_base->get_size().x, y), guide_color); + } + } + + // Dragged guide + Color text_color = get_color("font_color", "Editor"); + text_color.a = 0.5; + if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_V_GUIDE) { + String str = vformat("%d px", xform.affine_inverse().xform(edited_guide_pos).x); + Ref<Font> font = get_font("font", "Label"); + Size2 text_size = font->get_string_size(str); + viewport_base->draw_string(font, Point2(edited_guide_pos.x + 10, RULER_WIDTH + text_size.y / 2 + 10), str, text_color); + viewport_base->draw_line(Point2(edited_guide_pos.x, 0), Point2(edited_guide_pos.x, viewport_base->get_size().y), guide_color); + } + if (drag == DRAG_DOUBLE_GUIDE || drag == DRAG_H_GUIDE) { + String str = vformat("%d px", xform.affine_inverse().xform(edited_guide_pos).y); + Ref<Font> font = get_font("font", "Label"); + Size2 text_size = font->get_string_size(str); + viewport_base->draw_string(font, Point2(RULER_WIDTH + 10, edited_guide_pos.y + text_size.y / 2 + 10), str, text_color); + viewport_base->draw_line(Point2(0, edited_guide_pos.y), Point2(viewport_base->get_size().x, edited_guide_pos.y), guide_color); + } +} + void CanvasItemEditor::_draw_rulers() { Color graduation_color = get_color("font_color", "Editor"); graduation_color.a = 0.5; @@ -2149,12 +2395,6 @@ void CanvasItemEditor::_draw_rulers() { viewport_base->draw_rect(Rect2(Point2(), Size2(RULER_WIDTH, RULER_WIDTH)), graduation_color); } -void CanvasItemEditor::_draw_focus() { - if (viewport_base->has_focus()) { - get_stylebox("Focus", "EditorStyles")->draw(viewport_base->get_canvas_item(), Rect2(Point2(), viewport_base->get_size())); - } -} - void CanvasItemEditor::_draw_grid() { if (show_grid) { //Draw the grid @@ -2640,6 +2880,8 @@ void CanvasItemEditor::_get_encompassing_rect(Node *p_node, Rect2 &r_rect, const void CanvasItemEditor::_draw_viewport_base() { if (show_rulers) _draw_rulers(); + if (show_guides) + _draw_guides(); _draw_focus(); } @@ -3126,6 +3368,11 @@ void CanvasItemEditor::_popup_callback(int p_op) { int idx = smartsnap_config_popup->get_item_index(SNAP_USE_OTHER_NODES); smartsnap_config_popup->set_item_checked(idx, snap_other_nodes); } break; + case SNAP_USE_GUIDES: { + snap_guides = !snap_guides; + int idx = smartsnap_config_popup->get_item_index(SNAP_USE_GUIDES); + smartsnap_config_popup->set_item_checked(idx, snap_guides); + } break; case SNAP_USE_GRID: { snap_grid = !snap_grid; int idx = snap_config_menu->get_popup()->get_item_index(SNAP_USE_GRID); @@ -3171,6 +3418,13 @@ void CanvasItemEditor::_popup_callback(int p_op) { viewport->update(); viewport_base->update(); } break; + case SHOW_GUIDES: { + show_guides = !show_guides; + int idx = view_menu->get_popup()->get_item_index(SHOW_GUIDES); + view_menu->get_popup()->set_item_checked(idx, show_guides); + viewport->update(); + viewport_base->update(); + } break; case LOCK_SELECTED: { @@ -3884,6 +4138,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_anchors", TTR("Snap to node anchor")), SNAP_USE_NODE_ANCHORS); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_node_sides", TTR("Snap to node sides")), SNAP_USE_NODE_SIDES); smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_other_nodes", TTR("Snap to other nodes")), SNAP_USE_OTHER_NODES); + smartsnap_config_popup->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_guides", TTR("Snap to guides")), SNAP_USE_GUIDES); hb->add_child(memnew(VSeparator)); @@ -3935,6 +4190,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Show Grid"), KEY_G), SHOW_GRID); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show helpers"), KEY_H), SHOW_HELPERS); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show rulers"), KEY_R), SHOW_RULERS); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show guides"), KEY_Y), SHOW_GUIDES); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KEY_MASK_SHIFT | KEY_F), VIEW_FRAME_TO_SELECTION); @@ -4022,9 +4278,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_rot = true; key_scale = false; + edited_guide_pos = Point2(); + edited_guide_index = -1; + show_grid = false; show_helpers = false; show_rulers = false; + show_guides = true; zoom = 1; grid_offset = Point2(); grid_step = Point2(10, 10); @@ -4037,6 +4297,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { snap_node_sides = true; snap_other_nodes = true; snap_grid = true; + snap_guides = true; snap_rotation = false; snap_pixel = false; skeleton_show_bones = true; diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index a8183ba286..97e3b03569 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -87,6 +87,7 @@ class CanvasItemEditor : public VBoxContainer { SNAP_USE_NODE_SIDES, SNAP_USE_OTHER_NODES, SNAP_USE_GRID, + SNAP_USE_GUIDES, SNAP_USE_ROTATION, SNAP_RELATIVE, SNAP_CONFIGURE, @@ -94,6 +95,7 @@ class CanvasItemEditor : public VBoxContainer { SHOW_GRID, SHOW_HELPERS, SHOW_RULERS, + SHOW_GUIDES, LOCK_SELECTED, UNLOCK_SELECTED, GROUP_SELECTED, @@ -183,6 +185,9 @@ class CanvasItemEditor : public VBoxContainer { DRAG_ROTATE, DRAG_PIVOT, DRAG_NODE_2D, + DRAG_V_GUIDE, + DRAG_H_GUIDE, + DRAG_DOUBLE_GUIDE, }; enum KeyMoveMODE { @@ -213,6 +218,7 @@ class CanvasItemEditor : public VBoxContainer { Transform2D transform; bool show_grid; bool show_rulers; + bool show_guides; bool show_helpers; float zoom; @@ -228,6 +234,7 @@ class CanvasItemEditor : public VBoxContainer { bool snap_node_sides; bool snap_other_nodes; bool snap_grid; + bool snap_guides; bool snap_rotation; bool snap_relative; bool snap_pixel; @@ -333,6 +340,9 @@ class CanvasItemEditor : public VBoxContainer { Point2 display_rotate_from; Point2 display_rotate_to; + int edited_guide_index; + Point2 edited_guide_pos; + Ref<StyleBoxTexture> select_sb; Ref<Texture> select_handle; Ref<Texture> anchor_handle; @@ -402,6 +412,7 @@ class CanvasItemEditor : public VBoxContainer { void _draw_percentage_at_position(float p_value, Point2 p_position, Margin p_side); void _draw_rulers(); + void _draw_guides(); void _draw_focus(); void _draw_grid(); void _draw_selection(); @@ -417,8 +428,9 @@ class CanvasItemEditor : public VBoxContainer { void _focus_selection(int p_op); - void _snap_if_closer(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation = 0.0, float p_radius = 10.0); - void _snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap); + void _snap_if_closer_float(float p_value, float p_target_snap, float &r_current_snap, bool &r_snapped, float p_radius = 10.0); + void _snap_if_closer_point(Point2 p_value, Point2 p_target_snap, Point2 &r_current_snap, bool (&r_snapped)[2], real_t rotation = 0.0, float p_radius = 10.0); + void _snap_other_nodes(Point2 p_value, Point2 &r_current_snap, bool (&r_snapped)[2], const Node *p_current, const CanvasItem *p_to_snap = NULL); void _set_anchors_preset(Control::LayoutPreset p_preset); void _set_margins_preset(Control::LayoutPreset p_preset); @@ -476,13 +488,14 @@ protected: public: enum SnapMode { SNAP_GRID = 1 << 0, - SNAP_PIXEL = 1 << 1, - SNAP_NODE_PARENT = 1 << 2, - SNAP_NODE_ANCHORS = 1 << 3, - SNAP_NODE_SIDES = 1 << 4, - SNAP_OTHER_NODES = 1 << 5, - - SNAP_DEFAULT = 0x03, + SNAP_GUIDES = 1 << 1, + SNAP_PIXEL = 1 << 2, + SNAP_NODE_PARENT = 1 << 3, + SNAP_NODE_ANCHORS = 1 << 4, + SNAP_NODE_SIDES = 1 << 5, + SNAP_OTHER_NODES = 1 << 6, + + SNAP_DEFAULT = 0x07, }; Point2 snap_point(Point2 p_target, unsigned int p_modes = SNAP_DEFAULT, const CanvasItem *p_canvas_item = NULL, unsigned int p_forced_modes = 0); diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/gi_probe_editor_plugin.cpp index fcbf282758..443cd2e41f 100644 --- a/editor/plugins/gi_probe_editor_plugin.cpp +++ b/editor/plugins/gi_probe_editor_plugin.cpp @@ -60,6 +60,27 @@ void GIProbeEditorPlugin::make_visible(bool p_visible) { } } +EditorProgress *GIProbeEditorPlugin::tmp_progress = NULL; + +void GIProbeEditorPlugin::bake_func_begin(int p_steps) { + + ERR_FAIL_COND(tmp_progress != NULL); + + tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake GI Probe"), p_steps)); +} + +void GIProbeEditorPlugin::bake_func_step(int p_step, const String &p_description) { + + ERR_FAIL_COND(tmp_progress == NULL); + tmp_progress->step(p_description, p_step); +} + +void GIProbeEditorPlugin::bake_func_end() { + ERR_FAIL_COND(tmp_progress == NULL); + memdelete(tmp_progress); + tmp_progress = NULL; +} + void GIProbeEditorPlugin::_bind_methods() { ClassDB::bind_method("_bake", &GIProbeEditorPlugin::_bake); @@ -70,10 +91,15 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { editor = p_node; bake = memnew(Button); bake->set_icon(editor->get_gui_base()->get_icon("BakedLight", "EditorIcons")); + bake->set_text(TTR("Bake GI Probe")); bake->hide(); bake->connect("pressed", this, "_bake"); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake); gi_probe = NULL; + + GIProbe::bake_begin_function = bake_func_begin; + GIProbe::bake_step_function = bake_func_step; + GIProbe::bake_end_function = bake_func_end; } GIProbeEditorPlugin::~GIProbeEditorPlugin() { diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/gi_probe_editor_plugin.h index a1fecd2911..527f420510 100644 --- a/editor/plugins/gi_probe_editor_plugin.h +++ b/editor/plugins/gi_probe_editor_plugin.h @@ -44,6 +44,11 @@ class GIProbeEditorPlugin : public EditorPlugin { Button *bake; EditorNode *editor; + static EditorProgress *tmp_progress; + static void bake_func_begin(int p_steps); + static void bake_func_step(int p_step, const String &p_description); + static void bake_func_end(); + void _bake(); protected: diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index f96cbabde7..25ca2d731e 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -267,12 +267,12 @@ Vector3 SpatialEditorViewport::_get_camera_position() const { Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) { - return camera->unproject_position(p_point); + return camera->unproject_position(p_point) * viewport_container->get_stretch_shrink(); } Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const { - return camera->project_ray_origin(p_pos); + return camera->project_ray_origin(p_pos / viewport_container->get_stretch_shrink()); } Vector3 SpatialEditorViewport::_get_camera_normal() const { @@ -282,7 +282,7 @@ Vector3 SpatialEditorViewport::_get_camera_normal() const { Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) const { - return camera->project_ray_normal(p_pos); + return camera->project_ray_normal(p_pos / viewport_container->get_stretch_shrink()); } /* void SpatialEditorViewport::_clear_id(Spatial *p_node) { @@ -847,6 +847,7 @@ void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) { selection_menu->set_invalidate_click_until_motion(); } } + void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (previewing) @@ -1576,7 +1577,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } - } else if (m->get_button_mask() & BUTTON_MASK_RIGHT) { + } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) { if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) { nav_mode = NAVIGATION_ZOOM; @@ -1791,6 +1792,13 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { set_message(TTR("Animation Key Inserted.")); } + if (ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) { + set_freelook_active(!is_freelook_active()); + + } else if (k->get_scancode() == KEY_ESCAPE) { + set_freelook_active(false); + } + if (k->get_scancode() == KEY_SPACE) { if (!k->is_pressed()) emit_signal("toggle_maximize_view", this); } @@ -1815,9 +1823,15 @@ void SpatialEditorViewport::set_freelook_active(bool active_now) { freelook_speed = base_speed * cursor.distance; } + // Hide mouse like in an FPS (warping doesn't work) + OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_CAPTURED); + } else if (freelook_active && !active_now) { // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential cursor = camera_cursor; + + // Restore mouse + OS::get_singleton()->set_mouse_mode(OS::MOUSE_MODE_VISIBLE); } freelook_active = active_now; @@ -2036,6 +2050,12 @@ void SpatialEditorViewport::_notification(int p_what) { viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2)); viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3)); + bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)); + + if (shrink != viewport_container->get_stretch_shrink() > 1) { + viewport_container->set_stretch_shrink(shrink ? 2 : 1); + } + //update msaa if changed int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa"); @@ -2387,6 +2407,13 @@ void SpatialEditorViewport::_menu_option(int p_option) { view_menu->get_popup()->set_item_checked(idx, current); } break; + case VIEW_HALF_RESOLUTION: { + + int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION); + bool current = view_menu->get_popup()->is_item_checked(idx); + current = !current; + view_menu->get_popup()->set_item_checked(idx, current); + } break; case VIEW_INFORMATION: { int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION); @@ -2616,6 +2643,12 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { camera->set_doppler_tracking(doppler ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED); view_menu->get_popup()->set_item_checked(idx, doppler); } + if (p_state.has("half_res")) { + bool half_res = p_state["half_res"]; + + int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION); + view_menu->get_popup()->set_item_checked(idx, half_res); + } if (p_state.has("previewing")) { Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]); @@ -2641,6 +2674,7 @@ Dictionary SpatialEditorViewport::get_state() const { d["use_environment"] = camera->get_environment().is_valid(); d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; d["listener"] = viewport->is_audio_listener(); + d["half_res"] = viewport_container->get_stretch_shrink() > 1; if (previewing) { d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); } @@ -3058,6 +3092,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed spatial_editor = p_spatial_editor; ViewportContainer *c = memnew(ViewportContainer); + viewport_container = c; c->set_stretch(true); add_child(c); c->set_anchors_and_margins_preset(Control::PRESET_WIDE); @@ -3104,6 +3139,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true); view_menu->get_popup()->add_separator(); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION); + view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Doppler Enable")), VIEW_AUDIO_DOPPLER); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true); @@ -4595,6 +4632,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe"), KEY_Z); + ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F); + PopupMenu *p; transform_menu = memnew(MenuButton); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index f2a9886f2a..c2b698068f 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -83,6 +83,7 @@ class SpatialEditorViewport : public Control { VIEW_PERSPECTIVE, VIEW_ENVIRONMENT, VIEW_ORTHOGONAL, + VIEW_HALF_RESOLUTION, VIEW_AUDIO_LISTENER, VIEW_AUDIO_DOPPLER, VIEW_GIZMOS, @@ -120,6 +121,7 @@ private: UndoRedo *undo_redo; Button *preview_camera; + ViewportContainer *viewport_container; MenuButton *view_menu; diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 3f79d00f80..b21c176543 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -876,6 +876,7 @@ void ProjectSettingsEditor::_action_add() { r->select(0); input_editor->ensure_cursor_is_visible(); action_add_error->hide(); + action_name->clear(); } void ProjectSettingsEditor::_item_checked(const String &p_item, bool p_check) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index f3e59932c4..7438c7671e 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -319,6 +319,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editor->push_item(existing.ptr()); else { String path = selected->get_filename(); + if (path == "") { + String root_path = editor_data->get_edited_scene_root()->get_filename(); + if (root_path == "") { + path = "res://" + selected->get_name(); + } else { + path = root_path.get_base_dir() + "/" + selected->get_name(); + } + } script_create_dialog->config(selected->get_class(), path); script_create_dialog->popup_centered(); } diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index bcb998aee0..d9b10ff3fa 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -2111,9 +2111,9 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base for (List<String>::Element *E = opts.front(); E; E = E->next()) { String opt = E->get().strip_edges(); - if (opt.begins_with("\"") && opt.ends_with("\"")) { + if (opt.is_quoted()) { r_forced = true; - String idopt = opt.substr(1, opt.length() - 2); + String idopt = opt.unquote(); if (idopt.replace("/", "_").is_valid_identifier()) { options.insert(idopt); } else { diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 34d01c6beb..b43ec409a1 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -83,6 +83,8 @@ const char *GDFunctions::get_func_name(Function p_func) { "rad2deg", "linear2db", "db2linear", + "wrapi", + "wrapf", "max", "min", "clamp", @@ -405,6 +407,14 @@ void GDFunctions::call(Function p_func, const Variant **p_args, int p_arg_count, VALIDATE_ARG_NUM(0); r_ret = Math::db2linear((double)*p_args[0]); } break; + case MATH_WRAP: { + VALIDATE_ARG_COUNT(3); + r_ret = Math::wrapi((int64_t)*p_args[0], (int64_t)*p_args[1], (int64_t)*p_args[2]); + } break; + case MATH_WRAPF: { + VALIDATE_ARG_COUNT(3); + r_ret = Math::wrapf((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]); + } break; case LOGIC_MAX: { VALIDATE_ARG_COUNT(2); if (p_args[0]->get_type() == Variant::INT && p_args[1]->get_type() == Variant::INT) { @@ -1285,6 +1295,8 @@ bool GDFunctions::is_deterministic(Function p_func) { case MATH_RAD2DEG: case MATH_LINEAR2DB: case MATH_DB2LINEAR: + case MATH_WRAP: + case MATH_WRAPF: case LOGIC_MAX: case LOGIC_MIN: case LOGIC_CLAMP: @@ -1513,6 +1525,16 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type = Variant::REAL; return mi; } break; + case MATH_WRAP: { + MethodInfo mi("wrapi", PropertyInfo(Variant::INT, "value"), PropertyInfo(Variant::INT, "min"), PropertyInfo(Variant::INT, "max")); + mi.return_val.type = Variant::INT; + return mi; + } break; + case MATH_WRAPF: { + MethodInfo mi("wrapf", PropertyInfo(Variant::REAL, "value"), PropertyInfo(Variant::REAL, "min"), PropertyInfo(Variant::REAL, "max")); + mi.return_val.type = Variant::REAL; + return mi; + } break; case LOGIC_MAX: { MethodInfo mi("max", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b")); mi.return_val.type = Variant::REAL; diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index a568c8f1cf..0de09f2e71 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -75,6 +75,8 @@ public: MATH_RAD2DEG, MATH_LINEAR2DB, MATH_DB2LINEAR, + MATH_WRAP, + MATH_WRAPF, LOGIC_MAX, LOGIC_MIN, LOGIC_CLAMP, diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 3d91a6de6c..161e130a07 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -122,6 +122,9 @@ void CSharpLanguage::init() { void CSharpLanguage::finish() { + // Release gchandle bindings before finalizing mono runtime + gchandle_bindings.clear(); + if (gdmono) { memdelete(gdmono); gdmono = NULL; @@ -297,6 +300,20 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin return script; } +bool CSharpLanguage::is_using_templates() { + + return true; +} + +void CSharpLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) { + + String src = p_script->get_source_code(); + src = src.replace("%BASE%", p_base_class_name) + .replace("%CLASS%", p_class_name) + .replace("%TS%", _get_indentation()); + p_script->set_source_code(src); +} + Script *CSharpLanguage::create_script() const { return memnew(CSharpScript); @@ -396,6 +413,25 @@ String CSharpLanguage::make_function(const String &p_class, const String &p_name #endif } +String CSharpLanguage::_get_indentation() const { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", 0); + + if (use_space_indentation) { + int indent_size = EDITOR_DEF("text_editor/indent/size", 4); + + String space_indent = ""; + for (int i = 0; i < indent_size; i++) { + space_indent += " "; + } + return space_indent; + } + } +#endif + return "\t"; +} + void CSharpLanguage::frame() { const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle; @@ -794,6 +830,14 @@ void *CSharpLanguage::alloc_instance_binding_data(Object *p_object) { void CSharpLanguage::free_instance_binding_data(void *p_data) { + if (GDMono::get_singleton() == NULL) { +#ifdef DEBUG_ENABLED + CRASH_COND(!gchandle_bindings.empty()); +#endif + // Mono runtime finalized, all the gchandle bindings were already released + return; + } + #ifndef NO_THREADS script_bind_lock->lock(); #endif @@ -1411,6 +1455,34 @@ void CSharpScript::_resource_path_changed() { } } +bool CSharpScript::_get(const StringName &p_name, Variant &r_ret) const { + + if (p_name == CSharpLanguage::singleton->string_names._script_source) { + + r_ret = get_source_code(); + return true; + } + + return false; +} + +bool CSharpScript::_set(const StringName &p_name, const Variant &p_value) { + + if (p_name == CSharpLanguage::singleton->string_names._script_source) { + + set_source_code(p_value); + reload(); + return true; + } + + return false; +} + +void CSharpScript::_get_property_list(List<PropertyInfo> *p_properties) const { + + p_properties->push_back(PropertyInfo(Variant::STRING, CSharpLanguage::singleton->string_names._script_source, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); +} + void CSharpScript::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo(Variant::OBJECT, "new")); @@ -1984,5 +2056,6 @@ CSharpLanguage::StringNameCache::StringNameCache() { _set = StaticCString::create("_set"); _get = StaticCString::create("_get"); _notification = StaticCString::create("_notification"); + _script_source = StaticCString::create("script/source"); dotctor = StaticCString::create(".ctor"); } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 65a6450da5..255665b495 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -116,6 +116,9 @@ protected: Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); virtual void _resource_path_changed(); + bool _get(const StringName &p_name, Variant &r_ret) const; + bool _set(const StringName &p_name, const Variant &p_value); + void _get_property_list(List<PropertyInfo> *p_properties) const; public: virtual bool can_instance() const; @@ -228,16 +231,17 @@ class CSharpLanguage : public ScriptLanguage { StringName _set; StringName _get; StringName _notification; + StringName _script_source; StringName dotctor; // .ctor StringNameCache(); }; - StringNameCache string_names; - int lang_idx; public: + StringNameCache string_names; + _FORCE_INLINE_ int get_language_index() { return lang_idx; } void set_language_index(int p_idx); @@ -266,6 +270,8 @@ 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 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; } virtual Script *create_script() const; virtual bool has_named_classes() const; @@ -273,6 +279,7 @@ public: /* TODO? */ virtual int find_function(const String &p_function, const String &p_code) const { return -1; } virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const; /* TODO? */ Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; } + virtual String _get_indentation() const; /* TODO? */ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {} /* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {} diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 83d2bb1471..dbe0cc294c 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -61,10 +61,10 @@ String _find_build_engine_on_unix(const String &p_name) { }; for (int i = 0; i < sizeof(locations) / sizeof(const char *); i++) { - String location = locations[i]; + String hint_path = locations[i] + p_name; - if (FileAccess::exists(location + p_name)) { - return location; + if (FileAccess::exists(hint_path)) { + return hint_path; } } diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp index 39c57ee0be..837dbfde66 100644 --- a/modules/mono/editor/godotsharp_editor.cpp +++ b/modules/mono/editor/godotsharp_editor.cpp @@ -171,11 +171,6 @@ Error GodotSharpEditor::open_in_external_editor(const Ref<Script> &p_script, int String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); monodevel_instance->execute(script_path); } break; - case EDITOR_VISUAL_STUDIO: - // TODO - // devenv <PathToSolutionFolder> - // devenv /edit <PathToCsFile> /command "edit.goto <Line>" - // HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7 default: return ERR_UNAVAILABLE; } @@ -229,7 +224,7 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) { if (!ed_settings->has_setting("mono/editor/external_editor")) { ed_settings->set_setting("mono/editor/external_editor", EDITOR_NONE); } - ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio,Visual Studio Code")); + ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/editor/external_editor", PROPERTY_HINT_ENUM, "None,MonoDevelop,Visual Studio Code")); } GodotSharpEditor::~GodotSharpEditor() { diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h index 7b4b50b172..0f2c163582 100644 --- a/modules/mono/editor/godotsharp_editor.h +++ b/modules/mono/editor/godotsharp_editor.h @@ -69,7 +69,6 @@ public: enum ExternalEditor { EDITOR_NONE, EDITOR_MONODEVELOP, - EDITOR_VISUAL_STUDIO, EDITOR_CODE, }; diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp index d3ad968135..e10e06df0e 100644 --- a/modules/mono/mono_gc_handle.cpp +++ b/modules/mono/mono_gc_handle.cpp @@ -59,6 +59,10 @@ Ref<MonoGCHandle> MonoGCHandle::create_weak(MonoObject *p_object) { void MonoGCHandle::release() { +#ifdef DEBUG_ENABLED + CRASH_COND(GDMono::get_singleton() == NULL); +#endif + if (!released && GDMono::get_singleton()->is_runtime_initialized()) { mono_gchandle_free(handle); released = true; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 904a8ae2c7..c997b0f000 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -705,7 +705,7 @@ bool _GodotSharp::is_domain_loaded() { void _GodotSharp::queue_dispose(Object *p_object) { - if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { + if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { _dispose_object(p_object); } else { #ifndef NO_THREADS @@ -722,7 +722,7 @@ void _GodotSharp::queue_dispose(Object *p_object) { void _GodotSharp::queue_dispose(NodePath *p_node_path) { - if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { + if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { memdelete(p_node_path); } else { #ifndef NO_THREADS @@ -739,7 +739,7 @@ void _GodotSharp::queue_dispose(NodePath *p_node_path) { void _GodotSharp::queue_dispose(RID *p_rid) { - if (Thread::get_main_id() == Thread::get_caller_id() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { + if (GDMonoUtils::is_main_thread() && !GDMono::get_singleton()->is_finalizing_scripts_domain()) { memdelete(p_rid); } else { #ifndef NO_THREADS diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 77a1ef3cb0..01392447f3 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -600,7 +600,7 @@ MonoArray *Array_to_mono_array(const Array &p_array) { for (int i = 0; i < p_array.size(); i++) { MonoObject *boxed = variant_to_mono_object(p_array[i]); - mono_array_set(ret, MonoObject *, i, boxed); + mono_array_setref(ret, i, boxed); } return ret; diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index e3af57e78a..ebb5d28e4d 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -149,6 +149,10 @@ void attach_current_thread(); void detach_current_thread(); MonoThread *get_current_thread(); +_FORCE_INLINE_ bool is_main_thread() { + return mono_domain_get() != NULL && mono_thread_get_main() == mono_thread_current(); +} + GDMonoClass *get_object_class(MonoObject *p_object); GDMonoClass *type_get_proxy_class(const StringName &p_type); GDMonoClass *get_class_native_base(GDMonoClass *p_class); diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index c8581f6122..105c2c981e 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/modules/mono/utils/path_utils.cpp @@ -56,9 +56,6 @@ String path_which(const String &p_name) { for (int i = 0; i < env_path.size(); i++) { String p = path_join(env_path[i], p_name); - if (FileAccess::exists(p)) - return p; - #ifdef WINDOWS_ENABLED for (int j = 0; j < exts.size(); j++) { String p2 = p + exts[j]; @@ -66,6 +63,9 @@ String path_which(const String &p_name) { if (FileAccess::exists(p2)) return p2; } +#else + if (FileAccess::exists(p)) + return p; #endif } diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index 4b294325dc..7c9d306831 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -78,6 +78,8 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX "rad2deg", "linear2db", "db2linear", + "wrapi", + "wrapf", "max", "min", "clamp", @@ -198,6 +200,8 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) { case MATH_LERP: case MATH_INVERSE_LERP: case MATH_DECTIME: + case MATH_WRAP: + case MATH_WRAPF: case LOGIC_CLAMP: return 3; case MATH_RANGE_LERP: @@ -364,6 +368,22 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const case MATH_DB2LINEAR: { return PropertyInfo(Variant::REAL, "db"); } break; + case MATH_WRAP: { + if (p_idx == 0) + return PropertyInfo(Variant::INT, "value"); + else if (p_idx == 1) + return PropertyInfo(Variant::INT, "min"); + else + return PropertyInfo(Variant::INT, "max"); + } break; + case MATH_WRAPF: { + if (p_idx == 0) + return PropertyInfo(Variant::REAL, "value"); + else if (p_idx == 1) + return PropertyInfo(Variant::REAL, "min"); + else + return PropertyInfo(Variant::REAL, "max"); + } break; case LOGIC_MAX: { if (p_idx == 0) return PropertyInfo(Variant::REAL, "a"); @@ -549,9 +569,13 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons case MATH_DEG2RAD: case MATH_RAD2DEG: case MATH_LINEAR2DB: + case MATH_WRAPF: case MATH_DB2LINEAR: { t = Variant::REAL; } break; + case MATH_WRAP: { + t = Variant::INT; + } break; case LOGIC_MAX: case LOGIC_MIN: case LOGIC_CLAMP: { @@ -898,6 +922,18 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in VALIDATE_ARG_NUM(0); *r_return = Math::db2linear((double)*p_inputs[0]); } break; + case VisualScriptBuiltinFunc::MATH_WRAP: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]); + } break; + case VisualScriptBuiltinFunc::MATH_WRAPF: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; case VisualScriptBuiltinFunc::LOGIC_MAX: { if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { @@ -1258,6 +1294,8 @@ void VisualScriptBuiltinFunc::_bind_methods() { BIND_ENUM_CONSTANT(MATH_RAD2DEG); BIND_ENUM_CONSTANT(MATH_LINEAR2DB); BIND_ENUM_CONSTANT(MATH_DB2LINEAR); + BIND_ENUM_CONSTANT(MATH_WRAP); + BIND_ENUM_CONSTANT(MATH_WRAPF); BIND_ENUM_CONSTANT(LOGIC_MAX); BIND_ENUM_CONSTANT(LOGIC_MIN); BIND_ENUM_CONSTANT(LOGIC_CLAMP); @@ -1343,6 +1381,8 @@ void register_visual_script_builtin_func_node() { VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>); + VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/max", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>); VisualScriptLanguage::singleton->add_register_func("functions/built_in/min", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>); diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index 5758d23e8f..34a2825938 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -77,6 +77,8 @@ public: MATH_RAD2DEG, MATH_LINEAR2DB, MATH_DB2LINEAR, + MATH_WRAP, + MATH_WRAPF, LOGIC_MAX, LOGIC_MIN, LOGIC_CLAMP, diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index d67bc653c9..33586086dc 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1834,6 +1834,8 @@ OS::LatinKeyboardVariant OS_OSX::get_latin_keyboard_variant() const { layout = LATIN_KEYBOARD_DVORAK; } else if ([test isEqualToString:@"xvlcwk"]) { layout = LATIN_KEYBOARD_NEO; + } else if ([test isEqualToString:@"qwfpgj"]) { + layout = LATIN_KEYBOARD_COLEMAK; } [test release]; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 48e2d8f81e..09193e0a2b 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -2253,6 +2253,38 @@ Error OS_X11::move_to_trash(const String &p_path) { return err; } +OS::LatinKeyboardVariant OS_X11::get_latin_keyboard_variant() const { + + XkbDescRec *xkbdesc = XkbAllocKeyboard(); + ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY); + + XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc); + ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY); + ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY); + + char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols); + ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY); + + Vector<String> info = String(layout).split("+"); + ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY); + + if (info[1].find("colemak") != -1) { + return LATIN_KEYBOARD_COLEMAK; + } else if (info[1].find("qwertz") != -1) { + return LATIN_KEYBOARD_QWERTZ; + } else if (info[1].find("azerty") != -1) { + return LATIN_KEYBOARD_AZERTY; + } else if (info[1].find("qzerty") != -1) { + return LATIN_KEYBOARD_QZERTY; + } else if (info[1].find("dvorak") != -1) { + return LATIN_KEYBOARD_DVORAK; + } else if (info[1].find("neo") != -1) { + return LATIN_KEYBOARD_NEO; + } + + return LATIN_KEYBOARD_QWERTY; +} + OS_X11::OS_X11() { #ifdef PULSEAUDIO_ENABLED diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index 36355f11bc..b71b456d49 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -275,6 +275,8 @@ public: virtual Error move_to_trash(const String &p_path); + virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + OS_X11(); }; diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 69bad1623f..b98cdcc365 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -33,19 +33,49 @@ #include "physics_body_2d.h" #include "servers/physics_2d_server.h" -void Joint2D::_update_joint() { - - if (!is_inside_tree()) - return; +void Joint2D::_update_joint(bool p_only_free) { if (joint.is_valid()) { + if (ba.is_valid() && bb.is_valid()) + Physics2DServer::get_singleton()->body_remove_collision_exception(ba, bb); + Physics2DServer::get_singleton()->free(joint); + joint = RID(); + ba = RID(); + bb = RID(); } - joint = RID(); + if (p_only_free || !is_inside_tree()) + return; + + Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; + Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; + + if (!node_a || !node_b) + return; + + PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); + PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); + + if (!body_a || !body_b) + return; + + if (!body_a) { + SWAP(body_a, body_b); + } + + joint = _configure_joint(body_a, body_b); + + if (!joint.is_valid()) + return; - joint = _configure_joint(); Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias); + + ba = body_a->get_rid(); + bb = body_b->get_rid(); + + if (exclude_from_collision) + Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); } void Joint2D::set_node_a(const NodePath &p_node_a) { @@ -83,9 +113,7 @@ void Joint2D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { - - Physics2DServer::get_singleton()->free(joint); - joint = RID(); + _update_joint(true); } } break; } @@ -164,29 +192,8 @@ void PinJoint2D::_notification(int p_what) { } } -RID PinJoint2D::_configure_joint() { - - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; - - if (!node_a && !node_b) - return RID(); +RID PinJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) { - PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); - PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); - - if (!body_a && !body_b) - return RID(); - - if (!body_a) { - SWAP(body_a, body_b); - } else if (body_b) { - //add a collision exception between both - if (get_exclude_nodes_from_collision()) - Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); - else - Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid()); - } RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID()); Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness); return pj; @@ -241,24 +248,7 @@ void GrooveJoint2D::_notification(int p_what) { } } -RID GrooveJoint2D::_configure_joint() { - - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; - - if (!node_a || !node_b) - return RID(); - - PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); - PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); - - if (!body_a || !body_b) - return RID(); - - if (get_exclude_nodes_from_collision()) - Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); - else - Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid()); +RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) { Transform2D gt = get_global_transform(); Vector2 groove_A1 = gt.get_origin(); @@ -330,24 +320,7 @@ void DampedSpringJoint2D::_notification(int p_what) { } } -RID DampedSpringJoint2D::_configure_joint() { - - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; - - if (!node_a || !node_b) - return RID(); - - PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); - PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); - - if (!body_a || !body_b) - return RID(); - - if (get_exclude_nodes_from_collision()) - Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); - else - Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid()); +RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) { Transform2D gt = get_global_transform(); Vector2 anchor_A = gt.get_origin(); diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index 685299abc6..a6292be51c 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -32,11 +32,14 @@ #include "node_2d.h" +class PhysicsBody2D; + class Joint2D : public Node2D { GDCLASS(Joint2D, Node2D); RID joint; + RID ba, bb; NodePath a; NodePath b; @@ -45,10 +48,10 @@ class Joint2D : public Node2D { bool exclude_from_collision; protected: - void _update_joint(); + void _update_joint(bool p_only_free = false); void _notification(int p_what); - virtual RID _configure_joint() = 0; + virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0; static void _bind_methods(); @@ -77,7 +80,7 @@ class PinJoint2D : public Joint2D { protected: void _notification(int p_what); - virtual RID _configure_joint(); + virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b); static void _bind_methods(); public: @@ -96,7 +99,7 @@ class GrooveJoint2D : public Joint2D { protected: void _notification(int p_what); - virtual RID _configure_joint(); + virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b); static void _bind_methods(); public: @@ -120,7 +123,7 @@ class DampedSpringJoint2D : public Joint2D { protected: void _notification(int p_what); - virtual RID _configure_joint(); + virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b); static void _bind_methods(); public: diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index d5a030b35c..c0ca358717 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -1134,6 +1134,10 @@ void GIProbe::_find_meshes(Node *p_at_node, Baker *p_baker) { } } +GIProbe::BakeBeginFunc GIProbe::bake_begin_function = NULL; +GIProbe::BakeStepFunc GIProbe::bake_step_function = NULL; +GIProbe::BakeEndFunc GIProbe::bake_end_function = NULL; + void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { Baker baker; @@ -1177,14 +1181,25 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { _find_meshes(p_from_node ? p_from_node : get_parent(), &baker); + if (bake_begin_function) { + bake_begin_function(baker.mesh_list.size() + 1); + } + int pmc = 0; for (List<Baker::PlotMesh>::Element *E = baker.mesh_list.front(); E; E = E->next()) { - print_line("plotting mesh " + itos(pmc++) + "/" + itos(baker.mesh_list.size())); + if (bake_step_function) { + bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(baker.mesh_list.size())); + } + + pmc++; _plot_mesh(E->get().local_xform, E->get().mesh, &baker, E->get().instance_materials, E->get().override_material); } + if (bake_step_function) { + bake_step_function(pmc++, RTR("Finishing Plot")); + } _fixup_plot(0, 0, 0, 0, 0, &baker); @@ -1282,6 +1297,10 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { set_probe_data(probe_data); } + + if (bake_end_function) { + bake_end_function(); + } } void GIProbe::_debug_mesh(int p_idx, int p_level, const Rect3 &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, Baker *p_baker) { diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 5a06984a47..50d0c33d4f 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -95,6 +95,10 @@ public: }; + typedef void (*BakeBeginFunc)(int); + typedef void (*BakeStepFunc)(int, const String &); + typedef void (*BakeEndFunc)(); + private: //stuff used for bake struct Baker { @@ -190,6 +194,10 @@ protected: static void _bind_methods(); public: + static BakeBeginFunc bake_begin_function; + static BakeStepFunc bake_step_function; + static BakeEndFunc bake_end_function; + void set_probe_data(const Ref<GIProbeData> &p_data); Ref<GIProbeData> get_probe_data() const; diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index aa127ab79f..1d779d31fe 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -32,13 +32,8 @@ void Joint::_update_joint(bool p_only_free) { if (joint.is_valid()) { - if (ba.is_valid() && bb.is_valid()) { - - if (exclude_from_collision) - PhysicsServer::get_singleton()->body_add_collision_exception(ba, bb); - else - PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb); - } + if (ba.is_valid() && bb.is_valid()) + PhysicsServer::get_singleton()->body_remove_collision_exception(ba, bb); PhysicsServer::get_singleton()->free(joint); joint = RID(); @@ -52,33 +47,31 @@ void Joint::_update_joint(bool p_only_free) { Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; - if (!node_a && !node_b) + if (!node_a || !node_b) return; PhysicsBody *body_a = Object::cast_to<PhysicsBody>(node_a); PhysicsBody *body_b = Object::cast_to<PhysicsBody>(node_b); - if (!body_a && !body_b) + if (!body_a || !body_b) return; if (!body_a) { SWAP(body_a, body_b); - } else if (body_b) { - //add a collision exception between both - PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); } joint = _configure_joint(body_a, body_b); - if (joint.is_valid()) - PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority); + if (!joint.is_valid()) + return; + + PhysicsServer::get_singleton()->joint_set_solver_priority(joint, solver_priority); - if (body_b && joint.is_valid()) { + ba = body_a->get_rid(); + bb = body_b->get_rid(); - ba = body_a->get_rid(); - bb = body_b->get_rid(); + if (exclude_from_collision) PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid()); - } } void Joint::set_node_a(const NodePath &p_node_a) { @@ -129,8 +122,6 @@ void Joint::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { _update_joint(true); - //PhysicsServer::get_singleton()->free(joint); - joint = RID(); } } break; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index f57f58c18d..40e2dba6c2 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -1038,9 +1038,11 @@ void LineEdit::set_cursor_position(int p_pos) { Ref<StyleBox> style = get_stylebox("normal"); Ref<Font> font = get_font("font"); - if (cursor_pos < window_pos) { + if (cursor_pos <= window_pos) { /* Adjust window if cursor goes too much to the left */ - set_window_pos(cursor_pos); + if (window_pos > 0) + set_window_pos(window_pos - 1); + } else if (cursor_pos > window_pos) { /* Adjust window if cursor goes too much to the right */ int window_width = get_size().width - style->get_minimum_size().width; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index cfe924ecd4..581034ddee 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -90,6 +90,10 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { return; } + // Do not activate tabs when tabs is empty + if (get_tab_count() == 0) + return; + Vector<Control *> tabs = _get_tabs(); // Handle navigation buttons. @@ -298,6 +302,8 @@ void TabContainer::_notification(int p_what) { } int TabContainer::_get_tab_width(int p_index) const { + + ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0); Control *control = Object::cast_to<Control>(_get_tabs()[p_index]); if (!control || control->is_set_as_toplevel()) return 0; @@ -669,6 +675,7 @@ void TabContainer::_bind_methods() { TabContainer::TabContainer() { first_tab_cache = 0; + last_tab_cache = 0; buttons_visible_cache = false; tabs_ofs_cache = 0; current = 0; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index acf6d55eb5..ee7762b668 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2188,7 +2188,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } } - + begin_complex_operation(); bool first_line = false; if (k->get_command()) { if (k->get_shift()) { @@ -2204,8 +2204,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - _insert_text_at_cursor(ins); - _push_current_op(); + insert_text_at_cursor(ins); if (first_line) { cursor_set_line(0); @@ -2213,7 +2212,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_line(cursor.line - 1); cursor_set_column(text[cursor.line].length()); } - + end_complex_operation(); } break; case KEY_ESCAPE: { if (completion_hint != "") { @@ -4489,7 +4488,13 @@ void TextEdit::_update_completion_candidates() { completion_index = 0; completion_base = s; Vector<float> sim_cache; + bool single_quote = s.begins_with("'"); + 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("'"); + } + if (s == completion_strings[i]) { // A perfect match, stop completion _cancel_completion(); diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp index c321b873fd..9244d8de2f 100644 --- a/scene/gui/viewport_container.cpp +++ b/scene/gui/viewport_container.cpp @@ -62,6 +62,34 @@ bool ViewportContainer::is_stretch_enabled() const { return stretch; } +void ViewportContainer::set_stretch_shrink(int p_shrink) { + + ERR_FAIL_COND(p_shrink < 1); + if (shrink == p_shrink) + return; + + shrink = p_shrink; + + if (!stretch) + return; + + for (int i = 0; i < get_child_count(); i++) { + + Viewport *c = Object::cast_to<Viewport>(get_child(i)); + if (!c) + continue; + + c->set_size(get_size() / shrink); + } + + update(); +} + +int ViewportContainer::get_stretch_shrink() const { + + return shrink; +} + void ViewportContainer::_notification(int p_what) { if (p_what == NOTIFICATION_RESIZED) { @@ -75,7 +103,7 @@ void ViewportContainer::_notification(int p_what) { if (!c) continue; - c->set_size(get_size()); + c->set_size(get_size() / shrink); } } @@ -115,10 +143,15 @@ void ViewportContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &ViewportContainer::set_stretch); ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &ViewportContainer::is_stretch_enabled); + ClassDB::bind_method(D_METHOD("set_stretch_shrink", "amount"), &ViewportContainer::set_stretch_shrink); + ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &ViewportContainer::get_stretch_shrink); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink"); } ViewportContainer::ViewportContainer() { stretch = false; + shrink = 1; } diff --git a/scene/gui/viewport_container.h b/scene/gui/viewport_container.h index 630523b5fb..ebf5869ed9 100644 --- a/scene/gui/viewport_container.h +++ b/scene/gui/viewport_container.h @@ -37,6 +37,7 @@ class ViewportContainer : public Container { GDCLASS(ViewportContainer, Container); bool stretch; + int shrink; protected: void _notification(int p_what); @@ -46,6 +47,9 @@ public: void set_stretch(bool p_enable); bool is_stretch_enabled() const; + void set_stretch_shrink(int p_shrink); + int get_stretch_shrink() const; + virtual Size2 get_minimum_size() const; ViewportContainer(); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 18b7014595..697abead68 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -226,7 +226,7 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) { static int total = 0; ticks = OS::get_singleton()->get_ticks_msec(); - if ((ticks - first_ticks) > 10 * 1000) { + if ((ticks - first_ticks) > 10 * 1000 && count > 0) { print_line("Audio Driver " + String(AudioDriver::get_singleton()->get_name()) + " average latency: " + itos(total / count) + "ms (frame=" + itos(p_frames) + ")"); first_ticks = ticks; total = 0; diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 46a5192e52..6ced004118 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -45,8 +45,9 @@ void BodySW::_update_transform_dependant() { // update inertia tensor Basis tb = principal_inertia_axes; Basis tbt = tb.transposed(); - tb.scale(_inv_inertia); - _inv_inertia_tensor = tb * tbt; + Basis diag; + diag.scale(_inv_inertia); + _inv_inertia_tensor = tb * diag * tbt; } void BodySW::update_inertias() { diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp index 70cc549e2d..1e323be36c 100644 --- a/servers/physics/joints/generic_6dof_joint_sw.cpp +++ b/servers/physics/joints/generic_6dof_joint_sw.cpp @@ -219,9 +219,9 @@ Generic6DOFJointSW::Generic6DOFJointSW(BodySW *rbA, BodySW *rbB, const Transform } void Generic6DOFJointSW::calculateAngleInfo() { - Basis relative_frame = m_calculatedTransformA.basis.inverse() * m_calculatedTransformB.basis; + Basis relative_frame = m_calculatedTransformB.basis.inverse() * m_calculatedTransformA.basis; - m_calculatedAxisAngleDiff = relative_frame.get_euler(); + m_calculatedAxisAngleDiff = relative_frame.get_euler_xyz(); // in euler angle mode we do not actually constrain the angular velocity // along the axes axis[0] and axis[2] (although we do use axis[1]) : diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index a7c31cf16c..5ba935d47c 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -233,14 +233,7 @@ void PhysicsServerSW::area_set_space(RID p_area, RID p_space) { if (area->get_space() == space) return; //pointless - for (Set<ConstraintSW *>::Element *E = area->get_constraints().front(); E; E = E->next()) { - RID self = E->get()->get_self(); - if (!self.is_valid()) - continue; - free(self); - } area->clear_constraints(); - area->set_space(space); }; @@ -494,14 +487,7 @@ void PhysicsServerSW::body_set_space(RID p_body, RID p_space) { if (body->get_space() == space) return; //pointless - for (Map<ConstraintSW *, int>::Element *E = body->get_constraint_map().front(); E; E = E->next()) { - RID self = E->key()->get_self(); - if (!self.is_valid()) - continue; - free(self); - } body->clear_constraint_map(); - body->set_space(space); }; diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index df3bf72a31..5d3305c82d 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -299,14 +299,7 @@ void Physics2DServerSW::area_set_space(RID p_area, RID p_space) { if (area->get_space() == space) return; //pointless - for (Set<Constraint2DSW *>::Element *E = area->get_constraints().front(); E; E = E->next()) { - RID self = E->get()->get_self(); - if (!self.is_valid()) - continue; - free(self); - } area->clear_constraints(); - area->set_space(space); }; @@ -551,14 +544,7 @@ void Physics2DServerSW::body_set_space(RID p_body, RID p_space) { if (body->get_space() == space) return; //pointless - for (Map<Constraint2DSW *, int>::Element *E = body->get_constraint_map().front(); E; E = E->next()) { - RID self = E->key()->get_self(); - if (!self.is_valid()) - continue; - free(self); - } body->clear_constraint_map(); - body->set_space(space); }; diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index c644fd2d55..69e2d1c162 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -102,6 +102,7 @@ void VisualServerRaster::draw() { VSG::viewport->draw_viewports(); VSG::scene->render_probes(); + _draw_margins(); VSG::rasterizer->end_frame(); while (frame_drawn_callbacks.front()) { @@ -119,8 +120,6 @@ void VisualServerRaster::draw() { frame_drawn_callbacks.pop_front(); } - - _draw_margins(); } void VisualServerRaster::sync() { } |