|
@@ -29,6 +29,7 @@
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
|
|
#include "visual_server_canvas.h"
|
|
#include "visual_server_canvas.h"
|
|
|
|
+#include "core/math/transform_interpolator.h"
|
|
#include "visual_server_globals.h"
|
|
#include "visual_server_globals.h"
|
|
#include "visual_server_raster.h"
|
|
#include "visual_server_raster.h"
|
|
#include "visual_server_viewport.h"
|
|
#include "visual_server_viewport.h"
|
|
@@ -65,7 +66,7 @@ void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2
|
|
r_items[r_index] = child_items[i];
|
|
r_items[r_index] = child_items[i];
|
|
child_items[i]->ysort_modulate = p_modulate;
|
|
child_items[i]->ysort_modulate = p_modulate;
|
|
child_items[i]->ysort_xform = p_transform;
|
|
child_items[i]->ysort_xform = p_transform;
|
|
- child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.elements[2]);
|
|
|
|
|
|
+ child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform_curr.elements[2]);
|
|
child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
|
|
child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
|
|
child_items[i]->ysort_index = r_index;
|
|
child_items[i]->ysort_index = r_index;
|
|
}
|
|
}
|
|
@@ -74,7 +75,7 @@ void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2
|
|
|
|
|
|
if (child_items[i]->sort_y) {
|
|
if (child_items[i]->sort_y) {
|
|
_collect_ysort_children(child_items[i],
|
|
_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],
|
|
child_items[i]->use_parent_material ? p_material_owner : child_items[i],
|
|
p_modulate * child_items[i]->modulate,
|
|
p_modulate * child_items[i]->modulate,
|
|
r_items, r_index);
|
|
r_items, r_index);
|
|
@@ -241,6 +242,37 @@ void VisualServerCanvas::_calculate_canvas_item_bound(Item *p_canvas_item, Rect2
|
|
}
|
|
}
|
|
|
|
|
|
_finalize_and_merge_local_bound_to_branch(ci, r_branch_bound);
|
|
_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 VisualServerCanvas::_finalize_and_merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound) {
|
|
void VisualServerCanvas::_finalize_and_merge_local_bound_to_branch(Item *p_canvas_item, Rect2 *r_branch_bound) {
|
|
@@ -275,7 +307,7 @@ void VisualServerCanvas::_merge_local_bound_to_branch(Item *p_canvas_item, Rect2
|
|
return;
|
|
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()) {
|
|
if (!r_branch_bound->has_no_area()) {
|
|
*r_branch_bound = r_branch_bound->merge(this_item_total_local_bound);
|
|
*r_branch_bound = r_branch_bound->merge(this_item_total_local_bound);
|
|
@@ -297,10 +329,17 @@ void VisualServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item, c
|
|
}
|
|
}
|
|
|
|
|
|
Rect2 rect = ci->get_rect();
|
|
Rect2 rect = ci->get_rect();
|
|
- Transform2D xform = ci->xform;
|
|
|
|
- xform = p_transform * xform;
|
|
|
|
|
|
|
|
- Rect2 global_rect = xform.xform(rect);
|
|
|
|
|
|
+ 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);
|
|
global_rect.position += p_clip_rect.position;
|
|
global_rect.position += p_clip_rect.position;
|
|
|
|
|
|
if (ci->use_parent_material && p_material_owner) {
|
|
if (ci->use_parent_material && p_material_owner) {
|
|
@@ -360,14 +399,14 @@ void VisualServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item, c
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
if (ci->sort_y) {
|
|
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 {
|
|
} 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) {
|
|
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) {
|
|
if (ci->update_when_visible) {
|
|
@@ -376,7 +415,7 @@ void VisualServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item, c
|
|
|
|
|
|
if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
|
|
if ((!ci->commands.empty() && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
|
|
//something to draw?
|
|
//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->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 = global_rect;
|
|
ci->global_rect_cache.position -= p_clip_rect.position;
|
|
ci->global_rect_cache.position -= p_clip_rect.position;
|
|
@@ -401,9 +440,9 @@ void VisualServerCanvas::_render_canvas_item_cull_by_item(Item *p_canvas_item, c
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
if (ci->sort_y) {
|
|
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 {
|
|
} 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -418,9 +457,22 @@ void VisualServerCanvas::_render_canvas_item_cull_by_node(Item *p_canvas_item, c
|
|
// This should have been calculated as a pre-process.
|
|
// This should have been calculated as a pre-process.
|
|
DEV_ASSERT(!ci->bound_dirty);
|
|
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();
|
|
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;
|
|
final_xform = p_transform * final_xform;
|
|
|
|
|
|
Rect2 global_rect = final_xform.xform(rect);
|
|
Rect2 global_rect = final_xform.xform(rect);
|
|
@@ -825,7 +877,16 @@ void VisualServerCanvas::canvas_item_set_transform(RID p_item, const Transform2D
|
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
|
ERR_FAIL_COND(!canvas_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());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ canvas_item->xform_curr = p_transform;
|
|
|
|
|
|
// Special case!
|
|
// Special case!
|
|
// Modifying the transform DOES NOT affect the local bound.
|
|
// Modifying the transform DOES NOT affect the local bound.
|
|
@@ -1435,6 +1496,64 @@ void VisualServerCanvas::canvas_item_set_skeleton_relative_xform(RID p_item, Tra
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Useful especially for origin shifting.
|
|
|
|
+void VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
|
|
void VisualServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
|
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
|
Item *canvas_item = canvas_item_owner.getornull(p_item);
|
|
ERR_FAIL_COND(!canvas_item);
|
|
ERR_FAIL_COND(!canvas_item);
|
|
@@ -1573,7 +1692,16 @@ void VisualServerCanvas::canvas_light_set_transform(RID p_light, const Transform
|
|
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
|
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
|
ERR_FAIL_COND(!clight);
|
|
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 VisualServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) {
|
|
void VisualServerCanvas::canvas_light_set_texture(RID p_light, RID p_texture) {
|
|
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
|
RasterizerCanvas::Light *clight = canvas_light_owner.get(p_light);
|
|
@@ -1760,7 +1888,16 @@ void VisualServerCanvas::canvas_light_occluder_set_transform(RID p_occluder, con
|
|
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
|
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
|
ERR_FAIL_COND(!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 VisualServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
|
|
void VisualServerCanvas::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
|
|
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
|
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_occluder);
|
|
@@ -1871,6 +2008,7 @@ bool VisualServerCanvas::free(RID p_rid) {
|
|
Item *canvas_item = canvas_item_owner.get(p_rid);
|
|
Item *canvas_item = canvas_item_owner.get(p_rid);
|
|
ERR_FAIL_COND_V(!canvas_item, true);
|
|
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_item->parent.is_valid()) {
|
|
if (canvas_owner.owns(canvas_item->parent)) {
|
|
if (canvas_owner.owns(canvas_item->parent)) {
|
|
@@ -1904,6 +2042,7 @@ bool VisualServerCanvas::free(RID p_rid) {
|
|
} else if (canvas_light_owner.owns(p_rid)) {
|
|
} else if (canvas_light_owner.owns(p_rid)) {
|
|
RasterizerCanvas::Light *canvas_light = canvas_light_owner.get(p_rid);
|
|
RasterizerCanvas::Light *canvas_light = canvas_light_owner.get(p_rid);
|
|
ERR_FAIL_COND_V(!canvas_light, true);
|
|
ERR_FAIL_COND_V(!canvas_light, true);
|
|
|
|
+ _interpolation_data.notify_free_canvas_light(p_rid, *canvas_light);
|
|
|
|
|
|
if (canvas_light->canvas.is_valid()) {
|
|
if (canvas_light->canvas.is_valid()) {
|
|
Canvas *canvas = canvas_owner.get(canvas_light->canvas);
|
|
Canvas *canvas = canvas_owner.get(canvas_light->canvas);
|
|
@@ -1924,6 +2063,7 @@ bool VisualServerCanvas::free(RID p_rid) {
|
|
} else if (canvas_light_occluder_owner.owns(p_rid)) {
|
|
} else if (canvas_light_occluder_owner.owns(p_rid)) {
|
|
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid);
|
|
RasterizerCanvas::LightOccluderInstance *occluder = canvas_light_occluder_owner.get(p_rid);
|
|
ERR_FAIL_COND_V(!occluder, true);
|
|
ERR_FAIL_COND_V(!occluder, true);
|
|
|
|
+ _interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder);
|
|
|
|
|
|
if (occluder->polygon.is_valid()) {
|
|
if (occluder->polygon.is_valid()) {
|
|
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon);
|
|
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get(occluder->polygon);
|
|
@@ -2056,6 +2196,81 @@ void VisualServerCanvas::_print_tree_down(int p_child_id, int p_depth, const Ite
|
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+void VisualServerCanvas::tick() {
|
|
|
|
+ if (_interpolation_data.interpolation_enabled) {
|
|
|
|
+ update_interpolation_tick(true);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void VisualServerCanvas::update_interpolation_tick(bool p_process) {
|
|
|
|
+#define GODOT_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();
|
|
|
|
+
|
|
|
|
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner);
|
|
|
|
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RasterizerCanvas::Light, canvas_light_owner);
|
|
|
|
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RasterizerCanvas::LightOccluderInstance, canvas_light_occluder_owner);
|
|
|
|
+
|
|
|
|
+#undef GODOT_UPDATE_INTERPOLATION_TICK
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void VisualServerCanvas::InterpolationData::notify_free_canvas_item(RID p_rid, VisualServerCanvas::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 VisualServerCanvas::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 VisualServerCanvas::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);
|
|
|
|
+}
|
|
|
|
+
|
|
VisualServerCanvas::VisualServerCanvas() {
|
|
VisualServerCanvas::VisualServerCanvas() {
|
|
z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
|
|
z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
|
|
z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
|
|
z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
|