summaryrefslogtreecommitdiffstats
path: root/servers/rendering/renderer_canvas_cull.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/renderer_canvas_cull.cpp')
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp364
1 files changed, 281 insertions, 83 deletions
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index c5206017f7..e48c72cec7 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -32,22 +32,20 @@
#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
+#include "core/math/transform_interpolator.h"
#include "renderer_viewport.h"
#include "rendering_server_default.h"
#include "rendering_server_globals.h"
#include "servers/rendering/storage/texture_storage.h"
-void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask) {
+void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) {
RENDER_TIMESTAMP("Cull CanvasItem Tree");
memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
for (int i = 0; i < p_child_item_count; i++) {
- _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, canvas_cull_mask);
- }
- if (p_canvas_item) {
- _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, canvas_cull_mask);
+ _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask, p_child_items[i].mirror, 1);
}
RendererCanvasRender::Item *list = nullptr;
@@ -69,7 +67,7 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas
RENDER_TIMESTAMP("Render CanvasItems");
bool sdf_flag;
- RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, sdf_flag);
+ RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, sdf_flag, r_render_info);
if (sdf_flag) {
sdf_used = true;
}
@@ -84,7 +82,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
if (r_items) {
r_items[r_index] = child_items[i];
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_modulate = p_modulate;
child_items[i]->ysort_index = r_index;
@@ -101,7 +99,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
r_index++;
if (child_items[i]->sort_y) {
- _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z);
+ _collect_ysort_children(child_items[i], 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, abs_z);
}
}
}
@@ -114,29 +112,29 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<Renderer
} while (ysort_owner && ysort_owner->sort_y);
}
-void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
+void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &p_transform, const Rect2 &p_clip_rect, Rect2 p_global_rect, const Color &p_modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *r_canvas_group_from) {
if (ci->copy_back_buffer) {
- ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
+ ci->copy_back_buffer->screen_rect = p_transform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
}
if (p_use_canvas_group) {
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
- if (canvas_group_from == nullptr) {
+ if (r_canvas_group_from == nullptr) {
// no list before processing this item, means must put stuff in group from the beginning of list.
- canvas_group_from = r_z_list[zidx];
+ r_canvas_group_from = r_z_list[zidx];
} else {
// there was a list before processing, so begin group from this one.
- canvas_group_from = canvas_group_from->next;
+ r_canvas_group_from = r_canvas_group_from->next;
}
- if (canvas_group_from) {
+ if (r_canvas_group_from) {
// Has a place to begin the group from!
//compute a global rect (in global coords) for children in the same z layer
Rect2 rect_accum;
- RendererCanvasRender::Item *c = canvas_group_from;
+ RendererCanvasRender::Item *c = r_canvas_group_from;
while (c) {
- if (c == canvas_group_from) {
+ if (c == r_canvas_group_from) {
rect_accum = c->global_rect_cache;
} else {
rect_accum = rect_accum.merge(c->global_rect_cache);
@@ -161,28 +159,28 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
RendererCanvasRender::Item::CommandRect *crect = ci->alloc_command<RendererCanvasRender::Item::CommandRect>();
crect->flags = RendererCanvasRender::CANVAS_RECT_IS_GROUP; // so we can recognize it later
- crect->rect = xform.affine_inverse().xform(rect_accum);
+ crect->rect = p_transform.affine_inverse().xform(rect_accum);
crect->modulate = Color(1, 1, 1, 1);
//the global rect is used to do the copying, so update it
- global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin
- global_rect.position += p_clip_rect.position;
+ p_global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin
+ p_global_rect.position += p_clip_rect.position;
} else {
- global_rect.position -= p_clip_rect.position;
+ p_global_rect.position -= p_clip_rect.position;
- global_rect = global_rect.merge(rect_accum); //must use both rects for this
- global_rect = global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin
+ p_global_rect = p_global_rect.merge(rect_accum); //must use both rects for this
+ p_global_rect = p_global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin
- global_rect.position += p_clip_rect.position;
+ p_global_rect.position += p_clip_rect.position;
}
// Very important that this is cleared after used in RendererCanvasRender to avoid
// potential crashes.
- canvas_group_from->canvas_group_owner = ci;
+ r_canvas_group_from->canvas_group_owner = ci;
}
}
- if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
+ if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(p_global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
//something to draw?
if (ci->update_when_visible) {
@@ -190,9 +188,9 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
}
if (ci->commands != nullptr || ci->copy_back_buffer) {
- ci->final_transform = xform;
- ci->final_modulate = modulate * ci->self_modulate;
- ci->global_rect_cache = global_rect;
+ ci->final_transform = p_transform;
+ ci->final_modulate = p_modulate * ci->self_modulate;
+ ci->global_rect_cache = p_global_rect;
ci->global_rect_cache.position -= p_clip_rect.position;
ci->light_masked = false;
@@ -223,14 +221,14 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
}
}
-void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort, uint32_t canvas_cull_mask) {
+void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times) {
Item *ci = p_canvas_item;
if (!ci->visible) {
return;
}
- if (!(ci->visibility_layer & canvas_cull_mask)) {
+ if (!(ci->visibility_layer & p_canvas_cull_mask)) {
return;
}
@@ -247,13 +245,40 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
}
- Transform2D 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);
+ }
+
+ Transform2D parent_xform = p_parent_xform;
+
+ Point2 repeat_size = p_repeat_size;
+ int repeat_times = p_repeat_times;
+
+ if (ci->repeat_source) {
+ repeat_size = ci->repeat_size;
+ repeat_times = ci->repeat_times;
+ } else {
+ ci->repeat_size = repeat_size;
+ ci->repeat_times = repeat_times;
+
+ if (repeat_size.x || repeat_size.y) {
+ rect.size += repeat_size * repeat_times / final_xform.get_scale();
+ rect.position -= repeat_size * (repeat_times / 2);
+ }
+ }
+
if (snapping_2d_transforms_to_pixel) {
- xform.columns[2] = xform.columns[2].floor();
+ final_xform.columns[2] = final_xform.columns[2].round();
+ parent_xform.columns[2] = parent_xform.columns[2].round();
}
- xform = p_transform * xform;
- Rect2 global_rect = xform.xform(rect);
+ final_xform = parent_xform * final_xform;
+
+ Rect2 global_rect = final_xform.xform(rect);
global_rect.position += p_clip_rect.position;
if (ci->use_parent_material && p_material_owner) {
@@ -298,7 +323,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
if (ci->sort_y) {
- if (allow_y_sort) {
+ if (p_allow_y_sort) {
if (ci->ysort_children_count == -1) {
ci->ysort_children_count = 0;
_collect_ysort_children(ci, Transform2D(), p_material_owner, Color(1, 1, 1, 1), nullptr, ci->ysort_children_count, p_z);
@@ -307,18 +332,20 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
child_item_count = ci->ysort_children_count + 1;
child_items = (Item **)alloca(child_item_count * sizeof(Item *));
+ ci->ysort_xform = ci->xform_curr.affine_inverse();
+ ci->ysort_pos = Vector2();
+ ci->ysort_modulate = Color(1, 1, 1, 1);
+ ci->ysort_index = 0;
ci->ysort_parent_abs_z_index = parent_z;
child_items[0] = ci;
int i = 1;
_collect_ysort_children(ci, Transform2D(), p_material_owner, Color(1, 1, 1, 1), child_items, i, p_z);
- ci->ysort_xform = ci->xform.affine_inverse();
- ci->ysort_modulate = Color(1, 1, 1, 1);
SortArray<Item *, ItemPtrSort> sorter;
sorter.sort(child_items, child_item_count);
for (i = 0; i < child_item_count; i++) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, canvas_cull_mask);
+ _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
@@ -328,7 +355,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
canvas_group_from = r_z_last_list[zidx];
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
@@ -342,19 +369,19 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
if (!child_items[i]->behind && !use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, canvas_cull_mask);
+ _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
for (int i = 0; i < child_item_count; i++) {
if (child_items[i]->behind || use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, canvas_cull_mask);
+ _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
}
}
}
-void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask) {
+void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) {
RENDER_TIMESTAMP("> Render Canvas");
sdf_used = false;
@@ -368,38 +395,7 @@ void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, co
int l = p_canvas->child_items.size();
Canvas::ChildItem *ci = p_canvas->child_items.ptrw();
- bool has_mirror = false;
- for (int i = 0; i < l; i++) {
- if (ci[i].mirror.x || ci[i].mirror.y) {
- has_mirror = true;
- break;
- }
- }
-
- if (!has_mirror) {
- _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
-
- } else {
- //used for parallaxlayer mirroring
- for (int i = 0; i < l; i++) {
- const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
-
- //mirroring (useful for scrolling backgrounds)
- if (ci2.mirror.x != 0) {
- Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
- }
- if (ci2.mirror.y != 0) {
- Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
- }
- if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
- Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
- }
- }
- }
+ _render_canvas_item_tree(p_render_target, ci, l, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info);
RENDER_TIMESTAMP("< Render Canvas");
}
@@ -426,6 +422,15 @@ void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, con
canvas->child_items.write[idx].mirror = p_mirroring;
}
+void RendererCanvasCull::canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+
+ canvas_item->repeat_source = true;
+ canvas_item->repeat_size = p_repeat_size;
+ canvas_item->repeat_times = p_repeat_times;
+}
+
void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) {
Canvas *canvas = canvas_owner.get_or_null(p_canvas);
ERR_FAIL_NULL(canvas);
@@ -515,7 +520,16 @@ void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_NULL(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() > 0);
+ }
+ }
+
+ canvas_item->xform_curr = p_transform;
}
void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) {
@@ -1396,14 +1410,12 @@ void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector
ERR_FAIL_COND(!p_bones.is_empty() && p_bones.size() != vertex_count * 4);
ERR_FAIL_COND(!p_weights.is_empty() && p_weights.size() != vertex_count * 4);
- Vector<int> indices = p_indices;
-
Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
ERR_FAIL_NULL(polygon);
polygon->texture = p_texture;
- polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights);
+ polygon->polygon.create(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights);
polygon->primitive = RS::PRIMITIVE_TRIANGLES;
}
@@ -1627,6 +1639,26 @@ bool RendererCanvasCull::canvas_item_get_debug_redraw() const {
return debug_redraw;
}
+void RendererCanvasCull::canvas_item_set_interpolated(RID p_item, bool p_interpolated) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+ canvas_item->interpolated = p_interpolated;
+}
+
+void RendererCanvasCull::canvas_item_reset_physics_interpolation(RID p_item) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+ canvas_item->xform_prev = canvas_item->xform_curr;
+}
+
+// Useful especially for origin shifting.
+void RendererCanvasCull::canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+ canvas_item->xform_prev = p_transform * canvas_item->xform_prev;
+ canvas_item->xform_curr = p_transform * canvas_item->xform_curr;
+}
+
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_NULL(canvas_item);
@@ -1725,7 +1757,16 @@ void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_NULL(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() > 0);
+ }
+ }
+
+ clight->xform_curr = p_transform;
}
void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
@@ -1844,6 +1885,25 @@ void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smo
clight->shadow_smooth = p_smooth;
}
+void RendererCanvasCull::canvas_light_set_interpolated(RID p_light, bool p_interpolated) {
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(clight);
+ clight->interpolated = p_interpolated;
+}
+
+void RendererCanvasCull::canvas_light_reset_physics_interpolation(RID p_light) {
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(clight);
+ clight->xform_prev = clight->xform_curr;
+}
+
+void RendererCanvasCull::canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) {
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(clight);
+ clight->xform_prev = p_transform * clight->xform_prev;
+ clight->xform_curr = p_transform * clight->xform_curr;
+}
+
RID RendererCanvasCull::canvas_light_occluder_allocate() {
return canvas_light_occluder_owner.allocate_rid();
}
@@ -1910,13 +1970,24 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p
void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) {
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_NULL(occluder);
+
+ occluder->sdf_collision = p_enable;
}
void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_NULL(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() > 0);
+ }
+ }
+
+ occluder->xform_curr = p_xform;
}
void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
@@ -1926,6 +1997,25 @@ void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, in
occluder->light_mask = p_mask;
}
+void RendererCanvasCull::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) {
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
+ ERR_FAIL_NULL(occluder);
+ occluder->interpolated = p_interpolated;
+}
+
+void RendererCanvasCull::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) {
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
+ ERR_FAIL_NULL(occluder);
+ occluder->xform_prev = occluder->xform_curr;
+}
+
+void RendererCanvasCull::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) {
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
+ ERR_FAIL_NULL(occluder);
+ occluder->xform_prev = p_transform * occluder->xform_prev;
+ occluder->xform_curr = p_transform * occluder->xform_curr;
+}
+
RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
return canvas_light_occluder_polygon_owner.allocate_rid();
}
@@ -2016,7 +2106,7 @@ void RendererCanvasCull::update_visibility_notifiers() {
if (visibility_notifier->just_visible) {
visibility_notifier->just_visible = false;
- if (!visibility_notifier->enter_callable.is_null()) {
+ if (visibility_notifier->enter_callable.is_valid()) {
if (RSG::threaded) {
visibility_notifier->enter_callable.call_deferred();
} else {
@@ -2027,7 +2117,7 @@ void RendererCanvasCull::update_visibility_notifiers() {
if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
visibility_notifier_list.remove(E);
- if (!visibility_notifier->exit_callable.is_null()) {
+ if (visibility_notifier->exit_callable.is_valid()) {
if (RSG::threaded) {
visibility_notifier->exit_callable.call_deferred();
} else {
@@ -2041,6 +2131,12 @@ void RendererCanvasCull::update_visibility_notifiers() {
}
}
+Rect2 RendererCanvasCull::_debug_canvas_item_get_rect(RID p_item) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL_V(canvas_item, Rect2());
+ return canvas_item->get_rect();
+}
+
bool RendererCanvasCull::free(RID p_rid) {
if (canvas_owner.owns(p_rid)) {
Canvas *canvas = canvas_owner.get_or_null(p_rid);
@@ -2074,6 +2170,7 @@ bool RendererCanvasCull::free(RID p_rid) {
} else if (canvas_item_owner.owns(p_rid)) {
Item *canvas_item = canvas_item_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(canvas_item, true);
+ _interpolation_data.notify_free_canvas_item(p_rid, *canvas_item);
if (canvas_item->parent.is_valid()) {
if (canvas_owner.owns(canvas_item->parent)) {
@@ -2113,6 +2210,7 @@ bool RendererCanvasCull::free(RID p_rid) {
} else if (canvas_light_owner.owns(p_rid)) {
RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_NULL_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_or_null(canvas_light->canvas);
@@ -2128,6 +2226,7 @@ bool RendererCanvasCull::free(RID p_rid) {
} else if (canvas_light_occluder_owner.owns(p_rid)) {
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid);
ERR_FAIL_NULL_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_or_null(occluder->polygon);
@@ -2161,6 +2260,105 @@ bool RendererCanvasCull::free(RID p_rid) {
return true;
}
+template <typename T>
+void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) {
+ List<RID> owned;
+ p_owner.get_owned_list(&owned);
+ if (owned.size()) {
+ if (owned.size() == 1) {
+ WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
+ } else {
+ WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
+ }
+ for (const RID &E : owned) {
+ free(E);
+ }
+ }
+}
+
+void RendererCanvasCull::finalize() {
+ _free_rids(canvas_owner, "Canvas");
+ _free_rids(canvas_item_owner, "CanvasItem");
+ _free_rids(canvas_light_owner, "CanvasLight");
+ _free_rids(canvas_light_occluder_owner, "CanvasLightOccluder");
+ _free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon");
+}
+
+void RendererCanvasCull::tick() {
+ if (_interpolation_data.interpolation_enabled) {
+ update_interpolation_tick(true);
+ }
+}
+
+void RendererCanvasCull::update_interpolation_tick(bool p_process) {
+#define GODOT_UPDATE_INTERPOLATION_TICK(m_list_prev, m_list_curr, m_type, m_owner_list) \
+ /* Detect any that were on the previous transform list that are no longer active. */ \
+ for (unsigned int n = 0; n < _interpolation_data.m_list_prev->size(); n++) { \
+ const RID &rid = (*_interpolation_data.m_list_prev)[n]; \
+ m_type *item = m_owner_list.get_or_null(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.m_list_curr->size(); n++) { \
+ const RID &rid = (*_interpolation_data.m_list_curr)[n]; \
+ m_type *item = m_owner_list.get_or_null(rid); \
+ if (item) { \
+ item->xform_prev = item->xform_curr; \
+ item->on_interpolate_transform_list = false; \
+ } \
+ } \
+ } \
+ SWAP(_interpolation_data.m_list_curr, _interpolation_data.m_list_prev); \
+ _interpolation_data.m_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, RendererCanvasRender::Light, canvas_light_owner);
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RendererCanvasRender::LightOccluderInstance, canvas_light_occluder_owner);
+
+#undef GODOT_UPDATE_INTERPOLATION_TICK
+}
+
+void RendererCanvasCull::InterpolationData::notify_free_canvas_item(RID p_rid, RendererCanvasCull::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 RendererCanvasCull::InterpolationData::notify_free_canvas_light(RID p_rid, RendererCanvasRender::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 RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::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);
+}
+
RendererCanvasCull::RendererCanvasCull() {
z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));