mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-11-22 00:48:09 +01:00
Ported: 2D Fixed Timestep Interpolation
Adds support to canvas items and Camera2D.
- lawnjelly
5162efbfe9
This commit is contained in:
parent
87b91721da
commit
d977ed360e
@ -30,6 +30,8 @@
|
||||
|
||||
#include "transform_interpolator.h"
|
||||
|
||||
#include "core/math/transform_2d.h"
|
||||
|
||||
void TransformInterpolator::interpolate_transform(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction) {
|
||||
r_result.origin = p_prev.origin + ((p_curr.origin - p_prev.origin) * p_fraction);
|
||||
interpolate_basis(p_prev.basis, p_curr.basis, r_result.basis, p_fraction);
|
||||
@ -40,6 +42,49 @@ void TransformInterpolator::interpolate_basis(const Basis &p_prev, const Basis &
|
||||
interpolate_basis_via_method(p_prev, p_curr, r_result, p_fraction, method);
|
||||
}
|
||||
|
||||
void TransformInterpolator::interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction) {
|
||||
// Extract parameters.
|
||||
Vector2 p1 = p_prev.get_origin();
|
||||
Vector2 p2 = p_curr.get_origin();
|
||||
|
||||
// Special case for physics interpolation, if flipping, don't interpolate basis.
|
||||
// If the determinant polarity changes, the handedness of the coordinate system changes.
|
||||
if (_sign(p_prev.basis_determinant()) != _sign(p_curr.basis_determinant())) {
|
||||
r_result.columns[0] = p_curr.columns[0];
|
||||
r_result.columns[1] = p_curr.columns[1];
|
||||
r_result.set_origin(Vector2::linear_interpolate(p1, p2, p_fraction));
|
||||
return;
|
||||
}
|
||||
|
||||
real_t r1 = p_prev.get_rotation();
|
||||
real_t r2 = p_curr.get_rotation();
|
||||
|
||||
Size2 s1 = p_prev.get_scale();
|
||||
Size2 s2 = p_curr.get_scale();
|
||||
|
||||
// Slerp rotation.
|
||||
Vector2 v1(Math::cos(r1), Math::sin(r1));
|
||||
Vector2 v2(Math::cos(r2), Math::sin(r2));
|
||||
|
||||
real_t dot = v1.dot(v2);
|
||||
|
||||
dot = CLAMP(dot, -1, 1);
|
||||
|
||||
Vector2 v;
|
||||
|
||||
if (dot > 0.9995f) {
|
||||
v = Vector2::linear_interpolate(v1, v2, p_fraction).normalized(); // Linearly interpolate to avoid numerical precision issues.
|
||||
} else {
|
||||
real_t angle = p_fraction * Math::acos(dot);
|
||||
Vector2 v3 = (v2 - v1 * dot).normalized();
|
||||
v = v1 * Math::cos(angle) + v3 * Math::sin(angle);
|
||||
}
|
||||
|
||||
// Construct matrix.
|
||||
r_result = Transform2D(Math::atan2(v.y, v.x), Vector2::linear_interpolate(p1, p2, p_fraction));
|
||||
r_result.scale_basis(Vector2::linear_interpolate(s1, s2, p_fraction));
|
||||
}
|
||||
|
||||
void TransformInterpolator::interpolate_transform_via_method(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction, Method p_method) {
|
||||
r_result.origin = p_prev.origin + ((p_curr.origin - p_prev.origin) * p_fraction);
|
||||
interpolate_basis_via_method(p_prev.basis, p_curr.basis, r_result.basis, p_fraction, p_method);
|
||||
|
@ -46,6 +46,7 @@
|
||||
// than performing every frame.
|
||||
|
||||
struct Transform;
|
||||
struct Transform2D;
|
||||
|
||||
class TransformInterpolator {
|
||||
public:
|
||||
@ -65,6 +66,7 @@ private:
|
||||
static Quaternion _basis_to_quat_unchecked(const Basis &p_basis);
|
||||
static bool _basis_is_orthogonal(const Basis &p_basis, real_t p_epsilon = 0.01f);
|
||||
static bool _basis_is_orthogonal_any_scale(const Basis &p_basis);
|
||||
static bool _sign(real_t p_val) { return p_val >= 0; }
|
||||
|
||||
static void interpolate_basis_linear(const Basis &p_prev, const Basis &p_curr, Basis &r_result, real_t p_fraction);
|
||||
static void interpolate_basis_scaled_slerp(Basis p_prev, Basis p_curr, Basis &r_result, real_t p_fraction);
|
||||
@ -74,6 +76,7 @@ public:
|
||||
// These will be slower.
|
||||
static void interpolate_transform(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction);
|
||||
static void interpolate_basis(const Basis &p_prev, const Basis &p_curr, Basis &r_result, real_t p_fraction);
|
||||
static void interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction);
|
||||
|
||||
// Optimized function when you know ahead of time the method
|
||||
static void interpolate_transform_via_method(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction, Method p_method);
|
||||
|
@ -66,6 +66,7 @@ public:
|
||||
virtual void input_text(const String &p_text);
|
||||
|
||||
virtual void init();
|
||||
virtual void iteration_prepare() {}
|
||||
virtual bool iteration(float p_time);
|
||||
virtual void iteration_end() {}
|
||||
virtual bool idle(float p_time);
|
||||
|
@ -746,6 +746,7 @@
|
||||
<member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" enum="Control.MouseFilter" default="0">
|
||||
Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Also controls whether the control can receive the [signal mouse_entered], and [signal mouse_exited] signals. See the constants to learn what each does.
|
||||
</member>
|
||||
<member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" overrides="Node" enum="Node.PhysicsInterpolationMode" default="1" />
|
||||
<member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false">
|
||||
Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered.
|
||||
</member>
|
||||
|
@ -23,6 +23,7 @@
|
||||
<member name="motion_scale" type="Vector2" setter="set_motion_scale" getter="get_motion_scale" default="Vector2( 1, 1 )">
|
||||
Multiplies the ParallaxLayer's motion. If an axis is set to [code]0[/code], it will not scroll.
|
||||
</member>
|
||||
<member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" overrides="Node" enum="Node.PhysicsInterpolationMode" default="1" />
|
||||
</members>
|
||||
<constants>
|
||||
</constants>
|
||||
|
@ -315,6 +315,14 @@
|
||||
Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_reset_physics_interpolation">
|
||||
<return type="void" />
|
||||
<argument index="0" name="item" type="RID" />
|
||||
<description>
|
||||
Prevents physics interpolation for the current physics tick.
|
||||
This is useful when moving a canvas item to a new location, to give an instantaneous change rather than interpolation from the previous location.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_set_clip">
|
||||
<return type="void" />
|
||||
<argument index="0" name="item" type="RID" />
|
||||
@ -365,6 +373,14 @@
|
||||
Sets the index for the [CanvasItem].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_set_interpolated">
|
||||
<return type="void" />
|
||||
<argument index="0" name="item" type="RID" />
|
||||
<argument index="1" name="interpolated" type="bool" />
|
||||
<description>
|
||||
Turns on and off physics interpolation for the canvas item.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_set_light_mask">
|
||||
<return type="void" />
|
||||
<argument index="0" name="item" type="RID" />
|
||||
@ -453,6 +469,16 @@
|
||||
Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are drawn first).
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_item_transform_physics_interpolation">
|
||||
<return type="void" />
|
||||
<argument index="0" name="item" type="RID" />
|
||||
<argument index="1" name="xform" type="Transform2D" />
|
||||
<description>
|
||||
Transforms both the current and previous stored transform for a canvas item.
|
||||
This allows transforming a canvas item without creating a "glitch" in the interpolation.
|
||||
This is particularly useful for large worlds utilising a shifting origin.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_attach_to_canvas">
|
||||
<return type="void" />
|
||||
<argument index="0" name="light" type="RID" />
|
||||
@ -483,6 +509,14 @@
|
||||
Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_occluder_reset_physics_interpolation">
|
||||
<return type="void" />
|
||||
<argument index="0" name="occluder" type="RID" />
|
||||
<description>
|
||||
Prevents physics interpolation for the current physics tick.
|
||||
This is useful when moving an occluder to a new location, to give an instantaneous change rather than interpolation from the previous location.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_occluder_set_enabled">
|
||||
<return type="void" />
|
||||
<argument index="0" name="occluder" type="RID" />
|
||||
@ -491,6 +525,14 @@
|
||||
Enables or disables light occluder.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_occluder_set_interpolated">
|
||||
<return type="void" />
|
||||
<argument index="0" name="occluder" type="RID" />
|
||||
<argument index="1" name="interpolated" type="bool" />
|
||||
<description>
|
||||
Turns on and off physics interpolation for the occluder.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_occluder_set_light_mask">
|
||||
<return type="void" />
|
||||
<argument index="0" name="occluder" type="RID" />
|
||||
@ -515,6 +557,24 @@
|
||||
Sets a light occluder's [Transform2D].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_occluder_transform_physics_interpolation">
|
||||
<return type="void" />
|
||||
<argument index="0" name="occluder" type="RID" />
|
||||
<argument index="1" name="xform" type="Transform2D" />
|
||||
<description>
|
||||
Transforms both the current and previous stored transform for an occluder.
|
||||
This allows transforming an occluder without creating a "glitch" in the interpolation.
|
||||
This is particularly useful for large worlds utilising a shifting origin.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_reset_physics_interpolation">
|
||||
<return type="void" />
|
||||
<argument index="0" name="light" type="RID" />
|
||||
<description>
|
||||
Prevents physics interpolation for the current physics tick.
|
||||
This is useful when moving a light to a new location, to give an instantaneous change rather than interpolation from the previous location.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_set_color">
|
||||
<return type="void" />
|
||||
<argument index="0" name="light" type="RID" />
|
||||
@ -547,6 +607,14 @@
|
||||
Sets a canvas light's height.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_set_interpolated">
|
||||
<return type="void" />
|
||||
<argument index="0" name="light" type="RID" />
|
||||
<argument index="1" name="interpolated" type="bool" />
|
||||
<description>
|
||||
Turns on and off physics interpolation for the light.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_set_item_cull_mask">
|
||||
<return type="void" />
|
||||
<argument index="0" name="light" type="RID" />
|
||||
@ -669,6 +737,16 @@
|
||||
Sets the Z range of objects that will be affected by this light. Equivalent to [member Light2D.range_z_min] and [member Light2D.range_z_max].
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_light_transform_physics_interpolation">
|
||||
<return type="void" />
|
||||
<argument index="0" name="light" type="RID" />
|
||||
<argument index="1" name="xform" type="Transform2D" />
|
||||
<description>
|
||||
Transforms both the current and previous stored transform for a light.
|
||||
This allows transforming a light without creating a "glitch" in the interpolation.
|
||||
This is particularly useful for large worlds utilising a shifting origin.
|
||||
</description>
|
||||
</method>
|
||||
<method name="canvas_occluder_polygon_create">
|
||||
<return type="RID" />
|
||||
<description>
|
||||
|
@ -2366,6 +2366,12 @@ bool Main::iteration() {
|
||||
|
||||
PhysicsServer::get_singleton()->flush_queries();
|
||||
|
||||
// Prepare the fixed timestep interpolated nodes
|
||||
// BEFORE they are updated by the physics 2D,
|
||||
// otherwise the current and previous transforms
|
||||
// may be the same, and no interpolation takes place.
|
||||
OS::get_singleton()->get_main_loop()->iteration_prepare();
|
||||
|
||||
Physics2DServer::get_singleton()->sync();
|
||||
Physics2DServer::get_singleton()->flush_queries();
|
||||
|
||||
|
@ -56,8 +56,12 @@ void Camera2D::_update_scroll() {
|
||||
if (is_current()) {
|
||||
ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id));
|
||||
|
||||
Transform2D xform = get_camera_transform();
|
||||
|
||||
Transform2D xform;
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
xform = _interpolation_data.xform_prev.interpolate_with(_interpolation_data.xform_curr, Engine::get_singleton()->get_physics_interpolation_fraction());
|
||||
} else {
|
||||
xform = get_camera_transform();
|
||||
}
|
||||
viewport->set_canvas_transform(xform);
|
||||
|
||||
Size2 screen_size = viewport->get_visible_rect().size;
|
||||
@ -68,13 +72,24 @@ void Camera2D::_update_scroll() {
|
||||
}
|
||||
|
||||
void Camera2D::_update_process_mode() {
|
||||
// smoothing can be enabled in the editor but will never be active
|
||||
if (process_mode == CAMERA2D_PROCESS_IDLE) {
|
||||
set_process_internal(smoothing_active);
|
||||
set_physics_process_internal(false);
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
set_process_internal(is_current());
|
||||
set_physics_process_internal(is_current());
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (process_mode == CAMERA2D_PROCESS_IDLE) {
|
||||
WARN_PRINT_ONCE("Camera2D overridden to physics process mode due to use of physics interpolation.");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
set_process_internal(false);
|
||||
set_physics_process_internal(smoothing_active);
|
||||
// Smoothing can be enabled in the editor but will never be active.
|
||||
if (process_mode == CAMERA2D_PROCESS_IDLE) {
|
||||
set_process_internal(smoothing_active);
|
||||
set_physics_process_internal(false);
|
||||
} else {
|
||||
set_process_internal(false);
|
||||
set_physics_process_internal(smoothing_active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,8 +194,19 @@ Transform2D Camera2D::get_camera_transform() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO ..
|
||||
// There is a bug here.
|
||||
// Smoothing occurs rather confusingly
|
||||
// during the call to get_camera_transform().
|
||||
// It may be called MULTIPLE TIMES on certain frames,
|
||||
// therefore smoothing is not currently applied only once per frame / tick,
|
||||
// which will result in some haphazard results.
|
||||
if (smoothing_active) {
|
||||
float c = smoothing * (process_mode == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
|
||||
// Note that if we are using physics interpolation,
|
||||
// processing will always be physics based (it ignores the process mode set in the UI).
|
||||
bool physics_process = (process_mode == CAMERA2D_PROCESS_PHYSICS) || is_physics_interpolated_and_enabled();
|
||||
float delta = physics_process ? get_physics_process_delta_time() : get_process_delta_time();
|
||||
float c = smoothing * delta;
|
||||
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
|
||||
ret_camera_pos = smoothed_camera_pos;
|
||||
} else {
|
||||
@ -235,18 +261,51 @@ Transform2D Camera2D::get_camera_transform() {
|
||||
return (xform).affine_inverse();
|
||||
}
|
||||
|
||||
void Camera2D::_ensure_update_interpolation_data() {
|
||||
// The curr -> previous update can either occur
|
||||
// on the INTERNAL_PHYSICS_PROCESS OR
|
||||
// on NOTIFICATION_TRANSFORM_CHANGED,
|
||||
// if NOTIFICATION_TRANSFORM_CHANGED takes place
|
||||
// earlier than INTERNAL_PHYSICS_PROCESS on a tick.
|
||||
// This is to ensure that the data keeps flowing, but the new data
|
||||
// doesn't overwrite before prev has been set.
|
||||
|
||||
// Keep the data flowing.
|
||||
uint64_t tick = Engine::get_singleton()->get_physics_frames();
|
||||
if (_interpolation_data.last_update_physics_tick != tick) {
|
||||
_interpolation_data.xform_prev = _interpolation_data.xform_curr;
|
||||
_interpolation_data.last_update_physics_tick = tick;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera2D::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_INTERNAL_PROCESS:
|
||||
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||
case NOTIFICATION_INTERNAL_PROCESS: {
|
||||
_update_scroll();
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
_ensure_update_interpolation_data();
|
||||
_interpolation_data.xform_curr = get_camera_transform();
|
||||
} else {
|
||||
_update_scroll();
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
||||
// Force the limits etc to update.
|
||||
_interpolation_data.xform_curr = get_camera_transform();
|
||||
_interpolation_data.xform_prev = _interpolation_data.xform_curr;
|
||||
} break;
|
||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||
if (!smoothing_active) {
|
||||
if (!smoothing_active && !is_physics_interpolated_and_enabled()) {
|
||||
_update_scroll();
|
||||
}
|
||||
|
||||
if (is_physics_interpolated_and_enabled()) {
|
||||
_ensure_update_interpolation_data();
|
||||
_interpolation_data.xform_curr = get_camera_transform();
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
ERR_FAIL_COND(!is_inside_tree());
|
||||
@ -420,11 +479,13 @@ void Camera2D::_make_current(Object *p_which) {
|
||||
get_viewport()->_camera_2d_set(this);
|
||||
update();
|
||||
_update_scroll();
|
||||
_update_process_mode();
|
||||
}
|
||||
} else {
|
||||
if (is_inside_tree()) {
|
||||
if (get_viewport()->get_camera_2d() == this) {
|
||||
get_viewport()->_camera_2d_set(nullptr);
|
||||
_update_process_mode();
|
||||
}
|
||||
update();
|
||||
}
|
||||
@ -435,6 +496,7 @@ void Camera2D::make_current() {
|
||||
ERR_FAIL_COND(!enabled || !is_inside_tree());
|
||||
get_tree()->call_group(group_name, "_make_current", this);
|
||||
_update_scroll();
|
||||
_update_process_mode();
|
||||
}
|
||||
|
||||
void Camera2D::clear_current() {
|
||||
@ -442,6 +504,7 @@ void Camera2D::clear_current() {
|
||||
if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
|
||||
viewport->assign_next_enabled_camera_2d(group_name);
|
||||
}
|
||||
_update_process_mode();
|
||||
}
|
||||
|
||||
bool Camera2D::is_current() const {
|
||||
|
@ -84,6 +84,7 @@ protected:
|
||||
void _update_process_mode();
|
||||
void _update_scroll();
|
||||
void _setup_viewport();
|
||||
void _ensure_update_interpolation_data();
|
||||
|
||||
void _make_current(Object *p_which);
|
||||
|
||||
@ -93,6 +94,12 @@ protected:
|
||||
|
||||
Camera2DProcessMode process_mode;
|
||||
|
||||
struct InterpolationData {
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
uint32_t last_update_physics_tick = 0;
|
||||
} _interpolation_data;
|
||||
|
||||
protected:
|
||||
virtual Transform2D get_camera_transform();
|
||||
void _notification(int p_what);
|
||||
|
@ -570,6 +570,10 @@ void CanvasItem::_exit_canvas() {
|
||||
}
|
||||
}
|
||||
|
||||
void CanvasItem::_physics_interpolated_changed() {
|
||||
RenderingServer::get_singleton()->canvas_item_set_interpolated(canvas_item, is_physics_interpolated());
|
||||
}
|
||||
|
||||
void CanvasItem::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
@ -607,6 +611,11 @@ void CanvasItem::_notification(int p_what) {
|
||||
get_parent()->disconnect(SceneStringNames::get_singleton()->child_order_changed, get_viewport(), SceneStringNames::get_singleton()->canvas_parent_mark_dirty);
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
||||
if (is_visible_in_tree() && is_physics_interpolated()) {
|
||||
RenderingServer::get_singleton()->canvas_item_reset_physics_interpolation(canvas_item);
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_DRAW:
|
||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||
} break;
|
||||
|
@ -214,6 +214,7 @@ private:
|
||||
void _exit_canvas();
|
||||
|
||||
void _notify_transform(CanvasItem *p_node);
|
||||
virtual void _physics_interpolated_changed();
|
||||
|
||||
void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); }
|
||||
bool _is_on_top() const { return !is_draw_behind_parent_enabled(); }
|
||||
|
@ -297,22 +297,31 @@ Color Light2D::get_shadow_color() const {
|
||||
return shadow_color;
|
||||
}
|
||||
|
||||
void Light2D::_physics_interpolated_changed() {
|
||||
RenderingServer::get_singleton()->canvas_light_set_interpolated(canvas_light, is_physics_interpolated());
|
||||
}
|
||||
|
||||
void Light2D::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_ENTER_TREE) {
|
||||
RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas());
|
||||
_update_light_visibility();
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
||||
RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform());
|
||||
}
|
||||
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
|
||||
_update_light_visibility();
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_EXIT_TREE) {
|
||||
RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID());
|
||||
_update_light_visibility();
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas());
|
||||
_update_light_visibility();
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID());
|
||||
_update_light_visibility();
|
||||
} break;
|
||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||
RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform());
|
||||
} break;
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
_update_light_visibility();
|
||||
} break;
|
||||
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
||||
if (is_visible_in_tree() && is_physics_interpolated()) {
|
||||
RenderingServer::get_singleton()->canvas_light_reset_physics_interpolation(canvas_light);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +79,7 @@ private:
|
||||
void _update_light_visibility();
|
||||
|
||||
virtual void owner_changed_notify();
|
||||
virtual void _physics_interpolated_changed();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
@ -159,43 +159,52 @@ void LightOccluder2D::_poly_changed() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void LightOccluder2D::_physics_interpolated_changed() {
|
||||
RenderingServer::get_singleton()->canvas_light_occluder_set_interpolated(occluder, is_physics_interpolated());
|
||||
}
|
||||
|
||||
void LightOccluder2D::_notification(int p_what) {
|
||||
if (p_what == NOTIFICATION_ENTER_CANVAS) {
|
||||
RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
|
||||
RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
|
||||
RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
|
||||
}
|
||||
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
|
||||
RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
|
||||
}
|
||||
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
|
||||
RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
|
||||
}
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_CANVAS: {
|
||||
RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
|
||||
RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
|
||||
RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
|
||||
} break;
|
||||
case NOTIFICATION_TRANSFORM_CHANGED: {
|
||||
RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
|
||||
} break;
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree());
|
||||
} break;
|
||||
case NOTIFICATION_DRAW: {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (occluder_polygon.is_valid()) {
|
||||
PoolVector<Vector2> poly = occluder_polygon->get_polygon();
|
||||
|
||||
if (p_what == NOTIFICATION_DRAW) {
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
if (occluder_polygon.is_valid()) {
|
||||
PoolVector<Vector2> poly = occluder_polygon->get_polygon();
|
||||
|
||||
if (poly.size()) {
|
||||
if (occluder_polygon->is_closed()) {
|
||||
Vector<Color> color;
|
||||
color.push_back(Color(0, 0, 0, 0.6));
|
||||
draw_polygon(Variant(poly), color);
|
||||
} else {
|
||||
int ps = poly.size();
|
||||
PoolVector<Vector2>::Read r = poly.read();
|
||||
for (int i = 0; i < ps - 1; i++) {
|
||||
draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3);
|
||||
if (poly.size()) {
|
||||
if (occluder_polygon->is_closed()) {
|
||||
Vector<Color> color;
|
||||
color.push_back(Color(0, 0, 0, 0.6));
|
||||
draw_polygon(Variant(poly), color);
|
||||
} else {
|
||||
int ps = poly.size();
|
||||
PoolVector<Vector2>::Read r = poly.read();
|
||||
for (int i = 0; i < ps - 1; i++) {
|
||||
draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_EXIT_CANVAS) {
|
||||
RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID());
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_CANVAS: {
|
||||
RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID());
|
||||
} break;
|
||||
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
|
||||
if (is_visible_in_tree() && is_physics_interpolated()) {
|
||||
RenderingServer::get_singleton()->canvas_light_occluder_reset_physics_interpolation(occluder);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,7 @@ class LightOccluder2D : public Node2D {
|
||||
Ref<OccluderPolygon2D> occluder_polygon;
|
||||
|
||||
void _poly_changed();
|
||||
virtual void _physics_interpolated_changed();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
@ -163,4 +163,7 @@ void ParallaxLayer::_bind_methods() {
|
||||
|
||||
ParallaxLayer::ParallaxLayer() {
|
||||
motion_scale = Size2(1, 1);
|
||||
|
||||
// ParallaxLayer is always updated every frame so there is no need to interpolate.
|
||||
set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF);
|
||||
}
|
||||
|
@ -3008,6 +3008,8 @@ Control::Control() {
|
||||
}
|
||||
data.focus_mode = FOCUS_NONE;
|
||||
data.modal_prev_focus_owner = 0;
|
||||
|
||||
set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF);
|
||||
}
|
||||
|
||||
Control::~Control() {
|
||||
|
@ -603,6 +603,12 @@ void SceneTree::client_physics_interpolation_remove_spatial(SelfList<Spatial> *p
|
||||
_client_physics_interpolation._spatials_list.remove(p_elem);
|
||||
}
|
||||
|
||||
void SceneTree::iteration_prepare() {
|
||||
if (_physics_interpolation_enabled) {
|
||||
RenderingServer::get_singleton()->tick();
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::iteration_end() {
|
||||
// When physics interpolation is active, we want all pending transforms
|
||||
// to be flushed to the RenderingServer before finishing a physics tick.
|
||||
@ -616,10 +622,6 @@ bool SceneTree::iteration(float p_time) {
|
||||
|
||||
current_frame++;
|
||||
|
||||
if (_physics_interpolation_enabled) {
|
||||
RenderingServer::get_singleton()->tick();
|
||||
}
|
||||
|
||||
// Any objects performing client physics interpolation
|
||||
// should be given an opportunity to keep their previous transforms
|
||||
// up to take before each new physics tick.
|
||||
|
@ -313,6 +313,7 @@ public:
|
||||
virtual void input_event(const Ref<InputEvent> &p_event);
|
||||
virtual void init();
|
||||
|
||||
virtual void iteration_prepare();
|
||||
virtual bool iteration(float p_time);
|
||||
virtual void iteration_end();
|
||||
virtual bool idle(float p_time);
|
||||
|
@ -590,9 +590,12 @@ public:
|
||||
};
|
||||
|
||||
struct Light : public RID_Data {
|
||||
bool enabled;
|
||||
bool enabled : 1;
|
||||
bool on_interpolate_transform_list : 1;
|
||||
bool interpolated : 1;
|
||||
Color color;
|
||||
Transform2D xform;
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
float height;
|
||||
float energy;
|
||||
float scale;
|
||||
@ -631,6 +634,8 @@ public:
|
||||
|
||||
Light() {
|
||||
enabled = true;
|
||||
on_interpolate_transform_list = false;
|
||||
interpolated = true;
|
||||
color = Color(1, 1, 1);
|
||||
shadow_color = Color(0, 0, 0, 0);
|
||||
height = 0;
|
||||
@ -837,13 +842,19 @@ public:
|
||||
Rect2 rect;
|
||||
};
|
||||
|
||||
Transform2D xform;
|
||||
// For interpolation we store the current local xform,
|
||||
// and the previous xform from the previous tick.
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
|
||||
bool clip : 1;
|
||||
bool visible : 1;
|
||||
bool behind : 1;
|
||||
bool update_when_visible : 1;
|
||||
bool distance_field : 1;
|
||||
bool light_masked : 1;
|
||||
bool on_interpolate_transform_list : 1;
|
||||
bool interpolated : 1;
|
||||
mutable bool custom_rect : 1;
|
||||
mutable bool rect_dirty : 1;
|
||||
mutable bool bound_dirty : 1;
|
||||
@ -890,6 +901,13 @@ public:
|
||||
// in local space.
|
||||
Rect2 local_bound;
|
||||
|
||||
// When using interpolation, the local bound for culling
|
||||
// should be a combined bound of the previous and current.
|
||||
// To keep this up to date, we need to keep track of the previous
|
||||
// bound separately rather than just the combined bound.
|
||||
Rect2 local_bound_prev;
|
||||
uint32_t local_bound_last_update_tick;
|
||||
|
||||
const Rect2 &get_rect() const {
|
||||
if (custom_rect) {
|
||||
return rect;
|
||||
@ -1049,6 +1067,8 @@ public:
|
||||
memdelete(skinning_data);
|
||||
skinning_data = NULL;
|
||||
}
|
||||
|
||||
on_interpolate_transform_list = false;
|
||||
}
|
||||
|
||||
Item() {
|
||||
@ -1070,6 +1090,9 @@ public:
|
||||
distance_field = false;
|
||||
light_masked = false;
|
||||
update_when_visible = false;
|
||||
on_interpolate_transform_list = false;
|
||||
interpolated = true;
|
||||
local_bound_last_update_tick = 0;
|
||||
}
|
||||
|
||||
virtual ~Item() {
|
||||
@ -1089,12 +1112,15 @@ public:
|
||||
virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
|
||||
|
||||
struct LightOccluderInstance : public RID_Data {
|
||||
bool enabled;
|
||||
bool enabled : 1;
|
||||
bool on_interpolate_transform_list : 1;
|
||||
bool interpolated : 1;
|
||||
RID canvas;
|
||||
RID polygon;
|
||||
RID polygon_buffer;
|
||||
Rect2 aabb_cache;
|
||||
Transform2D xform;
|
||||
Transform2D xform_curr;
|
||||
Transform2D xform_prev;
|
||||
Transform2D xform_cache;
|
||||
int light_mask;
|
||||
RS::CanvasOccluderPolygonCullMode cull_cache;
|
||||
@ -1106,6 +1132,8 @@ public:
|
||||
next = nullptr;
|
||||
light_mask = 1;
|
||||
cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
|
||||
on_interpolate_transform_list = false;
|
||||
interpolated = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
#include "core/math/transform_interpolator.h"
|
||||
|
||||
#include "rendering_server_canvas.h"
|
||||
#include "rendering_server_globals.h"
|
||||
#include "rendering_server_raster.h"
|
||||
@ -67,7 +69,7 @@ void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transfo
|
||||
r_items[r_index] = child_items[i];
|
||||
child_items[i]->ysort_modulate = p_modulate;
|
||||
child_items[i]->ysort_xform = p_transform;
|
||||
child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]);
|
||||
child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform_curr.columns[2]);
|
||||
child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
|
||||
child_items[i]->ysort_index = r_index;
|
||||
}
|
||||
@ -76,7 +78,7 @@ void _collect_ysort_children(RenderingServerCanvas::Item *p_canvas_item, Transfo
|
||||
|
||||
if (child_items[i]->sort_y) {
|
||||
_collect_ysort_children(child_items[i],
|
||||
p_transform * child_items[i]->xform,
|
||||
p_transform * child_items[i]->xform_curr,
|
||||
child_items[i]->use_parent_material ? p_material_owner : child_items[i],
|
||||
p_modulate * child_items[i]->modulate,
|
||||
r_items, r_index);
|
||||
@ -243,6 +245,37 @@ void RenderingServerCanvas::_calculate_canvas_item_bound(Item *p_canvas_item, Re
|
||||
}
|
||||
|
||||
_finalize_and_merge_local_bound_to_branch(ci, r_branch_bound);
|
||||
|
||||
// If we are interpolating, we want to modify the local_bound (combined)
|
||||
// to include both the previous AND current bounds.
|
||||
if (local_bound && _interpolation_data.interpolation_enabled && ci->interpolated) {
|
||||
Rect2 bound_prev = ci->local_bound_prev;
|
||||
|
||||
// Keep track of the previously assigned exact bound for the next tick.
|
||||
ci->local_bound_prev = ci->local_bound;
|
||||
|
||||
// The combined bound is the exact current bound merged with the previous exact bound.
|
||||
ci->local_bound = ci->local_bound.merge(bound_prev);
|
||||
|
||||
// This can overflow, it's no problem, it is just rough to detect when items stop
|
||||
// having local bounds updated, so we can set prev to curr.
|
||||
ci->local_bound_last_update_tick = Engine::get_singleton()->get_physics_frames();
|
||||
|
||||
// Detect special case of overflow.
|
||||
// This is omitted but included for reference.
|
||||
// It is such a rare possibility, and even if it did occur
|
||||
// so it should just result in slightly larger culling bounds
|
||||
// probably for one tick (and no visual errors).
|
||||
// Would occur once every 828.5 days at 60 ticks per second
|
||||
// with uint32_t counter.
|
||||
#if 0
|
||||
if (!ci->local_bound_last_update_tick) {
|
||||
// Prevents it being treated as non-dirty.
|
||||
// Just has an increased delay of one tick in this very rare occurrence.
|
||||
ci->local_bound_last_update_tick = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::_finalize_and_merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound) {
|
||||
@ -277,7 +310,7 @@ void RenderingServerCanvas::_merge_local_bound_to_branch(Item *p_canvas_item, Re
|
||||
return;
|
||||
}
|
||||
|
||||
Rect2 this_item_total_local_bound = p_canvas_item->xform.xform(p_canvas_item->local_bound);
|
||||
Rect2 this_item_total_local_bound = p_canvas_item->xform_curr.xform(p_canvas_item->local_bound);
|
||||
|
||||
if (!r_branch_bound->has_no_area()) {
|
||||
*r_branch_bound = r_branch_bound->merge(this_item_total_local_bound);
|
||||
@ -299,10 +332,16 @@ void RenderingServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item
|
||||
}
|
||||
|
||||
Rect2 rect = ci->get_rect();
|
||||
Transform2D xform = ci->xform;
|
||||
xform = p_transform * xform;
|
||||
Transform2D final_xform;
|
||||
if (!_interpolation_data.interpolation_enabled || !ci->interpolated) {
|
||||
final_xform = ci->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f);
|
||||
}
|
||||
final_xform = p_transform * final_xform;
|
||||
|
||||
Rect2 global_rect = xform.xform(rect);
|
||||
Rect2 global_rect = final_xform.xform(rect);
|
||||
global_rect.position += p_clip_rect.position;
|
||||
|
||||
if (ci->use_parent_material && p_material_owner) {
|
||||
@ -362,14 +401,14 @@ void RenderingServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item
|
||||
continue;
|
||||
}
|
||||
if (ci->sort_y) {
|
||||
_render_canvas_item_cull_by_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
|
||||
_render_canvas_item_cull_by_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
|
||||
} else {
|
||||
_render_canvas_item_cull_by_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
|
||||
_render_canvas_item_cull_by_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (ci->copy_back_buffer) {
|
||||
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);
|
||||
ci->copy_back_buffer->screen_rect = final_xform.xform(ci->copy_back_buffer->rect).clip(p_clip_rect);
|
||||
}
|
||||
|
||||
if (ci->update_when_visible) {
|
||||
@ -378,7 +417,7 @@ void RenderingServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item
|
||||
|
||||
if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
|
||||
//something to draw?
|
||||
ci->final_transform = xform;
|
||||
ci->final_transform = final_xform;
|
||||
ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a);
|
||||
ci->global_rect_cache = global_rect;
|
||||
ci->global_rect_cache.position -= p_clip_rect.position;
|
||||
@ -403,9 +442,9 @@ void RenderingServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item
|
||||
continue;
|
||||
}
|
||||
if (ci->sort_y) {
|
||||
_render_canvas_item_cull_by_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
|
||||
_render_canvas_item_cull_by_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
|
||||
} else {
|
||||
_render_canvas_item_cull_by_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
|
||||
_render_canvas_item_cull_by_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -420,9 +459,23 @@ void RenderingServerCanvas::_render_canvas_item_cull_by_node(Item *p_canvas_item
|
||||
// This should have been calculated as a pre-process.
|
||||
DEV_ASSERT(!ci->bound_dirty);
|
||||
|
||||
// If we are interpolating, and the updates have stopped, we can reduce the local bound.
|
||||
if (ci->local_bound_last_update_tick && (ci->local_bound_last_update_tick != Engine::get_singleton()->get_physics_frames())) {
|
||||
// The combined bound is reduced to the last calculated exact bound.
|
||||
ci->local_bound = ci->local_bound_prev;
|
||||
ci->local_bound_last_update_tick = 0;
|
||||
}
|
||||
|
||||
Rect2 rect = ci->get_rect();
|
||||
|
||||
Transform2D final_xform = ci->xform;
|
||||
Transform2D final_xform;
|
||||
if (!_interpolation_data.interpolation_enabled || !ci->interpolated) {
|
||||
final_xform = ci->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f);
|
||||
}
|
||||
|
||||
final_xform = p_transform * final_xform;
|
||||
|
||||
Rect2 global_rect = final_xform.xform(rect);
|
||||
@ -828,7 +881,25 @@ void RenderingServerCanvas::canvas_item_set_transform(RID p_item, const Transfor
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
|
||||
canvas_item->xform = p_transform;
|
||||
if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) {
|
||||
if (!canvas_item->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item);
|
||||
canvas_item->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size());
|
||||
}
|
||||
}
|
||||
|
||||
if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) {
|
||||
if (!canvas_item->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item);
|
||||
canvas_item->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size());
|
||||
}
|
||||
}
|
||||
|
||||
canvas_item->xform_curr = p_transform;
|
||||
|
||||
// Special case!
|
||||
// Modifying the transform DOES NOT affect the local bound.
|
||||
@ -1421,6 +1492,64 @@ void RenderingServerCanvas::canvas_item_set_skeleton_relative_xform(RID p_item,
|
||||
}
|
||||
}
|
||||
|
||||
// Useful especially for origin shifting.
|
||||
void RenderingServerCanvas::canvas_item_transform_physics_interpolation(RID p_item, Transform2D p_transform) {
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
canvas_item->xform_prev = p_transform * canvas_item->xform_prev;
|
||||
canvas_item->xform_curr = p_transform * canvas_item->xform_curr;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_item_reset_physics_interpolation(RID p_item) {
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
canvas_item->xform_prev = canvas_item->xform_curr;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_item_set_interpolated(RID p_item, bool p_interpolated) {
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
canvas_item->interpolated = p_interpolated;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_set_interpolated(RID p_light, bool p_interpolated) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
clight->interpolated = p_interpolated;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_reset_physics_interpolation(RID p_light) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
clight->xform_prev = clight->xform_curr;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_transform_physics_interpolation(RID p_light, Transform2D p_transform) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
clight->xform_prev = p_transform * clight->xform_prev;
|
||||
clight->xform_curr = p_transform * clight->xform_curr;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) {
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
||||
ERR_FAIL_COND(!occluder);
|
||||
occluder->interpolated = p_interpolated;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) {
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
||||
ERR_FAIL_COND(!occluder);
|
||||
occluder->xform_prev = occluder->xform_curr;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, Transform2D p_transform) {
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
||||
ERR_FAIL_COND(!occluder);
|
||||
occluder->xform_prev = p_transform * occluder->xform_prev;
|
||||
occluder->xform_curr = p_transform * occluder->xform_curr;
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
|
||||
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
@ -1560,7 +1689,16 @@ void RenderingServerCanvas::canvas_light_set_transform(RID p_light, const Transf
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
||||
ERR_FAIL_COND(!clight);
|
||||
|
||||
clight->xform = p_transform;
|
||||
if (_interpolation_data.interpolation_enabled && clight->interpolated) {
|
||||
if (!clight->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_light_transform_update_list_curr->push_back(p_light);
|
||||
clight->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_light_transform_update_list_curr->size());
|
||||
}
|
||||
}
|
||||
|
||||
clight->xform_curr = p_transform;
|
||||
}
|
||||
void RenderingServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) {
|
||||
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
||||
@ -1747,7 +1885,16 @@ void RenderingServerCanvas::canvas_light_occluder_set_transform(RID p_occluder,
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
||||
ERR_FAIL_COND(!occluder);
|
||||
|
||||
occluder->xform = p_xform;
|
||||
if (_interpolation_data.interpolation_enabled && occluder->interpolated) {
|
||||
if (!occluder->on_interpolate_transform_list) {
|
||||
_interpolation_data.canvas_light_occluder_transform_update_list_curr->push_back(p_occluder);
|
||||
occluder->on_interpolate_transform_list = true;
|
||||
} else {
|
||||
DEV_ASSERT(_interpolation_data.canvas_light_occluder_transform_update_list_curr->size());
|
||||
}
|
||||
}
|
||||
|
||||
occluder->xform_curr = p_xform;
|
||||
}
|
||||
void RenderingServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
||||
@ -1857,7 +2004,8 @@ bool RenderingServerCanvas::free(RID p_rid) {
|
||||
} else if (canvas_item_owner.owns(p_rid)) {
|
||||
Item *canvas_item = canvas_item_owner.get(p_rid);
|
||||
ERR_FAIL_COND_V(!canvas_item, true);
|
||||
_make_bound_dirty(canvas_item);
|
||||
_make_bound_dirty(canvas_item);
|
||||
_interpolation_data.notify_free_canvas_item(p_rid, *canvas_item);
|
||||
|
||||
if (canvas_item->parent.is_valid()) {
|
||||
if (canvas_owner.owns(canvas_item->parent)) {
|
||||
@ -1891,6 +2039,7 @@ bool RenderingServerCanvas::free(RID p_rid) {
|
||||
} else if (canvas_light_owner.owns(p_rid)) {
|
||||
RasterizerCanvas::Light *canvas_light = canvas_light_owner.get(p_rid);
|
||||
ERR_FAIL_COND_V(!canvas_light, true);
|
||||
_interpolation_data.notify_free_canvas_light(p_rid, *canvas_light);
|
||||
|
||||
if (canvas_light->canvas.is_valid()) {
|
||||
Canvas *canvas = canvas_owner.get(canvas_light->canvas);
|
||||
@ -1911,6 +2060,7 @@ bool RenderingServerCanvas::free(RID p_rid) {
|
||||
} else if (canvas_light_occluder_owner.owns(p_rid)) {
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid);
|
||||
ERR_FAIL_COND_V(!occluder, true);
|
||||
_interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder);
|
||||
|
||||
if (occluder->polygon.is_valid()) {
|
||||
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon);
|
||||
@ -2043,6 +2193,83 @@ void RenderingServerCanvas::_print_tree_down(int p_child_id, int p_depth, const
|
||||
|
||||
#endif
|
||||
|
||||
void RenderingServerCanvas::tick() {
|
||||
if (_interpolation_data.interpolation_enabled) {
|
||||
update_interpolation_tick(true);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::update_interpolation_tick(bool p_process) {
|
||||
#define PANDEMONIUM_UPDATE_INTERPOLATION_TICK(LIST_PREV, LIST_CURR, TYPE, OWNER_LIST) \
|
||||
/* Detect any that were on the previous transform list that are no longer active. */ \
|
||||
for (unsigned int n = 0; n < _interpolation_data.LIST_PREV->size(); n++) { \
|
||||
const RID &rid = (*_interpolation_data.LIST_PREV)[n]; \
|
||||
TYPE *item = OWNER_LIST.getornull(rid); \
|
||||
/* no longer active? (either the instance deleted or no longer being transformed) */ \
|
||||
if (item && !item->on_interpolate_transform_list) { \
|
||||
item->xform_prev = item->xform_curr; \
|
||||
} \
|
||||
} \
|
||||
/* and now for any in the transform list (being actively interpolated), */ \
|
||||
/* keep the previous transform value up to date and ready for next tick */ \
|
||||
if (p_process) { \
|
||||
for (unsigned int n = 0; n < _interpolation_data.LIST_CURR->size(); n++) { \
|
||||
const RID &rid = (*_interpolation_data.LIST_CURR)[n]; \
|
||||
TYPE *item = OWNER_LIST.getornull(rid); \
|
||||
if (item) { \
|
||||
item->xform_prev = item->xform_curr; \
|
||||
item->on_interpolate_transform_list = false; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
SWAP(_interpolation_data.LIST_CURR, _interpolation_data.LIST_PREV); \
|
||||
_interpolation_data.LIST_CURR->clear();
|
||||
|
||||
PANDEMONIUM_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner);
|
||||
PANDEMONIUM_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RasterizerCanvas::Light, canvas_light_owner);
|
||||
PANDEMONIUM_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RasterizerCanvas::LightOccluderInstance, canvas_light_occluder_owner);
|
||||
|
||||
#undef PANDEMONIUM_UPDATE_INTERPOLATION_TICK
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::InterpolationData::notify_free_canvas_item(RID p_rid, RenderingServerCanvas::Item &r_canvas_item) {
|
||||
r_canvas_item.on_interpolate_transform_list = false;
|
||||
|
||||
if (!interpolation_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance was on any of the lists, remove.
|
||||
canvas_item_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||
canvas_item_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::InterpolationData::notify_free_canvas_light(RID p_rid, RasterizerCanvas::Light &r_canvas_light) {
|
||||
r_canvas_light.on_interpolate_transform_list = false;
|
||||
|
||||
if (!interpolation_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance was on any of the lists, remove.
|
||||
canvas_light_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||
canvas_light_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||
}
|
||||
|
||||
void RenderingServerCanvas::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RasterizerCanvas::LightOccluderInstance &r_canvas_light_occluder) {
|
||||
r_canvas_light_occluder.on_interpolate_transform_list = false;
|
||||
|
||||
if (!interpolation_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance was on any of the lists, remove.
|
||||
canvas_light_occluder_transform_update_list_curr->erase_multiple_unordered(p_rid);
|
||||
canvas_light_occluder_transform_update_list_prev->erase_multiple_unordered(p_rid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
RenderingServerCanvas::RenderingServerCanvas() {
|
||||
_canvas_cull_mode = CANVAS_CULL_MODE_NODE;
|
||||
|
||||
|
@ -256,9 +256,13 @@ public:
|
||||
void canvas_item_set_use_parent_material(RID p_item, bool p_enable);
|
||||
|
||||
void canvas_item_attach_skeleton(RID p_item, RID p_skeleton);
|
||||
void _canvas_item_skeleton_moved(RID p_item);
|
||||
void canvas_item_set_skeleton_relative_xform(RID p_item, Transform2D p_relative_xform);
|
||||
Rect2 _debug_canvas_item_get_rect(RID p_item);
|
||||
void _canvas_item_skeleton_moved(RID p_item);
|
||||
|
||||
void canvas_item_set_interpolated(RID p_item, bool p_interpolated);
|
||||
void canvas_item_reset_physics_interpolation(RID p_item);
|
||||
void canvas_item_transform_physics_interpolation(RID p_item, Transform2D p_transform);
|
||||
|
||||
RID canvas_light_create();
|
||||
void canvas_light_attach_to_canvas(RID p_light, RID p_canvas);
|
||||
@ -274,9 +278,7 @@ public:
|
||||
void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer);
|
||||
void canvas_light_set_item_cull_mask(RID p_light, int p_mask);
|
||||
void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask);
|
||||
|
||||
void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode);
|
||||
|
||||
void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
|
||||
void canvas_light_set_shadow_buffer_size(RID p_light, int p_size);
|
||||
void canvas_light_set_shadow_gradient_length(RID p_light, float p_length);
|
||||
@ -284,6 +286,10 @@ public:
|
||||
void canvas_light_set_shadow_color(RID p_light, const Color &p_color);
|
||||
void canvas_light_set_shadow_smooth(RID p_light, float p_smooth);
|
||||
|
||||
void canvas_light_set_interpolated(RID p_light, bool p_interpolated);
|
||||
void canvas_light_reset_physics_interpolation(RID p_light);
|
||||
void canvas_light_transform_physics_interpolation(RID p_light, Transform2D p_transform);
|
||||
|
||||
RID canvas_light_occluder_create();
|
||||
void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas);
|
||||
void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled);
|
||||
@ -291,6 +297,10 @@ public:
|
||||
void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform);
|
||||
void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask);
|
||||
|
||||
void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated);
|
||||
void canvas_light_occluder_reset_physics_interpolation(RID p_occluder);
|
||||
void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, Transform2D p_transform);
|
||||
|
||||
RID canvas_occluder_polygon_create();
|
||||
void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const PoolVector<Vector2> &p_shape, bool p_closed);
|
||||
void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const PoolVector<Vector2> &p_shape);
|
||||
@ -298,6 +308,32 @@ public:
|
||||
void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode);
|
||||
|
||||
bool free(RID p_rid);
|
||||
|
||||
// Interpolation
|
||||
void tick();
|
||||
void update_interpolation_tick(bool p_process = true);
|
||||
void set_physics_interpolation_enabled(bool p_enabled) { _interpolation_data.interpolation_enabled = p_enabled; }
|
||||
|
||||
struct InterpolationData {
|
||||
void notify_free_canvas_item(RID p_rid, RenderingServerCanvas::Item &r_canvas_item);
|
||||
void notify_free_canvas_light(RID p_rid, RasterizerCanvas::Light &r_canvas_light);
|
||||
void notify_free_canvas_light_occluder(RID p_rid, RasterizerCanvas::LightOccluderInstance &r_canvas_light_occluder);
|
||||
|
||||
LocalVector<RID> canvas_item_transform_update_lists[2];
|
||||
LocalVector<RID> *canvas_item_transform_update_list_curr = &canvas_item_transform_update_lists[0];
|
||||
LocalVector<RID> *canvas_item_transform_update_list_prev = &canvas_item_transform_update_lists[1];
|
||||
|
||||
LocalVector<RID> canvas_light_transform_update_lists[2];
|
||||
LocalVector<RID> *canvas_light_transform_update_list_curr = &canvas_light_transform_update_lists[0];
|
||||
LocalVector<RID> *canvas_light_transform_update_list_prev = &canvas_light_transform_update_lists[1];
|
||||
|
||||
LocalVector<RID> canvas_light_occluder_transform_update_lists[2];
|
||||
LocalVector<RID> *canvas_light_occluder_transform_update_list_curr = &canvas_light_occluder_transform_update_lists[0];
|
||||
LocalVector<RID> *canvas_light_occluder_transform_update_list_prev = &canvas_light_occluder_transform_update_lists[1];
|
||||
|
||||
bool interpolation_enabled = false;
|
||||
} _interpolation_data;
|
||||
|
||||
RenderingServerCanvas();
|
||||
~RenderingServerCanvas();
|
||||
};
|
||||
|
@ -135,6 +135,20 @@ void RenderingServerRaster::draw(bool p_swap_buffers, double frame_step) {
|
||||
void RenderingServerRaster::sync() {
|
||||
}
|
||||
|
||||
void RenderingServerRaster::set_physics_interpolation_enabled(bool p_enabled) {
|
||||
RSG::scene->set_physics_interpolation_enabled(p_enabled);
|
||||
RSG::canvas->set_physics_interpolation_enabled(p_enabled);
|
||||
}
|
||||
|
||||
void RenderingServerRaster::tick() {
|
||||
RSG::scene->tick();
|
||||
RSG::canvas->tick();
|
||||
}
|
||||
|
||||
void RenderingServerRaster::pre_draw(bool p_will_draw) {
|
||||
RSG::scene->pre_draw(p_will_draw);
|
||||
}
|
||||
|
||||
bool RenderingServerRaster::has_changed(ChangedPriority p_priority) const {
|
||||
switch (p_priority) {
|
||||
default: {
|
||||
|
@ -361,11 +361,6 @@ public:
|
||||
//from now on, calls forwarded to this singleton
|
||||
#define BINDBASE RSG::scene
|
||||
|
||||
/* EVENT QUEUING */
|
||||
|
||||
BIND0N(tick)
|
||||
BIND1N(pre_draw, bool)
|
||||
|
||||
/* CAMERA API */
|
||||
|
||||
BIND0R(RID, camera_create)
|
||||
@ -466,10 +461,6 @@ public:
|
||||
#undef BINDBASE
|
||||
#define BINDBASE RSG::scene
|
||||
|
||||
/* INTERPOLATION */
|
||||
|
||||
BIND1(set_physics_interpolation_enabled, bool)
|
||||
|
||||
/* SCENARIO API */
|
||||
|
||||
BIND0R(RID, scenario_create)
|
||||
@ -503,7 +494,7 @@ public:
|
||||
BIND2(instance_set_extra_visibility_margin, RID, real_t)
|
||||
|
||||
/* PORTALS */
|
||||
|
||||
|
||||
BIND2(instance_set_portal_mode, RID, InstancePortalMode)
|
||||
|
||||
BIND0R(RID, ghost_create)
|
||||
@ -524,7 +515,7 @@ public:
|
||||
BIND2(roomgroup_add_room, RID, RID)
|
||||
|
||||
/* OCCLUDERS */
|
||||
|
||||
|
||||
BIND0R(RID, occluder_instance_create)
|
||||
BIND2(occluder_instance_set_scenario, RID, RID)
|
||||
BIND2(occluder_instance_link_resource, RID, RID)
|
||||
@ -624,16 +615,18 @@ public:
|
||||
BIND2(canvas_item_set_z_index, RID, int)
|
||||
BIND2(canvas_item_set_z_as_relative_to_parent, RID, bool)
|
||||
BIND3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &)
|
||||
BIND1(canvas_item_clear, RID)
|
||||
BIND2(canvas_item_set_draw_index, RID, int)
|
||||
BIND2(canvas_item_set_material, RID, RID)
|
||||
BIND2(canvas_item_set_use_parent_material, RID, bool)
|
||||
|
||||
BIND2(canvas_item_attach_skeleton, RID, RID)
|
||||
BIND2(canvas_item_set_skeleton_relative_xform, RID, Transform2D)
|
||||
BIND1R(Rect2, _debug_canvas_item_get_rect, RID)
|
||||
|
||||
BIND1(canvas_item_clear, RID)
|
||||
BIND2(canvas_item_set_draw_index, RID, int)
|
||||
|
||||
BIND2(canvas_item_set_material, RID, RID)
|
||||
|
||||
BIND2(canvas_item_set_use_parent_material, RID, bool)
|
||||
BIND2(canvas_item_set_interpolated, RID, bool)
|
||||
BIND1(canvas_item_reset_physics_interpolation, RID)
|
||||
BIND2(canvas_item_transform_physics_interpolation, RID, Transform2D)
|
||||
|
||||
BIND0R(RID, canvas_light_create)
|
||||
BIND2(canvas_light_attach_to_canvas, RID, RID)
|
||||
@ -659,6 +652,10 @@ public:
|
||||
BIND2(canvas_light_set_shadow_color, RID, const Color &)
|
||||
BIND2(canvas_light_set_shadow_smooth, RID, float)
|
||||
|
||||
BIND2(canvas_light_set_interpolated, RID, bool)
|
||||
BIND1(canvas_light_reset_physics_interpolation, RID)
|
||||
BIND2(canvas_light_transform_physics_interpolation, RID, Transform2D)
|
||||
|
||||
BIND0R(RID, canvas_light_occluder_create)
|
||||
BIND2(canvas_light_occluder_attach_to_canvas, RID, RID)
|
||||
BIND2(canvas_light_occluder_set_enabled, RID, bool)
|
||||
@ -666,6 +663,10 @@ public:
|
||||
BIND2(canvas_light_occluder_set_transform, RID, const Transform2D &)
|
||||
BIND2(canvas_light_occluder_set_light_mask, RID, int)
|
||||
|
||||
BIND2(canvas_light_occluder_set_interpolated, RID, bool)
|
||||
BIND1(canvas_light_occluder_reset_physics_interpolation, RID)
|
||||
BIND2(canvas_light_occluder_transform_physics_interpolation, RID, Transform2D)
|
||||
|
||||
BIND0R(RID, canvas_occluder_polygon_create)
|
||||
BIND3(canvas_occluder_polygon_set_shape, RID, const PoolVector<Vector2> &, bool)
|
||||
BIND2(canvas_occluder_polygon_set_shape_as_lines, RID, const PoolVector<Vector2> &)
|
||||
@ -685,12 +686,16 @@ public:
|
||||
|
||||
virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata);
|
||||
|
||||
virtual void tick();
|
||||
virtual void pre_draw(bool p_will_draw);
|
||||
virtual void draw(bool p_swap_buffers, double frame_step);
|
||||
virtual void sync();
|
||||
virtual bool has_changed(ChangedPriority p_priority = CHANGED_PRIORITY_ANY) const;
|
||||
virtual void init();
|
||||
virtual void finish();
|
||||
|
||||
virtual void set_physics_interpolation_enabled(bool p_enabled);
|
||||
|
||||
/* STATUS INFORMATION */
|
||||
|
||||
virtual uint64_t get_render_info(RenderInfo p_info);
|
||||
|
@ -126,7 +126,14 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport) {
|
||||
|
||||
Vector2 offset = tsize / 2.0;
|
||||
cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize);
|
||||
cl->xform_cache = xf * cl->xform;
|
||||
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
|
||||
cl->xform_cache = xf * cl->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
|
||||
cl->xform_cache = xf * cl->xform_cache;
|
||||
}
|
||||
|
||||
if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) {
|
||||
cl->filter_next_ptr = lights;
|
||||
@ -171,13 +178,22 @@ void RenderingServerViewport::_draw_viewport(Viewport *p_viewport) {
|
||||
Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
|
||||
|
||||
for (RBSet<RasterizerCanvas::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) {
|
||||
if (!F->get()->enabled) {
|
||||
RasterizerCanvas::LightOccluderInstance *occluder = F->get();
|
||||
if (!occluder->enabled) {
|
||||
continue;
|
||||
}
|
||||
F->get()->xform_cache = xf * F->get()->xform;
|
||||
if (shadow_rect.intersects_transformed(F->get()->xform_cache, F->get()->aabb_cache)) {
|
||||
F->get()->next = occluders;
|
||||
occluders = F->get();
|
||||
|
||||
if (!RSG::canvas->_interpolation_data.interpolation_enabled || !occluder->interpolated) {
|
||||
occluder->xform_cache = xf * occluder->xform_curr;
|
||||
} else {
|
||||
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
|
||||
TransformInterpolator::interpolate_transform_2d(occluder->xform_prev, occluder->xform_curr, occluder->xform_cache, f);
|
||||
occluder->xform_cache = xf * occluder->xform_cache;
|
||||
}
|
||||
|
||||
if (shadow_rect.intersects_transformed(occluder->xform_cache, occluder->aabb_cache)) {
|
||||
occluder->next = occluders;
|
||||
occluders = occluder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,30 @@ void RenderingServerWrapMT::thread_loop() {
|
||||
|
||||
/* EVENT QUEUING */
|
||||
|
||||
void RenderingServerWrapMT::set_physics_interpolation_enabled(bool p_enabled) {
|
||||
if (Thread::get_caller_id() != server_thread) {
|
||||
command_queue.push(rendering_server, &RenderingServer::set_physics_interpolation_enabled, p_enabled);
|
||||
} else {
|
||||
rendering_server->set_physics_interpolation_enabled(p_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerWrapMT::tick() {
|
||||
if (Thread::get_caller_id() != server_thread) {
|
||||
command_queue.push(rendering_server, &RenderingServer::tick);
|
||||
} else {
|
||||
rendering_server->tick();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerWrapMT::pre_draw(bool p_will_draw) {
|
||||
if (Thread::get_caller_id() != server_thread) {
|
||||
command_queue.push(rendering_server, &RenderingServer::pre_draw, p_will_draw);
|
||||
} else {
|
||||
rendering_server->pre_draw(p_will_draw);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingServerWrapMT::sync() {
|
||||
if (create_thread) {
|
||||
draw_pending.increment();
|
||||
|
@ -374,10 +374,6 @@ public:
|
||||
FUNC7(environment_set_fog_depth, RID, bool, float, float, float, bool, float)
|
||||
FUNC5(environment_set_fog_height, RID, bool, float, float, float)
|
||||
|
||||
/* INTERPOLATION API */
|
||||
|
||||
FUNC1(set_physics_interpolation_enabled, bool)
|
||||
|
||||
/* SCENARIO API */
|
||||
|
||||
FUNCRID(scenario)
|
||||
@ -527,16 +523,18 @@ public:
|
||||
FUNC2(canvas_item_set_z_index, RID, int)
|
||||
FUNC2(canvas_item_set_z_as_relative_to_parent, RID, bool)
|
||||
FUNC3(canvas_item_set_copy_to_backbuffer, RID, bool, const Rect2 &)
|
||||
FUNC1(canvas_item_clear, RID)
|
||||
FUNC2(canvas_item_set_draw_index, RID, int)
|
||||
FUNC2(canvas_item_set_material, RID, RID)
|
||||
FUNC2(canvas_item_set_use_parent_material, RID, bool)
|
||||
|
||||
FUNC2(canvas_item_attach_skeleton, RID, RID)
|
||||
FUNC2(canvas_item_set_skeleton_relative_xform, RID, Transform2D)
|
||||
FUNC1R(Rect2, _debug_canvas_item_get_rect, RID)
|
||||
|
||||
FUNC1(canvas_item_clear, RID)
|
||||
FUNC2(canvas_item_set_draw_index, RID, int)
|
||||
|
||||
FUNC2(canvas_item_set_material, RID, RID)
|
||||
|
||||
FUNC2(canvas_item_set_use_parent_material, RID, bool)
|
||||
FUNC2(canvas_item_set_interpolated, RID, bool)
|
||||
FUNC1(canvas_item_reset_physics_interpolation, RID)
|
||||
FUNC2(canvas_item_transform_physics_interpolation, RID, Transform2D)
|
||||
|
||||
FUNC0R(RID, canvas_light_create)
|
||||
FUNC2(canvas_light_attach_to_canvas, RID, RID)
|
||||
@ -562,6 +560,10 @@ public:
|
||||
FUNC2(canvas_light_set_shadow_color, RID, const Color &)
|
||||
FUNC2(canvas_light_set_shadow_smooth, RID, float)
|
||||
|
||||
FUNC2(canvas_light_set_interpolated, RID, bool)
|
||||
FUNC1(canvas_light_reset_physics_interpolation, RID)
|
||||
FUNC2(canvas_light_transform_physics_interpolation, RID, Transform2D)
|
||||
|
||||
FUNCRID(canvas_light_occluder)
|
||||
FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID)
|
||||
FUNC2(canvas_light_occluder_set_enabled, RID, bool)
|
||||
@ -569,6 +571,10 @@ public:
|
||||
FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &)
|
||||
FUNC2(canvas_light_occluder_set_light_mask, RID, int)
|
||||
|
||||
FUNC2(canvas_light_occluder_set_interpolated, RID, bool)
|
||||
FUNC1(canvas_light_occluder_reset_physics_interpolation, RID)
|
||||
FUNC2(canvas_light_occluder_transform_physics_interpolation, RID, Transform2D)
|
||||
|
||||
FUNCRID(canvas_occluder_polygon)
|
||||
FUNC3(canvas_occluder_polygon_set_shape, RID, const PoolVector<Vector2> &, bool)
|
||||
FUNC2(canvas_occluder_polygon_set_shape_as_lines, RID, const PoolVector<Vector2> &)
|
||||
@ -590,11 +596,12 @@ public:
|
||||
|
||||
virtual void init();
|
||||
virtual void finish();
|
||||
virtual void tick();
|
||||
virtual void pre_draw(bool p_will_draw);
|
||||
virtual void draw(bool p_swap_buffers, double frame_step);
|
||||
virtual void sync();
|
||||
FUNC0(tick)
|
||||
FUNC1(pre_draw, bool)
|
||||
FUNC1RC(bool, has_changed, ChangedPriority)
|
||||
virtual void set_physics_interpolation_enabled(bool p_enabled);
|
||||
|
||||
/* RENDER INFO */
|
||||
|
||||
|
@ -2133,6 +2133,9 @@ void RenderingServer::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_z_index", "item", "z_index"), &RenderingServer::canvas_item_set_z_index);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_z_as_relative_to_parent", "item", "enabled"), &RenderingServer::canvas_item_set_z_as_relative_to_parent);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_copy_to_backbuffer", "item", "enabled", "rect"), &RenderingServer::canvas_item_set_copy_to_backbuffer);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_interpolated", "item", "interpolated"), &RenderingServer::canvas_item_set_interpolated);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_reset_physics_interpolation", "item"), &RenderingServer::canvas_item_reset_physics_interpolation);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_transform_physics_interpolation", "item", "xform"), &RenderingServer::canvas_item_transform_physics_interpolation);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_clear", "item"), &RenderingServer::canvas_item_clear);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_draw_index", "item", "index"), &RenderingServer::canvas_item_set_draw_index);
|
||||
ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &RenderingServer::canvas_item_set_material);
|
||||
@ -2159,6 +2162,9 @@ void RenderingServer::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_filter", "light", "filter"), &RenderingServer::canvas_light_set_shadow_filter);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_set_interpolated", "light", "interpolated"), &RenderingServer::canvas_light_set_interpolated);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_reset_physics_interpolation", "light"), &RenderingServer::canvas_light_reset_physics_interpolation);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_transform_physics_interpolation", "light", "xform"), &RenderingServer::canvas_light_transform_physics_interpolation);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_create"), &RenderingServer::canvas_light_occluder_create);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_attach_to_canvas", "occluder", "canvas"), &RenderingServer::canvas_light_occluder_attach_to_canvas);
|
||||
@ -2166,6 +2172,9 @@ void RenderingServer::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_polygon", "occluder", "polygon"), &RenderingServer::canvas_light_occluder_set_polygon);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_interpolated", "occluder", "interpolated"), &RenderingServer::canvas_light_occluder_set_interpolated);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_reset_physics_interpolation", "occluder"), &RenderingServer::canvas_light_occluder_reset_physics_interpolation);
|
||||
ClassDB::bind_method(D_METHOD("canvas_light_occluder_transform_physics_interpolation", "occluder", "xform"), &RenderingServer::canvas_light_occluder_transform_physics_interpolation);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &RenderingServer::canvas_occluder_polygon_create);
|
||||
ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &RenderingServer::canvas_occluder_polygon_set_shape);
|
||||
|
@ -942,6 +942,10 @@ public:
|
||||
virtual void canvas_item_set_z_index(RID p_item, int p_z) = 0;
|
||||
virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) = 0;
|
||||
virtual void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) = 0;
|
||||
virtual void canvas_item_clear(RID p_item) = 0;
|
||||
virtual void canvas_item_set_draw_index(RID p_item, int p_index) = 0;
|
||||
virtual void canvas_item_set_material(RID p_item, RID p_material) = 0;
|
||||
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
|
||||
|
||||
virtual void canvas_item_attach_skeleton(RID p_item, RID p_skeleton) = 0;
|
||||
virtual void canvas_item_set_skeleton_relative_xform(RID p_item, Transform2D p_relative_xform) = 0;
|
||||
@ -955,12 +959,9 @@ public:
|
||||
}
|
||||
virtual Rect2 _debug_canvas_item_get_rect(RID p_item) = 0;
|
||||
|
||||
virtual void canvas_item_clear(RID p_item) = 0;
|
||||
virtual void canvas_item_set_draw_index(RID p_item, int p_index) = 0;
|
||||
|
||||
virtual void canvas_item_set_material(RID p_item, RID p_material) = 0;
|
||||
|
||||
virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0;
|
||||
virtual void canvas_item_set_interpolated(RID p_item, bool p_interpolated) = 0;
|
||||
virtual void canvas_item_reset_physics_interpolation(RID p_item) = 0;
|
||||
virtual void canvas_item_transform_physics_interpolation(RID p_item, Transform2D p_transform) = 0;
|
||||
|
||||
virtual RID canvas_light_create() = 0;
|
||||
virtual void canvas_light_attach_to_canvas(RID p_light, RID p_canvas) = 0;
|
||||
@ -977,6 +978,10 @@ public:
|
||||
virtual void canvas_light_set_item_cull_mask(RID p_light, int p_mask) = 0;
|
||||
virtual void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) = 0;
|
||||
|
||||
virtual void canvas_light_set_interpolated(RID p_light, bool p_interpolated) = 0;
|
||||
virtual void canvas_light_reset_physics_interpolation(RID p_light) = 0;
|
||||
virtual void canvas_light_transform_physics_interpolation(RID p_light, Transform2D p_transform) = 0;
|
||||
|
||||
enum CanvasLightMode {
|
||||
CANVAS_LIGHT_MODE_ADD,
|
||||
CANVAS_LIGHT_MODE_SUB,
|
||||
@ -1009,6 +1014,10 @@ public:
|
||||
virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0;
|
||||
virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0;
|
||||
|
||||
virtual void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) = 0;
|
||||
virtual void canvas_light_occluder_reset_physics_interpolation(RID p_occluder) = 0;
|
||||
virtual void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, Transform2D p_transform) = 0;
|
||||
|
||||
virtual RID canvas_occluder_polygon_create() = 0;
|
||||
virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const PoolVector<Vector2> &p_shape, bool p_closed) = 0;
|
||||
virtual void canvas_occluder_polygon_set_shape_as_lines(RID p_occluder_polygon, const PoolVector<Vector2> &p_shape) = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user