diff options
41 files changed, 519 insertions, 434 deletions
diff --git a/core/error_macros.h b/core/error_macros.h index 80ceede043..4a3ea28957 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -108,8 +108,6 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * running application to fail or crash. * Always try to return processable data, so the engine can keep running well. * Use the _MSG versions to print a meaningful message to help with debugging. - * - * Note: See https://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for */ // Index out of bounds error macros. @@ -124,25 +122,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, the current function returns. */ -#define ERR_FAIL_INDEX(m_index, m_size) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_INDEX(m_index, m_size) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ + return; \ + } else \ + ((void)0) /** * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, prints `m_msg` and the current function returns. */ -#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_INDEX_V_MSG`. @@ -151,25 +147,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, the current function returns `m_retval`. */ -#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_INDEX_V(m_index, m_size, m_retval) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ + return m_retval; \ + } else \ + ((void)0) /** * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, prints `m_msg` and the current function returns `m_retval`. */ -#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return m_retval; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`. @@ -179,13 +173,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, the application crashes. */ -#define CRASH_BAD_INDEX(m_index, m_size) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ - GENERATE_TRAP(); \ - } \ - } while (0) +#define CRASH_BAD_INDEX(m_index, m_size) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ + GENERATE_TRAP(); \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`. @@ -194,13 +187,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. * If not, prints `m_msg` and the application crashes. */ -#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg), true); \ - GENERATE_TRAP(); \ - } \ - } while (0) +#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg), true); \ + GENERATE_TRAP(); \ + } else \ + ((void)0) // Unsigned integer index out of bounds error macros. @@ -211,25 +203,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, the current function returns. */ -#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_UNSIGNED_INDEX(m_index, m_size) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ + return; \ + } else \ + ((void)0) /** * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, prints `m_msg` and the current function returns. */ -#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. @@ -238,25 +228,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, the current function returns `m_retval`. */ -#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_UNSIGNED_INDEX_V(m_index, m_size, m_retval) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ + return m_retval; \ + } else \ + ((void)0) /** * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, prints `m_msg` and the current function returns `m_retval`. */ -#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return m_retval; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. @@ -266,13 +254,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, the application crashes. */ -#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ - GENERATE_TRAP(); \ - } \ - } while (0) +#define CRASH_BAD_UNSIGNED_INDEX(m_index, m_size) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ + GENERATE_TRAP(); \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. @@ -281,13 +268,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures an unsigned integer index `m_index` is less than `m_size`. * If not, prints `m_msg` and the application crashes. */ -#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg), true); \ - GENERATE_TRAP(); \ - } \ - } while (0) +#define CRASH_BAD_UNSIGNED_INDEX_MSG(m_index, m_size, m_msg) \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg), true); \ + GENERATE_TRAP(); \ + } else \ + ((void)0) // Null reference error macros. @@ -298,25 +284,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures a pointer `m_param` is not null. * If it is null, the current function returns. */ -#define ERR_FAIL_NULL(m_param) \ - do { \ - if (unlikely(!m_param)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_NULL(m_param) \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ + return; \ + } else \ + ((void)0) /** * Ensures a pointer `m_param` is not null. * If it is null, prints `m_msg` and the current function returns. */ -#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ - do { \ - if (unlikely(!m_param)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ + return; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_NULL_V_MSG`. @@ -325,25 +309,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures a pointer `m_param` is not null. * If it is null, the current function returns `m_retval`. */ -#define ERR_FAIL_NULL_V(m_param, m_retval) \ - do { \ - if (unlikely(!m_param)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_NULL_V(m_param, m_retval) \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null."); \ + return m_retval; \ + } else \ + ((void)0) /** * Ensures a pointer `m_param` is not null. * If it is null, prints `m_msg` and the current function returns `m_retval`. */ -#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ - do { \ - if (unlikely(!m_param)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", DEBUG_STR(m_msg)); \ + return m_retval; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_MSG`. @@ -354,13 +336,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures `m_cond` is false. * If `m_cond` is true, the current function returns. */ -#define ERR_FAIL_COND(m_cond) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_COND(m_cond) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true."); \ + return; \ + } else \ + ((void)0) /** * Ensures `m_cond` is false. @@ -369,13 +350,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If checking for null use ERR_FAIL_NULL_MSG instead. * If checking index bounds use ERR_FAIL_INDEX_MSG instead. */ -#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", DEBUG_STR(m_msg)); \ - return; \ - } \ - } while (0) +#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", DEBUG_STR(m_msg)); \ + return; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_V_MSG`. @@ -386,13 +366,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures `m_cond` is false. * If `m_cond` is true, the current function returns `m_retval`. */ -#define ERR_FAIL_COND_V(m_cond, m_retval) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. returned: " _STR(m_retval)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_COND_V(m_cond, m_retval) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. returned: " _STR(m_retval)); \ + return m_retval; \ + } else \ + ((void)0) /** * Ensures `m_cond` is false. @@ -401,13 +380,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If checking for null use ERR_FAIL_NULL_V_MSG instead. * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead. */ -#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. returned: " _STR(m_retval), DEBUG_STR(m_msg)); \ - return m_retval; \ - } \ - } while (0) +#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. returned: " _STR(m_retval), DEBUG_STR(m_msg)); \ + return m_retval; \ + } else \ + ((void)0) /** * Try using `ERR_CONTINUE_MSG`. @@ -416,25 +394,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures `m_cond` is false. * If `m_cond` is true, the current loop continues. */ -#define ERR_CONTINUE(m_cond) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \ - continue; \ - } \ - } while (0) +#define ERR_CONTINUE(m_cond) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing."); \ + continue; \ + } else \ + ((void)0) /** * Ensures `m_cond` is false. * If `m_cond` is true, prints `m_msg` and the current loop continues. */ -#define ERR_CONTINUE_MSG(m_cond, m_msg) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", DEBUG_STR(m_msg)); \ - continue; \ - } \ - } while (0) +#define ERR_CONTINUE_MSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", DEBUG_STR(m_msg)); \ + continue; \ + } else \ + ((void)0) /** * Try using `ERR_BREAK_MSG`. @@ -443,25 +419,23 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures `m_cond` is false. * If `m_cond` is true, the current loop breaks. */ -#define ERR_BREAK(m_cond) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \ - break; \ - } \ - } while (0) +#define ERR_BREAK(m_cond) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking."); \ + break; \ + } else \ + ((void)0) /** * Ensures `m_cond` is false. * If `m_cond` is true, prints `m_msg` and the current loop breaks. */ -#define ERR_BREAK_MSG(m_cond, m_msg) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", DEBUG_STR(m_msg)); \ - break; \ - } \ - } while (0) +#define ERR_BREAK_MSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", DEBUG_STR(m_msg)); \ + break; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`. @@ -471,13 +445,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures `m_cond` is false. * If `m_cond` is true, the application crashes. */ -#define CRASH_COND(m_cond) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \ - GENERATE_TRAP(); \ - } \ - } while (0) +#define CRASH_COND(m_cond) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true."); \ + GENERATE_TRAP(); \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`. @@ -486,13 +459,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Ensures `m_cond` is false. * If `m_cond` is true, prints `m_msg` and the application crashes. */ -#define CRASH_COND_MSG(m_cond, m_msg) \ - do { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", DEBUG_STR(m_msg)); \ - GENERATE_TRAP(); \ - } \ - } while (0) +#define CRASH_COND_MSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition \"" _STR(m_cond) "\" is true.", DEBUG_STR(m_msg)); \ + GENERATE_TRAP(); \ + } else \ + ((void)0) // Generic error macros. @@ -504,10 +476,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * The current function returns. */ #define ERR_FAIL() \ - do { \ + if (1) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed."); \ return; \ - } while (0) + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_MSG`. @@ -516,10 +489,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg`, and the current function returns. */ #define ERR_FAIL_MSG(m_msg) \ - do { \ + if (1) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed.", DEBUG_STR(m_msg)); \ return; \ - } while (0) + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`. @@ -529,10 +503,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * The current function returns `m_retval`. */ #define ERR_FAIL_V(m_retval) \ - do { \ + if (1) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_value)); \ return m_retval; \ - } while (0) + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_V_MSG`. @@ -541,10 +516,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg`, and the current function returns `m_retval`. */ #define ERR_FAIL_V_MSG(m_retval, m_msg) \ - do { \ + if (1) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_value), DEBUG_STR(m_msg)); \ return m_retval; \ - } while (0) + } else \ + ((void)0) /** * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG. @@ -553,22 +529,21 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * * Prints `m_msg`. */ -#define ERR_PRINT(m_msg) \ - do { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg)); \ - } while (0) +#define ERR_PRINT(m_msg) \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg)) /** * Prints `m_msg` once during the application lifetime. */ #define ERR_PRINT_ONCE(m_msg) \ - do { \ + if (1) { \ static bool first_print = true; \ if (first_print) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg)); \ first_print = false; \ } \ - } while (0) + } else \ + ((void)0) // Print warning message macros. @@ -577,10 +552,8 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. */ -#define WARN_PRINT(m_msg) \ - do { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \ - } while (0) +#define WARN_PRINT(m_msg) \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg), ERR_HANDLER_WARNING) /** * Prints `m_msg` once during the application lifetime. @@ -588,13 +561,14 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. */ #define WARN_PRINT_ONCE(m_msg) \ - do { \ + if (1) { \ static bool first_print = true; \ if (first_print) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \ first_print = false; \ } \ - } while (0) + } else \ + ((void)0) // Print deprecated warning message macros. @@ -602,25 +576,27 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Warns that the current function is deprecated. */ #define WARN_DEPRECATED \ - do { \ + if (1) { \ static volatile bool warning_shown = false; \ if (!warning_shown) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \ warning_shown = true; \ } \ - } while (0) + } else \ + ((void)0) /** * Warns that the current function is deprecated and prints `m_msg`. */ #define WARN_DEPRECATED_MSG(m_msg) \ - do { \ + if (1) { \ static volatile bool warning_shown = false; \ if (!warning_shown) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \ warning_shown = true; \ } \ - } while (0) + } else \ + ((void)0) /** * Do not use. @@ -629,10 +605,11 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * The application crashes. */ #define CRASH_NOW() \ - do { \ + if (1) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/Function Failed."); \ GENERATE_TRAP(); \ - } while (0) + } else \ + ((void)0) /** * Only use if the application should never reach this point. @@ -640,9 +617,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * Prints `m_msg`, and then the application crashes. */ #define CRASH_NOW_MSG(m_msg) \ - do { \ + if (1) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/Function Failed.", DEBUG_STR(m_msg)); \ GENERATE_TRAP(); \ - } while (0) + } else \ + ((void)0) #endif diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml index 214afd519b..4b5d4c853a 100644 --- a/doc/classes/BoxContainer.xml +++ b/doc/classes/BoxContainer.xml @@ -23,7 +23,6 @@ <member name="alignment" type="int" setter="set_alignment" getter="get_alignment" enum="BoxContainer.AlignMode" default="0"> The alignment of the container's children (must be one of [constant ALIGN_BEGIN], [constant ALIGN_CENTER] or [constant ALIGN_END]). </member> - <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" override="true" enum="Control.MouseFilter" default="1" /> </members> <constants> <constant name="ALIGN_BEGIN" value="0" enum="AlignMode"> diff --git a/doc/classes/Container.xml b/doc/classes/Container.xml index 4593e00e05..c285b448d8 100644 --- a/doc/classes/Container.xml +++ b/doc/classes/Container.xml @@ -29,6 +29,9 @@ </description> </method> </methods> + <members> + <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" override="true" enum="Control.MouseFilter" default="1" /> + </members> <signals> <signal name="sort_children"> <description> diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml index 7834390247..61d240c1dc 100644 --- a/doc/classes/EditorInspector.xml +++ b/doc/classes/EditorInspector.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="EditorInspector" inherits="ScrollContainer" version="4.0"> <brief_description> + A tab used to edit properties of the selected node. </brief_description> <description> + The editor inspector is by default located on the right-hand side of the editor. It's used to edit the properties of the selected node. For example, you can select a node such as the Sprite2D then edit its transform through the inspector tool. The editor inspector is an essential tool in the game development workflow. </description> <tutorials> </tutorials> diff --git a/doc/classes/EditorSceneImporterAssimp.xml b/doc/classes/EditorSceneImporterAssimp.xml index ede3c75b09..c72d4ee25a 100644 --- a/doc/classes/EditorSceneImporterAssimp.xml +++ b/doc/classes/EditorSceneImporterAssimp.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="EditorSceneImporterAssimp" inherits="EditorSceneImporter" version="4.0"> <brief_description> - Multi-format 3D asset importer based on [url=http://assimp.org/]Assimp[/url]. + FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/url]. </brief_description> <description> - This is a multi-format 3D asset importer based on [url=http://assimp.org/]Assimp[/url]. See [url=https://assimp-docs.readthedocs.io/en/latest/about/intoduction.html#installation]this page[/url] for a full list of supported formats. + This is an FBX 3D asset importer based on [url=http://assimp.org/]Assimp[/url]. It currently has many known limitations and works best with static meshes. Most animated meshes won't import correctly. If exporting a FBX scene from Autodesk Maya, use these FBX export settings: [codeblock] - Smoothing Groups diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml index 3387150429..cc6e3dc7f9 100644 --- a/doc/classes/GraphNode.xml +++ b/doc/classes/GraphNode.xml @@ -184,6 +184,7 @@ <member name="comment" type="bool" setter="set_comment" getter="is_comment" default="false"> If [code]true[/code], the GraphNode is a comment node. </member> + <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" override="true" enum="Control.MouseFilter" default="0" /> <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> The offset of the GraphNode, relative to the scroll offset of the [GraphEdit]. [b]Note:[/b] You cannot use position directly, as [GraphEdit] is a [Container]. diff --git a/doc/classes/GridContainer.xml b/doc/classes/GridContainer.xml index 472578f29b..4493ee8dc1 100644 --- a/doc/classes/GridContainer.xml +++ b/doc/classes/GridContainer.xml @@ -15,7 +15,6 @@ <member name="columns" type="int" setter="set_columns" getter="get_columns" default="1"> The number of columns in the [GridContainer]. If modified, [GridContainer] reorders its children to accommodate the new layout. </member> - <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" override="true" enum="Control.MouseFilter" default="1" /> </members> <constants> </constants> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 512401d2de..f2574360cb 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -22,6 +22,8 @@ - Ctrl + N: Like the down arrow key, move the cursor to the next line - Ctrl + D: Like the Delete key, delete the character on the right side of cursor - Ctrl + H: Like the Backspace key, delete the character on the left side of the cursor + - Ctrl + A: Like the Home key, move the cursor to the beginning of the line + - Ctrl + E: Like the End key, move the cursor to the end of the line - Command + Left arrow: Like the Home key, move the cursor to the beginning of the line - Command + Right arrow: Like the End key, move the cursor to the end of the line </description> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index b2d979239c..67b6045152 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -161,9 +161,6 @@ <constant name="ARRAY_FORMAT_INDEX" value="256" enum="ArrayFormat"> Mesh array uses indices. </constant> - <constant name="ARRAY_COMPRESS_BASE" value="9" enum="ArrayFormat"> - Used internally to calculate other [code]ARRAY_COMPRESS_*[/code] enum values. Do not use. - </constant> <constant name="ARRAY_COMPRESS_VERTEX" value="512" enum="ArrayFormat"> Flag used to mark a compressed (half float) vertex array. </constant> diff --git a/doc/classes/PanelContainer.xml b/doc/classes/PanelContainer.xml index 5863093662..9803a8dc51 100644 --- a/doc/classes/PanelContainer.xml +++ b/doc/classes/PanelContainer.xml @@ -10,6 +10,9 @@ </tutorials> <methods> </methods> + <members> + <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" override="true" enum="Control.MouseFilter" default="0" /> + </members> <constants> </constants> <theme_items> diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml index 558ba84068..e1b7d60763 100644 --- a/doc/classes/Skeleton2D.xml +++ b/doc/classes/Skeleton2D.xml @@ -4,7 +4,7 @@ Skeleton for 2D characters and animated objects. </brief_description> <description> - Skeleton2D parents a hierarchy of [Bone2D] objects. It is a requirement of [Bone2D]. Skeleton2D holds a reference to the rest pose of its children and acts as a single point of access to its bones. + Skeleton2D parents a hierarchy of [Bone2D] objects. It is a requirement of [Bone2D]. Skeleton2D holds a reference to the rest pose of its children and acts as a single point of access to its bones. </description> <tutorials> <link>https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html</link> diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 83259afb35..c76ff9d679 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -197,7 +197,7 @@ void GroupDialog::_add_group(String p_name) { } String name = p_name.strip_edges(); - if (name == "" || groups->search_item_text(name)) { + if (name.empty() || groups->get_item_with_text(name)) { return; } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1d8f3a2bbd..bf21abb455 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -58,6 +58,7 @@ #define RULER_WIDTH (15 * EDSCALE) #define SCALE_HANDLE_DISTANCE 25 +#define MOVE_HANDLE_DISTANCE 25 class SnapDialog : public ConfirmationDialog { @@ -1866,14 +1867,16 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { drag_type = DRAG_SCALE_BOTH; - Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); - Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); - if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { - drag_type = DRAG_SCALE_X; - } - Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); - if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { - drag_type = DRAG_SCALE_Y; + if (show_transformation_gizmos) { + Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE); + Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_SCALE_X; + } + Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_SCALE_Y; + } } drag_from = transform.affine_inverse().xform(b->get_position()); @@ -1924,7 +1927,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { scale.y = scale.x * ratio; } } else if (drag_type == DRAG_SCALE_Y) { - scale.y += scale_factor.y; + scale.y -= scale_factor.y; if (uniform) { scale.x = scale.y / ratio; } @@ -1983,6 +1986,24 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if (selection.size() > 0) { drag_type = DRAG_MOVE; + + CanvasItem *canvas_item = drag_selection[0]; + Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse(); + Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized(); + Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + + if (show_transformation_gizmos) { + Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE); + Rect2 x_handle_rect = Rect2(move_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_MOVE_X; + } + Rect2 y_handle_rect = Rect2(-5 * EDSCALE, move_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) { + drag_type = DRAG_MOVE_Y; + } + } + drag_from = transform.affine_inverse().xform(b->get_position()); drag_selection = selection; _save_canvas_item_state(drag_selection); @@ -1992,7 +2013,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } } - if (drag_type == DRAG_MOVE) { + if (drag_type == DRAG_MOVE || drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y) { // Move the nodes if (m.is_valid()) { @@ -2014,7 +2035,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } else { previous_pos = _get_encompassing_rect_from_list(drag_selection).position; } + Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, NULL, drag_selection); + + if (drag_type == DRAG_MOVE_X) { + new_pos.y = previous_pos.y; + } else if (drag_type == DRAG_MOVE_Y) { + new_pos.x = previous_pos.x; + } + bool single_axis = m->get_shift(); if (single_axis) { if (ABS(new_pos.x - previous_pos.x) > ABS(new_pos.y - previous_pos.y)) { @@ -3235,10 +3264,39 @@ void CanvasItemEditor::_draw_selection() { } } - // Draw the rescale handles + // Draw the move handles bool is_ctrl = Input::get_singleton()->is_key_pressed(KEY_CONTROL); bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); - if ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) { + if (tool == TOOL_MOVE && show_transformation_gizmos) { + if (_is_node_movable(canvas_item)) { + Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); + Transform2D simple_xform = viewport->get_transform() * unscaled_transform; + + Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE); + viewport->draw_set_transform_matrix(simple_xform); + + Vector<Point2> points; + points.push_back(Vector2(move_factor.x * EDSCALE, 5 * EDSCALE)); + points.push_back(Vector2(move_factor.x * EDSCALE, -5 * EDSCALE)); + points.push_back(Vector2((move_factor.x + 10) * EDSCALE, 0)); + + viewport->draw_colored_polygon(points, get_color("axis_x_color", "Editor")); + viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_color("axis_x_color", "Editor"), Math::round(EDSCALE), true); + + points.clear(); + points.push_back(Vector2(5 * EDSCALE, move_factor.y * EDSCALE)); + points.push_back(Vector2(-5 * EDSCALE, move_factor.y * EDSCALE)); + points.push_back(Vector2(0, (move_factor.y + 10) * EDSCALE)); + + viewport->draw_colored_polygon(points, get_color("axis_y_color", "Editor")); + viewport->draw_line(Point2(), Point2(0, move_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE), true); + + viewport->draw_set_transform_matrix(viewport->get_transform()); + } + } + + // Draw the rescale handles + if (show_transformation_gizmos && ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y)) { if (_is_node_movable(canvas_item)) { Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized(); Transform2D simple_xform = viewport->get_transform() * unscaled_transform; @@ -3253,9 +3311,9 @@ void CanvasItemEditor::_draw_selection() { scale_factor.y += offset.x; } } else if (drag_type == DRAG_SCALE_Y) { - scale_factor.y -= offset.y; + scale_factor.y += offset.y; if (uniform) { - scale_factor.x -= offset.y; + scale_factor.x += offset.y; } } @@ -3264,9 +3322,9 @@ void CanvasItemEditor::_draw_selection() { viewport->draw_rect(x_handle_rect, get_color("axis_x_color", "Editor")); viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_color("axis_x_color", "Editor"), Math::round(EDSCALE), true); - Rect2 y_handle_rect = Rect2(-5 * EDSCALE, -(scale_factor.y + 10) * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); + Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE); viewport->draw_rect(y_handle_rect, get_color("axis_y_color", "Editor")); - viewport->draw_line(Point2(), Point2(0, -scale_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE), true); + viewport->draw_line(Point2(), Point2(0, scale_factor.y * EDSCALE), get_color("axis_y_color", "Editor"), Math::round(EDSCALE), true); viewport->draw_set_transform_matrix(viewport->get_transform()); } @@ -4381,10 +4439,8 @@ void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { } void CanvasItemEditor::_popup_callback(int p_op) { - last_option = MenuOption(p_op); switch (p_op) { - case SHOW_GRID: { show_grid = !show_grid; int idx = view_menu->get_popup()->get_item_index(SHOW_GRID); @@ -4409,6 +4465,12 @@ void CanvasItemEditor::_popup_callback(int p_op) { view_menu->get_popup()->set_item_checked(idx, show_edit_locks); viewport->update(); } break; + case SHOW_TRANSFORMATION_GIZMOS: { + show_transformation_gizmos = !show_transformation_gizmos; + int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); + view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); + viewport->update(); + } break; case SNAP_USE_NODE_PARENT: { snap_node_parent = !snap_node_parent; int idx = smartsnap_config_popup->get_item_index(SNAP_USE_NODE_PARENT); @@ -4967,6 +5029,7 @@ void CanvasItemEditor::_focus_selection(int p_op) { zoom = scale_x < scale_y ? scale_x : scale_y; zoom *= 0.90; viewport->update(); + _update_zoom_label(); call_deferred("_popup_callback", VIEW_CENTER_TO_SELECTION); } } @@ -5034,6 +5097,7 @@ Dictionary CanvasItemEditor::get_state() const { state["show_helpers"] = show_helpers; state["show_zoom_control"] = zoom_hb->is_visible(); state["show_edit_locks"] = show_edit_locks; + state["show_transformation_gizmos"] = show_transformation_gizmos; state["snap_rotation"] = snap_rotation; state["snap_scale"] = snap_scale; state["snap_relative"] = snap_relative; @@ -5172,6 +5236,12 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { view_menu->get_popup()->set_item_checked(idx, show_edit_locks); } + if (state.has("show_transformation_gizmos")) { + show_transformation_gizmos = state["show_transformation_gizmos"]; + int idx = view_menu->get_popup()->get_item_index(SHOW_TRANSFORMATION_GIZMOS); + view_menu->get_popup()->set_item_checked(idx, show_transformation_gizmos); + } + if (state.has("show_zoom_control")) { // This one is not user-controllable, but instrumentable zoom_hb->set_visible(state["show_zoom_control"]); @@ -5264,6 +5334,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { show_helpers = false; show_rulers = true; show_guides = true; + show_transformation_gizmos = true; show_edit_locks = true; zoom = 1.0 / MAX(1, EDSCALE); view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH); @@ -5595,6 +5666,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_origin", TTR("Show Origin")), SHOW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_viewport", TTR("Show Viewport")), SHOW_VIEWPORT); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_edit_locks", TTR("Show Group And Lock Icons")), SHOW_EDIT_LOCKS); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_transformation_gizmos", TTR("Show Transformation Gizmos")), SHOW_TRANSFORMATION_GIZMOS); p->add_separator(); p->add_shortcut(ED_SHORTCUT("canvas_item_editor/center_selection", TTR("Center Selection"), KEY_F), VIEW_CENTER_TO_SELECTION); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 3291d6b9bf..37bc47ecd4 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -119,6 +119,7 @@ private: SHOW_ORIGIN, SHOW_VIEWPORT, SHOW_EDIT_LOCKS, + SHOW_TRANSFORMATION_GIZMOS, LOCK_SELECTED, UNLOCK_SELECTED, GROUP_SELECTED, @@ -189,7 +190,6 @@ private: SKELETON_SHOW_BONES, SKELETON_SET_IK_CHAIN, SKELETON_CLEAR_IK_CHAIN - }; enum DragType { @@ -209,6 +209,8 @@ private: DRAG_ANCHOR_BOTTOM_LEFT, DRAG_ANCHOR_ALL, DRAG_MOVE, + DRAG_MOVE_X, + DRAG_MOVE_Y, DRAG_SCALE_X, DRAG_SCALE_Y, DRAG_SCALE_BOTH, @@ -248,6 +250,8 @@ private: bool show_viewport; bool show_helpers; bool show_edit_locks; + bool show_transformation_gizmos; + float zoom; Point2 view_offset; Point2 previous_update_view_offset; diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index be9e5b0e3a..179ebca562 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -448,8 +448,8 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla float radius = shape->get_radius(); float height = shape->get_height() / 2; - handles.write[0] = Point2(radius, -height); - handles.write[1] = Point2(0, -(height + radius)); + handles.write[0] = Point2(radius, height); + handles.write[1] = Point2(0, height + radius); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); @@ -502,8 +502,8 @@ void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overla handles.resize(3); Vector2 ext = shape->get_extents(); handles.write[0] = Point2(ext.x, 0); - handles.write[1] = Point2(0, -ext.y); - handles.write[2] = Point2(ext.x, -ext.y); + handles.write[1] = Point2(0, ext.y); + handles.write[2] = Point2(ext.x, ext.y); p_overlay->draw_texture(h, gt.xform(handles[0]) - size); p_overlay->draw_texture(h, gt.xform(handles[1]) - size); diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp index 8b5fe7d2c5..9101c64eab 100644 --- a/editor/plugins/skeleton_editor_plugin.cpp +++ b/editor/plugins/skeleton_editor_plugin.cpp @@ -103,8 +103,10 @@ void SkeletonEditor::create_physical_skeleton() { PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) { - real_t half_height(skeleton->get_bone_rest(bone_child_id).origin.length() * 0.5); - real_t radius(half_height * 0.2); + const Transform child_rest = skeleton->get_bone_rest(bone_child_id); + + const real_t half_height(child_rest.origin.length() * 0.5); + const real_t radius(half_height * 0.2); CapsuleShape *bone_shape_capsule = memnew(CapsuleShape); bone_shape_capsule->set_height((half_height - radius) * 2); @@ -114,7 +116,8 @@ PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_i bone_shape->set_shape(bone_shape_capsule); Transform body_transform; - body_transform.origin = Vector3(0, 0, -half_height); + body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin, Vector3(0, 1, 0)); + body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height)); Transform joint_transform; joint_transform.origin = Vector3(0, 0, half_height); diff --git a/editor/plugins/skeleton_ik_editor_plugin.cpp b/editor/plugins/skeleton_ik_editor_plugin.cpp index 43dc13b270..eb6ad9498d 100644 --- a/editor/plugins/skeleton_ik_editor_plugin.cpp +++ b/editor/plugins/skeleton_ik_editor_plugin.cpp @@ -41,21 +41,12 @@ void SkeletonIKEditorPlugin::_play() { return; if (play_btn->is_pressed()) { - - initial_bone_poses.resize(skeleton_ik->get_parent_skeleton()->get_bone_count()); - for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { - initial_bone_poses.write[i] = skeleton_ik->get_parent_skeleton()->get_bone_pose(i); - } - skeleton_ik->start(); } else { skeleton_ik->stop(); - if (initial_bone_poses.size() != skeleton_ik->get_parent_skeleton()->get_bone_count()) - return; - for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { - skeleton_ik->get_parent_skeleton()->set_bone_pose(i, initial_bone_poses[i]); + skeleton_ik->get_parent_skeleton()->set_bone_global_pose_override(i, Transform(), 0); } } } diff --git a/editor/plugins/skeleton_ik_editor_plugin.h b/editor/plugins/skeleton_ik_editor_plugin.h index 06c07031f6..814eb8ff5b 100644 --- a/editor/plugins/skeleton_ik_editor_plugin.h +++ b/editor/plugins/skeleton_ik_editor_plugin.h @@ -44,7 +44,6 @@ class SkeletonIKEditorPlugin : public EditorPlugin { Button *play_btn; EditorNode *editor; - Vector<Transform> initial_bone_poses; void _play(); diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index f4c0ffa6eb..a7988279c0 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -168,6 +168,7 @@ void SoftBodyBullet::set_node_position(int p_node_index, const Vector3 &p_global void SoftBodyBullet::set_node_position(int p_node_index, const btVector3 &p_global_position) { if (bt_soft_body) { + bt_soft_body->m_nodes[p_node_index].m_q = bt_soft_body->m_nodes[p_node_index].m_x; bt_soft_body->m_nodes[p_node_index].m_x = p_global_position; } } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 752fc9e2cc..2847f3b414 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1721,8 +1721,7 @@ bool CSharpInstance::has_method(const StringName &p_method) const { Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - if (!script.is_valid()) - ERR_FAIL_V(Variant()); + ERR_FAIL_COND_V(!script.is_valid(), Variant()); GD_MONO_SCOPE_THREAD_ATTACH; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 0462ef1125..1d1a49945f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -318,9 +318,9 @@ namespace Godot return res; } - public int ToAbgr32() + public uint ToAbgr32() { - int c = (byte)Math.Round(a * 255); + uint c = (byte)Math.Round(a * 255); c <<= 8; c |= (byte)Math.Round(b * 255); c <<= 8; @@ -331,9 +331,9 @@ namespace Godot return c; } - public long ToAbgr64() + public ulong ToAbgr64() { - long c = (ushort)Math.Round(a * 65535); + ulong c = (ushort)Math.Round(a * 65535); c <<= 16; c |= (ushort)Math.Round(b * 65535); c <<= 16; @@ -344,9 +344,9 @@ namespace Godot return c; } - public int ToArgb32() + public uint ToArgb32() { - int c = (byte)Math.Round(a * 255); + uint c = (byte)Math.Round(a * 255); c <<= 8; c |= (byte)Math.Round(r * 255); c <<= 8; @@ -357,9 +357,9 @@ namespace Godot return c; } - public long ToArgb64() + public ulong ToArgb64() { - long c = (ushort)Math.Round(a * 65535); + ulong c = (ushort)Math.Round(a * 65535); c <<= 16; c |= (ushort)Math.Round(r * 65535); c <<= 16; @@ -370,9 +370,9 @@ namespace Godot return c; } - public int ToRgba32() + public uint ToRgba32() { - int c = (byte)Math.Round(r * 255); + uint c = (byte)Math.Round(r * 255); c <<= 8; c |= (byte)Math.Round(g * 255); c <<= 8; @@ -383,9 +383,9 @@ namespace Godot return c; } - public long ToRgba64() + public ulong ToRgba64() { - long c = (ushort)Math.Round(r * 65535); + ulong c = (ushort)Math.Round(r * 65535); c <<= 16; c |= (ushort)Math.Round(g * 65535); c <<= 16; @@ -419,7 +419,7 @@ namespace Godot this.a = a; } - public Color(int rgba) + public Color(uint rgba) { a = (rgba & 0xFF) / 255.0f; rgba >>= 8; @@ -430,7 +430,7 @@ namespace Godot r = (rgba & 0xFF) / 255.0f; } - public Color(long rgba) + public Color(ulong rgba) { a = (rgba & 0xFFFF) / 65535.0f; rgba >>= 16; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index b926037e5a..e096d37a6f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -474,7 +474,7 @@ namespace Godot int source = 0; int target = 0; - while (instance[source] != 0 && text[target] != 0) + while (source < len && target < text.Length) { bool match; @@ -491,7 +491,7 @@ namespace Godot if (match) { source++; - if (instance[source] == 0) + if (source >= len) return true; } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 44c5b5d6b4..e5d9bdc60c 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -507,9 +507,8 @@ void OS_Android::process_double_tap(Point2 p_pos) { ev.instance(); ev->set_position(p_pos); ev->set_global_position(p_pos); - ev->set_pressed(true); + ev->set_pressed(false); ev->set_doubleclick(true); - ev->set_button_index(1); input->parse_input_event(ev); } diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index caeae90238..a1a221b5bb 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1562,6 +1562,24 @@ void PhysicalBone::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse); } +void PhysicalBone::reset_physics_simulation_state() { + if (simulate_physics) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } +} + +void PhysicalBone::reset_to_rest_position() { + if (parent_skeleton) { + if (-1 == bone_id) { + set_global_transform(parent_skeleton->get_global_transform() * body_offset); + } else { + set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); + } + } +} + bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) { if (JointData::_set(p_name, p_value, j)) { return true; @@ -2167,7 +2185,7 @@ void PhysicalBone::_notification(int p_what) { parent_skeleton = find_skeleton_parent(get_parent()); update_bone_id(); reset_to_rest_position(); - _reset_physics_simulation_state(); + reset_physics_simulation_state(); if (!joint.is_valid() && joint_data) { _reload_joint(); } @@ -2238,8 +2256,6 @@ void PhysicalBone::_bind_methods() { ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset); ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset); - ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body); - ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics); ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); @@ -2508,26 +2524,13 @@ const Transform &PhysicalBone::get_joint_offset() const { return joint_offset; } -void PhysicalBone::set_static_body(bool p_static) { - - static_body = p_static; - - set_as_toplevel(!static_body); - - _reset_physics_simulation_state(); -} - -bool PhysicalBone::is_static_body() { - return static_body; -} - void PhysicalBone::set_simulate_physics(bool p_simulate) { if (simulate_physics == p_simulate) { return; } simulate_physics = p_simulate; - _reset_physics_simulation_state(); + reset_physics_simulation_state(); } bool PhysicalBone::get_simulate_physics() { @@ -2535,7 +2538,7 @@ bool PhysicalBone::get_simulate_physics() { } bool PhysicalBone::is_simulating_physics() { - return _internal_simulate_physics && !_internal_static_body; + return _internal_simulate_physics; } void PhysicalBone::set_bone_name(const String &p_name) { @@ -2618,8 +2621,6 @@ PhysicalBone::PhysicalBone() : #endif joint_data(NULL), parent_skeleton(NULL), - static_body(false), - _internal_static_body(false), simulate_physics(false), _internal_simulate_physics(false), bone_id(-1), @@ -2629,8 +2630,7 @@ PhysicalBone::PhysicalBone() : friction(1), gravity_scale(1) { - set_static_body(static_body); - _reset_physics_simulation_state(); + reset_physics_simulation_state(); } PhysicalBone::~PhysicalBone() { @@ -2657,8 +2657,7 @@ void PhysicalBone::update_bone_id() { parent_skeleton->bind_physical_bone_to_bone(bone_id, this); _fix_joint_offset(); - _internal_static_body = !static_body; // Force staticness reset - _reset_staticness_state(); + reset_physics_simulation_state(); } } @@ -2680,49 +2679,6 @@ void PhysicalBone::update_offset() { #endif } -void PhysicalBone::reset_to_rest_position() { - if (parent_skeleton) { - if (-1 == bone_id) { - set_global_transform(parent_skeleton->get_global_transform() * body_offset); - } else { - set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset); - } - } -} - -void PhysicalBone::_reset_physics_simulation_state() { - if (simulate_physics && !static_body) { - _start_physics_simulation(); - } else { - _stop_physics_simulation(); - } - - _reset_staticness_state(); -} - -void PhysicalBone::_reset_staticness_state() { - - if (parent_skeleton && -1 != bone_id) { - if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary - - if (_internal_static_body) { - return; - } - - parent_skeleton->bind_child_node_to_bone(bone_id, this); - _internal_static_body = true; - } else { - - if (!_internal_static_body) { - return; - } - - parent_skeleton->unbind_child_node_from_bone(bone_id, this); - _internal_static_body = false; - } - } -} - void PhysicalBone::_start_physics_simulation() { if (_internal_simulate_physics || !parent_skeleton) { return; @@ -2732,17 +2688,27 @@ void PhysicalBone::_start_physics_simulation() { PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); + set_as_toplevel(true); _internal_simulate_physics = true; } void PhysicalBone::_stop_physics_simulation() { - if (!_internal_simulate_physics || !parent_skeleton) { + if (!parent_skeleton) { return; } - PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); - PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); - PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); - _internal_simulate_physics = false; + if (parent_skeleton->get_animate_physical_bones()) { + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_KINEMATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + } else { + PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC); + PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); + } + if (_internal_simulate_physics) { + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); + set_as_toplevel(false); + _internal_simulate_physics = false; + } } diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 05bcbe22f0..6a1e803eaf 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -562,8 +562,6 @@ private: Skeleton *parent_skeleton; Transform body_offset; Transform body_offset_inverse; - bool static_body; - bool _internal_static_body; bool simulate_physics; bool _internal_simulate_physics; int bone_id; @@ -613,9 +611,6 @@ public: void set_body_offset(const Transform &p_offset); const Transform &get_body_offset() const; - void set_static_body(bool p_static); - bool is_static_body(); - void set_simulate_physics(bool p_simulate); bool get_simulate_physics(); bool is_simulating_physics(); @@ -641,16 +636,15 @@ public: void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse); + void reset_physics_simulation_state(); + void reset_to_rest_position(); + PhysicalBone(); ~PhysicalBone(); private: void update_bone_id(); void update_offset(); - void reset_to_rest_position(); - - void _reset_physics_simulation_state(); - void _reset_staticness_state(); void _start_physics_simulation(); void _stop_physics_simulation(); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 17e67c47d1..4089e0c23b 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -32,6 +32,7 @@ #include "core/message_queue.h" +#include "core/engine.h" #include "core/project_settings.h" #include "scene/3d/physics_body.h" #include "scene/resources/surface_tool.h" @@ -332,6 +333,27 @@ void Skeleton::_notification(int p_what) { dirty = false; } break; + +#ifndef _3D_DISABLED + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // This is active only if the skeleton animates the physical bones + // and the state of the bone is not active. + if (animate_physical_bones) { + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + if (bones[i].physical_bone->is_simulating_physics() == false) { + bones[i].physical_bone->reset_to_rest_position(); + } + } + } + } + } break; + case NOTIFICATION_READY: { + if (Engine::get_singleton()->is_editor_hint()) { + set_physics_process_internal(true); + } + } break; +#endif } } @@ -584,6 +606,27 @@ void Skeleton::localize_rests() { #ifndef _3D_DISABLED +void Skeleton::set_animate_physical_bones(bool p_animate) { + animate_physical_bones = p_animate; + + if (Engine::get_singleton()->is_editor_hint() == false) { + bool sim = false; + for (int i = 0; i < bones.size(); i += 1) { + if (bones[i].physical_bone) { + bones[i].physical_bone->reset_physics_simulation_state(); + if (bones[i].physical_bone->is_simulating_physics()) { + sim = true; + } + } + } + set_physics_process_internal(sim == false && p_animate); + } +} + +bool Skeleton::get_animate_physical_bones() const { + return animate_physical_bones; +} + void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) { ERR_FAIL_INDEX(p_bone, bones.size()); ERR_FAIL_COND(bones[p_bone].physical_bone); @@ -653,12 +696,14 @@ void _pb_stop_simulation(Node *p_node) { PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); if (pb) { pb->set_simulate_physics(false); - pb->set_static_body(false); } } void Skeleton::physical_bones_stop_simulation() { _pb_stop_simulation(this); + if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) { + set_physics_process_internal(true); + } } void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) { @@ -669,24 +714,17 @@ void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node); if (pb) { - bool sim = false; for (int i = p_sim_bones.size() - 1; 0 <= i; --i) { if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { - sim = true; + pb->set_simulate_physics(true); break; } } - - pb->set_simulate_physics(true); - if (sim) { - pb->set_static_body(false); - } else { - pb->set_static_body(true); - } } } void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) { + set_physics_process_internal(false); Vector<int> sim_bones; if (p_bones.size() <= 0) { @@ -836,11 +874,15 @@ void Skeleton::_bind_methods() { #ifndef _3D_DISABLED + ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton::set_animate_physical_bones); + ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton::get_animate_physical_bones); + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception); ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones"); #endif // _3D_DISABLED BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); @@ -848,6 +890,7 @@ void Skeleton::_bind_methods() { Skeleton::Skeleton() { + animate_physical_bones = true; dirty = false; process_order_dirty = true; } diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 056f70e22b..9599510850 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -115,6 +115,7 @@ private: } }; + bool animate_physical_bones; Vector<Bone> bones; Vector<int> process_order; bool process_order_dirty; @@ -199,6 +200,9 @@ public: #ifndef _3D_DISABLED // Physical bone API + void set_animate_physical_bones(bool p_animate); + bool get_animate_physical_bones() const; + void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone); void unbind_physical_bone_from_bone(int p_bone); diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index ef13985bf4..435bef7247 100644 --- a/scene/3d/soft_body.cpp +++ b/scene/3d/soft_body.cpp @@ -247,7 +247,7 @@ bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Var } void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) { - update_physics_server(); + prepare_physics_server(); _reset_points_offsets(); #ifdef TOOLS_ENABLED if (p_changed == this) { @@ -267,7 +267,7 @@ void SoftBody::_notification(int p_what) { RID space = get_world()->get_space(); PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space); - update_physics_server(); + prepare_physics_server(); } break; case NOTIFICATION_READY: { if (!parent_collision_ignore.is_empty()) @@ -290,21 +290,6 @@ void SoftBody::_notification(int p_what) { set_notify_transform(true); } break; - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - - if (!simulation_started) - return; - - _update_cache_pin_points_datas(); - // Submit bone attachment - const int pinned_points_indices_size = pinned_points.size(); - PoolVector<PinnedPoint>::Read r = pinned_points.read(); - for (int i = 0; i < pinned_points_indices_size; ++i) { - if (r[i].spatial_attachment) { - PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); - } - } - } break; case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); @@ -421,6 +406,21 @@ String SoftBody::get_configuration_warning() const { return warning; } +void SoftBody::_update_physics_server() { + if (!simulation_started) + return; + + _update_cache_pin_points_datas(); + // Submit bone attachment + const int pinned_points_indices_size = pinned_points.size(); + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + for (int i = 0; i < pinned_points_indices_size; ++i) { + if (r[i].spatial_attachment) { + PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); + } + } +} + void SoftBody::_draw_soft_mesh() { if (get_mesh().is_null()) return; @@ -435,6 +435,8 @@ void SoftBody::_draw_soft_mesh() { call_deferred("set_transform", Transform()); } + _update_physics_server(); + visual_server_handler.open(); PhysicsServer::get_singleton()->soft_body_update_visual_server(physics_rid, &visual_server_handler); visual_server_handler.close(); @@ -442,7 +444,7 @@ void SoftBody::_draw_soft_mesh() { visual_server_handler.commit_changes(); } -void SoftBody::update_physics_server() { +void SoftBody::prepare_physics_server() { if (Engine::get_singleton()->is_editor_hint()) { @@ -706,8 +708,6 @@ SoftBody::SoftBody() : ray_pickable(true) { PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id()); - //set_notify_transform(true); - set_physics_process_internal(true); } SoftBody::~SoftBody() { diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h index 629c2e42a5..800db12594 100644 --- a/scene/3d/soft_body.h +++ b/scene/3d/soft_body.h @@ -116,10 +116,11 @@ protected: virtual String get_configuration_warning() const; protected: + void _update_physics_server(); void _draw_soft_mesh(); public: - void update_physics_server(); + void prepare_physics_server(); void become_mesh_owner(); void set_collision_mask(uint32_t p_mask); diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 46028a9ce2..518c243dd0 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -329,17 +329,6 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove } } -void FabrikInverseKinematic::reset(Task *p_task) { - ChainItem *ci(&p_task->chain.chain_root); - while (ci) { - p_task->skeleton->set_bone_global_pose_override(ci->bone, Transform(), 0); - if (!ci->children.empty()) - ci = &ci->children.write[0]; - else - ci = NULL; - } -} - void SkeletonIK::_validate_property(PropertyInfo &property) const { if (property.name == "root_bone" || property.name == "tip_bone") { @@ -542,8 +531,6 @@ void SkeletonIK::start(bool p_one_time) { void SkeletonIK::stop() { set_process_internal(false); - if (task) - FabrikInverseKinematic::reset(task); } Transform SkeletonIK::_get_target_transform() { diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h index 8fc8a58b99..9ae010dc4e 100644 --- a/scene/animation/skeleton_ik.h +++ b/scene/animation/skeleton_ik.h @@ -139,7 +139,6 @@ public: static void set_goal(Task *p_task, const Transform &p_goal); static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta); static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position); - static void reset(Task *p_task); }; class SkeletonIK : public Node { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 7afc3b0d00..2504989d2c 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -184,6 +184,12 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case KEY_H: { remap_key = KEY_BACKSPACE; } break; + case KEY_A: { + remap_key = KEY_HOME; + } break; + case KEY_E: { + remap_key = KEY_END; + } break; } if (remap_key != KEY_UNKNOWN) { @@ -240,15 +246,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { deselect(); text = text.substr(cursor_pos, text.length() - cursor_pos); - - Ref<Font> font = get_font("font"); - - cached_width = 0; - if (font != NULL) { - for (int i = 0; i < text.length(); i++) - cached_width += font->get_char_size(text[i]).width; - } - + update_cached_width(); set_cursor_position(0); _text_changed(); } @@ -1358,18 +1356,10 @@ void LineEdit::set_window_pos(int p_pos) { void LineEdit::append_at_cursor(String p_text) { if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) { - - Ref<Font> font = get_font("font"); - if (font != NULL) { - for (int i = 0; i < p_text.length(); i++) - cached_width += font->get_char_size(p_text[i]).width; - } else { - cached_width = 0; - } - String pre = text.substr(0, cursor_pos); String post = text.substr(cursor_pos, text.length() - cursor_pos); text = pre + p_text + post; + update_cached_width(); set_cursor_position(cursor_pos + p_text.length()); } else { emit_signal("text_change_rejected"); @@ -1499,6 +1489,7 @@ bool LineEdit::is_editable() const { void LineEdit::set_secret(bool p_secret) { pass = p_secret; + update_cached_width(); update(); } @@ -1514,6 +1505,7 @@ void LineEdit::set_secret_character(const String &p_string) { ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)."); secret_character = p_string; + update_cached_width(); update(); } @@ -1685,6 +1677,17 @@ void LineEdit::_emit_text_change() { text_changed_dirty = false; } +void LineEdit::update_cached_width() { + Ref<Font> font = get_font("font"); + cached_width = 0; + if (font != NULL) { + String text = get_text(); + for (int i = 0; i < text.length(); i++) { + cached_width += font->get_char_size(pass ? secret_character[0] : text[i]).width; + } + } +} + void LineEdit::update_placeholder_width() { if ((max_length <= 0) || (placeholder_translated.length() <= max_length)) { Ref<Font> font = get_font("font"); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index cf597d11b6..037238d682 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -132,6 +132,7 @@ private: void _emit_text_change(); bool expand_to_text_length; + void update_cached_width(); void update_placeholder_width(); bool caret_blink_enabled; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index af5d0e2f45..b19e1d8362 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -204,6 +204,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int line_ascent = cfont->get_ascent(); int line_descent = cfont->get_descent(); + int backtrack = 0; // for dynamic hidden content. + int nonblank_line_count = 0; //number of nonblank lines as counted during PROCESS_DRAW Variant meta; @@ -214,6 +216,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & { \ if (p_mode != PROCESS_CACHE) { \ line++; \ + backtrack = 0; \ if (!line_is_blank) { \ nonblank_line_count++; \ } \ @@ -263,7 +266,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & l.maximum_width = MAX(l.maximum_width, MIN(p_width, wofs + m_width)); \ l.minimum_width = MAX(l.minimum_width, m_width); \ } \ - if (wofs + m_width > p_width) { \ + if (wofs - backtrack + m_width > p_width) { \ line_wrapped = true; \ if (p_mode == PROCESS_CACHE) { \ if (spaces > 0) \ @@ -390,6 +393,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & int fw = 0; lh = 0; + if (p_mode != PROCESS_CACHE) { lh = line < l.height_caches.size() ? l.height_caches[line] : 1; line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; @@ -432,13 +436,12 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & { - int ofs = 0; + int ofs = 0 - backtrack; for (int i = 0; i < end; i++) { int pofs = wofs + ofs; if (p_mode == PROCESS_POINTER && r_click_char && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) { - //int o = (wofs+w)-p_click_pos.x; int cw = font->get_char_size(c[i], c[i + 1]).x; @@ -481,7 +484,10 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & bool visible = visible_characters < 0 || ((p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent)) && faded_visibility > 0.0f); + const bool previously_visible = visible; + for (int j = 0; j < fx_stack.size(); j++) { + ItemFX *item_fx = fx_stack[j]; if (item_fx->type == ITEM_CUSTOMFX && custom_fx_ok) { @@ -575,6 +581,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & } else { cw = drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], fx_color); } + } else if (previously_visible) { + backtrack += font->get_char_size(fx_char, c[i + 1]).x; } p_char_count++; @@ -648,6 +656,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & case ITEM_NEWLINE: { lh = 0; + if (p_mode != PROCESS_CACHE) { lh = line < l.height_caches.size() ? l.height_caches[line] : 1; line_is_blank = true; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 964f376dbd..790e1d5f4f 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1121,7 +1121,7 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co } rect.position.y += Math::floor((rect.size.y - font->get_height()) / 2.0) + font->get_ascent(); - font->draw(ci, rect.position, text, p_color, rect.size.x); + font->draw(ci, rect.position, text, p_color, MAX(0, rect.size.width)); } int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item) { @@ -3630,6 +3630,17 @@ TreeItem *Tree::search_item_text(const String &p_find, int *r_col, bool p_select return _search_item_text(from->get_next_visible(true), p_find, r_col, p_selectable); } +TreeItem *Tree::get_item_with_text(const String &p_find) const { + for (TreeItem *current = root; current; current = current->get_next_visible()) { + for (int i = 0; i < columns.size(); i++) { + if (current->get_text(i) == p_find) { + return current; + } + } + } + return NULL; +} + void Tree::_do_incr_search(const String &p_add) { uint64_t time = OS::get_singleton()->get_ticks_usec() / 1000; // convert to msec diff --git a/scene/gui/tree.h b/scene/gui/tree.h index d87de6e773..f3c88eb5ac 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -577,7 +577,10 @@ public: Rect2 get_item_rect(TreeItem *p_item, int p_column = -1) const; bool edit_selected(); + // First item that starts with the text, from the current focused item down and wraps around. TreeItem *search_item_text(const String &p_find, int *r_col = NULL, bool p_selectable = false); + // First item that matches the whole text, from the first item down. + TreeItem *get_item_with_text(const String &p_find) const; Point2 get_scroll() const; void scroll_to_item(TreeItem *p_item); diff --git a/scene/resources/line_shape_2d.cpp b/scene/resources/line_shape_2d.cpp index 7f39467403..84da8125ea 100644 --- a/scene/resources/line_shape_2d.cpp +++ b/scene/resources/line_shape_2d.cpp @@ -115,7 +115,7 @@ void LineShape2D::_bind_methods() { LineShape2D::LineShape2D() : Shape2D(Physics2DServer::get_singleton()->line_shape_create()) { - normal = Vector2(0, -1); + normal = Vector2(0, 1); d = 0; _update_shape(); } diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 0599920303..8f68cc5286 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -518,7 +518,6 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_BASE); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_VERTEX); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_NORMAL); BIND_ENUM_CONSTANT(ARRAY_COMPRESS_TANGENT); diff --git a/thirdparty/README.md b/thirdparty/README.md index 9b6f670972..7c3378dec3 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -281,6 +281,7 @@ Files extracted from upstream source: - All `*.c` and `*.h` files from `miniupnpc` to `thirdparty/miniupnpc/miniupnpc` - Remove `test*`, `minihttptestserver.c` and `wingenminiupnpcstrings.c` +The patch `windows_fix.diff` is applied to `minissdpc.c` to fix an upstream issue. The only modified file is miniupnpcstrings.h, which was created for Godot (it is usually autogenerated by cmake). diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c index 29f8110155..ea9af02e1f 100644 --- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c +++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c @@ -683,11 +683,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], #endif } else { struct in_addr mc_if; -#if defined(_WIN32) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA) - InetPtonA(AF_INET, multicastif, &mc_if); -#else mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ -#endif if(mc_if.s_addr != INADDR_NONE) { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; diff --git a/thirdparty/miniupnpc/windows_fix.diff b/thirdparty/miniupnpc/windows_fix.diff new file mode 100644 index 0000000000..460b596888 --- /dev/null +++ b/thirdparty/miniupnpc/windows_fix.diff @@ -0,0 +1,16 @@ +diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c +index 29f8110155..ea9af02e1f 100644 +--- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c ++++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c +@@ -683,11 +683,7 @@ ssdpDiscoverDevices(const char * const deviceTypes[], + #endif + } else { + struct in_addr mc_if; +-#if defined(_WIN32) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA) +- InetPtonA(AF_INET, multicastif, &mc_if); +-#else + mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ +-#endif + if(mc_if.s_addr != INADDR_NONE) + { + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; |