summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/animation/animation_blend_space_1d.cpp180
-rw-r--r--scene/animation/animation_blend_space_1d.h17
-rw-r--r--scene/gui/control.cpp6
-rw-r--r--scene/gui/control.h3
-rw-r--r--scene/main/canvas_item.cpp17
-rw-r--r--scene/main/canvas_item.h3
-rw-r--r--scene/main/viewport.cpp11
-rw-r--r--scene/main/window.cpp8
-rw-r--r--scene/main/window.h2
9 files changed, 185 insertions, 62 deletions
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index a2028b8de8..d28a6fcc04 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -30,12 +30,20 @@
#include "animation_blend_space_1d.h"
+#include "animation_blend_tree.h"
+
void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position));
+ r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
- return 0;
+ if (p_parameter == closest) {
+ return -1;
+ } else {
+ return 0;
+ }
}
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
@@ -77,6 +85,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace1D::set_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace1D::get_blend_mode);
+
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
@@ -91,7 +102,12 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
+
+ BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
}
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -214,6 +230,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
return value_label;
}
+void AnimationNodeBlendSpace1D::set_blend_mode(BlendMode p_blend_mode) {
+ blend_mode = p_blend_mode;
+}
+
+AnimationNodeBlendSpace1D::BlendMode AnimationNodeBlendSpace1D::get_blend_mode() const {
+ return blend_mode;
+}
+
void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
sync = p_sync;
}
@@ -241,79 +265,125 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
}
double blend_pos = get_parameter(blend_position);
+ int cur_closest = get_parameter(closest);
+ double cur_length_internal = get_parameter(length_internal);
+ double max_time_remaining = 0.0;
- float weights[MAX_BLEND_POINTS] = {};
+ if (blend_mode == BLEND_MODE_INTERPOLATED) {
+ float weights[MAX_BLEND_POINTS] = {};
+
+ int point_lower = -1;
+ float pos_lower = 0.0;
+ int point_higher = -1;
+ float pos_higher = 0.0;
+
+ // find the closest two points to blend between
+ for (int i = 0; i < blend_points_used; i++) {
+ float pos = blend_points[i].position;
+
+ if (pos <= blend_pos) {
+ if (point_lower == -1) {
+ point_lower = i;
+ pos_lower = pos;
+ } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
+ point_lower = i;
+ pos_lower = pos;
+ }
+ } else {
+ if (point_higher == -1) {
+ point_higher = i;
+ pos_higher = pos;
+ } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
+ point_higher = i;
+ pos_higher = pos;
+ }
+ }
+ }
- int point_lower = -1;
- float pos_lower = 0.0;
- int point_higher = -1;
- float pos_higher = 0.0;
+ // fill in weights
- // find the closest two points to blend between
- for (int i = 0; i < blend_points_used; i++) {
- float pos = blend_points[i].position;
-
- if (pos <= blend_pos) {
- if (point_lower == -1) {
- point_lower = i;
- pos_lower = pos;
- } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
- point_lower = i;
- pos_lower = pos;
- }
+ if (point_lower == -1 && point_higher != -1) {
+ // we are on the left side, no other point to the left
+ // we just play the next point.
+
+ weights[point_higher] = 1.0;
+ } else if (point_higher == -1) {
+ // we are on the right side, no other point to the right
+ // we just play the previous point
+
+ weights[point_lower] = 1.0;
} else {
- if (point_higher == -1) {
- point_higher = i;
- pos_higher = pos;
- } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
- point_higher = i;
- pos_higher = pos;
- }
- }
- }
+ // we are between two points.
+ // figure out weights, then blend the animations
- // fill in weights
+ float distance_between_points = pos_higher - pos_lower;
- if (point_lower == -1 && point_higher != -1) {
- // we are on the left side, no other point to the left
- // we just play the next point.
+ float current_pos_inbetween = blend_pos - pos_lower;
- weights[point_higher] = 1.0;
- } else if (point_higher == -1) {
- // we are on the right side, no other point to the right
- // we just play the previous point
+ float blend_percentage = current_pos_inbetween / distance_between_points;
- weights[point_lower] = 1.0;
- } else {
- // we are between two points.
- // figure out weights, then blend the animations
+ float blend_lower = 1.0 - blend_percentage;
+ float blend_higher = blend_percentage;
- float distance_between_points = pos_higher - pos_lower;
+ weights[point_lower] = blend_lower;
+ weights[point_higher] = blend_higher;
+ }
- float current_pos_inbetween = blend_pos - pos_lower;
+ // actually blend the animations now
- float blend_percentage = current_pos_inbetween / distance_between_points;
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i == point_lower || i == point_higher) {
+ double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
+ max_time_remaining = MAX(max_time_remaining, remaining);
+ } else if (sync) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
+ }
+ } else {
+ int new_closest = -1;
+ double new_closest_dist = 1e20;
+
+ for (int i = 0; i < blend_points_used; i++) {
+ double d = abs(blend_points[i].position - blend_pos);
+ if (d < new_closest_dist) {
+ new_closest = i;
+ new_closest_dist = d;
+ }
+ }
- float blend_lower = 1.0 - blend_percentage;
- float blend_higher = blend_percentage;
+ if (new_closest != cur_closest && new_closest != -1) {
+ double from = 0.0;
+ if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
+ //for ping-pong loop
+ Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
+ Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
+ if (!na_c.is_null() && !na_n.is_null()) {
+ na_n->set_backward(na_c->is_backward());
+ }
+ //see how much animation remains
+ from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
+ }
- weights[point_lower] = blend_lower;
- weights[point_higher] = blend_higher;
- }
+ max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ cur_length_internal = from + max_time_remaining;
- // actually blend the animations now
+ cur_closest = new_closest;
- double max_time_remaining = 0.0;
+ } else {
+ max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ }
- for (int i = 0; i < blend_points_used; i++) {
- if (i == point_lower || i == point_higher) {
- double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
- max_time_remaining = MAX(max_time_remaining, remaining);
- } else if (sync) {
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ if (sync) {
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i != cur_closest) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
+ }
}
}
+ set_parameter(this->closest, cur_closest);
+ set_parameter(this->length_internal, cur_length_internal);
return max_time_remaining;
}
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index af93783c0d..a1e9a7a764 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -36,6 +36,14 @@
class AnimationNodeBlendSpace1D : public AnimationRootNode {
GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode);
+public:
+ enum BlendMode {
+ BLEND_MODE_INTERPOLATED,
+ BLEND_MODE_DISCRETE,
+ BLEND_MODE_DISCRETE_CARRY,
+ };
+
+protected:
enum {
MAX_BLEND_POINTS = 64
};
@@ -61,6 +69,10 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void _tree_changed();
StringName blend_position = "blend_position";
+ StringName closest = "closest";
+ StringName length_internal = "length_internal";
+
+ BlendMode blend_mode = BLEND_MODE_INTERPOLATED;
protected:
bool sync = false;
@@ -95,6 +107,9 @@ public:
void set_value_label(const String &p_label);
String get_value_label() const;
+ void set_blend_mode(BlendMode p_blend_mode);
+ BlendMode get_blend_mode() const;
+
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -107,4 +122,6 @@ public:
~AnimationNodeBlendSpace1D();
};
+VARIANT_ENUM_CAST(AnimationNodeBlendSpace1D::BlendMode)
+
#endif // ANIMATION_BLEND_SPACE_1D_H
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index f7c056316d..6f5e2cf058 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -692,6 +692,12 @@ Transform2D Control::get_transform() const {
return xform;
}
+void Control::_toplevel_changed_on_parent() {
+ // Update root control status.
+ _notification(NOTIFICATION_EXIT_CANVAS);
+ _notification(NOTIFICATION_ENTER_CANVAS);
+}
+
/// Anchors and offsets.
void Control::_set_anchor(Side p_side, real_t p_anchor) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index a93a88e5b4..5977f4dbea 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -292,6 +292,9 @@ private:
void _update_minimum_size();
void _size_changed();
+ void _toplevel_changed() override{}; // Controls don't need to do anything, only other CanvasItems.
+ void _toplevel_changed_on_parent() override;
+
void _clear_size_warning();
// Input events.
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 35176f0edd..cde3503bdf 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -400,11 +400,28 @@ void CanvasItem::set_as_top_level(bool p_top_level) {
_exit_canvas();
top_level = p_top_level;
+ _toplevel_changed();
_enter_canvas();
_notify_transform();
}
+void CanvasItem::_toplevel_changed() {
+ // Inform children that toplevel status has changed on a parent.
+ int childs = get_child_count();
+ for (int i = 0; i < childs; i++) {
+ CanvasItem *child = Object::cast_to<CanvasItem>(get_child(i));
+ if (child) {
+ child->_toplevel_changed_on_parent();
+ }
+ }
+}
+
+void CanvasItem::_toplevel_changed_on_parent() {
+ // Inform children that toplevel status has changed on a parent.
+ _toplevel_changed();
+}
+
bool CanvasItem::is_set_as_top_level() const {
return top_level;
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 1c84ea338a..1ddfaa288c 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -125,6 +125,9 @@ private:
void _propagate_visibility_changed(bool p_parent_visible_in_tree);
void _handle_visibility_change(bool p_visible);
+ virtual void _toplevel_changed();
+ virtual void _toplevel_changed_on_parent();
+
void _redraw_callback();
void _enter_canvas();
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 48cff5aa8e..64bd3fe2c1 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1110,14 +1110,11 @@ Viewport::PositionalShadowAtlasQuadrantSubdiv Viewport::get_positional_shadow_at
}
Transform2D Viewport::_get_input_pre_xform() const {
- Transform2D pre_xf;
-
- if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
- pre_xf.columns[2] = -to_screen_rect.position;
- pre_xf.scale(Vector2(size) / to_screen_rect.size);
+ const Window *this_window = Object::cast_to<Window>(this);
+ if (this_window) {
+ return this_window->window_transform.affine_inverse();
}
-
- return pre_xf;
+ return Transform2D();
}
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 869d12b4df..1f629aaf94 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -907,6 +907,7 @@ void Window::_update_viewport_size() {
Rect2i attach_to_screen_rect(Point2i(), size);
Transform2D stretch_transform_new;
float font_oversampling = 1.0;
+ window_transform = Transform2D();
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
font_oversampling = content_scale_factor;
@@ -993,11 +994,18 @@ void Window::_update_viewport_size() {
Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
stretch_transform_new.scale(scale);
+ window_transform.translate_local(margin);
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
final_size = (viewport_size / content_scale_factor).floor();
attach_to_screen_rect = Rect2(margin, screen_size);
+ window_transform.translate_local(margin);
+ if (final_size.x != 0 && final_size.y != 0) {
+ Transform2D scale_transform;
+ scale_transform.scale(Vector2(attach_to_screen_rect.size) / Vector2(final_size));
+ window_transform *= scale_transform;
+ }
} break;
}
}
diff --git a/scene/main/window.h b/scene/main/window.h
index 182caf5f0c..1730de0b33 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -173,6 +173,8 @@ private:
Viewport *embedder = nullptr;
+ Transform2D window_transform;
+
friend class Viewport; //friend back, can call the methods below
void _window_input(const Ref<InputEvent> &p_ev);