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 | |
39 | 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) { |
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 | |
77 | void _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 | |
109 | void _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 | |
116 | 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) { |
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 | |
225 | 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) { |
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 | |
356 | 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) { |
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 | |
406 | bool RendererCanvasCull::was_sdf_used() { |
407 | return sdf_used; |
408 | } |
409 | |
410 | RID RendererCanvasCull::canvas_allocate() { |
411 | return canvas_owner.allocate_rid(); |
412 | } |
413 | void RendererCanvasCull::canvas_initialize(RID p_rid) { |
414 | canvas_owner.initialize_rid(p_rid); |
415 | } |
416 | |
417 | void 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 | |
428 | void 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 | |
434 | void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) { |
435 | disable_scale = p_disable; |
436 | } |
437 | |
438 | void 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 | |
446 | RID RendererCanvasCull::canvas_item_allocate() { |
447 | return canvas_item_owner.allocate_rid(); |
448 | } |
449 | void RendererCanvasCull::canvas_item_initialize(RID p_rid) { |
450 | canvas_item_owner.initialize_rid(p_rid); |
451 | } |
452 | |
453 | void 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 | |
497 | void 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 | |
506 | void 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 | |
513 | void 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 | |
520 | void 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 | |
527 | uint32_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 | |
534 | void 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 | |
541 | void 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 | |
548 | void 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 | |
556 | void 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 | |
563 | void 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 | |
570 | void 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 | |
577 | void 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 | |
584 | void 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 | |
772 | static 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 | |
792 | static 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 | |
815 | void 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 | |
1082 | void 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 | |
1129 | void 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 | |
1139 | void 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 | |
1178 | void 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 | |
1209 | void 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 | |
1243 | void 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 | |
1275 | void 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 | |
1316 | void 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 | |
1337 | void 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 | |
1366 | void 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 | |
1387 | void 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 | |
1410 | void 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 | |
1419 | void 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 | |
1438 | void 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 | |
1452 | void 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 | |
1463 | void 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 | |
1472 | void 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 | |
1484 | void 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 | |
1493 | void 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 | |
1502 | void 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 | |
1509 | void 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 | |
1538 | void 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 | |
1555 | void 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 | |
1562 | void 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 | |
1581 | void 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 | |
1588 | void 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 | |
1595 | void 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 | |
1615 | 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) { |
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 | |
1636 | RID RendererCanvasCull::canvas_light_allocate() { |
1637 | return canvas_light_owner.allocate_rid(); |
1638 | } |
1639 | void 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 | |
1645 | void 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 | |
1666 | void 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 | |
1695 | void 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 | |
1702 | void 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 | |
1709 | void 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 | |
1716 | void 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 | |
1728 | void 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 | |
1735 | void 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 | |
1742 | void 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 | |
1749 | void 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 | |
1756 | void 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 | |
1764 | void 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 | |
1772 | void 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 | |
1779 | void 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 | |
1786 | void 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 | |
1793 | void 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 | |
1800 | void 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 | |
1812 | void 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 | |
1819 | void 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 | |
1826 | void 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 | |
1832 | RID RendererCanvasCull::canvas_light_occluder_allocate() { |
1833 | return canvas_light_occluder_owner.allocate_rid(); |
1834 | } |
1835 | void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) { |
1836 | return canvas_light_occluder_owner.initialize_rid(p_rid); |
1837 | } |
1838 | |
1839 | void 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 | |
1860 | void 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 | |
1867 | void 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 | |
1895 | void 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 | |
1900 | void 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 | |
1907 | void 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 | |
1914 | RID RendererCanvasCull::canvas_occluder_polygon_allocate() { |
1915 | return canvas_light_occluder_polygon_owner.allocate_rid(); |
1916 | } |
1917 | void 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 | |
1923 | void 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 | |
1947 | void 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 | |
1957 | void RendererCanvasCull::canvas_set_shadow_texture_size(int p_size) { |
1958 | RSG::canvas_render->set_shadow_texture_size(p_size); |
1959 | } |
1960 | |
1961 | RID RendererCanvasCull::canvas_texture_allocate() { |
1962 | return RSG::texture_storage->canvas_texture_allocate(); |
1963 | } |
1964 | void RendererCanvasCull::canvas_texture_initialize(RID p_rid) { |
1965 | RSG::texture_storage->canvas_texture_initialize(p_rid); |
1966 | } |
1967 | |
1968 | void 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 | |
1972 | void 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 | |
1976 | void 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 | |
1980 | void 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 | |
1984 | void 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 | } |
1989 | void 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 | |
1995 | void 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 | |
2033 | bool 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 | |
2153 | RendererCanvasCull::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 | |
2160 | RendererCanvasCull::~RendererCanvasCull() { |
2161 | memfree(z_list); |
2162 | memfree(z_last_list); |
2163 | } |
2164 | |