From 8c7268664da7ef98f802ec90fa2ba17b4d695847 Mon Sep 17 00:00:00 2001 From: reduz Date: Thu, 3 Feb 2022 22:16:58 +0100 Subject: [PATCH] Fix integer vector mul/div operators and bindings. * Vector2i and Vector3i mul/div by a float results in Vector2 and Vector3 respectively. * Create specializations to allow proper bindings. This fixes #44408 and supersedes #44441 and keeps the same rule of int float returnig float, like with scalars. --- core/math/audio_frame.h | 12 ++++ core/math/vector2.h | 35 +++++----- core/math/vector2i.h | 10 +-- core/math/vector3.h | 3 + core/math/vector3i.h | 10 +-- core/variant/variant_op.cpp | 132 ++++++++++++++++++++++++++++++++++-- doc/classes/Vector2i.xml | 10 +-- doc/classes/Vector3i.xml | 10 +-- doc/classes/float.xml | 12 ++-- 9 files changed, 188 insertions(+), 46 deletions(-) diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h index 94fc3de2b13..8b244e9fe4b 100644 --- a/core/math/audio_frame.h +++ b/core/math/audio_frame.h @@ -140,4 +140,16 @@ struct AudioFrame { _ALWAYS_INLINE_ AudioFrame() {} }; +_ALWAYS_INLINE_ AudioFrame operator*(float p_scalar, const AudioFrame &p_frame) { + return AudioFrame(p_frame.l * p_scalar, p_frame.r * p_scalar); +} + +_ALWAYS_INLINE_ AudioFrame operator*(int32_t p_scalar, const AudioFrame &p_frame) { + return AudioFrame(p_frame.l * p_scalar, p_frame.r * p_scalar); +} + +_ALWAYS_INLINE_ AudioFrame operator*(int64_t p_scalar, const AudioFrame &p_frame) { + return AudioFrame(p_frame.l * p_scalar, p_frame.r * p_scalar); +} + #endif // AUDIO_FRAME_H diff --git a/core/math/vector2.h b/core/math/vector2.h index 9edaaebf893..123e3dc7b64 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -180,22 +180,6 @@ _FORCE_INLINE_ Vector2 Vector2::plane_project(const real_t p_d, const Vector2 &p return p_vec - *this * (dot(p_vec) - p_d); } -_FORCE_INLINE_ Vector2 operator*(const float p_scalar, const Vector2 &p_vec) { - return p_vec * p_scalar; -} - -_FORCE_INLINE_ Vector2 operator*(const double p_scalar, const Vector2 &p_vec) { - return p_vec * p_scalar; -} - -_FORCE_INLINE_ Vector2 operator*(const int32_t p_scalar, const Vector2 &p_vec) { - return p_vec * p_scalar; -} - -_FORCE_INLINE_ Vector2 operator*(const int64_t p_scalar, const Vector2 &p_vec) { - return p_vec * p_scalar; -} - _FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const { return Vector2(x + p_v.x, y + p_v.y); } @@ -280,6 +264,25 @@ Vector2 Vector2::direction_to(const Vector2 &p_to) const { return ret; } +// Multiplication operators required to workaround issues with LLVM using implicit conversion +// to Vector2i instead for integers where it should not. + +_FORCE_INLINE_ Vector2 operator*(const float p_scalar, const Vector2 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector2 operator*(const double p_scalar, const Vector2 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector2 operator*(const int32_t p_scalar, const Vector2 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector2 operator*(const int64_t p_scalar, const Vector2 &p_vec) { + return p_vec * p_scalar; +} + typedef Vector2 Size2; typedef Vector2 Point2; diff --git a/core/math/vector2i.h b/core/math/vector2i.h index 446e05f5dda..707c8c94900 100644 --- a/core/math/vector2i.h +++ b/core/math/vector2i.h @@ -119,19 +119,21 @@ struct _NO_DISCARD_ Vector2i { } }; -_FORCE_INLINE_ Vector2i operator*(const int32_t &p_scalar, const Vector2i &p_vector) { +// Multiplication operators required to workaround issues with LLVM using implicit conversion. + +_FORCE_INLINE_ Vector2i operator*(const int32_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(const int64_t &p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(const int64_t p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(const float &p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(const float p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } -_FORCE_INLINE_ Vector2i operator*(const double &p_scalar, const Vector2i &p_vector) { +_FORCE_INLINE_ Vector2i operator*(const double p_scalar, const Vector2i &p_vector) { return p_vector * p_scalar; } diff --git a/core/math/vector3.h b/core/math/vector3.h index 79ba5c4f15d..345329f7f35 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -343,6 +343,9 @@ Vector3 &Vector3::operator*=(const real_t p_scalar) { return *this; } +// Multiplication operators required to workaround issues with LLVM using implicit conversion +// to Vector2i instead for integers where it should not. + _FORCE_INLINE_ Vector3 operator*(const float p_scalar, const Vector3 &p_vec) { return p_vec * p_scalar; } diff --git a/core/math/vector3i.h b/core/math/vector3i.h index 1564ee91730..d166de80aa1 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -194,6 +194,12 @@ Vector3i &Vector3i::operator*=(const int32_t p_scalar) { return *this; } +Vector3i Vector3i::operator*(const int32_t p_scalar) const { + return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar); +} + +// Multiplication operators required to workaround issues with LLVM using implicit conversion. + _FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar, const Vector3i &p_vector) { return p_vector * p_scalar; } @@ -210,10 +216,6 @@ _FORCE_INLINE_ Vector3i operator*(const double p_scalar, const Vector3i &p_vecto return p_vector * p_scalar; } -Vector3i Vector3i::operator*(const int32_t p_scalar) const { - return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar); -} - Vector3i &Vector3i::operator/=(const int32_t p_scalar) { x /= p_scalar; y /= p_scalar; diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index e0ffcc9d11b..f35774204bc 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -45,6 +45,126 @@ void register_op(Variant::Operator p_op, Variant::Type p_type_a, Variant::Type p ptr_operator_evaluator_table[p_op][p_type_a][p_type_b] = T::ptr_evaluate; } +// Special cases that can't be done otherwise because of the forced casting to float. + +template <> +class OperatorEvaluatorMul { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector2i &a = *VariantGetInternalPtr::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr::get_ptr(&p_right); + *r_ret = Vector2(a.x, a.y) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr::get_ptr(r_ret) = Vector2(VariantGetInternalPtr::get_ptr(left)->x, VariantGetInternalPtr::get_ptr(left)->y) * *VariantGetInternalPtr::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(Vector2(PtrToArg::convert(left).x, PtrToArg::convert(left).y) * PtrToArg::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorMul { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector2i &a = *VariantGetInternalPtr::get_ptr(&p_right); + const double &b = *VariantGetInternalPtr::get_ptr(&p_left); + *r_ret = Vector2(a.x, a.y) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr::get_ptr(r_ret) = Vector2(VariantGetInternalPtr::get_ptr(right)->x, VariantGetInternalPtr::get_ptr(right)->y) * *VariantGetInternalPtr::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(Vector2(PtrToArg::convert(right).x, PtrToArg::convert(right).y) * PtrToArg::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorDivNZ { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector2i &a = *VariantGetInternalPtr::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr::get_ptr(&p_right); + if (unlikely(b == 0)) { + r_valid = false; + *r_ret = "Division by zero error"; + return; + } + *r_ret = Vector2(a.x, a.y) / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr::get_ptr(r_ret) = Vector2(VariantGetInternalPtr::get_ptr(left)->x, VariantGetInternalPtr::get_ptr(left)->y) / *VariantGetInternalPtr::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(Vector2(PtrToArg::convert(left).x, PtrToArg::convert(left).y) / PtrToArg::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorMul { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector3i &a = *VariantGetInternalPtr::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr::get_ptr(&p_right); + *r_ret = Vector3(a.x, a.y, a.z) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr::get_ptr(r_ret) = Vector3(VariantGetInternalPtr::get_ptr(left)->x, VariantGetInternalPtr::get_ptr(left)->y, VariantGetInternalPtr::get_ptr(left)->z) * *VariantGetInternalPtr::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(Vector3(PtrToArg::convert(left).x, PtrToArg::convert(left).y, PtrToArg::convert(left).z) * PtrToArg::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorMul { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector3i &a = *VariantGetInternalPtr::get_ptr(&p_right); + const double &b = *VariantGetInternalPtr::get_ptr(&p_left); + *r_ret = Vector3(a.x, a.y, a.z) * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr::get_ptr(r_ret) = Vector3(VariantGetInternalPtr::get_ptr(right)->x, VariantGetInternalPtr::get_ptr(right)->y, VariantGetInternalPtr::get_ptr(right)->z) * *VariantGetInternalPtr::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(Vector3(PtrToArg::convert(right).x, PtrToArg::convert(right).y, PtrToArg::convert(right).z) * PtrToArg::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + +template <> +class OperatorEvaluatorDivNZ { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector3i &a = *VariantGetInternalPtr::get_ptr(&p_left); + const double &b = *VariantGetInternalPtr::get_ptr(&p_right); + if (unlikely(b == 0)) { + r_valid = false; + *r_ret = "Division by zero error"; + return; + } + *r_ret = Vector3(a.x, a.y, a.z) / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr::get_ptr(r_ret) = Vector3(VariantGetInternalPtr::get_ptr(left)->x, VariantGetInternalPtr::get_ptr(left)->y, VariantGetInternalPtr::get_ptr(left)->z) / *VariantGetInternalPtr::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg::encode(Vector3(PtrToArg::convert(left).x, PtrToArg::convert(left).y, PtrToArg::convert(left).z) / PtrToArg::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo::VARIANT_TYPE; } +}; + void Variant::_register_variant_operators() { memset(operator_return_type_table, 0, sizeof(operator_return_type_table)); memset(operator_evaluator_table, 0, sizeof(operator_evaluator_table)); @@ -94,9 +214,9 @@ void Variant::_register_variant_operators() { register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::FLOAT); register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::INT); register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2); - register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2I); + register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR2I); register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3); - register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3I); + register_op>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::VECTOR3I); register_op>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::VECTOR2); register_op>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::INT); @@ -104,7 +224,7 @@ void Variant::_register_variant_operators() { register_op>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::VECTOR2I); register_op>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::INT); - register_op>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::FLOAT); + register_op>(Variant::OP_MULTIPLY, Variant::VECTOR2I, Variant::FLOAT); register_op>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::VECTOR3); register_op>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::INT); @@ -112,7 +232,7 @@ void Variant::_register_variant_operators() { register_op>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::VECTOR3I); register_op>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT); - register_op>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); + register_op>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); register_op>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); register_op>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); @@ -172,7 +292,7 @@ void Variant::_register_variant_operators() { register_op>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT); register_op>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::VECTOR2I); - register_op>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT); + register_op>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT); register_op>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT); register_op>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2); @@ -184,7 +304,7 @@ void Variant::_register_variant_operators() { register_op>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT); register_op>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::VECTOR3I); - register_op>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); + register_op>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); register_op>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT); register_op>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT); diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml index 721c73d6039..d7e010cc535 100644 --- a/doc/classes/Vector2i.xml +++ b/doc/classes/Vector2i.xml @@ -174,12 +174,12 @@ - + - Multiplies each component of the [Vector2i] by the given [float] truncated to an integer. + Multiplies each component of the [Vector2i] by the given [float]. Returns a [Vector2]. [codeblock] - print(Vector2i(10, 20) * 0.9) # Prints "(0, 0)" + print(Vector2i(10, 15) * 0.9) # Prints "(9, 13.5)" [/codeblock] @@ -221,10 +221,10 @@ - + - Divides each component of the [Vector2i] by the given [float] truncated to an integer. + Divides each component of the [Vector2i] by the given [float]. Returns a [Vector2]. [codeblock] print(Vector2i(10, 20) / 2.9) # Prints "(5, 10)" [/codeblock] diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml index da729e1ec2c..8a901fdf371 100644 --- a/doc/classes/Vector3i.xml +++ b/doc/classes/Vector3i.xml @@ -180,12 +180,12 @@ - + - Multiplies each component of the [Vector3i] by the given [float] truncated to an integer. + Multiplies each component of the [Vector3i] by the given [float]. Returns a [Vector3]. [codeblock] - print(Vector3i(10, 20, 30) * 0.9) # Prints "(0, 0, 0)" + print(Vector3i(10, 15, 20) * 0.9) # Prints "(9, 13.5, 18)" [/codeblock] @@ -227,10 +227,10 @@ - + - Divides each component of the [Vector3i] by the given [float] truncated to an integer. + Divides each component of the [Vector3i] by the given [float]. Returns a [Vector3]. [codeblock] print(Vector3i(10, 20, 30) / 2.9) # Prints "(5, 10, 15)" [/codeblock] diff --git a/doc/classes/float.xml b/doc/classes/float.xml index 9effe9d5bf7..2dae7275b58 100644 --- a/doc/classes/float.xml +++ b/doc/classes/float.xml @@ -89,12 +89,12 @@ - + - Multiplies each component of the [Vector2i] by the given [float] truncated to an integer. + Multiplies each component of the [Vector2i] by the given [float]. Returns a [Vector2]. [codeblock] - print(0.9 * Vector2i(10, 20)) # Prints "(0, 0)" + print(0.9 * Vector2i(10, 15)) # Prints "(9, 13.5)" [/codeblock] @@ -106,12 +106,12 @@ - + - Multiplies each component of the [Vector3i] by the given [float] truncated to an integer. + Multiplies each component of the [Vector3i] by the given [float]. Returns a [Vector3]. [codeblock] - print(0.9 * Vector3i(10, 20, 30)) # Prints "(0, 0, 0)" + print(0.9 * Vector3i(10, 15, 20)) # Prints "(9, 13.5, 18)" [/codeblock]