1/**************************************************************************/
2/* renderer_canvas_cull.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "renderer_canvas_cull.h"
32
33#include "core/math/geometry_2d.h"
34#include "renderer_viewport.h"
35#include "rendering_server_default.h"
36#include "rendering_server_globals.h"
37#include "servers/rendering/storage/texture_storage.h"
38
39void 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) {
40 RENDER_TIMESTAMP("Cull CanvasItem Tree");
41
42 memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
43 memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
44
45 for (int i = 0; i < p_child_item_count; i++) {
46 _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);
47 }
48 if (p_canvas_item) {
49 _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);
50 }
51
52 RendererCanvasRender::Item *list = nullptr;
53 RendererCanvasRender::Item *list_end = nullptr;
54
55 for (int i = 0; i < z_range; i++) {
56 if (!z_list[i]) {
57 continue;
58 }
59 if (!list) {
60 list = z_list[i];
61 list_end = z_last_list[i];
62 } else {
63 list_end->next = z_list[i];
64 list_end = z_last_list[i];
65 }
66 }
67
68 RENDER_TIMESTAMP("Render CanvasItems");
69
70 bool sdf_flag;
71 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);
72 if (sdf_flag) {
73 sdf_used = true;
74 }
75}
76
77void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2D p_transform, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int p_z) {
78 int child_item_count = p_canvas_item->child_items.size();
79 RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw();
80 for (int i = 0; i < child_item_count; i++) {
81 int abs_z = 0;
82 if (child_items[i]->visible) {
83 if (r_items) {
84 r_items[r_index] = child_items[i];
85 child_items[i]->ysort_xform = p_transform;
86 child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]);
87 child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
88 child_items[i]->ysort_modulate = p_modulate;
89 child_items[i]->ysort_index = r_index;
90 child_items[i]->ysort_parent_abs_z_index = p_z;
91
92 // Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items.
93 if (child_items[i]->z_relative) {
94 abs_z = CLAMP(p_z + child_items[i]->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
95 } else {
96 abs_z = child_items[i]->z_index;
97 }
98 }
99
100 r_index++;
101
102 if (child_items[i]->sort_y) {
103 _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);
104 }
105 }
106 }
107}
108
109void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<RendererCanvasCull::Item, true> &canvas_item_owner) {
110 do {
111 ysort_owner->ysort_children_count = -1;
112 ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.get_or_null(ysort_owner->parent) : nullptr;
113 } while (ysort_owner && ysort_owner->sort_y);
114}
115
116void 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) {
117 if (ci->copy_back_buffer) {
118 ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
119 }
120
121 if (p_use_canvas_group) {
122 int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
123 if (canvas_group_from == nullptr) {
124 // no list before processing this item, means must put stuff in group from the beginning of list.
125 canvas_group_from = r_z_list[zidx];
126 } else {
127 // there was a list before processing, so begin group from this one.
128 canvas_group_from = canvas_group_from->next;
129 }
130
131 if (canvas_group_from) {
132 // Has a place to begin the group from!
133
134 //compute a global rect (in global coords) for children in the same z layer
135 Rect2 rect_accum;
136 RendererCanvasRender::Item *c = canvas_group_from;
137 while (c) {
138 if (c == canvas_group_from) {
139 rect_accum = c->global_rect_cache;
140 } else {
141 rect_accum = rect_accum.merge(c->global_rect_cache);
142 }
143
144 c = c->next;
145 }
146
147 // We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this.
148 // If nothing has been drawn, we just take it over and draw it ourselves.
149 if (ci->canvas_group->fit_empty && (ci->commands == nullptr || (ci->commands->next == nullptr && ci->commands->type == RendererCanvasCull::Item::Command::TYPE_RECT && (static_cast<RendererCanvasCull::Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) {
150 // No commands, or sole command is the one used to draw, so we (re)create the draw command.
151 ci->clear();
152
153 if (rect_accum == Rect2()) {
154 rect_accum.size = Size2(1, 1);
155 }
156
157 rect_accum = rect_accum.grow(ci->canvas_group->fit_margin);
158
159 //draw it?
160 RendererCanvasRender::Item::CommandRect *crect = ci->alloc_command<RendererCanvasRender::Item::CommandRect>();
161
162 crect->flags = RendererCanvasRender::CANVAS_RECT_IS_GROUP; // so we can recognize it later
163 crect->rect = xform.affine_inverse().xform(rect_accum);
164 crect->modulate = Color(1, 1, 1, 1);
165
166 //the global rect is used to do the copying, so update it
167 global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin
168 global_rect.position += p_clip_rect.position;
169 } else {
170 global_rect.position -= p_clip_rect.position;
171
172 global_rect = global_rect.merge(rect_accum); //must use both rects for this
173 global_rect = global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin
174
175 global_rect.position += p_clip_rect.position;
176 }
177
178 // Very important that this is cleared after used in RendererCanvasRender to avoid
179 // potential crashes.
180 canvas_group_from->canvas_group_owner = ci;
181 }
182 }
183
184 if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
185 //something to draw?
186
187 if (ci->update_when_visible) {
188 RenderingServerDefault::redraw_request();
189 }
190
191 if (ci->commands != nullptr || ci->copy_back_buffer) {
192 ci->final_transform = xform;
193 ci->final_modulate = modulate * ci->self_modulate;
194 ci->global_rect_cache = global_rect;
195 ci->global_rect_cache.position -= p_clip_rect.position;
196 ci->light_masked = false;
197
198 int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
199
200 if (r_z_last_list[zidx]) {
201 r_z_last_list[zidx]->next = ci;
202 r_z_last_list[zidx] = ci;
203
204 } else {
205 r_z_list[zidx] = ci;
206 r_z_last_list[zidx] = ci;
207 }
208
209 ci->z_final = p_z;
210
211 ci->next = nullptr;
212 }
213
214 if (ci->visibility_notifier) {
215 if (!ci->visibility_notifier->visible_element.in_list()) {
216 visibility_notifier_list.add(&ci->visibility_notifier->visible_element);
217 ci->visibility_notifier->just_visible = true;
218 }
219
220 ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
221 }
222 }
223}
224
225void 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) {
226 Item *ci = p_canvas_item;
227
228 if (!ci->visible) {
229 return;
230 }
231
232 if (!(ci->visibility_layer & canvas_cull_mask)) {
233 return;
234 }
235
236 if (ci->children_order_dirty) {
237 ci->child_items.sort_custom<ItemIndexSort>();
238 ci->children_order_dirty = false;
239 }
240
241 Rect2 rect = ci->get_rect();
242
243 if (ci->visibility_notifier) {
244 if (ci->visibility_notifier->area.size != Vector2()) {
245 rect = rect.merge(ci->visibility_notifier->area);
246 }
247 }
248
249 Transform2D xform = ci->xform;
250 if (snapping_2d_transforms_to_pixel) {
251 xform.columns[2] = xform.columns[2].floor();
252 }
253 xform = p_transform * xform;
254
255 Rect2 global_rect = xform.xform(rect);
256 global_rect.position += p_clip_rect.position;
257
258 if (ci->use_parent_material && p_material_owner) {
259 ci->material_owner = p_material_owner;
260 } else {
261 p_material_owner = ci;
262 ci->material_owner = nullptr;
263 }
264
265 Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a);
266
267 if (modulate.a < 0.007) {
268 return;
269 }
270
271 int child_item_count = ci->child_items.size();
272 Item **child_items = ci->child_items.ptrw();
273
274 if (ci->clip) {
275 if (p_canvas_clip != nullptr) {
276 ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect);
277 } else {
278 ci->final_clip_rect = p_clip_rect.intersection(global_rect);
279 }
280 if (ci->final_clip_rect.size.width < 0.5 || ci->final_clip_rect.size.height < 0.5) {
281 // The clip rect area is 0, so don't draw the item.
282 return;
283 }
284 ci->final_clip_rect.position = ci->final_clip_rect.position.round();
285 ci->final_clip_rect.size = ci->final_clip_rect.size.round();
286 ci->final_clip_owner = ci;
287
288 } else {
289 ci->final_clip_owner = p_canvas_clip;
290 }
291
292 int parent_z = p_z;
293 if (ci->z_relative) {
294 p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
295 } else {
296 p_z = ci->z_index;
297 }
298
299 if (ci->sort_y) {
300 if (allow_y_sort) {
301 if (ci->ysort_children_count == -1) {
302 ci->ysort_children_count = 0;
303 _collect_ysort_children(ci, Transform2D(), p_material_owner, Color(1, 1, 1, 1), nullptr, ci->ysort_children_count, p_z);
304 }
305
306 child_item_count = ci->ysort_children_count + 1;
307 child_items = (Item **)alloca(child_item_count * sizeof(Item *));
308
309 ci->ysort_parent_abs_z_index = parent_z;
310 child_items[0] = ci;
311 int i = 1;
312 _collect_ysort_children(ci, Transform2D(), p_material_owner, Color(1, 1, 1, 1), child_items, i, p_z);
313 ci->ysort_xform = ci->xform.affine_inverse();
314 ci->ysort_modulate = Color(1, 1, 1, 1);
315
316 SortArray<Item *, ItemPtrSort> sorter;
317 sorter.sort(child_items, child_item_count);
318
319 for (i = 0; i < child_item_count; i++) {
320 _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);
321 }
322 } else {
323 RendererCanvasRender::Item *canvas_group_from = nullptr;
324 bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
325 if (use_canvas_group) {
326 int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
327 canvas_group_from = r_z_last_list[zidx];
328 }
329
330 _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);
331 }
332 } else {
333 RendererCanvasRender::Item *canvas_group_from = nullptr;
334 bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
335 if (use_canvas_group) {
336 int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
337 canvas_group_from = r_z_last_list[zidx];
338 }
339
340 for (int i = 0; i < child_item_count; i++) {
341 if (!child_items[i]->behind && !use_canvas_group) {
342 continue;
343 }
344 _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);
345 }
346 _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);
347 for (int i = 0; i < child_item_count; i++) {
348 if (child_items[i]->behind || use_canvas_group) {
349 continue;
350 }
351 _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);
352 }
353 }
354}
355
356void 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) {
357 RENDER_TIMESTAMP("> Render Canvas");
358
359 sdf_used = false;
360 snapping_2d_transforms_to_pixel = p_snap_2d_transforms_to_pixel;
361
362 if (p_canvas->children_order_dirty) {
363 p_canvas->child_items.sort();
364 p_canvas->children_order_dirty = false;
365 }
366
367 int l = p_canvas->child_items.size();
368 Canvas::ChildItem *ci = p_canvas->child_items.ptrw();
369
370 bool has_mirror = false;
371 for (int i = 0; i < l; i++) {
372 if (ci[i].mirror.x || ci[i].mirror.y) {
373 has_mirror = true;
374 break;
375 }
376 }
377
378 if (!has_mirror) {
379 _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);
380
381 } else {
382 //used for parallaxlayer mirroring
383 for (int i = 0; i < l; i++) {
384 const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
385 _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);
386
387 //mirroring (useful for scrolling backgrounds)
388 if (ci2.mirror.x != 0) {
389 Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
390 _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);
391 }
392 if (ci2.mirror.y != 0) {
393 Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
394 _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);
395 }
396 if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
397 Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
398 _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);
399 }
400 }
401 }
402
403 RENDER_TIMESTAMP("< Render Canvas");
404}
405
406bool RendererCanvasCull::was_sdf_used() {
407 return sdf_used;
408}
409
410RID RendererCanvasCull::canvas_allocate() {
411 return canvas_owner.allocate_rid();
412}
413void RendererCanvasCull::canvas_initialize(RID p_rid) {
414 canvas_owner.initialize_rid(p_rid);
415}
416
417void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) {
418 Canvas *canvas = canvas_owner.get_or_null(p_canvas);
419 ERR_FAIL_COND(!canvas);
420 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
421 ERR_FAIL_COND(!canvas_item);
422
423 int idx = canvas->find_item(canvas_item);
424 ERR_FAIL_COND(idx == -1);
425 canvas->child_items.write[idx].mirror = p_mirroring;
426}
427
428void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) {
429 Canvas *canvas = canvas_owner.get_or_null(p_canvas);
430 ERR_FAIL_COND(!canvas);
431 canvas->modulate = p_color;
432}
433
434void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) {
435 disable_scale = p_disable;
436}
437
438void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) {
439 Canvas *canvas = canvas_owner.get_or_null(p_canvas);
440 ERR_FAIL_COND(!canvas);
441
442 canvas->parent = p_parent;
443 canvas->parent_scale = p_scale;
444}
445
446RID RendererCanvasCull::canvas_item_allocate() {
447 return canvas_item_owner.allocate_rid();
448}
449void RendererCanvasCull::canvas_item_initialize(RID p_rid) {
450 canvas_item_owner.initialize_rid(p_rid);
451}
452
453void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
454 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
455 ERR_FAIL_COND(!canvas_item);
456
457 if (canvas_item->parent.is_valid()) {
458 if (canvas_owner.owns(canvas_item->parent)) {
459 Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
460 canvas->erase_item(canvas_item);
461 } else if (canvas_item_owner.owns(canvas_item->parent)) {
462 Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent);
463 item_owner->child_items.erase(canvas_item);
464
465 if (item_owner->sort_y) {
466 _mark_ysort_dirty(item_owner, canvas_item_owner);
467 }
468 }
469
470 canvas_item->parent = RID();
471 }
472
473 if (p_parent.is_valid()) {
474 if (canvas_owner.owns(p_parent)) {
475 Canvas *canvas = canvas_owner.get_or_null(p_parent);
476 Canvas::ChildItem ci;
477 ci.item = canvas_item;
478 canvas->child_items.push_back(ci);
479 canvas->children_order_dirty = true;
480 } else if (canvas_item_owner.owns(p_parent)) {
481 Item *item_owner = canvas_item_owner.get_or_null(p_parent);
482 item_owner->child_items.push_back(canvas_item);
483 item_owner->children_order_dirty = true;
484
485 if (item_owner->sort_y) {
486 _mark_ysort_dirty(item_owner, canvas_item_owner);
487 }
488
489 } else {
490 ERR_FAIL_MSG("Invalid parent.");
491 }
492 }
493
494 canvas_item->parent = p_parent;
495}
496
497void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) {
498 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
499 ERR_FAIL_COND(!canvas_item);
500
501 canvas_item->visible = p_visible;
502
503 _mark_ysort_dirty(canvas_item, canvas_item_owner);
504}
505
506void RendererCanvasCull::canvas_item_set_light_mask(RID p_item, int p_mask) {
507 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
508 ERR_FAIL_COND(!canvas_item);
509
510 canvas_item->light_mask = p_mask;
511}
512
513void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) {
514 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
515 ERR_FAIL_COND(!canvas_item);
516
517 canvas_item->xform = p_transform;
518}
519
520void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) {
521 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
522 ERR_FAIL_COND(!canvas_item);
523
524 canvas_item->visibility_layer = p_visibility_layer;
525}
526
527uint32_t RendererCanvasCull::canvas_item_get_visibility_layer(RID p_item) {
528 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
529 if (!canvas_item)
530 return 0;
531 return canvas_item->visibility_layer;
532}
533
534void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) {
535 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
536 ERR_FAIL_COND(!canvas_item);
537
538 canvas_item->clip = p_clip;
539}
540
541void RendererCanvasCull::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) {
542 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
543 ERR_FAIL_COND(!canvas_item);
544
545 canvas_item->distance_field = p_enable;
546}
547
548void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) {
549 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
550 ERR_FAIL_COND(!canvas_item);
551
552 canvas_item->custom_rect = p_custom_rect;
553 canvas_item->rect = p_rect;
554}
555
556void RendererCanvasCull::canvas_item_set_modulate(RID p_item, const Color &p_color) {
557 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
558 ERR_FAIL_COND(!canvas_item);
559
560 canvas_item->modulate = p_color;
561}
562
563void RendererCanvasCull::canvas_item_set_self_modulate(RID p_item, const Color &p_color) {
564 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
565 ERR_FAIL_COND(!canvas_item);
566
567 canvas_item->self_modulate = p_color;
568}
569
570void RendererCanvasCull::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) {
571 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
572 ERR_FAIL_COND(!canvas_item);
573
574 canvas_item->behind = p_enable;
575}
576
577void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_update) {
578 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
579 ERR_FAIL_COND(!canvas_item);
580
581 canvas_item->update_when_visible = p_update;
582}
583
584void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width, bool p_antialiased) {
585 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
586 ERR_FAIL_COND(!canvas_item);
587
588 Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
589 ERR_FAIL_COND(!line);
590
591 Vector2 diff = (p_from - p_to);
592 Vector2 dir = diff.orthogonal().normalized();
593 Vector2 t = dir * p_width * 0.5;
594
595 Vector2 begin_left;
596 Vector2 begin_right;
597 Vector2 end_left;
598 Vector2 end_right;
599
600 if (p_width >= 0.0) {
601 begin_left = p_from + t;
602 begin_right = p_from - t;
603 end_left = p_to + t;
604 end_right = p_to - t;
605
606 line->points[0] = begin_left;
607 line->points[1] = begin_right;
608 line->points[2] = end_right;
609 line->points[3] = end_left;
610 line->point_count = 4;
611 } else {
612 begin_left = p_from;
613 begin_right = p_from;
614 end_left = p_to;
615 end_right = p_to;
616
617 line->points[0] = p_from;
618 line->points[1] = p_to;
619 line->point_count = 2;
620 }
621 for (uint32_t i = 0; i < line->point_count; i++) {
622 line->colors[i] = p_color;
623 }
624
625 if (p_antialiased) {
626 // Use the same antialiasing feather size as StyleBoxFlat's default
627 // (but doubled, as it's specified for both sides here).
628 // This value is empirically determined to provide good antialiasing quality
629 // while not making lines appear too soft.
630 float border_size = 1.25f;
631 if (0.0f <= p_width && p_width < 1.0f) {
632 border_size *= p_width;
633 }
634 Vector2 dir2 = diff.normalized();
635
636 Vector2 border = dir * border_size;
637 Vector2 border2 = dir2 * border_size;
638
639 Color transparent = Color(p_color.r, p_color.g, p_color.b, 0.0);
640
641 {
642 Item::CommandPrimitive *left_border = canvas_item->alloc_command<Item::CommandPrimitive>();
643 ERR_FAIL_COND(!left_border);
644
645 left_border->points[0] = begin_left;
646 left_border->points[1] = begin_left + border;
647 left_border->points[2] = end_left + border;
648 left_border->points[3] = end_left;
649
650 left_border->colors[0] = p_color;
651 left_border->colors[1] = transparent;
652 left_border->colors[2] = transparent;
653 left_border->colors[3] = p_color;
654
655 left_border->point_count = 4;
656 }
657 {
658 Item::CommandPrimitive *right_border = canvas_item->alloc_command<Item::CommandPrimitive>();
659 ERR_FAIL_COND(!right_border);
660
661 right_border->points[0] = begin_right;
662 right_border->points[1] = begin_right - border;
663 right_border->points[2] = end_right - border;
664 right_border->points[3] = end_right;
665
666 right_border->colors[0] = p_color;
667 right_border->colors[1] = transparent;
668 right_border->colors[2] = transparent;
669 right_border->colors[3] = p_color;
670
671 right_border->point_count = 4;
672 }
673 {
674 Item::CommandPrimitive *top_border = canvas_item->alloc_command<Item::CommandPrimitive>();
675 ERR_FAIL_COND(!top_border);
676
677 top_border->points[0] = begin_left;
678 top_border->points[1] = begin_left + border2;
679 top_border->points[2] = begin_right + border2;
680 top_border->points[3] = begin_right;
681
682 top_border->colors[0] = p_color;
683 top_border->colors[1] = transparent;
684 top_border->colors[2] = transparent;
685 top_border->colors[3] = p_color;
686
687 top_border->point_count = 4;
688 }
689 {
690 Item::CommandPrimitive *bottom_border = canvas_item->alloc_command<Item::CommandPrimitive>();
691 ERR_FAIL_COND(!bottom_border);
692
693 bottom_border->points[0] = end_left;
694 bottom_border->points[1] = end_left - border2;
695 bottom_border->points[2] = end_right - border2;
696 bottom_border->points[3] = end_right;
697
698 bottom_border->colors[0] = p_color;
699 bottom_border->colors[1] = transparent;
700 bottom_border->colors[2] = transparent;
701 bottom_border->colors[3] = p_color;
702
703 bottom_border->point_count = 4;
704 }
705 {
706 Item::CommandPrimitive *top_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
707 ERR_FAIL_COND(!top_left_corner);
708
709 top_left_corner->points[0] = begin_left;
710 top_left_corner->points[1] = begin_left + border2;
711 top_left_corner->points[2] = begin_left + border + border2;
712 top_left_corner->points[3] = begin_left + border;
713
714 top_left_corner->colors[0] = p_color;
715 top_left_corner->colors[1] = transparent;
716 top_left_corner->colors[2] = transparent;
717 top_left_corner->colors[3] = transparent;
718
719 top_left_corner->point_count = 4;
720 }
721 {
722 Item::CommandPrimitive *top_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
723 ERR_FAIL_COND(!top_right_corner);
724
725 top_right_corner->points[0] = begin_right;
726 top_right_corner->points[1] = begin_right + border2;
727 top_right_corner->points[2] = begin_right - border + border2;
728 top_right_corner->points[3] = begin_right - border;
729
730 top_right_corner->colors[0] = p_color;
731 top_right_corner->colors[1] = transparent;
732 top_right_corner->colors[2] = transparent;
733 top_right_corner->colors[3] = transparent;
734
735 top_right_corner->point_count = 4;
736 }
737 {
738 Item::CommandPrimitive *bottom_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
739 ERR_FAIL_COND(!bottom_left_corner);
740
741 bottom_left_corner->points[0] = end_left;
742 bottom_left_corner->points[1] = end_left - border2;
743 bottom_left_corner->points[2] = end_left + border - border2;
744 bottom_left_corner->points[3] = end_left + border;
745
746 bottom_left_corner->colors[0] = p_color;
747 bottom_left_corner->colors[1] = transparent;
748 bottom_left_corner->colors[2] = transparent;
749 bottom_left_corner->colors[3] = transparent;
750
751 bottom_left_corner->point_count = 4;
752 }
753 {
754 Item::CommandPrimitive *bottom_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
755 ERR_FAIL_COND(!bottom_right_corner);
756
757 bottom_right_corner->points[0] = end_right;
758 bottom_right_corner->points[1] = end_right - border2;
759 bottom_right_corner->points[2] = end_right - border - border2;
760 bottom_right_corner->points[3] = end_right - border;
761
762 bottom_right_corner->colors[0] = p_color;
763 bottom_right_corner->colors[1] = transparent;
764 bottom_right_corner->colors[2] = transparent;
765 bottom_right_corner->colors[3] = transparent;
766
767 bottom_right_corner->point_count = 4;
768 }
769 }
770}
771
772static Vector2 compute_polyline_segment_dir(const Vector<Point2> &p_points, int p_index, const Vector2 &p_prev_segment_dir) {
773 int point_count = p_points.size();
774
775 bool is_last_point = (p_index == point_count - 1);
776
777 Vector2 segment_dir;
778
779 if (is_last_point) {
780 segment_dir = p_prev_segment_dir;
781 } else {
782 segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized();
783
784 if (segment_dir.is_zero_approx()) {
785 segment_dir = p_prev_segment_dir;
786 }
787 }
788
789 return segment_dir;
790}
791
792static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) {
793 Vector2 bisector;
794 float length = 1.0f;
795
796 bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized();
797
798 float angle = atan2f(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir));
799 float sin_angle = sinf(angle);
800
801 if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) {
802 length = 1.0f / sin_angle;
803 length = CLAMP(length, -3.0f, 3.0f);
804 } else {
805 bisector = p_segment_dir.orthogonal();
806 }
807
808 if (bisector.is_zero_approx()) {
809 bisector = p_segment_dir.orthogonal();
810 }
811
812 return bisector * length;
813}
814
815void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
816 ERR_FAIL_COND(p_points.size() < 2);
817 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
818 ERR_FAIL_COND(!canvas_item);
819
820 Color color = Color(1, 1, 1, 1);
821
822 Vector<int> indices;
823 int point_count = p_points.size();
824
825 Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
826 ERR_FAIL_COND(!pline);
827
828 if (p_width < 0) {
829 if (p_antialiased) {
830 WARN_PRINT("Antialiasing is not supported for thin polylines drawn using line strips (`p_width < 0`).");
831 }
832
833 pline->primitive = RS::PRIMITIVE_LINE_STRIP;
834
835 if (p_colors.size() == 1 || p_colors.size() == point_count) {
836 pline->polygon.create(indices, p_points, p_colors);
837 } else {
838 Vector<Color> colors;
839 if (p_colors.is_empty()) {
840 colors.push_back(color);
841 } else {
842 colors.resize(point_count);
843 Color *colors_ptr = colors.ptrw();
844 for (int i = 0; i < point_count; i++) {
845 if (i < p_colors.size()) {
846 color = p_colors[i];
847 }
848 colors_ptr[i] = color;
849 }
850 }
851 pline->polygon.create(indices, p_points, colors);
852 }
853 return;
854 }
855
856 int polyline_point_count = point_count * 2;
857
858 bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]);
859 Vector2 first_segment_dir;
860 Vector2 last_segment_dir;
861
862 // Search for first non-zero vector between two segments.
863 for (int i = 1; i < point_count; i++) {
864 first_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
865
866 if (!first_segment_dir.is_zero_approx()) {
867 break;
868 }
869 }
870
871 // Search for last non-zero vector between two segments.
872 for (int i = point_count - 1; i >= 1; i--) {
873 last_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
874
875 if (!last_segment_dir.is_zero_approx()) {
876 break;
877 }
878 }
879
880 PackedColorArray colors;
881 PackedVector2Array points;
882
883 // Additional 2+2 vertices to antialias begin+end of the middle triangle strip.
884 colors.resize(polyline_point_count + ((p_antialiased && !loop) ? 4 : 0));
885 points.resize(polyline_point_count + ((p_antialiased && !loop) ? 4 : 0));
886
887 Vector2 *points_ptr = points.ptrw();
888 Color *colors_ptr = colors.ptrw();
889
890 if (p_antialiased) {
891 // Use the same antialiasing feather size as StyleBoxFlat's default
892 // (but doubled, as it's specified for both sides here).
893 // This value is empirically determined to provide good antialiasing quality
894 // while not making lines appear too soft.
895 float border_size = 1.25f;
896 if (p_width < 1.0f) {
897 border_size *= p_width;
898 }
899 Color color2 = Color(1, 1, 1, 0);
900
901 Item::CommandPolygon *pline_left = canvas_item->alloc_command<Item::CommandPolygon>();
902 ERR_FAIL_COND(!pline_left);
903
904 Item::CommandPolygon *pline_right = canvas_item->alloc_command<Item::CommandPolygon>();
905 ERR_FAIL_COND(!pline_right);
906
907 PackedColorArray colors_left;
908 PackedVector2Array points_left;
909
910 PackedColorArray colors_right;
911 PackedVector2Array points_right;
912
913 // 2+2 additional vertices for begin+end corners.
914 // 1 additional vertex to swap the orientation of the triangles within the end corner's quad.
915 colors_left.resize(polyline_point_count + (loop ? 0 : 5));
916 points_left.resize(polyline_point_count + (loop ? 0 : 5));
917
918 colors_right.resize(polyline_point_count + (loop ? 0 : 5));
919 points_right.resize(polyline_point_count + (loop ? 0 : 5));
920
921 Color *colors_left_ptr = colors_left.ptrw();
922 Vector2 *points_left_ptr = points_left.ptrw();
923
924 Vector2 *points_right_ptr = points_right.ptrw();
925 Color *colors_right_ptr = colors_right.ptrw();
926
927 Vector2 prev_segment_dir;
928 for (int i = 0; i < point_count; i++) {
929 bool is_first_point = (i == 0);
930 bool is_last_point = (i == point_count - 1);
931
932 Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
933 if (is_first_point && loop) {
934 prev_segment_dir = last_segment_dir;
935 } else if (is_last_point && loop) {
936 prev_segment_dir = first_segment_dir;
937 }
938
939 Vector2 base_edge_offset;
940 if (is_first_point && !loop) {
941 base_edge_offset = first_segment_dir.orthogonal();
942 } else if (is_last_point && !loop) {
943 base_edge_offset = last_segment_dir.orthogonal();
944 } else {
945 base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
946 }
947
948 Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
949 Vector2 border = base_edge_offset * border_size;
950 Vector2 pos = p_points[i];
951
952 int j = i * 2 + (loop ? 0 : 2);
953
954 points_ptr[j + 0] = pos + edge_offset;
955 points_ptr[j + 1] = pos - edge_offset;
956
957 points_left_ptr[j + 0] = pos + edge_offset;
958 points_left_ptr[j + 1] = pos + edge_offset + border;
959
960 points_right_ptr[j + 0] = pos - edge_offset;
961 points_right_ptr[j + 1] = pos - edge_offset - border;
962
963 if (i < p_colors.size()) {
964 color = p_colors[i];
965 color2 = Color(color.r, color.g, color.b, 0);
966 }
967
968 colors_ptr[j + 0] = color;
969 colors_ptr[j + 1] = color;
970
971 colors_left_ptr[j + 0] = color;
972 colors_left_ptr[j + 1] = color2;
973
974 colors_right_ptr[j + 0] = color;
975 colors_right_ptr[j + 1] = color2;
976
977 if (is_first_point && !loop) {
978 Vector2 begin_border = -segment_dir * border_size;
979
980 points_ptr[0] = pos + edge_offset + begin_border;
981 points_ptr[1] = pos - edge_offset + begin_border;
982
983 colors_ptr[0] = color2;
984 colors_ptr[1] = color2;
985
986 points_left_ptr[0] = pos + edge_offset + begin_border;
987 points_left_ptr[1] = pos + edge_offset + begin_border + border;
988
989 colors_left_ptr[0] = color2;
990 colors_left_ptr[1] = color2;
991
992 points_right_ptr[0] = pos - edge_offset + begin_border;
993 points_right_ptr[1] = pos - edge_offset + begin_border - border;
994
995 colors_right_ptr[0] = color2;
996 colors_right_ptr[1] = color2;
997 }
998
999 if (is_last_point && !loop) {
1000 Vector2 end_border = prev_segment_dir * border_size;
1001 int end_index = polyline_point_count + 2;
1002
1003 points_ptr[end_index + 0] = pos + edge_offset + end_border;
1004 points_ptr[end_index + 1] = pos - edge_offset + end_border;
1005
1006 colors_ptr[end_index + 0] = color2;
1007 colors_ptr[end_index + 1] = color2;
1008
1009 // Swap orientation of the triangles within both end corner quads so the visual seams
1010 // between triangles goes from the edge corner. Done by going back to the edge corner
1011 // (1 additional vertex / zero-area triangle per left/right corner).
1012 points_left_ptr[end_index + 0] = pos + edge_offset;
1013 points_left_ptr[end_index + 1] = pos + edge_offset + end_border + border;
1014 points_left_ptr[end_index + 2] = pos + edge_offset + end_border;
1015
1016 colors_left_ptr[end_index + 0] = color;
1017 colors_left_ptr[end_index + 1] = color2;
1018 colors_left_ptr[end_index + 2] = color2;
1019
1020 points_right_ptr[end_index + 0] = pos - edge_offset;
1021 points_right_ptr[end_index + 1] = pos - edge_offset + end_border - border;
1022 points_right_ptr[end_index + 2] = pos - edge_offset + end_border;
1023
1024 colors_right_ptr[end_index + 0] = color;
1025 colors_right_ptr[end_index + 1] = color2;
1026 colors_right_ptr[end_index + 2] = color2;
1027 }
1028
1029 prev_segment_dir = segment_dir;
1030 }
1031
1032 pline_left->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1033 pline_left->polygon.create(indices, points_left, colors_left);
1034
1035 pline_right->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1036 pline_right->polygon.create(indices, points_right, colors_right);
1037 } else {
1038 // Makes a single triangle strip for drawing the line.
1039
1040 Vector2 prev_segment_dir;
1041 for (int i = 0; i < point_count; i++) {
1042 bool is_first_point = (i == 0);
1043 bool is_last_point = (i == point_count - 1);
1044
1045 Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
1046 if (is_first_point && loop) {
1047 prev_segment_dir = last_segment_dir;
1048 } else if (is_last_point && loop) {
1049 prev_segment_dir = first_segment_dir;
1050 }
1051
1052 Vector2 base_edge_offset;
1053 if (is_first_point && !loop) {
1054 base_edge_offset = first_segment_dir.orthogonal();
1055 } else if (is_last_point && !loop) {
1056 base_edge_offset = last_segment_dir.orthogonal();
1057 } else {
1058 base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
1059 }
1060
1061 Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
1062 Vector2 pos = p_points[i];
1063
1064 points_ptr[i * 2 + 0] = pos + edge_offset;
1065 points_ptr[i * 2 + 1] = pos - edge_offset;
1066
1067 if (i < p_colors.size()) {
1068 color = p_colors[i];
1069 }
1070
1071 colors_ptr[i * 2 + 0] = color;
1072 colors_ptr[i * 2 + 1] = color;
1073
1074 prev_segment_dir = segment_dir;
1075 }
1076 }
1077
1078 pline->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1079 pline->polygon.create(indices, points, colors);
1080}
1081
1082void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
1083 ERR_FAIL_COND(p_points.is_empty() || p_points.size() % 2 != 0);
1084 ERR_FAIL_COND(p_colors.size() != 1 && p_colors.size() * 2 != p_points.size());
1085
1086 // TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out.
1087 if (p_width < 0) {
1088 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1089 ERR_FAIL_COND(!canvas_item);
1090
1091 Vector<Color> colors;
1092 if (p_colors.size() == 1) {
1093 colors = p_colors;
1094 } else { //} else if (p_colors.size() << 1 == p_points.size()) {
1095 colors.resize(p_points.size());
1096 Color *colors_ptr = colors.ptrw();
1097 for (int i = 0; i < p_colors.size(); i++) {
1098 Color color = p_colors[i];
1099 colors_ptr[i * 2 + 0] = color;
1100 colors_ptr[i * 2 + 1] = color;
1101 }
1102 }
1103
1104 Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
1105 ERR_FAIL_COND(!pline);
1106 pline->primitive = RS::PRIMITIVE_LINES;
1107 pline->polygon.create(Vector<int>(), p_points, colors);
1108 } else {
1109 if (p_colors.size() == 1) {
1110 Color color = p_colors[0];
1111 for (int i = 0; i < p_points.size() >> 1; i++) {
1112 Vector2 from = p_points[i * 2 + 0];
1113 Vector2 to = p_points[i * 2 + 1];
1114
1115 canvas_item_add_line(p_item, from, to, color, p_width);
1116 }
1117 } else { //} else if (p_colors.size() << 1 == p_points.size()) {
1118 for (int i = 0; i < p_colors.size(); i++) {
1119 Color color = p_colors[i];
1120 Vector2 from = p_points[i * 2 + 0];
1121 Vector2 to = p_points[i * 2 + 1];
1122
1123 canvas_item_add_line(p_item, from, to, color, p_width);
1124 }
1125 }
1126 }
1127}
1128
1129void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) {
1130 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1131 ERR_FAIL_COND(!canvas_item);
1132
1133 Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1134 ERR_FAIL_COND(!rect);
1135 rect->modulate = p_color;
1136 rect->rect = p_rect;
1137}
1138
1139void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) {
1140 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1141 ERR_FAIL_COND(!canvas_item);
1142
1143 Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>();
1144 ERR_FAIL_COND(!circle);
1145
1146 circle->primitive = RS::PRIMITIVE_TRIANGLES;
1147
1148 Vector<int> indices;
1149 Vector<Vector2> points;
1150
1151 static const int circle_points = 64;
1152
1153 points.resize(circle_points);
1154 Vector2 *points_ptr = points.ptrw();
1155 const real_t circle_point_step = Math_TAU / circle_points;
1156
1157 for (int i = 0; i < circle_points; i++) {
1158 float angle = i * circle_point_step;
1159 points_ptr[i].x = Math::cos(angle) * p_radius;
1160 points_ptr[i].y = Math::sin(angle) * p_radius;
1161 points_ptr[i] += p_pos;
1162 }
1163
1164 indices.resize((circle_points - 2) * 3);
1165 int *indices_ptr = indices.ptrw();
1166
1167 for (int i = 0; i < circle_points - 2; i++) {
1168 indices_ptr[i * 3 + 0] = 0;
1169 indices_ptr[i * 3 + 1] = i + 1;
1170 indices_ptr[i * 3 + 2] = i + 2;
1171 }
1172
1173 Vector<Color> color;
1174 color.push_back(p_color);
1175 circle->polygon.create(indices, points, color);
1176}
1177
1178void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) {
1179 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1180 ERR_FAIL_COND(!canvas_item);
1181
1182 Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1183 ERR_FAIL_COND(!rect);
1184 rect->modulate = p_modulate;
1185 rect->rect = p_rect;
1186 rect->flags = 0;
1187 if (p_tile) {
1188 rect->flags |= RendererCanvasRender::CANVAS_RECT_TILE;
1189 rect->flags |= RendererCanvasRender::CANVAS_RECT_REGION;
1190 rect->source = Rect2(0, 0, ABS(p_rect.size.width), ABS(p_rect.size.height));
1191 }
1192
1193 if (p_rect.size.x < 0) {
1194 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1195 rect->rect.size.x = -rect->rect.size.x;
1196 }
1197 if (p_rect.size.y < 0) {
1198 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1199 rect->rect.size.y = -rect->rect.size.y;
1200 }
1201 if (p_transpose) {
1202 rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE;
1203 SWAP(rect->rect.size.x, rect->rect.size.y);
1204 }
1205
1206 rect->texture = p_texture;
1207}
1208
1209void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range, float p_scale) {
1210 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1211 ERR_FAIL_COND(!canvas_item);
1212
1213 Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1214 ERR_FAIL_COND(!rect);
1215 rect->modulate = p_modulate;
1216 rect->rect = p_rect;
1217
1218 rect->texture = p_texture;
1219
1220 rect->source = p_src_rect;
1221 rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_MSDF;
1222
1223 if (p_rect.size.x < 0) {
1224 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1225 rect->rect.size.x = -rect->rect.size.x;
1226 }
1227 if (p_src_rect.size.x < 0) {
1228 rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1229 rect->source.size.x = -rect->source.size.x;
1230 }
1231 if (p_rect.size.y < 0) {
1232 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1233 rect->rect.size.y = -rect->rect.size.y;
1234 }
1235 if (p_src_rect.size.y < 0) {
1236 rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1237 rect->source.size.y = -rect->source.size.y;
1238 }
1239 rect->outline = (float)p_outline_size / p_scale / 4.0;
1240 rect->px_range = p_px_range;
1241}
1242
1243void RendererCanvasCull::canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate) {
1244 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1245 ERR_FAIL_COND(!canvas_item);
1246
1247 Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1248 ERR_FAIL_COND(!rect);
1249 rect->modulate = p_modulate;
1250 rect->rect = p_rect;
1251
1252 rect->texture = p_texture;
1253
1254 rect->source = p_src_rect;
1255 rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_LCD;
1256
1257 if (p_rect.size.x < 0) {
1258 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1259 rect->rect.size.x = -rect->rect.size.x;
1260 }
1261 if (p_src_rect.size.x < 0) {
1262 rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1263 rect->source.size.x = -rect->source.size.x;
1264 }
1265 if (p_rect.size.y < 0) {
1266 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1267 rect->rect.size.y = -rect->rect.size.y;
1268 }
1269 if (p_src_rect.size.y < 0) {
1270 rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1271 rect->source.size.y = -rect->source.size.y;
1272 }
1273}
1274
1275void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
1276 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1277 ERR_FAIL_COND(!canvas_item);
1278
1279 Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1280 ERR_FAIL_COND(!rect);
1281 rect->modulate = p_modulate;
1282 rect->rect = p_rect;
1283
1284 rect->texture = p_texture;
1285
1286 rect->source = p_src_rect;
1287 rect->flags = RendererCanvasRender::CANVAS_RECT_REGION;
1288
1289 if (p_rect.size.x < 0) {
1290 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1291 rect->rect.size.x = -rect->rect.size.x;
1292 }
1293 if (p_src_rect.size.x < 0) {
1294 rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1295 rect->source.size.x = -rect->source.size.x;
1296 }
1297 if (p_rect.size.y < 0) {
1298 rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1299 rect->rect.size.y = -rect->rect.size.y;
1300 }
1301 if (p_src_rect.size.y < 0) {
1302 rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1303 rect->source.size.y = -rect->source.size.y;
1304 }
1305
1306 if (p_transpose) {
1307 rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE;
1308 SWAP(rect->rect.size.x, rect->rect.size.y);
1309 }
1310
1311 if (p_clip_uv) {
1312 rect->flags |= RendererCanvasRender::CANVAS_RECT_CLIP_UV;
1313 }
1314}
1315
1316void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) {
1317 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1318 ERR_FAIL_COND(!canvas_item);
1319
1320 Item::CommandNinePatch *style = canvas_item->alloc_command<Item::CommandNinePatch>();
1321 ERR_FAIL_COND(!style);
1322
1323 style->texture = p_texture;
1324
1325 style->rect = p_rect;
1326 style->source = p_source;
1327 style->draw_center = p_draw_center;
1328 style->color = p_modulate;
1329 style->margin[SIDE_LEFT] = p_topleft.x;
1330 style->margin[SIDE_TOP] = p_topleft.y;
1331 style->margin[SIDE_RIGHT] = p_bottomright.x;
1332 style->margin[SIDE_BOTTOM] = p_bottomright.y;
1333 style->axis_x = p_x_axis_mode;
1334 style->axis_y = p_y_axis_mode;
1335}
1336
1337void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) {
1338 uint32_t pc = p_points.size();
1339 ERR_FAIL_COND(pc == 0 || pc > 4);
1340
1341 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1342 ERR_FAIL_COND(!canvas_item);
1343
1344 Item::CommandPrimitive *prim = canvas_item->alloc_command<Item::CommandPrimitive>();
1345 ERR_FAIL_COND(!prim);
1346
1347 for (int i = 0; i < p_points.size(); i++) {
1348 prim->points[i] = p_points[i];
1349 if (i < p_uvs.size()) {
1350 prim->uvs[i] = p_uvs[i];
1351 }
1352 if (i < p_colors.size()) {
1353 prim->colors[i] = p_colors[i];
1354 } else if (p_colors.size()) {
1355 prim->colors[i] = p_colors[0];
1356 } else {
1357 prim->colors[i] = Color(1, 1, 1, 1);
1358 }
1359 }
1360
1361 prim->point_count = p_points.size();
1362
1363 prim->texture = p_texture;
1364}
1365
1366void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) {
1367 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1368 ERR_FAIL_COND(!canvas_item);
1369#ifdef DEBUG_ENABLED
1370 int pointcount = p_points.size();
1371 ERR_FAIL_COND(pointcount < 3);
1372 int color_size = p_colors.size();
1373 int uv_size = p_uvs.size();
1374 ERR_FAIL_COND(color_size != 0 && color_size != 1 && color_size != pointcount);
1375 ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount));
1376#endif
1377 Vector<int> indices = Geometry2D::triangulate_polygon(p_points);
1378 ERR_FAIL_COND_MSG(indices.is_empty(), "Invalid polygon data, triangulation failed.");
1379
1380 Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
1381 ERR_FAIL_COND(!polygon);
1382 polygon->primitive = RS::PRIMITIVE_TRIANGLES;
1383 polygon->texture = p_texture;
1384 polygon->polygon.create(indices, p_points, p_colors, p_uvs);
1385}
1386
1387void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) {
1388 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1389 ERR_FAIL_COND(!canvas_item);
1390
1391 int vertex_count = p_points.size();
1392 ERR_FAIL_COND(vertex_count == 0);
1393 ERR_FAIL_COND(!p_colors.is_empty() && p_colors.size() != vertex_count && p_colors.size() != 1);
1394 ERR_FAIL_COND(!p_uvs.is_empty() && p_uvs.size() != vertex_count);
1395 ERR_FAIL_COND(!p_bones.is_empty() && p_bones.size() != vertex_count * 4);
1396 ERR_FAIL_COND(!p_weights.is_empty() && p_weights.size() != vertex_count * 4);
1397
1398 Vector<int> indices = p_indices;
1399
1400 Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
1401 ERR_FAIL_COND(!polygon);
1402
1403 polygon->texture = p_texture;
1404
1405 polygon->polygon.create(indices, p_points, p_colors, p_uvs, p_bones, p_weights);
1406
1407 polygon->primitive = RS::PRIMITIVE_TRIANGLES;
1408}
1409
1410void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) {
1411 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1412 ERR_FAIL_COND(!canvas_item);
1413
1414 Item::CommandTransform *tr = canvas_item->alloc_command<Item::CommandTransform>();
1415 ERR_FAIL_COND(!tr);
1416 tr->xform = p_transform;
1417}
1418
1419void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) {
1420 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1421 ERR_FAIL_COND(!canvas_item);
1422 ERR_FAIL_COND(!p_mesh.is_valid());
1423
1424 Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>();
1425 ERR_FAIL_COND(!m);
1426 m->mesh = p_mesh;
1427 if (canvas_item->skeleton.is_valid()) {
1428 m->mesh_instance = RSG::mesh_storage->mesh_instance_create(p_mesh);
1429 RSG::mesh_storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton);
1430 }
1431
1432 m->texture = p_texture;
1433
1434 m->transform = p_transform;
1435 m->modulate = p_modulate;
1436}
1437
1438void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) {
1439 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1440 ERR_FAIL_COND(!canvas_item);
1441
1442 Item::CommandParticles *part = canvas_item->alloc_command<Item::CommandParticles>();
1443 ERR_FAIL_COND(!part);
1444 part->particles = p_particles;
1445
1446 part->texture = p_texture;
1447
1448 //take the chance and request processing for them, at least once until they become visible again
1449 RSG::particles_storage->particles_request_process(p_particles);
1450}
1451
1452void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) {
1453 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1454 ERR_FAIL_COND(!canvas_item);
1455
1456 Item::CommandMultiMesh *mm = canvas_item->alloc_command<Item::CommandMultiMesh>();
1457 ERR_FAIL_COND(!mm);
1458 mm->multimesh = p_mesh;
1459
1460 mm->texture = p_texture;
1461}
1462
1463void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) {
1464 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1465 ERR_FAIL_COND(!canvas_item);
1466
1467 Item::CommandClipIgnore *ci = canvas_item->alloc_command<Item::CommandClipIgnore>();
1468 ERR_FAIL_COND(!ci);
1469 ci->ignore = p_ignore;
1470}
1471
1472void RendererCanvasCull::canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
1473 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1474 ERR_FAIL_COND(!canvas_item);
1475
1476 Item::CommandAnimationSlice *as = canvas_item->alloc_command<Item::CommandAnimationSlice>();
1477 ERR_FAIL_COND(!as);
1478 as->animation_length = p_animation_length;
1479 as->slice_begin = p_slice_begin;
1480 as->slice_end = p_slice_end;
1481 as->offset = p_offset;
1482}
1483
1484void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
1485 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1486 ERR_FAIL_COND(!canvas_item);
1487
1488 canvas_item->sort_y = p_enable;
1489
1490 _mark_ysort_dirty(canvas_item, canvas_item_owner);
1491}
1492
1493void RendererCanvasCull::canvas_item_set_z_index(RID p_item, int p_z) {
1494 ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX);
1495
1496 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1497 ERR_FAIL_COND(!canvas_item);
1498
1499 canvas_item->z_index = p_z;
1500}
1501
1502void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) {
1503 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1504 ERR_FAIL_COND(!canvas_item);
1505
1506 canvas_item->z_relative = p_enable;
1507}
1508
1509void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
1510 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1511 ERR_FAIL_COND(!canvas_item);
1512 if (canvas_item->skeleton == p_skeleton) {
1513 return;
1514 }
1515 canvas_item->skeleton = p_skeleton;
1516
1517 Item::Command *c = canvas_item->commands;
1518
1519 while (c) {
1520 if (c->type == Item::Command::TYPE_MESH) {
1521 Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c);
1522 if (canvas_item->skeleton.is_valid()) {
1523 if (cm->mesh_instance.is_null()) {
1524 cm->mesh_instance = RSG::mesh_storage->mesh_instance_create(cm->mesh);
1525 }
1526 RSG::mesh_storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton);
1527 } else {
1528 if (cm->mesh_instance.is_valid()) {
1529 RSG::mesh_storage->mesh_instance_free(cm->mesh_instance);
1530 cm->mesh_instance = RID();
1531 }
1532 }
1533 }
1534 c = c->next;
1535 }
1536}
1537
1538void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
1539 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1540 ERR_FAIL_COND(!canvas_item);
1541 if (p_enable && (canvas_item->copy_back_buffer == nullptr)) {
1542 canvas_item->copy_back_buffer = memnew(RendererCanvasRender::Item::CopyBackBuffer);
1543 }
1544 if (!p_enable && (canvas_item->copy_back_buffer != nullptr)) {
1545 memdelete(canvas_item->copy_back_buffer);
1546 canvas_item->copy_back_buffer = nullptr;
1547 }
1548
1549 if (p_enable) {
1550 canvas_item->copy_back_buffer->rect = p_rect;
1551 canvas_item->copy_back_buffer->full = p_rect == Rect2();
1552 }
1553}
1554
1555void RendererCanvasCull::canvas_item_clear(RID p_item) {
1556 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1557 ERR_FAIL_COND(!canvas_item);
1558
1559 canvas_item->clear();
1560}
1561
1562void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) {
1563 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1564 ERR_FAIL_COND(!canvas_item);
1565
1566 canvas_item->index = p_index;
1567
1568 if (canvas_item_owner.owns(canvas_item->parent)) {
1569 Item *canvas_item_parent = canvas_item_owner.get_or_null(canvas_item->parent);
1570 canvas_item_parent->children_order_dirty = true;
1571 return;
1572 }
1573
1574 Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
1575 if (canvas) {
1576 canvas->children_order_dirty = true;
1577 return;
1578 }
1579}
1580
1581void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) {
1582 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1583 ERR_FAIL_COND(!canvas_item);
1584
1585 canvas_item->material = p_material;
1586}
1587
1588void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
1589 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1590 ERR_FAIL_COND(!canvas_item);
1591
1592 canvas_item->use_parent_material = p_enable;
1593}
1594
1595void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) {
1596 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1597 ERR_FAIL_COND(!canvas_item);
1598
1599 if (p_enable) {
1600 if (!canvas_item->visibility_notifier) {
1601 canvas_item->visibility_notifier = visibility_notifier_allocator.alloc();
1602 }
1603 canvas_item->visibility_notifier->area = p_area;
1604 canvas_item->visibility_notifier->enter_callable = p_enter_callable;
1605 canvas_item->visibility_notifier->exit_callable = p_exit_callable;
1606
1607 } else {
1608 if (canvas_item->visibility_notifier) {
1609 visibility_notifier_allocator.free(canvas_item->visibility_notifier);
1610 canvas_item->visibility_notifier = nullptr;
1611 }
1612 }
1613}
1614
1615void 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) {
1616 Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1617 ERR_FAIL_COND(!canvas_item);
1618
1619 if (p_mode == RS::CANVAS_GROUP_MODE_DISABLED) {
1620 if (canvas_item->canvas_group != nullptr) {
1621 memdelete(canvas_item->canvas_group);
1622 canvas_item->canvas_group = nullptr;
1623 }
1624 } else {
1625 if (canvas_item->canvas_group == nullptr) {
1626 canvas_item->canvas_group = memnew(RendererCanvasRender::Item::CanvasGroup);
1627 }
1628 canvas_item->canvas_group->mode = p_mode;
1629 canvas_item->canvas_group->fit_empty = p_fit_empty;
1630 canvas_item->canvas_group->fit_margin = p_fit_margin;
1631 canvas_item->canvas_group->blur_mipmaps = p_blur_mipmaps;
1632 canvas_item->canvas_group->clear_margin = p_clear_margin;
1633 }
1634}
1635
1636RID RendererCanvasCull::canvas_light_allocate() {
1637 return canvas_light_owner.allocate_rid();
1638}
1639void RendererCanvasCull::canvas_light_initialize(RID p_rid) {
1640 canvas_light_owner.initialize_rid(p_rid);
1641 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_rid);
1642 clight->light_internal = RSG::canvas_render->light_create();
1643}
1644
1645void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
1646 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1647 ERR_FAIL_COND(!clight);
1648
1649 if (clight->mode == p_mode) {
1650 return;
1651 }
1652
1653 RID canvas = clight->canvas;
1654
1655 if (canvas.is_valid()) {
1656 canvas_light_attach_to_canvas(p_light, RID());
1657 }
1658
1659 clight->mode = p_mode;
1660
1661 if (canvas.is_valid()) {
1662 canvas_light_attach_to_canvas(p_light, canvas);
1663 }
1664}
1665
1666void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
1667 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1668 ERR_FAIL_COND(!clight);
1669
1670 if (clight->canvas.is_valid()) {
1671 Canvas *canvas = canvas_owner.get_or_null(clight->canvas);
1672 if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
1673 canvas->lights.erase(clight);
1674 } else {
1675 canvas->directional_lights.erase(clight);
1676 }
1677 }
1678
1679 if (!canvas_owner.owns(p_canvas)) {
1680 p_canvas = RID();
1681 }
1682
1683 clight->canvas = p_canvas;
1684
1685 if (clight->canvas.is_valid()) {
1686 Canvas *canvas = canvas_owner.get_or_null(clight->canvas);
1687 if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
1688 canvas->lights.insert(clight);
1689 } else {
1690 canvas->directional_lights.insert(clight);
1691 }
1692 }
1693}
1694
1695void RendererCanvasCull::canvas_light_set_enabled(RID p_light, bool p_enabled) {
1696 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1697 ERR_FAIL_COND(!clight);
1698
1699 clight->enabled = p_enabled;
1700}
1701
1702void RendererCanvasCull::canvas_light_set_texture_scale(RID p_light, float p_scale) {
1703 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1704 ERR_FAIL_COND(!clight);
1705
1706 clight->scale = p_scale;
1707}
1708
1709void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) {
1710 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1711 ERR_FAIL_COND(!clight);
1712
1713 clight->xform = p_transform;
1714}
1715
1716void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
1717 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1718 ERR_FAIL_COND(!clight);
1719
1720 if (clight->texture == p_texture) {
1721 return;
1722 }
1723 clight->texture = p_texture;
1724 clight->version++;
1725 RSG::canvas_render->light_set_texture(clight->light_internal, p_texture);
1726}
1727
1728void RendererCanvasCull::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) {
1729 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1730 ERR_FAIL_COND(!clight);
1731
1732 clight->texture_offset = p_offset;
1733}
1734
1735void RendererCanvasCull::canvas_light_set_color(RID p_light, const Color &p_color) {
1736 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1737 ERR_FAIL_COND(!clight);
1738
1739 clight->color = p_color;
1740}
1741
1742void RendererCanvasCull::canvas_light_set_height(RID p_light, float p_height) {
1743 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1744 ERR_FAIL_COND(!clight);
1745
1746 clight->height = p_height;
1747}
1748
1749void RendererCanvasCull::canvas_light_set_energy(RID p_light, float p_energy) {
1750 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1751 ERR_FAIL_COND(!clight);
1752
1753 clight->energy = p_energy;
1754}
1755
1756void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) {
1757 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1758 ERR_FAIL_COND(!clight);
1759
1760 clight->z_min = p_min_z;
1761 clight->z_max = p_max_z;
1762}
1763
1764void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) {
1765 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1766 ERR_FAIL_COND(!clight);
1767
1768 clight->layer_max = p_max_layer;
1769 clight->layer_min = p_min_layer;
1770}
1771
1772void RendererCanvasCull::canvas_light_set_item_cull_mask(RID p_light, int p_mask) {
1773 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1774 ERR_FAIL_COND(!clight);
1775
1776 clight->item_mask = p_mask;
1777}
1778
1779void RendererCanvasCull::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) {
1780 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1781 ERR_FAIL_COND(!clight);
1782
1783 clight->item_shadow_mask = p_mask;
1784}
1785
1786void RendererCanvasCull::canvas_light_set_directional_distance(RID p_light, float p_distance) {
1787 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1788 ERR_FAIL_COND(!clight);
1789
1790 clight->directional_distance = p_distance;
1791}
1792
1793void RendererCanvasCull::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) {
1794 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1795 ERR_FAIL_COND(!clight);
1796
1797 clight->blend_mode = p_mode;
1798}
1799
1800void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) {
1801 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1802 ERR_FAIL_COND(!clight);
1803
1804 if (clight->use_shadow == p_enabled) {
1805 return;
1806 }
1807 clight->use_shadow = p_enabled;
1808 clight->version++;
1809 RSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow);
1810}
1811
1812void RendererCanvasCull::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) {
1813 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1814 ERR_FAIL_COND(!clight);
1815
1816 clight->shadow_filter = p_filter;
1817}
1818
1819void RendererCanvasCull::canvas_light_set_shadow_color(RID p_light, const Color &p_color) {
1820 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1821 ERR_FAIL_COND(!clight);
1822
1823 clight->shadow_color = p_color;
1824}
1825
1826void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) {
1827 RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
1828 ERR_FAIL_COND(!clight);
1829 clight->shadow_smooth = p_smooth;
1830}
1831
1832RID RendererCanvasCull::canvas_light_occluder_allocate() {
1833 return canvas_light_occluder_owner.allocate_rid();
1834}
1835void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) {
1836 return canvas_light_occluder_owner.initialize_rid(p_rid);
1837}
1838
1839void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) {
1840 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
1841 ERR_FAIL_COND(!occluder);
1842
1843 if (occluder->canvas.is_valid()) {
1844 Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
1845 canvas->occluders.erase(occluder);
1846 }
1847
1848 if (!canvas_owner.owns(p_canvas)) {
1849 p_canvas = RID();
1850 }
1851
1852 occluder->canvas = p_canvas;
1853
1854 if (occluder->canvas.is_valid()) {
1855 Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
1856 canvas->occluders.insert(occluder);
1857 }
1858}
1859
1860void RendererCanvasCull::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) {
1861 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
1862 ERR_FAIL_COND(!occluder);
1863
1864 occluder->enabled = p_enabled;
1865}
1866
1867void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) {
1868 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
1869 ERR_FAIL_COND(!occluder);
1870
1871 if (occluder->polygon.is_valid()) {
1872 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
1873 if (occluder_poly) {
1874 occluder_poly->owners.erase(occluder);
1875 }
1876 }
1877
1878 occluder->polygon = p_polygon;
1879 occluder->occluder = RID();
1880
1881 if (occluder->polygon.is_valid()) {
1882 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon);
1883 if (!occluder_poly) {
1884 occluder->polygon = RID();
1885 ERR_FAIL_COND(!occluder_poly);
1886 } else {
1887 occluder_poly->owners.insert(occluder);
1888 occluder->occluder = occluder_poly->occluder;
1889 occluder->aabb_cache = occluder_poly->aabb;
1890 occluder->cull_cache = occluder_poly->cull_mode;
1891 }
1892 }
1893}
1894
1895void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) {
1896 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
1897 ERR_FAIL_COND(!occluder);
1898}
1899
1900void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
1901 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
1902 ERR_FAIL_COND(!occluder);
1903
1904 occluder->xform = p_xform;
1905}
1906
1907void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
1908 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
1909 ERR_FAIL_COND(!occluder);
1910
1911 occluder->light_mask = p_mask;
1912}
1913
1914RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
1915 return canvas_light_occluder_polygon_owner.allocate_rid();
1916}
1917void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) {
1918 canvas_light_occluder_polygon_owner.initialize_rid(p_rid);
1919 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid);
1920 occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create();
1921}
1922
1923void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
1924 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon);
1925 ERR_FAIL_COND(!occluder_poly);
1926
1927 uint32_t pc = p_shape.size();
1928 ERR_FAIL_COND(pc < 2);
1929
1930 occluder_poly->aabb = Rect2();
1931 const Vector2 *r = p_shape.ptr();
1932 for (uint32_t i = 0; i < pc; i++) {
1933 if (i == 0) {
1934 occluder_poly->aabb.position = r[i];
1935 } else {
1936 occluder_poly->aabb.expand_to(r[i]);
1937 }
1938 }
1939
1940 RSG::canvas_render->occluder_polygon_set_shape(occluder_poly->occluder, p_shape, p_closed);
1941
1942 for (RendererCanvasRender::LightOccluderInstance *E : occluder_poly->owners) {
1943 E->aabb_cache = occluder_poly->aabb;
1944 }
1945}
1946
1947void RendererCanvasCull::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) {
1948 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon);
1949 ERR_FAIL_COND(!occluder_poly);
1950 occluder_poly->cull_mode = p_mode;
1951 RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode);
1952 for (RendererCanvasRender::LightOccluderInstance *E : occluder_poly->owners) {
1953 E->cull_cache = p_mode;
1954 }
1955}
1956
1957void RendererCanvasCull::canvas_set_shadow_texture_size(int p_size) {
1958 RSG::canvas_render->set_shadow_texture_size(p_size);
1959}
1960
1961RID RendererCanvasCull::canvas_texture_allocate() {
1962 return RSG::texture_storage->canvas_texture_allocate();
1963}
1964void RendererCanvasCull::canvas_texture_initialize(RID p_rid) {
1965 RSG::texture_storage->canvas_texture_initialize(p_rid);
1966}
1967
1968void RendererCanvasCull::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
1969 RSG::texture_storage->canvas_texture_set_channel(p_canvas_texture, p_channel, p_texture);
1970}
1971
1972void RendererCanvasCull::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) {
1973 RSG::texture_storage->canvas_texture_set_shading_parameters(p_canvas_texture, p_base_color, p_shininess);
1974}
1975
1976void RendererCanvasCull::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
1977 RSG::texture_storage->canvas_texture_set_texture_filter(p_canvas_texture, p_filter);
1978}
1979
1980void RendererCanvasCull::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
1981 RSG::texture_storage->canvas_texture_set_texture_repeat(p_canvas_texture, p_repeat);
1982}
1983
1984void RendererCanvasCull::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) {
1985 Item *ci = canvas_item_owner.get_or_null(p_item);
1986 ERR_FAIL_COND(!ci);
1987 ci->texture_filter = p_filter;
1988}
1989void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) {
1990 Item *ci = canvas_item_owner.get_or_null(p_item);
1991 ERR_FAIL_COND(!ci);
1992 ci->texture_repeat = p_repeat;
1993}
1994
1995void RendererCanvasCull::update_visibility_notifiers() {
1996 SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first();
1997 while (E) {
1998 SelfList<Item::VisibilityNotifierData> *N = E->next();
1999
2000 Item::VisibilityNotifierData *visibility_notifier = E->self();
2001 if (visibility_notifier->just_visible) {
2002 visibility_notifier->just_visible = false;
2003
2004 if (!visibility_notifier->enter_callable.is_null()) {
2005 if (RSG::threaded) {
2006 visibility_notifier->enter_callable.call_deferred();
2007 } else {
2008 Callable::CallError ce;
2009 Variant ret;
2010 visibility_notifier->enter_callable.callp(nullptr, 0, ret, ce);
2011 }
2012 }
2013 } else {
2014 if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
2015 visibility_notifier_list.remove(E);
2016
2017 if (!visibility_notifier->exit_callable.is_null()) {
2018 if (RSG::threaded) {
2019 visibility_notifier->exit_callable.call_deferred();
2020 } else {
2021 Callable::CallError ce;
2022 Variant ret;
2023 visibility_notifier->exit_callable.callp(nullptr, 0, ret, ce);
2024 }
2025 }
2026 }
2027 }
2028
2029 E = N;
2030 }
2031}
2032
2033bool RendererCanvasCull::free(RID p_rid) {
2034 if (canvas_owner.owns(p_rid)) {
2035 Canvas *canvas = canvas_owner.get_or_null(p_rid);
2036 ERR_FAIL_COND_V(!canvas, false);
2037
2038 while (canvas->viewports.size()) {
2039 RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.get_or_null(*canvas->viewports.begin());
2040 ERR_FAIL_COND_V(!vp, true);
2041
2042 HashMap<RID, RendererViewport::Viewport::CanvasData>::Iterator E = vp->canvas_map.find(p_rid);
2043 ERR_FAIL_COND_V(!E, true);
2044 vp->canvas_map.erase(p_rid);
2045
2046 canvas->viewports.erase(*canvas->viewports.begin());
2047 }
2048
2049 for (int i = 0; i < canvas->child_items.size(); i++) {
2050 canvas->child_items[i].item->parent = RID();
2051 }
2052
2053 for (RendererCanvasRender::Light *E : canvas->lights) {
2054 E->canvas = RID();
2055 }
2056
2057 for (RendererCanvasRender::LightOccluderInstance *E : canvas->occluders) {
2058 E->canvas = RID();
2059 }
2060
2061 canvas_owner.free(p_rid);
2062
2063 } else if (canvas_item_owner.owns(p_rid)) {
2064 Item *canvas_item = canvas_item_owner.get_or_null(p_rid);
2065 ERR_FAIL_COND_V(!canvas_item, true);
2066
2067 if (canvas_item->parent.is_valid()) {
2068 if (canvas_owner.owns(canvas_item->parent)) {
2069 Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
2070 canvas->erase_item(canvas_item);
2071 } else if (canvas_item_owner.owns(canvas_item->parent)) {
2072 Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent);
2073 item_owner->child_items.erase(canvas_item);
2074
2075 if (item_owner->sort_y) {
2076 _mark_ysort_dirty(item_owner, canvas_item_owner);
2077 }
2078 }
2079 }
2080
2081 for (int i = 0; i < canvas_item->child_items.size(); i++) {
2082 canvas_item->child_items[i]->parent = RID();
2083 }
2084
2085 if (canvas_item->visibility_notifier != nullptr) {
2086 visibility_notifier_allocator.free(canvas_item->visibility_notifier);
2087 }
2088
2089 /*
2090 if (canvas_item->material) {
2091 canvas_item->material->owners.erase(canvas_item);
2092 }
2093 */
2094
2095 if (canvas_item->canvas_group != nullptr) {
2096 memdelete(canvas_item->canvas_group);
2097 canvas_item->canvas_group = nullptr;
2098 }
2099
2100 canvas_item_owner.free(p_rid);
2101
2102 } else if (canvas_light_owner.owns(p_rid)) {
2103 RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid);
2104 ERR_FAIL_COND_V(!canvas_light, true);
2105
2106 if (canvas_light->canvas.is_valid()) {
2107 Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas);
2108 if (canvas) {
2109 canvas->lights.erase(canvas_light);
2110 }
2111 }
2112
2113 RSG::canvas_render->free(canvas_light->light_internal);
2114
2115 canvas_light_owner.free(p_rid);
2116
2117 } else if (canvas_light_occluder_owner.owns(p_rid)) {
2118 RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid);
2119 ERR_FAIL_COND_V(!occluder, true);
2120
2121 if (occluder->polygon.is_valid()) {
2122 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
2123 if (occluder_poly) {
2124 occluder_poly->owners.erase(occluder);
2125 }
2126 }
2127
2128 if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) {
2129 Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
2130 canvas->occluders.erase(occluder);
2131 }
2132
2133 canvas_light_occluder_owner.free(p_rid);
2134
2135 } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
2136 LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid);
2137 ERR_FAIL_COND_V(!occluder_poly, true);
2138 RSG::canvas_render->free(occluder_poly->occluder);
2139
2140 while (occluder_poly->owners.size()) {
2141 (*occluder_poly->owners.begin())->polygon = RID();
2142 occluder_poly->owners.remove(occluder_poly->owners.begin());
2143 }
2144
2145 canvas_light_occluder_polygon_owner.free(p_rid);
2146 } else {
2147 return false;
2148 }
2149
2150 return true;
2151}
2152
2153RendererCanvasCull::RendererCanvasCull() {
2154 z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
2155 z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
2156
2157 disable_scale = false;
2158}
2159
2160RendererCanvasCull::~RendererCanvasCull() {
2161 memfree(z_list);
2162 memfree(z_last_list);
2163}
2164