summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite_2d.cpp54
-rw-r--r--scene/2d/animated_sprite_2d.h3
-rw-r--r--scene/3d/sprite_3d.cpp52
-rw-r--r--scene/3d/sprite_3d.h3
-rw-r--r--scene/animation/animation_blend_tree.cpp3
-rw-r--r--scene/animation/animation_player.cpp10
-rw-r--r--scene/animation/animation_tree.cpp58
-rw-r--r--scene/animation/animation_tree.h2
-rw-r--r--scene/animation/tween.cpp271
-rw-r--r--scene/animation/tween.h1
-rw-r--r--scene/main/viewport.cpp47
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/main/window.cpp18
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/resources/animation.cpp464
-rw-r--r--scene/resources/animation.h6
-rw-r--r--scene/resources/material.cpp30
-rw-r--r--scene/resources/material.h11
18 files changed, 658 insertions, 379 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 7fe464d2f4..afa4633848 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -63,9 +63,13 @@ Rect2 AnimatedSprite2D::_edit_get_rect() const {
}
bool AnimatedSprite2D::_edit_use_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return false;
}
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return false;
+ }
+
Ref<Texture2D> t;
if (animation) {
t = frames->get_frame(animation, frame);
@@ -79,7 +83,10 @@ Rect2 AnimatedSprite2D::get_anchorable_rect() const {
}
Rect2 AnimatedSprite2D::_get_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2();
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2();
}
@@ -161,29 +168,22 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
void AnimatedSprite2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- if (!frames->has_animation(animation)) {
- return;
- }
- if (frame < 0) {
- return;
+
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
}
+ int last_frame = frames->get_frame_count(animation) - 1;
double remaining = get_process_delta_time();
-
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; // Do nothing.
- }
-
if (timeout <= 0) {
timeout = _get_frame_duration();
- int last_frame = frames->get_frame_count(animation) - 1;
- if (!backwards) {
+ if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
if (frames->get_animation_loop(animation)) {
@@ -229,13 +229,7 @@ void AnimatedSprite2D::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- if (frames.is_null()) {
- return;
- }
- if (frame < 0) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
@@ -327,9 +321,14 @@ int AnimatedSprite2D::get_frame() const {
}
void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
+ if (speed_scale == p_speed_scale) {
+ return;
+ }
+
double elapsed = _get_frame_duration() - timeout;
- speed_scale = MAX(p_speed_scale, 0.0f);
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
// We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
@@ -398,12 +397,13 @@ bool AnimatedSprite2D::is_playing() const {
return playing;
}
-void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite2D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -418,7 +418,7 @@ void AnimatedSprite2D::stop() {
double AnimatedSprite2D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
if (speed > 0) {
return 1.0 / speed;
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 0a19e250d8..be1cc5353e 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -39,6 +39,7 @@ class AnimatedSprite2D : public Node2D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool playing_backwards = false;
bool backwards = false;
StringName animation = "default";
int frame = 0;
@@ -81,7 +82,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void play(const StringName &p_animation = StringName(), bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 7a89bf81bb..380172f396 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -447,7 +447,7 @@ void Sprite3D::_draw() {
if (get_base() != get_mesh()) {
set_base(get_mesh());
}
- if (!texture.is_valid()) {
+ if (texture.is_null()) {
set_base(RID());
return;
}
@@ -807,15 +807,7 @@ void AnimatedSprite3D::_draw() {
set_base(get_mesh());
}
- if (frames.is_null()) {
- return;
- }
-
- if (frame < 0) {
- return;
- }
-
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
@@ -1050,29 +1042,22 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
void AnimatedSprite3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- if (frame < 0) {
- return;
+
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
}
+ int last_frame = frames->get_frame_count(animation) - 1;
double remaining = get_process_delta_time();
-
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; // Do nothing.
- }
-
if (timeout <= 0) {
timeout = _get_frame_duration();
- int last_frame = frames->get_frame_count(animation) - 1;
- if (!backwards) {
+ if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
if (frames->get_animation_loop(animation)) {
@@ -1177,9 +1162,14 @@ int AnimatedSprite3D::get_frame() const {
}
void AnimatedSprite3D::set_speed_scale(double p_speed_scale) {
+ if (speed_scale == p_speed_scale) {
+ return;
+ }
+
double elapsed = _get_frame_duration() - timeout;
- speed_scale = MAX(p_speed_scale, 0.0f);
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
// We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
@@ -1191,7 +1181,10 @@ double AnimatedSprite3D::get_speed_scale() const {
}
Rect2 AnimatedSprite3D::get_item_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2(0, 0, 1, 1);
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2(0, 0, 1, 1);
}
@@ -1236,12 +1229,13 @@ bool AnimatedSprite3D::is_playing() const {
return playing;
}
-void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite3D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -1256,7 +1250,7 @@ void AnimatedSprite3D::stop() {
double AnimatedSprite3D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
if (speed > 0) {
return 1.0 / speed;
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index e6a546a76d..f6ad1bbdb8 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -209,6 +209,7 @@ class AnimatedSprite3D : public SpriteBase3D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool playing_backwards = false;
bool backwards = false;
StringName animation = "default";
int frame = 0;
@@ -237,7 +238,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void play(const StringName &p_animation = StringName(), bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 99f17a1eef..1efbaacb3b 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1175,6 +1175,7 @@ void AnimationNodeBlendTree::_tree_changed() {
void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
ERR_FAIL_COND(!nodes.has(p_node));
nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
+ emit_signal(SNAME("node_changed"), p_node);
}
void AnimationNodeBlendTree::_bind_methods() {
@@ -1200,6 +1201,8 @@ void AnimationNodeBlendTree::_bind_methods() {
BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT);
BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE);
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
+
+ ADD_SIGNAL(MethodInfo("node_changed", PropertyInfo(Variant::STRING_NAME, "node_name")));
}
void AnimationNodeBlendTree::_initialize_node_tree() {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 096f4edee2..ce9406883d 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -650,15 +650,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
double c = Math::ease(p_time / first_key_time, transition);
Variant first_value = a->track_get_key_value(i, first_key);
first_value = _post_process_key_value(a, i, first_value, nc->node);
- Variant interp_value;
- Variant::interpolate(pa->capture, first_value, c, interp_value);
+ Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c);
if (pa->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
cache_update_prop[cache_update_prop_size++] = pa;
pa->value_accum = interp_value;
pa->accum_pass = accum_pass;
} else {
- Variant::interpolate(pa->value_accum, interp_value, p_interp, pa->value_accum);
+ pa->value_accum = Animation::interpolate_variant(pa->value_accum, interp_value, p_interp);
}
continue; //handled
@@ -679,7 +678,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
pa->value_accum = value;
pa->accum_pass = accum_pass;
} else {
- Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum);
+ pa->value_accum = Animation::interpolate_variant(pa->value_accum, value, p_interp);
}
} else if (p_is_current && p_delta != 0) {
@@ -1270,6 +1269,8 @@ void AnimationPlayer::_animation_set_cache_update() {
// If something was modified or removed, caches need to be cleared
clear_caches();
}
+
+ emit_signal(SNAME("animation_list_changed"));
}
void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) {
@@ -2150,6 +2151,7 @@ void AnimationPlayer::_bind_methods() {
ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
+ ADD_SIGNAL(MethodInfo("animation_list_changed"));
ADD_SIGNAL(MethodInfo("caches_cleared"));
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index d06324f0aa..776706d7f3 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -847,6 +847,11 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
return true;
}
+void AnimationTree::_animation_player_changed() {
+ emit_signal(SNAME("animation_player_changed"));
+ _clear_caches();
+}
+
void AnimationTree::_clear_caches() {
for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
memdelete(K.value);
@@ -1378,8 +1383,13 @@ void AnimationTree::_process_graph(double p_delta) {
}
t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
} else {
- Variant::sub(value, t->init_value, value);
- Variant::blend(t->value, value, blend, t->value);
+ if (t->init_value.get_type() == Variant::BOOL) {
+ value = Animation::subtract_variant(value.operator real_t(), t->init_value.operator real_t());
+ t->value = Animation::blend_variant(t->value.operator real_t(), value.operator real_t(), blend);
+ } else {
+ value = Animation::subtract_variant(value, t->init_value);
+ t->value = Animation::blend_variant(t->value, value, blend);
+ }
}
} else {
if (blend < CMP_EPSILON) {
@@ -1698,7 +1708,11 @@ void AnimationTree::_process_graph(double p_delta) {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
- t->object->set_indexed(t->subpath, t->value);
+ if (t->init_value.get_type() == Variant::BOOL) {
+ t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5);
+ } else {
+ t->object->set_indexed(t->subpath, t->value);
+ }
} break;
case Animation::TYPE_BEZIER: {
@@ -1738,6 +1752,7 @@ void AnimationTree::advance(real_t p_time) {
void AnimationTree::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ _setup_animation_player();
if (last_animation_player.is_valid()) {
Object *player = ObjectDB::get_instance(last_animation_player);
if (player) {
@@ -1770,8 +1785,43 @@ void AnimationTree::_notification(int p_what) {
}
}
+void AnimationTree::_setup_animation_player() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ AnimationPlayer *new_player = nullptr;
+ if (!animation_player.is_empty()) {
+ new_player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
+ if (new_player && !new_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) {
+ new_player->connect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed));
+ }
+ }
+
+ if (new_player) {
+ if (!last_animation_player.is_valid()) {
+ // Animation player set newly.
+ emit_signal(SNAME("animation_player_changed"));
+ return;
+ } else if (last_animation_player == new_player->get_instance_id()) {
+ // Animation player isn't changed.
+ return;
+ }
+ } else if (!last_animation_player.is_valid()) {
+ // Animation player is being empty.
+ return;
+ }
+
+ AnimationPlayer *old_player = Object::cast_to<AnimationPlayer>(ObjectDB::get_instance(last_animation_player));
+ if (old_player && old_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) {
+ old_player->disconnect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed));
+ }
+ emit_signal(SNAME("animation_player_changed"));
+}
+
void AnimationTree::set_animation_player(const NodePath &p_player) {
animation_player = p_player;
+ _setup_animation_player();
update_configuration_warnings();
}
@@ -2008,6 +2058,8 @@ void AnimationTree::_bind_methods() {
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
+
+ ADD_SIGNAL(MethodInfo("animation_player_changed"));
}
AnimationTree::AnimationTree() {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index ee0c0303dc..573448be93 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -282,6 +282,8 @@ private:
bool cache_valid = false;
void _node_removed(Node *p_node);
+ void _setup_animation_player();
+ void _animation_player_changed();
void _clear_caches();
bool _update_caches(AnimationPlayer *player);
void _process_graph(double p_delta);
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 5b18d4e457..beadfbaeef 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -32,6 +32,7 @@
#include "scene/animation/easing_equations.h"
#include "scene/main/node.h"
+#include "scene/resources/animation.h"
Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
{ &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
@@ -375,264 +376,14 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
-// Helper macro to run equation on sub-elements of the value (e.g. x and y of Vector2).
-#define APPLY_EQUATION(element) \
- r.element = run_equation(p_trans, p_ease, p_time, i.element, d.element, p_duration);
-
- switch (p_initial_val.get_type()) {
- case Variant::BOOL: {
- return (run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration)) >= 0.5;
- }
-
- case Variant::INT: {
- return (int)run_equation(p_trans, p_ease, p_time, (int)p_initial_val, (int)p_delta_val, p_duration);
- }
-
- case Variant::FLOAT: {
- return run_equation(p_trans, p_ease, p_time, (real_t)p_initial_val, (real_t)p_delta_val, p_duration);
- }
-
- case Variant::VECTOR2: {
- Vector2 i = p_initial_val;
- Vector2 d = p_delta_val;
- Vector2 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- return r;
- }
-
- case Variant::VECTOR2I: {
- Vector2i i = p_initial_val;
- Vector2i d = p_delta_val;
- Vector2i r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- return r;
- }
-
- case Variant::RECT2: {
- Rect2 i = p_initial_val;
- Rect2 d = p_delta_val;
- Rect2 r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- return r;
- }
-
- case Variant::RECT2I: {
- Rect2i i = p_initial_val;
- Rect2i d = p_delta_val;
- Rect2i r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- return r;
- }
-
- case Variant::VECTOR3: {
- Vector3 i = p_initial_val;
- Vector3 d = p_delta_val;
- Vector3 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- return r;
- }
-
- case Variant::VECTOR3I: {
- Vector3i i = p_initial_val;
- Vector3i d = p_delta_val;
- Vector3i r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- return r;
- }
-
- case Variant::TRANSFORM2D: {
- Transform2D i = p_initial_val;
- Transform2D d = p_delta_val;
- Transform2D r;
-
- APPLY_EQUATION(columns[0][0]);
- APPLY_EQUATION(columns[0][1]);
- APPLY_EQUATION(columns[1][0]);
- APPLY_EQUATION(columns[1][1]);
- APPLY_EQUATION(columns[2][0]);
- APPLY_EQUATION(columns[2][1]);
- return r;
- }
- case Variant::VECTOR4: {
- Vector4 i = p_initial_val;
- Vector4 d = p_delta_val;
- Vector4 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- APPLY_EQUATION(w);
- return r;
- }
-
- case Variant::QUATERNION: {
- Quaternion i = p_initial_val;
- Quaternion d = p_delta_val;
- Quaternion r = i * d;
- r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
- return r;
- }
-
- case Variant::AABB: {
- AABB i = p_initial_val;
- AABB d = p_delta_val;
- AABB r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(position.z);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- APPLY_EQUATION(size.z);
- return r;
- }
-
- case Variant::BASIS: {
- Basis i = p_initial_val;
- Basis d = p_delta_val;
- Basis r;
-
- APPLY_EQUATION(rows[0][0]);
- APPLY_EQUATION(rows[0][1]);
- APPLY_EQUATION(rows[0][2]);
- APPLY_EQUATION(rows[1][0]);
- APPLY_EQUATION(rows[1][1]);
- APPLY_EQUATION(rows[1][2]);
- APPLY_EQUATION(rows[2][0]);
- APPLY_EQUATION(rows[2][1]);
- APPLY_EQUATION(rows[2][2]);
- return r;
- }
-
- case Variant::TRANSFORM3D: {
- Transform3D i = p_initial_val;
- Transform3D d = p_delta_val;
- Transform3D r;
-
- APPLY_EQUATION(basis.rows[0][0]);
- APPLY_EQUATION(basis.rows[0][1]);
- APPLY_EQUATION(basis.rows[0][2]);
- APPLY_EQUATION(basis.rows[1][0]);
- APPLY_EQUATION(basis.rows[1][1]);
- APPLY_EQUATION(basis.rows[1][2]);
- APPLY_EQUATION(basis.rows[2][0]);
- APPLY_EQUATION(basis.rows[2][1]);
- APPLY_EQUATION(basis.rows[2][2]);
- APPLY_EQUATION(origin.x);
- APPLY_EQUATION(origin.y);
- APPLY_EQUATION(origin.z);
- return r;
- }
-
- case Variant::COLOR: {
- Color i = p_initial_val;
- Color d = p_delta_val;
- Color r;
-
- APPLY_EQUATION(r);
- APPLY_EQUATION(g);
- APPLY_EQUATION(b);
- APPLY_EQUATION(a);
- return r;
- }
-
- default: {
- return p_initial_val;
- }
- };
-#undef APPLY_EQUATION
-}
-
-Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) {
- ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type()));
-
- switch (p_intial_val.get_type()) {
- case Variant::BOOL: {
- return (int)p_final_val - (int)p_intial_val;
- }
-
- case Variant::RECT2: {
- Rect2 i = p_intial_val;
- Rect2 f = p_final_val;
- return Rect2(f.position - i.position, f.size - i.size);
- }
-
- case Variant::RECT2I: {
- Rect2i i = p_intial_val;
- Rect2i f = p_final_val;
- return Rect2i(f.position - i.position, f.size - i.size);
- }
-
- case Variant::TRANSFORM2D: {
- Transform2D i = p_intial_val;
- Transform2D f = p_final_val;
- return Transform2D(f.columns[0][0] - i.columns[0][0],
- f.columns[0][1] - i.columns[0][1],
- f.columns[1][0] - i.columns[1][0],
- f.columns[1][1] - i.columns[1][1],
- f.columns[2][0] - i.columns[2][0],
- f.columns[2][1] - i.columns[2][1]);
- }
-
- case Variant::AABB: {
- AABB i = p_intial_val;
- AABB f = p_final_val;
- return AABB(f.position - i.position, f.size - i.size);
- }
-
- case Variant::BASIS: {
- Basis i = p_intial_val;
- Basis f = p_final_val;
- return Basis(f.rows[0][0] - i.rows[0][0],
- f.rows[0][1] - i.rows[0][1],
- f.rows[0][2] - i.rows[0][2],
- f.rows[1][0] - i.rows[1][0],
- f.rows[1][1] - i.rows[1][1],
- f.rows[1][2] - i.rows[1][2],
- f.rows[2][0] - i.rows[2][0],
- f.rows[2][1] - i.rows[2][1],
- f.rows[2][2] - i.rows[2][2]);
- }
-
- case Variant::TRANSFORM3D: {
- Transform3D i = p_intial_val;
- Transform3D f = p_final_val;
- return Transform3D(f.basis.rows[0][0] - i.basis.rows[0][0],
- f.basis.rows[0][1] - i.basis.rows[0][1],
- f.basis.rows[0][2] - i.basis.rows[0][2],
- f.basis.rows[1][0] - i.basis.rows[1][0],
- f.basis.rows[1][1] - i.basis.rows[1][1],
- f.basis.rows[1][2] - i.basis.rows[1][2],
- f.basis.rows[2][0] - i.basis.rows[2][0],
- f.basis.rows[2][1] - i.basis.rows[2][1],
- f.basis.rows[2][2] - i.basis.rows[2][2],
- f.origin.x - i.origin.x,
- f.origin.y - i.origin.y,
- f.origin.z - i.origin.z);
- }
+ // Special case for bool.
+ if (p_initial_val.get_type() == Variant::BOOL) {
+ return run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration) >= 0.5;
+ }
- default: {
- return Variant::evaluate(Variant::OP_SUBTRACT, p_final_val, p_intial_val);
- }
- };
+ Variant ret = Animation::add_variant(p_initial_val, p_delta_val);
+ ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
+ return ret;
}
void Tween::_bind_methods() {
@@ -748,10 +499,10 @@ void PropertyTweener::start() {
}
if (relative) {
- final_val = Variant::evaluate(Variant::Operator::OP_ADD, initial_val, base_final_val);
+ final_val = Animation::add_variant(initial_val, base_final_val);
}
- delta_val = tween->calculate_delta_value(initial_val, final_val);
+ delta_val = Animation::subtract_variant(final_val, initial_val);
}
bool PropertyTweener::step(float &r_delta) {
@@ -973,7 +724,7 @@ void MethodTweener::_bind_methods() {
MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
callback = p_callback;
initial_val = p_from;
- delta_val = tween->calculate_delta_value(p_from, p_to);
+ delta_val = Animation::subtract_variant(p_to, p_from);
final_val = p_to;
duration = p_duration;
}
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index b57ec2e5e7..da7a8b5d71 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -164,7 +164,6 @@ public:
static real_t run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
static Variant interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, Tween::TransitionType p_trans, Tween::EaseType p_ease);
- Variant calculate_delta_value(Variant p_intial_val, Variant p_final_val);
bool step(float p_delta);
bool can_process(bool p_tree_paused) const;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 5295de5c09..879d494909 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -795,11 +795,20 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
stretch_transform = p_stretch_transform;
to_screen_rect = p_to_screen_rect;
- if (p_allocated) {
- RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- } else {
- RS::get_singleton()->viewport_set_size(viewport, 0, 0);
- }
+#ifndef _3D_DISABLED
+ if (!use_xr) {
+#endif
+
+ if (p_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+
+#ifndef _3D_DISABLED
+ } // if (!use_xr)
+#endif
+
_update_global_transform();
update_configuration_warnings();
@@ -813,6 +822,19 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
}
Size2i Viewport::_get_size() const {
+#ifndef _3D_DISABLED
+ if (use_xr) {
+ if (XRServer::get_singleton() != nullptr) {
+ Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface();
+ if (xr_interface.is_valid() && xr_interface->is_initialized()) {
+ Size2 xr_size = xr_interface->get_render_target_size();
+ return (Size2i)xr_size;
+ }
+ }
+ return Size2i();
+ }
+#endif // _3D_DISABLED
+
return size;
}
@@ -3612,9 +3634,20 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
}
void Viewport::set_use_xr(bool p_use_xr) {
- use_xr = p_use_xr;
+ if (use_xr != p_use_xr) {
+ use_xr = p_use_xr;
- RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+
+ if (!use_xr) {
+ // Set viewport to previous size when exiting XR.
+ if (size_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+ }
+ }
}
bool Viewport::is_using_xr() {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index afea3ea56c..c7c474c70f 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -568,7 +568,7 @@ public:
bool is_input_disabled() const;
Vector2 get_mouse_position() const;
- virtual void warp_mouse(const Vector2 &p_position);
+ void warp_mouse(const Vector2 &p_position);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 04f56bb874..ebe9587b31 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -986,18 +986,6 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
-void Window::warp_mouse(const Vector2 &p_position) {
- Transform2D xform = get_screen_transform();
- Vector2 gpos = xform.xform(p_position);
-
- if (transient_parent && !transient_parent->is_embedding_subwindows()) {
- Transform2D window_trans = Transform2D().translated(get_position() + (transient_parent->get_visible_rect().size - transient_parent->get_real_size()));
- gpos = window_trans.xform(gpos);
- }
-
- Input::get_singleton()->warp_mouse(gpos);
-}
-
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
@@ -1153,7 +1141,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1179,7 +1167,7 @@ void Window::popup_centered(const Size2i &p_minsize) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1207,7 +1195,7 @@ void Window::popup_centered_ratio(float p_ratio) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
diff --git a/scene/main/window.h b/scene/main/window.h
index 8113117103..8c6ca65436 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -254,8 +254,6 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
- void warp_mouse(const Vector2 &p_position) override;
-
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 9d5bc18c96..4f16f75389 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2317,9 +2317,7 @@ Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b,
}
Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const {
- Variant dst;
- Variant::interpolate(p_a, p_b, p_c, dst);
- return dst;
+ return interpolate_variant(p_a, p_b, p_c);
}
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
@@ -5563,6 +5561,466 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
return false;
}
+// Helper math fuctions for Variant.
+Variant Animation::add_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) + (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal, pa.d + pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position, aa.size + ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * (b.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * (b.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * (b.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_ADD, a, b);
+ }
+ }
+}
+
+Variant Animation::subtract_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) - (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal - pb.normal, pa.d - pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position - ab.position, aa.size - ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (b.operator Quaternion()).inverse() * (a.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (b.operator Transform2D()).inverse() * (a.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (b.operator Transform3D()).inverse() * (a.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_SUBTRACT, a, b);
+ }
+ }
+}
+
+Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + vb * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ return int((a.operator int64_t()) + (b.operator int64_t()) * c + 0.5);
+ }
+ case Variant::FLOAT: {
+ return (a.operator double()) + (b.operator double()) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()) + (b.operator Vector2()) * c;
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position * c, ra.size + rb.size * c);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + rb.position.x * c + 0.5), int32_t(ra.position.y + rb.position.y * c + 0.5), int32_t(ra.size.x + rb.size.x * c + 0.5), int32_t(ra.size.y + rb.size.y * c + 0.5));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()) + (b.operator Vector3()) * c;
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()) + (b.operator Vector4()) * c;
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5), int32_t(va.w + vb.w * c + 0.5));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal * c, pa.d + pb.d * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()) + (b.operator Color()) * c;
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position * c, aa.size + ab.size * c);
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()) + (b.operator Basis()) * c;
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * Quaternion().slerp((b.operator Quaternion()), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * Transform2D().interpolate_with((b.operator Transform2D()), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * Transform3D().interpolate_with((b.operator Transform3D()), c);
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
+Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + (vb - va) * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ const int64_t va = a.operator int64_t();
+ return int(va + ((b.operator int64_t()) - va) * c);
+ }
+ case Variant::FLOAT: {
+ const real_t va = a.operator real_t();
+ return va + ((b.operator real_t()) - va) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()).lerp(b.operator Vector2(), c);
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position.lerp(rb.position, c), ra.size.lerp(rb.size, c));
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + (rb.position.x - ra.position.x) * c), int32_t(ra.position.y + (rb.position.y - ra.position.y) * c), int32_t(ra.size.x + (rb.size.x - ra.size.x) * c), int32_t(ra.size.y + (rb.size.y - ra.size.y) * c));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()).lerp(b.operator Vector3(), c);
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()).lerp(b.operator Vector4(), c);
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c), int32_t(va.w + (vb.w - va.w) * c));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal.lerp(pb.normal, c), pa.d + (pb.d - pa.d) * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()).lerp(b.operator Color(), c);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position.lerp(ab.position, c), aa.size.lerp(ab.size, c));
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()).lerp(b.operator Basis(), c);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()).slerp(b.operator Quaternion(), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()).interpolate_with(b.operator Transform2D(), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()).interpolate_with(b.operator Transform3D(), c);
+ }
+ case Variant::STRING: {
+ // This is pretty funny and bizarre, but artists like to use it for typewriter effects.
+ const String sa = a.operator String();
+ const String sb = b.operator String();
+ String dst;
+ int sa_len = sa.length();
+ int sb_len = sb.length();
+ int csize = sa_len + (sb_len - sa_len) * c;
+ if (csize == 0) {
+ return "";
+ }
+ dst.resize(csize + 1);
+ dst[csize] = 0;
+ int split = csize / 2;
+
+ for (int i = 0; i < csize; i++) {
+ char32_t chr = ' ';
+
+ if (i < split) {
+ if (i < sa.length()) {
+ chr = sa[i];
+ } else if (i < sb.length()) {
+ chr = sb[i];
+ }
+
+ } else {
+ if (i < sb.length()) {
+ chr = sb[i];
+ } else if (i < sa.length()) {
+ chr = sa[i];
+ }
+ }
+
+ dst[i] = chr;
+ }
+
+ return dst;
+ }
+ case Variant::PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a);
+ const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b);
+ int32_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int32_t> v;
+ v.resize(sz);
+ {
+ int32_t *vw = v.ptrw();
+ const int32_t *ar = arr_a->ptr();
+ const int32_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int32_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a);
+ const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b);
+ int64_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int64_t> v;
+ v.resize(sz);
+ {
+ int64_t *vw = v.ptrw();
+ const int64_t *ar = arr_a->ptr();
+ const int64_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int64_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a);
+ const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<float> v;
+ v.resize(sz);
+ {
+ float *vw = v.ptrw();
+ const float *ar = arr_a->ptr();
+ const float *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a);
+ const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<double> v;
+ v.resize(sz);
+ {
+ double *vw = v.ptrw();
+ const double *ar = arr_a->ptr();
+ const double *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a);
+ const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector2> v;
+ v.resize(sz);
+ {
+ Vector2 *vw = v.ptrw();
+ const Vector2 *ar = arr_a->ptr();
+ const Vector2 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a);
+ const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector3> v;
+ v.resize(sz);
+ {
+ Vector3 *vw = v.ptrw();
+ const Vector3 *ar = arr_a->ptr();
+ const Vector3 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a);
+ const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Color> v;
+ v.resize(sz);
+ {
+ Color *vw = v.ptrw();
+ const Color *ar = arr_a->ptr();
+ const Color *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
Animation::Animation() {}
Animation::~Animation() {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 46a88df130..112a6c28aa 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -496,6 +496,12 @@ public:
void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
+ // Helper math fuctions for Variant.
+ static Variant add_variant(const Variant &a, const Variant &b);
+ static Variant subtract_variant(const Variant &a, const Variant &b);
+ static Variant blend_variant(const Variant &a, const Variant &b, float c);
+ static Variant interpolate_variant(const Variant &a, const Variant &b, float c);
+
Animation();
~Animation();
};
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index e47bfef576..c1e30dd93c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -257,23 +257,25 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
groups[last_group][last_subgroup].push_back(info);
}
- // Sort groups alphabetically.
- List<UniformProp> props;
+ List<String> group_names;
for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
- for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
- for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
- if (subgroup->key == "<None>") {
- props.push_back({ group->key, item->get() });
- } else {
- props.push_back({ group->key + "::" + subgroup->key, item->get() });
- }
- }
- }
+ group_names.push_back(group->key);
}
- props.sort_custom<UniformPropComparator>();
+ group_names.sort();
- for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
- p_list->push_back(E->get().info);
+ for (const String &group_name : group_names) {
+ List<String> subgroup_names;
+ HashMap<String, List<PropertyInfo>> &subgroups = groups[group_name];
+ for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = subgroups.begin(); subgroup; ++subgroup) {
+ subgroup_names.push_back(subgroup->key);
+ }
+ subgroup_names.sort();
+ for (const String &subgroup_name : subgroup_names) {
+ List<PropertyInfo> &prop_infos = subgroups[subgroup_name];
+ for (List<PropertyInfo>::Element *item = prop_infos.front(); item; item = item->next()) {
+ p_list->push_back(item->get());
+ }
+ }
}
}
}
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 6c81293ee3..dd9589c577 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -84,17 +84,6 @@ class ShaderMaterial : public Material {
HashMap<StringName, Variant> param_cache;
- struct UniformProp {
- String str;
- PropertyInfo info;
- };
-
- struct UniformPropComparator {
- bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
- return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
- }
- };
-
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;