Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/servers/rendering/renderer_canvas_cull.cpp
11351 views
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/config/project_settings.h"
34
#include "core/math/geometry_2d.h"
35
#include "core/math/transform_interpolator.h"
36
#include "renderer_viewport.h"
37
#include "rendering_server_default.h"
38
#include "rendering_server_globals.h"
39
#include "servers/rendering/storage/texture_storage.h"
40
41
// Use the same antialiasing feather size as StyleBoxFlat's default
42
// (but doubled, as it's specified for both sides here).
43
// This value is empirically determined to provide good antialiasing quality
44
// while not making lines appear too soft.
45
const static float FEATHER_SIZE = 1.25f;
46
47
static RendererCanvasCull *_canvas_cull_singleton = nullptr;
48
49
void RendererCanvasCull::_dependency_changed(Dependency::DependencyChangedNotification p_notification, DependencyTracker *p_tracker) {
50
Item *item = (Item *)p_tracker->userdata;
51
52
switch (p_notification) {
53
case Dependency::DEPENDENCY_CHANGED_MATERIAL: {
54
_canvas_cull_singleton->_item_queue_update(item, true);
55
} break;
56
default: {
57
} break;
58
}
59
}
60
61
void RendererCanvasCull::_dependency_deleted(const RID &p_dependency, DependencyTracker *p_tracker) {
62
Item *item = (Item *)p_tracker->userdata;
63
64
if (p_dependency == item->material) {
65
_canvas_cull_singleton->canvas_item_set_material(item->self, RID());
66
}
67
_canvas_cull_singleton->_item_queue_update(item, true);
68
}
69
70
void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) {
71
RENDER_TIMESTAMP("Cull CanvasItem Tree");
72
73
// This is used to avoid passing the camera transform down the rendering
74
// function calls, as it won't be used in 99% of cases, because the camera
75
// transform is normally concatenated with the item global transform.
76
_current_camera_transform = p_transform;
77
78
memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
79
memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
80
81
for (int i = 0; i < p_child_item_count; i++) {
82
_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, false, p_canvas_cull_mask, Point2(), 1, nullptr);
83
}
84
85
RendererCanvasRender::Item *list = nullptr;
86
RendererCanvasRender::Item *list_end = nullptr;
87
88
for (int i = 0; i < z_range; i++) {
89
if (!z_list[i]) {
90
continue;
91
}
92
if (!list) {
93
list = z_list[i];
94
list_end = z_last_list[i];
95
} else {
96
list_end->next = z_list[i];
97
list_end = z_last_list[i];
98
}
99
}
100
101
RENDER_TIMESTAMP("Render CanvasItems");
102
103
bool sdf_flag;
104
RSG::canvas_render->canvas_render_items(p_to_render_target, list, p_modulate, p_lights, p_directional_lights, p_transform, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, sdf_flag, r_render_info);
105
if (sdf_flag) {
106
sdf_used = true;
107
}
108
}
109
110
void RendererCanvasCull::_collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, RendererCanvasCull::Item *p_material_owner, const Color &p_modulate, RendererCanvasCull::Item **r_items, int &r_index, int &r_ysort_children_count, int p_z, uint32_t p_canvas_cull_mask) {
111
int child_item_count = p_canvas_item->child_items.size();
112
RendererCanvasCull::Item **child_items = p_canvas_item->child_items.ptrw();
113
for (int i = 0; i < child_item_count; i++) {
114
if (child_items[i]->visible) {
115
if (child_items[i]->visibility_layer & p_canvas_cull_mask) {
116
// To y-sort according to the item's final position, physics interpolation
117
// and transform snapping need to be applied before y-sorting.
118
Transform2D child_xform;
119
if (!_interpolation_data.interpolation_enabled || !child_items[i]->interpolated) {
120
child_xform = child_items[i]->xform_curr;
121
} else {
122
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
123
TransformInterpolator::interpolate_transform_2d(child_items[i]->xform_prev, child_items[i]->xform_curr, child_xform, f);
124
}
125
126
if (snapping_2d_transforms_to_pixel) {
127
child_xform.columns[2] = (child_xform.columns[2] + Point2(0.5, 0.5)).floor();
128
}
129
130
r_items[r_index] = child_items[i];
131
child_items[i]->ysort_xform = p_canvas_item->ysort_xform * child_xform;
132
child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
133
child_items[i]->ysort_modulate = p_modulate;
134
child_items[i]->ysort_index = r_index;
135
child_items[i]->ysort_parent_abs_z_index = p_z;
136
137
if (!child_items[i]->repeat_source) {
138
child_items[i]->repeat_size = p_canvas_item->repeat_size;
139
child_items[i]->repeat_times = p_canvas_item->repeat_times;
140
child_items[i]->repeat_source_item = p_canvas_item->repeat_source_item;
141
}
142
143
// Y sorted canvas items are flattened into r_items. Calculate their absolute z index to use when rendering r_items.
144
int abs_z = 0;
145
if (child_items[i]->z_relative) {
146
abs_z = CLAMP(p_z + child_items[i]->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
147
} else {
148
abs_z = child_items[i]->z_index;
149
}
150
151
r_index++;
152
153
if (child_items[i]->sort_y) {
154
_collect_ysort_children(child_items[i], child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, r_ysort_children_count, abs_z, p_canvas_cull_mask);
155
}
156
} else {
157
r_ysort_children_count--;
158
if (child_items[i]->sort_y) {
159
r_ysort_children_count -= child_items[i]->ysort_children_count;
160
}
161
}
162
}
163
}
164
}
165
166
int RendererCanvasCull::_count_ysort_children(RendererCanvasCull::Item *p_canvas_item) {
167
int ysort_children_count = 0;
168
int child_item_count = p_canvas_item->child_items.size();
169
RendererCanvasCull::Item *const *child_items = p_canvas_item->child_items.ptr();
170
for (int i = 0; i < child_item_count; i++) {
171
if (child_items[i]->visible) {
172
ysort_children_count++;
173
if (child_items[i]->sort_y) {
174
if (child_items[i]->ysort_children_count == -1) {
175
child_items[i]->ysort_children_count = _count_ysort_children(child_items[i]);
176
}
177
ysort_children_count += child_items[i]->ysort_children_count;
178
}
179
}
180
}
181
return ysort_children_count;
182
}
183
184
void RendererCanvasCull::_mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner) {
185
do {
186
ysort_owner->ysort_children_count = -1;
187
ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.get_or_null(ysort_owner->parent) : nullptr;
188
} while (ysort_owner && ysort_owner->sort_y);
189
}
190
191
void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &p_transform, const Rect2 &p_clip_rect, Rect2 p_global_rect, const Color &p_modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *r_canvas_group_from) {
192
if (ci->copy_back_buffer) {
193
ci->copy_back_buffer->screen_rect = p_transform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
194
}
195
196
if (p_use_canvas_group) {
197
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
198
if (r_canvas_group_from == nullptr) {
199
// no list before processing this item, means must put stuff in group from the beginning of list.
200
r_canvas_group_from = r_z_list[zidx];
201
} else {
202
// there was a list before processing, so begin group from this one.
203
r_canvas_group_from = r_canvas_group_from->next;
204
}
205
206
if (r_canvas_group_from) {
207
// Has a place to begin the group from!
208
209
//compute a global rect (in global coords) for children in the same z layer
210
Rect2 rect_accum;
211
RendererCanvasRender::Item *c = r_canvas_group_from;
212
while (c) {
213
if (c == r_canvas_group_from) {
214
rect_accum = c->global_rect_cache;
215
} else {
216
rect_accum = rect_accum.merge(c->global_rect_cache);
217
}
218
219
c = c->next;
220
}
221
222
// 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.
223
// If nothing has been drawn, we just take it over and draw it ourselves.
224
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)))) {
225
// No commands, or sole command is the one used to draw, so we (re)create the draw command.
226
ci->clear();
227
228
if (rect_accum == Rect2()) {
229
rect_accum.size = Size2(1, 1);
230
}
231
232
rect_accum = rect_accum.grow(ci->canvas_group->fit_margin);
233
234
//draw it?
235
RendererCanvasRender::Item::CommandRect *crect = ci->alloc_command<RendererCanvasRender::Item::CommandRect>();
236
237
crect->flags = RendererCanvasRender::CANVAS_RECT_IS_GROUP; // so we can recognize it later
238
crect->rect = p_transform.affine_inverse().xform(rect_accum);
239
crect->modulate = Color(1, 1, 1, 1);
240
241
//the global rect is used to do the copying, so update it
242
p_global_rect = rect_accum.grow(ci->canvas_group->clear_margin); //grow again by clear margin
243
p_global_rect.position += p_clip_rect.position;
244
} else {
245
p_global_rect.position -= p_clip_rect.position;
246
247
p_global_rect = p_global_rect.merge(rect_accum); //must use both rects for this
248
p_global_rect = p_global_rect.grow(ci->canvas_group->clear_margin); //grow by clear margin
249
250
p_global_rect.position += p_clip_rect.position;
251
}
252
253
// Very important that this is cleared after used in RendererCanvasRender to avoid
254
// potential crashes.
255
r_canvas_group_from->canvas_group_owner = ci;
256
}
257
}
258
259
if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(p_global_rect, true)) || ci->vp_render || ci->copy_back_buffer) {
260
// Something to draw?
261
262
if (ci->update_when_visible) {
263
RenderingServerDefault::redraw_request();
264
}
265
266
if (ci->commands != nullptr || ci->copy_back_buffer) {
267
ci->final_transform = !ci->use_identity_transform ? p_transform : _current_camera_transform;
268
ci->final_modulate = p_modulate * ci->self_modulate;
269
ci->global_rect_cache = p_global_rect;
270
ci->global_rect_cache.position -= p_clip_rect.position;
271
ci->light_masked = false;
272
273
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
274
275
if (r_z_last_list[zidx]) {
276
r_z_last_list[zidx]->next = ci;
277
r_z_last_list[zidx] = ci;
278
279
} else {
280
r_z_list[zidx] = ci;
281
r_z_last_list[zidx] = ci;
282
}
283
284
ci->z_final = p_z;
285
286
ci->next = nullptr;
287
}
288
289
if (ci->visibility_notifier) {
290
if (!ci->visibility_notifier->visible_element.in_list()) {
291
visibility_notifier_list.add(&ci->visibility_notifier->visible_element);
292
ci->visibility_notifier->just_visible = true;
293
}
294
295
ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number();
296
}
297
} else if (ci->repeat_source) {
298
// If repeat source does not draw itself it still needs transform updated as its child items' repeat offsets are relative to it.
299
ci->final_transform = p_transform;
300
}
301
}
302
303
void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_is_already_y_sorted, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times, RendererCanvasRender::Item *p_repeat_source_item) {
304
Item *ci = p_canvas_item;
305
306
if (!ci->visible) {
307
return;
308
}
309
310
if (!(ci->visibility_layer & p_canvas_cull_mask)) {
311
return;
312
}
313
314
if (ci->children_order_dirty) {
315
ci->child_items.sort_custom<ItemIndexSort>();
316
ci->children_order_dirty = false;
317
}
318
319
if (ci->use_parent_material && p_material_owner) {
320
ci->material_owner = p_material_owner;
321
} else {
322
p_material_owner = ci;
323
ci->material_owner = nullptr;
324
}
325
326
Color modulate = ci->modulate * p_modulate;
327
328
if (modulate.a < 0.007) {
329
return;
330
}
331
332
Rect2 rect = ci->get_rect();
333
334
if (ci->visibility_notifier) {
335
if (ci->visibility_notifier->area.size != Vector2()) {
336
rect = rect.merge(ci->visibility_notifier->area);
337
}
338
}
339
340
// Always calculate final transform as if not using identity xform.
341
// This is so the expected transform is passed to children.
342
// However, if use_identity_xform is set,
343
// we can override the transform for rendering purposes for this item only.
344
Transform2D self_xform;
345
Transform2D final_xform;
346
if (p_is_already_y_sorted) {
347
// Y-sorted item's final transform is calculated before y-sorting,
348
// and is passed as `p_parent_xform` afterwards. No need to recalculate.
349
final_xform = p_parent_xform;
350
} else {
351
if (!_interpolation_data.interpolation_enabled || !ci->interpolated) {
352
self_xform = ci->xform_curr;
353
} else {
354
real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
355
TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, self_xform, f);
356
}
357
358
Transform2D parent_xform = p_parent_xform;
359
360
if (snapping_2d_transforms_to_pixel) {
361
self_xform.columns[2] = (self_xform.columns[2] + Point2(0.5, 0.5)).floor();
362
parent_xform.columns[2] = (parent_xform.columns[2] + Point2(0.5, 0.5)).floor();
363
}
364
365
final_xform = parent_xform * self_xform;
366
}
367
368
Point2 repeat_size = p_repeat_size;
369
int repeat_times = p_repeat_times;
370
RendererCanvasRender::Item *repeat_source_item = p_repeat_source_item;
371
372
if (ci->repeat_source) {
373
repeat_size = ci->repeat_size;
374
repeat_times = ci->repeat_times;
375
repeat_source_item = ci;
376
} else {
377
ci->repeat_size = repeat_size;
378
ci->repeat_times = repeat_times;
379
ci->repeat_source_item = repeat_source_item;
380
}
381
382
Rect2 global_rect;
383
if (!p_canvas_item->use_identity_transform) {
384
global_rect = final_xform.xform(rect);
385
} else {
386
global_rect = _current_camera_transform.xform(rect);
387
}
388
if (repeat_source_item && (repeat_size.x || repeat_size.y)) {
389
// Top-left repeated rect.
390
Rect2 corner_rect = global_rect;
391
corner_rect.position -= repeat_source_item->final_transform.basis_xform((repeat_times / 2) * repeat_size);
392
global_rect = corner_rect;
393
394
// Plus top-right repeated rect.
395
Size2 size_x_offset = repeat_source_item->final_transform.basis_xform(repeat_times * Size2(repeat_size.x, 0));
396
corner_rect.position += size_x_offset;
397
global_rect = global_rect.merge(corner_rect);
398
399
// Plus bottom-right repeated rect.
400
corner_rect.position += repeat_source_item->final_transform.basis_xform(repeat_times * Size2(0, repeat_size.y));
401
global_rect = global_rect.merge(corner_rect);
402
403
// Plus bottom-left repeated rect.
404
corner_rect.position -= size_x_offset;
405
global_rect = global_rect.merge(corner_rect);
406
}
407
global_rect.position += p_clip_rect.position;
408
409
int child_item_count = ci->child_items.size();
410
Item **child_items = ci->child_items.ptrw();
411
412
if (ci->clip) {
413
if (p_canvas_clip != nullptr) {
414
ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect);
415
} else {
416
ci->final_clip_rect = p_clip_rect.intersection(global_rect);
417
}
418
if (ci->final_clip_rect.size.width < 0.5 || ci->final_clip_rect.size.height < 0.5) {
419
// The clip rect area is 0, so don't draw the item.
420
return;
421
}
422
ci->final_clip_rect.position = ci->final_clip_rect.position.round();
423
ci->final_clip_rect.size = ci->final_clip_rect.size.round();
424
ci->final_clip_owner = ci;
425
426
} else {
427
ci->final_clip_owner = p_canvas_clip;
428
}
429
430
int parent_z = p_z;
431
if (ci->z_relative) {
432
p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX);
433
} else {
434
p_z = ci->z_index;
435
}
436
437
if (ci->sort_y) {
438
if (!p_is_already_y_sorted) {
439
if (ci->ysort_children_count == -1) {
440
ci->ysort_children_count = _count_ysort_children(ci);
441
}
442
443
child_item_count = ci->ysort_children_count + 1;
444
child_items = (Item **)alloca(child_item_count * sizeof(Item *));
445
446
ci->ysort_xform = Transform2D();
447
ci->ysort_modulate = Color(1, 1, 1, 1) / ci->modulate;
448
ci->ysort_index = 0;
449
ci->ysort_parent_abs_z_index = parent_z;
450
child_items[0] = ci;
451
int i = 1;
452
_collect_ysort_children(ci, p_material_owner, Color(1, 1, 1, 1), child_items, i, child_item_count, p_z, p_canvas_cull_mask);
453
454
SortArray<Item *, ItemYSort> sorter;
455
sorter.sort(child_items, child_item_count);
456
457
for (i = 0; i < child_item_count; i++) {
458
_cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, true, p_canvas_cull_mask, child_items[i]->repeat_size, child_items[i]->repeat_times, child_items[i]->repeat_source_item);
459
}
460
} else {
461
RendererCanvasRender::Item *canvas_group_from = nullptr;
462
bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
463
if (use_canvas_group) {
464
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
465
canvas_group_from = r_z_last_list[zidx];
466
}
467
468
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
469
}
470
} else {
471
RendererCanvasRender::Item *canvas_group_from = nullptr;
472
bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
473
if (use_canvas_group) {
474
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
475
canvas_group_from = r_z_last_list[zidx];
476
}
477
478
for (int i = 0; i < child_item_count; i++) {
479
if (!child_items[i]->behind && !use_canvas_group) {
480
continue;
481
}
482
_cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times, repeat_source_item);
483
}
484
_attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
485
for (int i = 0; i < child_item_count; i++) {
486
if (child_items[i]->behind || use_canvas_group) {
487
continue;
488
}
489
_cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times, repeat_source_item);
490
}
491
}
492
}
493
494
void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) {
495
RENDER_TIMESTAMP("> Render Canvas");
496
497
sdf_used = false;
498
snapping_2d_transforms_to_pixel = p_snap_2d_transforms_to_pixel;
499
500
if (p_canvas->children_order_dirty) {
501
p_canvas->child_items.sort();
502
p_canvas->children_order_dirty = false;
503
}
504
505
int l = p_canvas->child_items.size();
506
Canvas::ChildItem *ci = p_canvas->child_items.ptrw();
507
508
_render_canvas_item_tree(p_render_target, ci, l, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info);
509
510
RENDER_TIMESTAMP("< Render Canvas");
511
}
512
513
bool RendererCanvasCull::was_sdf_used() {
514
return sdf_used;
515
}
516
517
RID RendererCanvasCull::canvas_allocate() {
518
return canvas_owner.allocate_rid();
519
}
520
void RendererCanvasCull::canvas_initialize(RID p_rid) {
521
canvas_owner.initialize_rid(p_rid);
522
}
523
524
void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) {
525
Canvas *canvas = canvas_owner.get_or_null(p_canvas);
526
ERR_FAIL_NULL(canvas);
527
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
528
ERR_FAIL_NULL(canvas_item);
529
530
int idx = canvas->find_item(canvas_item);
531
ERR_FAIL_COND(idx == -1);
532
533
bool is_repeat_source = (p_mirroring.x || p_mirroring.y);
534
canvas_item->repeat_source = is_repeat_source;
535
canvas_item->repeat_source_item = is_repeat_source ? canvas_item : nullptr;
536
canvas_item->repeat_size = p_mirroring;
537
canvas_item->repeat_times = 1;
538
}
539
540
void RendererCanvasCull::canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times) {
541
ERR_FAIL_COND(p_repeat_times < 0);
542
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
543
ERR_FAIL_NULL(canvas_item);
544
545
bool is_repeat_source = (p_repeat_size.x || p_repeat_size.y) && p_repeat_times;
546
canvas_item->repeat_source = is_repeat_source;
547
canvas_item->repeat_source_item = is_repeat_source ? canvas_item : nullptr;
548
canvas_item->repeat_size = p_repeat_size;
549
canvas_item->repeat_times = p_repeat_times;
550
}
551
552
void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) {
553
Canvas *canvas = canvas_owner.get_or_null(p_canvas);
554
ERR_FAIL_NULL(canvas);
555
canvas->modulate = p_color;
556
}
557
558
void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) {
559
disable_scale = p_disable;
560
}
561
562
void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) {
563
Canvas *canvas = canvas_owner.get_or_null(p_canvas);
564
ERR_FAIL_NULL(canvas);
565
566
canvas->parent = p_parent;
567
canvas->parent_scale = p_scale;
568
}
569
570
RID RendererCanvasCull::canvas_item_allocate() {
571
return canvas_item_owner.allocate_rid();
572
}
573
void RendererCanvasCull::canvas_item_initialize(RID p_rid) {
574
canvas_item_owner.initialize_rid(p_rid);
575
Item *instance = canvas_item_owner.get_or_null(p_rid);
576
instance->self = p_rid;
577
}
578
579
void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) {
580
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
581
ERR_FAIL_NULL(canvas_item);
582
583
if (canvas_item->parent.is_valid()) {
584
if (canvas_owner.owns(canvas_item->parent)) {
585
Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
586
canvas->erase_item(canvas_item);
587
} else if (canvas_item_owner.owns(canvas_item->parent)) {
588
Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent);
589
item_owner->child_items.erase(canvas_item);
590
591
if (item_owner->sort_y) {
592
_mark_ysort_dirty(item_owner);
593
}
594
}
595
596
canvas_item->parent = RID();
597
}
598
599
if (p_parent.is_valid()) {
600
if (canvas_owner.owns(p_parent)) {
601
Canvas *canvas = canvas_owner.get_or_null(p_parent);
602
Canvas::ChildItem ci;
603
ci.item = canvas_item;
604
canvas->child_items.push_back(ci);
605
canvas->children_order_dirty = true;
606
} else if (canvas_item_owner.owns(p_parent)) {
607
Item *item_owner = canvas_item_owner.get_or_null(p_parent);
608
item_owner->child_items.push_back(canvas_item);
609
item_owner->children_order_dirty = true;
610
611
if (item_owner->sort_y) {
612
_mark_ysort_dirty(item_owner);
613
}
614
615
} else {
616
ERR_FAIL_MSG("Invalid parent.");
617
}
618
}
619
620
canvas_item->parent = p_parent;
621
}
622
623
void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) {
624
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
625
ERR_FAIL_NULL(canvas_item);
626
627
canvas_item->visible = p_visible;
628
629
_mark_ysort_dirty(canvas_item);
630
}
631
632
void RendererCanvasCull::canvas_item_set_light_mask(RID p_item, int p_mask) {
633
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
634
ERR_FAIL_NULL(canvas_item);
635
636
canvas_item->light_mask = p_mask;
637
}
638
639
void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) {
640
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
641
ERR_FAIL_NULL(canvas_item);
642
643
if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) {
644
if (!canvas_item->on_interpolate_transform_list) {
645
_interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item);
646
canvas_item->on_interpolate_transform_list = true;
647
} else {
648
DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size() > 0);
649
}
650
}
651
652
canvas_item->xform_curr = p_transform;
653
}
654
655
void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) {
656
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
657
ERR_FAIL_NULL(canvas_item);
658
659
canvas_item->visibility_layer = p_visibility_layer;
660
}
661
662
uint32_t RendererCanvasCull::canvas_item_get_visibility_layer(RID p_item) {
663
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
664
if (!canvas_item) {
665
return 0;
666
}
667
return canvas_item->visibility_layer;
668
}
669
670
void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) {
671
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
672
ERR_FAIL_NULL(canvas_item);
673
674
canvas_item->clip = p_clip;
675
}
676
677
void RendererCanvasCull::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) {
678
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
679
ERR_FAIL_NULL(canvas_item);
680
681
canvas_item->distance_field = p_enable;
682
}
683
684
void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) {
685
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
686
ERR_FAIL_NULL(canvas_item);
687
688
canvas_item->custom_rect = p_custom_rect;
689
canvas_item->rect = p_rect;
690
}
691
692
void RendererCanvasCull::canvas_item_set_modulate(RID p_item, const Color &p_color) {
693
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
694
ERR_FAIL_NULL(canvas_item);
695
696
canvas_item->modulate = p_color;
697
}
698
699
void RendererCanvasCull::canvas_item_set_self_modulate(RID p_item, const Color &p_color) {
700
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
701
ERR_FAIL_NULL(canvas_item);
702
703
canvas_item->self_modulate = p_color;
704
}
705
706
void RendererCanvasCull::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) {
707
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
708
ERR_FAIL_NULL(canvas_item);
709
710
canvas_item->behind = p_enable;
711
}
712
713
void RendererCanvasCull::canvas_item_set_use_identity_transform(RID p_item, bool p_enable) {
714
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
715
ERR_FAIL_NULL(canvas_item);
716
717
canvas_item->use_identity_transform = p_enable;
718
}
719
720
void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_update) {
721
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
722
ERR_FAIL_NULL(canvas_item);
723
724
canvas_item->update_when_visible = p_update;
725
}
726
727
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) {
728
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
729
ERR_FAIL_NULL(canvas_item);
730
731
Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>();
732
ERR_FAIL_NULL(line);
733
734
Vector2 diff = (p_from - p_to);
735
Vector2 dir = diff.orthogonal().normalized();
736
Vector2 t = dir * p_width * 0.5;
737
738
Vector2 begin_left;
739
Vector2 begin_right;
740
Vector2 end_left;
741
Vector2 end_right;
742
743
if (p_width >= 0.0) {
744
begin_left = p_from + t;
745
begin_right = p_from - t;
746
end_left = p_to + t;
747
end_right = p_to - t;
748
749
line->points[0] = begin_left;
750
line->points[1] = begin_right;
751
line->points[2] = end_right;
752
line->points[3] = end_left;
753
line->point_count = 4;
754
} else {
755
begin_left = p_from;
756
begin_right = p_from;
757
end_left = p_to;
758
end_right = p_to;
759
760
line->points[0] = p_from;
761
line->points[1] = p_to;
762
line->point_count = 2;
763
}
764
for (uint32_t i = 0; i < line->point_count; i++) {
765
line->colors[i] = p_color;
766
}
767
768
if (p_antialiased) {
769
float border_size = FEATHER_SIZE;
770
771
if (0.0f <= p_width && p_width < 1.0f) {
772
border_size *= p_width;
773
}
774
Vector2 dir2 = diff.normalized();
775
776
Vector2 border = dir * border_size;
777
Vector2 border2 = dir2 * border_size;
778
779
Color transparent = Color(p_color, 0.0);
780
781
{
782
Item::CommandPrimitive *left_border = canvas_item->alloc_command<Item::CommandPrimitive>();
783
ERR_FAIL_NULL(left_border);
784
785
left_border->points[0] = begin_left;
786
left_border->points[1] = begin_left + border;
787
left_border->points[2] = end_left + border;
788
left_border->points[3] = end_left;
789
790
left_border->colors[0] = p_color;
791
left_border->colors[1] = transparent;
792
left_border->colors[2] = transparent;
793
left_border->colors[3] = p_color;
794
795
left_border->point_count = 4;
796
}
797
{
798
Item::CommandPrimitive *right_border = canvas_item->alloc_command<Item::CommandPrimitive>();
799
ERR_FAIL_NULL(right_border);
800
801
right_border->points[0] = begin_right;
802
right_border->points[1] = begin_right - border;
803
right_border->points[2] = end_right - border;
804
right_border->points[3] = end_right;
805
806
right_border->colors[0] = p_color;
807
right_border->colors[1] = transparent;
808
right_border->colors[2] = transparent;
809
right_border->colors[3] = p_color;
810
811
right_border->point_count = 4;
812
}
813
{
814
Item::CommandPrimitive *top_border = canvas_item->alloc_command<Item::CommandPrimitive>();
815
ERR_FAIL_NULL(top_border);
816
817
top_border->points[0] = begin_left;
818
top_border->points[1] = begin_left + border2;
819
top_border->points[2] = begin_right + border2;
820
top_border->points[3] = begin_right;
821
822
top_border->colors[0] = p_color;
823
top_border->colors[1] = transparent;
824
top_border->colors[2] = transparent;
825
top_border->colors[3] = p_color;
826
827
top_border->point_count = 4;
828
}
829
{
830
Item::CommandPrimitive *bottom_border = canvas_item->alloc_command<Item::CommandPrimitive>();
831
ERR_FAIL_NULL(bottom_border);
832
833
bottom_border->points[0] = end_left;
834
bottom_border->points[1] = end_left - border2;
835
bottom_border->points[2] = end_right - border2;
836
bottom_border->points[3] = end_right;
837
838
bottom_border->colors[0] = p_color;
839
bottom_border->colors[1] = transparent;
840
bottom_border->colors[2] = transparent;
841
bottom_border->colors[3] = p_color;
842
843
bottom_border->point_count = 4;
844
}
845
{
846
Item::CommandPrimitive *top_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
847
ERR_FAIL_NULL(top_left_corner);
848
849
top_left_corner->points[0] = begin_left;
850
top_left_corner->points[1] = begin_left + border2;
851
top_left_corner->points[2] = begin_left + border + border2;
852
top_left_corner->points[3] = begin_left + border;
853
854
top_left_corner->colors[0] = p_color;
855
top_left_corner->colors[1] = transparent;
856
top_left_corner->colors[2] = transparent;
857
top_left_corner->colors[3] = transparent;
858
859
top_left_corner->point_count = 4;
860
}
861
{
862
Item::CommandPrimitive *top_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
863
ERR_FAIL_NULL(top_right_corner);
864
865
top_right_corner->points[0] = begin_right;
866
top_right_corner->points[1] = begin_right + border2;
867
top_right_corner->points[2] = begin_right - border + border2;
868
top_right_corner->points[3] = begin_right - border;
869
870
top_right_corner->colors[0] = p_color;
871
top_right_corner->colors[1] = transparent;
872
top_right_corner->colors[2] = transparent;
873
top_right_corner->colors[3] = transparent;
874
875
top_right_corner->point_count = 4;
876
}
877
{
878
Item::CommandPrimitive *bottom_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
879
ERR_FAIL_NULL(bottom_left_corner);
880
881
bottom_left_corner->points[0] = end_left;
882
bottom_left_corner->points[1] = end_left - border2;
883
bottom_left_corner->points[2] = end_left + border - border2;
884
bottom_left_corner->points[3] = end_left + border;
885
886
bottom_left_corner->colors[0] = p_color;
887
bottom_left_corner->colors[1] = transparent;
888
bottom_left_corner->colors[2] = transparent;
889
bottom_left_corner->colors[3] = transparent;
890
891
bottom_left_corner->point_count = 4;
892
}
893
{
894
Item::CommandPrimitive *bottom_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
895
ERR_FAIL_NULL(bottom_right_corner);
896
897
bottom_right_corner->points[0] = end_right;
898
bottom_right_corner->points[1] = end_right - border2;
899
bottom_right_corner->points[2] = end_right - border - border2;
900
bottom_right_corner->points[3] = end_right - border;
901
902
bottom_right_corner->colors[0] = p_color;
903
bottom_right_corner->colors[1] = transparent;
904
bottom_right_corner->colors[2] = transparent;
905
bottom_right_corner->colors[3] = transparent;
906
907
bottom_right_corner->point_count = 4;
908
}
909
}
910
}
911
912
static Vector2 compute_polyline_segment_dir(const Vector<Point2> &p_points, int p_index, const Vector2 &p_prev_segment_dir) {
913
int point_count = p_points.size();
914
915
bool is_last_point = (p_index == point_count - 1);
916
917
Vector2 segment_dir;
918
919
if (is_last_point) {
920
segment_dir = p_prev_segment_dir;
921
} else {
922
segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized();
923
924
if (segment_dir.is_zero_approx()) {
925
segment_dir = p_prev_segment_dir;
926
}
927
}
928
929
return segment_dir;
930
}
931
932
static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) {
933
Vector2 bisector;
934
float length = 1.0f;
935
936
bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized();
937
938
float angle = std::atan2(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir));
939
float sin_angle = std::sin(angle);
940
941
if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) {
942
length = 1.0f / sin_angle;
943
length = CLAMP(length, -3.0f, 3.0f);
944
} else {
945
bisector = p_segment_dir.orthogonal();
946
}
947
948
if (bisector.is_zero_approx()) {
949
bisector = p_segment_dir.orthogonal();
950
}
951
952
return bisector * length;
953
}
954
955
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) {
956
ERR_FAIL_COND(p_points.size() < 2);
957
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
958
ERR_FAIL_NULL(canvas_item);
959
960
Color color = Color(1, 1, 1, 1);
961
962
Vector<int> indices;
963
int point_count = p_points.size();
964
965
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
966
ERR_FAIL_NULL(pline);
967
968
if (p_width < 0) {
969
if (p_antialiased) {
970
WARN_PRINT("Antialiasing is not supported for thin polylines drawn using line strips (`p_width < 0`).");
971
}
972
973
pline->primitive = RS::PRIMITIVE_LINE_STRIP;
974
975
if (p_colors.size() == 1 || p_colors.size() == point_count) {
976
pline->polygon.create(indices, p_points, p_colors);
977
} else {
978
Vector<Color> colors;
979
if (p_colors.is_empty()) {
980
colors.push_back(color);
981
} else {
982
colors.resize(point_count);
983
Color *colors_ptr = colors.ptrw();
984
for (int i = 0; i < point_count; i++) {
985
if (i < p_colors.size()) {
986
color = p_colors[i];
987
}
988
colors_ptr[i] = color;
989
}
990
}
991
pline->polygon.create(indices, p_points, colors);
992
}
993
return;
994
}
995
996
int polyline_point_count = point_count * 2;
997
998
bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]);
999
Vector2 first_segment_dir;
1000
Vector2 last_segment_dir;
1001
1002
// Search for first non-zero vector between two segments.
1003
for (int i = 1; i < point_count; i++) {
1004
first_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
1005
1006
if (!first_segment_dir.is_zero_approx()) {
1007
break;
1008
}
1009
}
1010
1011
// Search for last non-zero vector between two segments.
1012
for (int i = point_count - 1; i >= 1; i--) {
1013
last_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
1014
1015
if (!last_segment_dir.is_zero_approx()) {
1016
break;
1017
}
1018
}
1019
1020
PackedColorArray colors;
1021
PackedVector2Array points;
1022
1023
// Additional 2+2 vertices to antialias begin+end of the middle triangle strip.
1024
colors.resize(polyline_point_count + ((p_antialiased && !loop) ? 4 : 0));
1025
points.resize(polyline_point_count + ((p_antialiased && !loop) ? 4 : 0));
1026
1027
Vector2 *points_ptr = points.ptrw();
1028
Color *colors_ptr = colors.ptrw();
1029
1030
if (p_antialiased) {
1031
float border_size = FEATHER_SIZE;
1032
if (p_width < 1.0f) {
1033
border_size *= p_width;
1034
}
1035
Color color2 = Color(1, 1, 1, 0);
1036
1037
Item::CommandPolygon *pline_left = canvas_item->alloc_command<Item::CommandPolygon>();
1038
ERR_FAIL_NULL(pline_left);
1039
1040
Item::CommandPolygon *pline_right = canvas_item->alloc_command<Item::CommandPolygon>();
1041
ERR_FAIL_NULL(pline_right);
1042
1043
PackedColorArray colors_left;
1044
PackedVector2Array points_left;
1045
1046
PackedColorArray colors_right;
1047
PackedVector2Array points_right;
1048
1049
// 2+2 additional vertices for begin+end corners.
1050
// 1 additional vertex to swap the orientation of the triangles within the end corner's quad.
1051
colors_left.resize(polyline_point_count + (loop ? 0 : 5));
1052
points_left.resize(polyline_point_count + (loop ? 0 : 5));
1053
1054
colors_right.resize(polyline_point_count + (loop ? 0 : 5));
1055
points_right.resize(polyline_point_count + (loop ? 0 : 5));
1056
1057
Color *colors_left_ptr = colors_left.ptrw();
1058
Vector2 *points_left_ptr = points_left.ptrw();
1059
1060
Vector2 *points_right_ptr = points_right.ptrw();
1061
Color *colors_right_ptr = colors_right.ptrw();
1062
1063
Vector2 prev_segment_dir;
1064
for (int i = 0; i < point_count; i++) {
1065
bool is_first_point = (i == 0);
1066
bool is_last_point = (i == point_count - 1);
1067
1068
Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
1069
if (is_first_point && loop) {
1070
prev_segment_dir = last_segment_dir;
1071
} else if (is_last_point && loop) {
1072
prev_segment_dir = first_segment_dir;
1073
}
1074
1075
Vector2 base_edge_offset;
1076
if (is_first_point && !loop) {
1077
base_edge_offset = first_segment_dir.orthogonal();
1078
} else if (is_last_point && !loop) {
1079
base_edge_offset = last_segment_dir.orthogonal();
1080
} else {
1081
base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
1082
}
1083
1084
Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
1085
Vector2 border = base_edge_offset * border_size;
1086
Vector2 pos = p_points[i];
1087
1088
int j = i * 2 + (loop ? 0 : 2);
1089
1090
points_ptr[j + 0] = pos + edge_offset;
1091
points_ptr[j + 1] = pos - edge_offset;
1092
1093
points_left_ptr[j + 0] = pos + edge_offset;
1094
points_left_ptr[j + 1] = pos + edge_offset + border;
1095
1096
points_right_ptr[j + 0] = pos - edge_offset;
1097
points_right_ptr[j + 1] = pos - edge_offset - border;
1098
1099
if (i < p_colors.size()) {
1100
color = p_colors[i];
1101
color2 = Color(color.r, color.g, color.b, 0);
1102
}
1103
1104
colors_ptr[j + 0] = color;
1105
colors_ptr[j + 1] = color;
1106
1107
colors_left_ptr[j + 0] = color;
1108
colors_left_ptr[j + 1] = color2;
1109
1110
colors_right_ptr[j + 0] = color;
1111
colors_right_ptr[j + 1] = color2;
1112
1113
if (is_first_point && !loop) {
1114
Vector2 begin_border = -segment_dir * border_size;
1115
1116
points_ptr[0] = pos + edge_offset + begin_border;
1117
points_ptr[1] = pos - edge_offset + begin_border;
1118
1119
colors_ptr[0] = color2;
1120
colors_ptr[1] = color2;
1121
1122
points_left_ptr[0] = pos + edge_offset + begin_border;
1123
points_left_ptr[1] = pos + edge_offset + begin_border + border;
1124
1125
colors_left_ptr[0] = color2;
1126
colors_left_ptr[1] = color2;
1127
1128
points_right_ptr[0] = pos - edge_offset + begin_border;
1129
points_right_ptr[1] = pos - edge_offset + begin_border - border;
1130
1131
colors_right_ptr[0] = color2;
1132
colors_right_ptr[1] = color2;
1133
}
1134
1135
if (is_last_point && !loop) {
1136
Vector2 end_border = prev_segment_dir * border_size;
1137
int end_index = polyline_point_count + 2;
1138
1139
points_ptr[end_index + 0] = pos + edge_offset + end_border;
1140
points_ptr[end_index + 1] = pos - edge_offset + end_border;
1141
1142
colors_ptr[end_index + 0] = color2;
1143
colors_ptr[end_index + 1] = color2;
1144
1145
// Swap orientation of the triangles within both end corner quads so the visual seams
1146
// between triangles goes from the edge corner. Done by going back to the edge corner
1147
// (1 additional vertex / zero-area triangle per left/right corner).
1148
points_left_ptr[end_index + 0] = pos + edge_offset;
1149
points_left_ptr[end_index + 1] = pos + edge_offset + end_border + border;
1150
points_left_ptr[end_index + 2] = pos + edge_offset + end_border;
1151
1152
colors_left_ptr[end_index + 0] = color;
1153
colors_left_ptr[end_index + 1] = color2;
1154
colors_left_ptr[end_index + 2] = color2;
1155
1156
points_right_ptr[end_index + 0] = pos - edge_offset;
1157
points_right_ptr[end_index + 1] = pos - edge_offset + end_border - border;
1158
points_right_ptr[end_index + 2] = pos - edge_offset + end_border;
1159
1160
colors_right_ptr[end_index + 0] = color;
1161
colors_right_ptr[end_index + 1] = color2;
1162
colors_right_ptr[end_index + 2] = color2;
1163
}
1164
1165
prev_segment_dir = segment_dir;
1166
}
1167
1168
pline_left->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1169
pline_left->polygon.create(indices, points_left, colors_left);
1170
1171
pline_right->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1172
pline_right->polygon.create(indices, points_right, colors_right);
1173
} else {
1174
// Makes a single triangle strip for drawing the line.
1175
1176
Vector2 prev_segment_dir;
1177
for (int i = 0; i < point_count; i++) {
1178
bool is_first_point = (i == 0);
1179
bool is_last_point = (i == point_count - 1);
1180
1181
Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
1182
if (is_first_point && loop) {
1183
prev_segment_dir = last_segment_dir;
1184
} else if (is_last_point && loop) {
1185
prev_segment_dir = first_segment_dir;
1186
}
1187
1188
Vector2 base_edge_offset;
1189
if (is_first_point && !loop) {
1190
base_edge_offset = first_segment_dir.orthogonal();
1191
} else if (is_last_point && !loop) {
1192
base_edge_offset = last_segment_dir.orthogonal();
1193
} else {
1194
base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
1195
}
1196
1197
Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
1198
Vector2 pos = p_points[i];
1199
1200
points_ptr[i * 2 + 0] = pos + edge_offset;
1201
points_ptr[i * 2 + 1] = pos - edge_offset;
1202
1203
if (i < p_colors.size()) {
1204
color = p_colors[i];
1205
}
1206
1207
colors_ptr[i * 2 + 0] = color;
1208
colors_ptr[i * 2 + 1] = color;
1209
1210
prev_segment_dir = segment_dir;
1211
}
1212
}
1213
1214
pline->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1215
pline->polygon.create(indices, points, colors);
1216
}
1217
1218
void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
1219
ERR_FAIL_COND(p_points.is_empty() || p_points.size() % 2 != 0);
1220
ERR_FAIL_COND(p_colors.size() != 1 && p_colors.size() * 2 != p_points.size());
1221
1222
// TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out.
1223
if (p_width < 0) {
1224
if (p_antialiased) {
1225
WARN_PRINT("Antialiasing is not supported for thin multilines drawn using line strips (`p_width < 0`).");
1226
}
1227
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1228
ERR_FAIL_NULL(canvas_item);
1229
1230
Vector<Color> colors;
1231
if (p_colors.size() == 1) {
1232
colors = p_colors;
1233
} else { //} else if (p_colors.size() << 1 == p_points.size()) {
1234
colors.resize(p_points.size());
1235
Color *colors_ptr = colors.ptrw();
1236
for (int i = 0; i < p_colors.size(); i++) {
1237
Color color = p_colors[i];
1238
colors_ptr[i * 2 + 0] = color;
1239
colors_ptr[i * 2 + 1] = color;
1240
}
1241
}
1242
1243
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
1244
ERR_FAIL_NULL(pline);
1245
pline->primitive = RS::PRIMITIVE_LINES;
1246
pline->polygon.create(Vector<int>(), p_points, colors);
1247
} else {
1248
if (p_colors.size() == 1) {
1249
Color color = p_colors[0];
1250
for (int i = 0; i < p_points.size() >> 1; i++) {
1251
Vector2 from = p_points[i * 2 + 0];
1252
Vector2 to = p_points[i * 2 + 1];
1253
1254
canvas_item_add_line(p_item, from, to, color, p_width, p_antialiased);
1255
}
1256
} else { //} else if (p_colors.size() << 1 == p_points.size()) {
1257
for (int i = 0; i < p_colors.size(); i++) {
1258
Color color = p_colors[i];
1259
Vector2 from = p_points[i * 2 + 0];
1260
Vector2 to = p_points[i * 2 + 1];
1261
1262
canvas_item_add_line(p_item, from, to, color, p_width, p_antialiased);
1263
}
1264
}
1265
}
1266
}
1267
1268
void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color, bool p_antialiased) {
1269
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1270
ERR_FAIL_NULL(canvas_item);
1271
1272
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1273
ERR_FAIL_NULL(rect);
1274
rect->modulate = p_color;
1275
rect->rect = p_rect;
1276
1277
// Add feathers.
1278
if (p_antialiased) {
1279
float border_size = FEATHER_SIZE;
1280
1281
const real_t size = MIN(p_rect.size.width, p_rect.size.height);
1282
if (0.0f <= size && size < 1.0f) {
1283
border_size *= size;
1284
}
1285
1286
const Vector2 vec_down = Vector2(0.0f, p_rect.size.height);
1287
const Vector2 vec_right = Vector2(p_rect.size.width, 0.0f);
1288
1289
const Vector2 begin_left = p_rect.position;
1290
const Vector2 begin_right = p_rect.position + vec_down;
1291
const Vector2 end_left = p_rect.position + vec_right;
1292
const Vector2 end_right = p_rect.position + p_rect.size;
1293
1294
const Vector2 dir = Vector2(0.0f, -1.0f);
1295
const Vector2 dir2 = Vector2(-1.0f, 0.0f);
1296
const Vector2 border = dir * border_size;
1297
const Vector2 border2 = dir2 * border_size;
1298
1299
Color transparent = Color(p_color, 0.0);
1300
1301
{
1302
Item::CommandPrimitive *left_border = canvas_item->alloc_command<Item::CommandPrimitive>();
1303
ERR_FAIL_NULL(left_border);
1304
1305
left_border->points[0] = begin_left;
1306
left_border->points[1] = begin_left + border;
1307
left_border->points[2] = end_left + border;
1308
left_border->points[3] = end_left;
1309
1310
left_border->colors[0] = p_color;
1311
left_border->colors[1] = transparent;
1312
left_border->colors[2] = transparent;
1313
left_border->colors[3] = p_color;
1314
1315
left_border->point_count = 4;
1316
}
1317
{
1318
Item::CommandPrimitive *right_border = canvas_item->alloc_command<Item::CommandPrimitive>();
1319
ERR_FAIL_NULL(right_border);
1320
1321
right_border->points[0] = begin_right;
1322
right_border->points[1] = begin_right - border;
1323
right_border->points[2] = end_right - border;
1324
right_border->points[3] = end_right;
1325
1326
right_border->colors[0] = p_color;
1327
right_border->colors[1] = transparent;
1328
right_border->colors[2] = transparent;
1329
right_border->colors[3] = p_color;
1330
1331
right_border->point_count = 4;
1332
}
1333
{
1334
Item::CommandPrimitive *top_border = canvas_item->alloc_command<Item::CommandPrimitive>();
1335
ERR_FAIL_NULL(top_border);
1336
1337
top_border->points[0] = begin_left;
1338
top_border->points[1] = begin_left + border2;
1339
top_border->points[2] = begin_right + border2;
1340
top_border->points[3] = begin_right;
1341
1342
top_border->colors[0] = p_color;
1343
top_border->colors[1] = transparent;
1344
top_border->colors[2] = transparent;
1345
top_border->colors[3] = p_color;
1346
1347
top_border->point_count = 4;
1348
}
1349
{
1350
Item::CommandPrimitive *bottom_border = canvas_item->alloc_command<Item::CommandPrimitive>();
1351
ERR_FAIL_NULL(bottom_border);
1352
1353
bottom_border->points[0] = end_left;
1354
bottom_border->points[1] = end_left - border2;
1355
bottom_border->points[2] = end_right - border2;
1356
bottom_border->points[3] = end_right;
1357
1358
bottom_border->colors[0] = p_color;
1359
bottom_border->colors[1] = transparent;
1360
bottom_border->colors[2] = transparent;
1361
bottom_border->colors[3] = p_color;
1362
1363
bottom_border->point_count = 4;
1364
}
1365
{
1366
Item::CommandPrimitive *top_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
1367
ERR_FAIL_NULL(top_left_corner);
1368
1369
top_left_corner->points[0] = begin_left;
1370
top_left_corner->points[1] = begin_left + border2;
1371
top_left_corner->points[2] = begin_left + border + border2;
1372
top_left_corner->points[3] = begin_left + border;
1373
1374
top_left_corner->colors[0] = p_color;
1375
top_left_corner->colors[1] = transparent;
1376
top_left_corner->colors[2] = transparent;
1377
top_left_corner->colors[3] = transparent;
1378
1379
top_left_corner->point_count = 4;
1380
}
1381
{
1382
Item::CommandPrimitive *top_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
1383
ERR_FAIL_NULL(top_right_corner);
1384
1385
top_right_corner->points[0] = begin_right;
1386
top_right_corner->points[1] = begin_right + border2;
1387
top_right_corner->points[2] = begin_right - border + border2;
1388
top_right_corner->points[3] = begin_right - border;
1389
1390
top_right_corner->colors[0] = p_color;
1391
top_right_corner->colors[1] = transparent;
1392
top_right_corner->colors[2] = transparent;
1393
top_right_corner->colors[3] = transparent;
1394
1395
top_right_corner->point_count = 4;
1396
}
1397
{
1398
Item::CommandPrimitive *bottom_left_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
1399
ERR_FAIL_NULL(bottom_left_corner);
1400
1401
bottom_left_corner->points[0] = end_left;
1402
bottom_left_corner->points[1] = end_left - border2;
1403
bottom_left_corner->points[2] = end_left + border - border2;
1404
bottom_left_corner->points[3] = end_left + border;
1405
1406
bottom_left_corner->colors[0] = p_color;
1407
bottom_left_corner->colors[1] = transparent;
1408
bottom_left_corner->colors[2] = transparent;
1409
bottom_left_corner->colors[3] = transparent;
1410
1411
bottom_left_corner->point_count = 4;
1412
}
1413
{
1414
Item::CommandPrimitive *bottom_right_corner = canvas_item->alloc_command<Item::CommandPrimitive>();
1415
ERR_FAIL_NULL(bottom_right_corner);
1416
1417
bottom_right_corner->points[0] = end_right;
1418
bottom_right_corner->points[1] = end_right - border2;
1419
bottom_right_corner->points[2] = end_right - border - border2;
1420
bottom_right_corner->points[3] = end_right - border;
1421
1422
bottom_right_corner->colors[0] = p_color;
1423
bottom_right_corner->colors[1] = transparent;
1424
bottom_right_corner->colors[2] = transparent;
1425
bottom_right_corner->colors[3] = transparent;
1426
1427
bottom_right_corner->point_count = 4;
1428
}
1429
}
1430
}
1431
1432
void RendererCanvasCull::canvas_item_add_ellipse(RID p_item, const Point2 &p_pos, float p_major, float p_minor, const Color &p_color, bool p_antialiased) {
1433
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1434
ERR_FAIL_NULL(canvas_item);
1435
1436
static const int ellipse_segments = 64;
1437
1438
{
1439
Item::CommandPolygon *ellipse = canvas_item->alloc_command<Item::CommandPolygon>();
1440
ERR_FAIL_NULL(ellipse);
1441
1442
ellipse->primitive = RS::PRIMITIVE_TRIANGLES;
1443
1444
Vector<int> indices;
1445
Vector<Vector2> points;
1446
1447
points.resize(ellipse_segments + 2);
1448
Vector2 *points_ptr = points.ptrw();
1449
1450
// Store ellipse center in the last point.
1451
points_ptr[ellipse_segments + 1] = p_pos;
1452
1453
const real_t ellipse_point_step = Math::TAU / ellipse_segments;
1454
1455
for (int i = 0; i < ellipse_segments + 1; i++) {
1456
float angle = i * ellipse_point_step;
1457
points_ptr[i].x = Math::cos(angle) * p_major;
1458
points_ptr[i].y = Math::sin(angle) * p_minor;
1459
points_ptr[i] += p_pos;
1460
}
1461
1462
indices.resize(ellipse_segments * 3);
1463
int *indices_ptr = indices.ptrw();
1464
1465
for (int i = 0; i < ellipse_segments; i++) {
1466
indices_ptr[i * 3 + 0] = ellipse_segments + 1;
1467
indices_ptr[i * 3 + 1] = i;
1468
indices_ptr[i * 3 + 2] = i + 1;
1469
}
1470
1471
Vector<Color> color;
1472
color.push_back(p_color);
1473
ellipse->polygon.create(indices, points, color);
1474
}
1475
1476
if (p_antialiased) {
1477
float border_size = FEATHER_SIZE;
1478
1479
const float max_axis = fmax(p_major, p_minor) * 2.0f;
1480
if (0.0f <= max_axis && max_axis < 1.0f) {
1481
border_size *= max_axis * 0.5f;
1482
}
1483
1484
Item::CommandPolygon *feather = canvas_item->alloc_command<Item::CommandPolygon>();
1485
ERR_FAIL_NULL(feather);
1486
feather->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
1487
1488
Color transparent = Color(p_color, 0.0);
1489
1490
Vector<int> indices;
1491
Vector<Color> colors;
1492
Vector<Vector2> points;
1493
1494
points.resize(2 * ellipse_segments + 2);
1495
colors.resize(2 * ellipse_segments + 2);
1496
1497
const real_t ellipse_point_step = Math::TAU / ellipse_segments;
1498
1499
Vector2 *points_ptr = points.ptrw();
1500
Color *colors_ptr = colors.ptrw();
1501
1502
for (int i = 0; i < ellipse_segments + 1; i++) {
1503
const float angle = i * ellipse_point_step;
1504
const float c = Math::cos(angle);
1505
const float s = Math::sin(angle);
1506
1507
points_ptr[i * 2].x = c * p_major;
1508
points_ptr[i * 2].y = s * p_minor;
1509
points_ptr[i * 2] += p_pos;
1510
1511
points_ptr[i * 2 + 1].x = c * (p_major + border_size);
1512
points_ptr[i * 2 + 1].y = s * (p_minor + border_size);
1513
points_ptr[i * 2 + 1] += p_pos;
1514
1515
colors_ptr[i * 2] = p_color;
1516
colors_ptr[i * 2 + 1] = transparent;
1517
}
1518
1519
feather->polygon.create(indices, points, colors);
1520
}
1521
}
1522
1523
void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color, bool p_antialiased) {
1524
canvas_item_add_ellipse(p_item, p_pos, p_radius, p_radius, p_color, p_antialiased);
1525
}
1526
1527
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) {
1528
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1529
ERR_FAIL_NULL(canvas_item);
1530
1531
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1532
ERR_FAIL_NULL(rect);
1533
rect->modulate = p_modulate;
1534
rect->rect = p_rect;
1535
rect->flags = 0;
1536
if (p_tile) {
1537
rect->flags |= RendererCanvasRender::CANVAS_RECT_TILE;
1538
rect->flags |= RendererCanvasRender::CANVAS_RECT_REGION;
1539
rect->source = Rect2(0, 0, Math::abs(p_rect.size.width), Math::abs(p_rect.size.height));
1540
}
1541
1542
if (p_rect.size.x < 0) {
1543
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1544
rect->rect.size.x = -rect->rect.size.x;
1545
}
1546
if (p_rect.size.y < 0) {
1547
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1548
rect->rect.size.y = -rect->rect.size.y;
1549
}
1550
if (p_transpose) {
1551
rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE;
1552
SWAP(rect->rect.size.x, rect->rect.size.y);
1553
}
1554
1555
rect->texture = p_texture;
1556
}
1557
1558
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) {
1559
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1560
ERR_FAIL_NULL(canvas_item);
1561
1562
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1563
ERR_FAIL_NULL(rect);
1564
rect->modulate = p_modulate;
1565
rect->rect = p_rect;
1566
1567
rect->texture = p_texture;
1568
1569
rect->source = p_src_rect;
1570
rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_MSDF;
1571
1572
if (p_rect.size.x < 0) {
1573
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1574
rect->rect.size.x = -rect->rect.size.x;
1575
}
1576
if (p_src_rect.size.x < 0) {
1577
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1578
rect->source.size.x = -rect->source.size.x;
1579
}
1580
if (p_rect.size.y < 0) {
1581
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1582
rect->rect.size.y = -rect->rect.size.y;
1583
}
1584
if (p_src_rect.size.y < 0) {
1585
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1586
rect->source.size.y = -rect->source.size.y;
1587
}
1588
rect->outline = (float)p_outline_size / p_scale / 4.0;
1589
rect->px_range = p_px_range;
1590
}
1591
1592
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) {
1593
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1594
ERR_FAIL_NULL(canvas_item);
1595
1596
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1597
ERR_FAIL_NULL(rect);
1598
rect->modulate = p_modulate;
1599
rect->rect = p_rect;
1600
1601
rect->texture = p_texture;
1602
1603
rect->source = p_src_rect;
1604
rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_LCD;
1605
1606
if (p_rect.size.x < 0) {
1607
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1608
rect->rect.size.x = -rect->rect.size.x;
1609
}
1610
if (p_src_rect.size.x < 0) {
1611
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1612
rect->source.size.x = -rect->source.size.x;
1613
}
1614
if (p_rect.size.y < 0) {
1615
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1616
rect->rect.size.y = -rect->rect.size.y;
1617
}
1618
if (p_src_rect.size.y < 0) {
1619
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1620
rect->source.size.y = -rect->source.size.y;
1621
}
1622
}
1623
1624
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) {
1625
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1626
ERR_FAIL_NULL(canvas_item);
1627
1628
Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
1629
ERR_FAIL_NULL(rect);
1630
rect->modulate = p_modulate;
1631
rect->rect = p_rect;
1632
1633
rect->texture = p_texture;
1634
1635
rect->source = p_src_rect;
1636
rect->flags = RendererCanvasRender::CANVAS_RECT_REGION;
1637
1638
if (p_rect.size.x < 0) {
1639
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1640
rect->rect.size.x = -rect->rect.size.x;
1641
}
1642
if (p_src_rect.size.x < 0) {
1643
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
1644
rect->source.size.x = -rect->source.size.x;
1645
}
1646
if (p_rect.size.y < 0) {
1647
rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1648
rect->rect.size.y = -rect->rect.size.y;
1649
}
1650
if (p_src_rect.size.y < 0) {
1651
rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
1652
rect->source.size.y = -rect->source.size.y;
1653
}
1654
1655
if (p_transpose) {
1656
rect->flags |= RendererCanvasRender::CANVAS_RECT_TRANSPOSE;
1657
SWAP(rect->rect.size.x, rect->rect.size.y);
1658
}
1659
1660
if (p_clip_uv) {
1661
rect->flags |= RendererCanvasRender::CANVAS_RECT_CLIP_UV;
1662
}
1663
}
1664
1665
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) {
1666
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1667
ERR_FAIL_NULL(canvas_item);
1668
1669
Item::CommandNinePatch *style = canvas_item->alloc_command<Item::CommandNinePatch>();
1670
ERR_FAIL_NULL(style);
1671
1672
style->texture = p_texture;
1673
1674
style->rect = p_rect;
1675
style->source = p_source;
1676
style->draw_center = p_draw_center;
1677
style->color = p_modulate;
1678
style->margin[SIDE_LEFT] = p_topleft.x;
1679
style->margin[SIDE_TOP] = p_topleft.y;
1680
style->margin[SIDE_RIGHT] = p_bottomright.x;
1681
style->margin[SIDE_BOTTOM] = p_bottomright.y;
1682
style->axis_x = p_x_axis_mode;
1683
style->axis_y = p_y_axis_mode;
1684
}
1685
1686
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) {
1687
uint32_t pc = p_points.size();
1688
ERR_FAIL_COND(pc == 0 || pc > 4);
1689
1690
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1691
ERR_FAIL_NULL(canvas_item);
1692
1693
Item::CommandPrimitive *prim = canvas_item->alloc_command<Item::CommandPrimitive>();
1694
ERR_FAIL_NULL(prim);
1695
1696
for (int i = 0; i < p_points.size(); i++) {
1697
prim->points[i] = p_points[i];
1698
if (i < p_uvs.size()) {
1699
prim->uvs[i] = p_uvs[i];
1700
}
1701
if (i < p_colors.size()) {
1702
prim->colors[i] = p_colors[i];
1703
} else if (p_colors.size()) {
1704
prim->colors[i] = p_colors[0];
1705
} else {
1706
prim->colors[i] = Color(1, 1, 1, 1);
1707
}
1708
}
1709
1710
prim->point_count = p_points.size();
1711
1712
prim->texture = p_texture;
1713
}
1714
1715
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) {
1716
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1717
ERR_FAIL_NULL(canvas_item);
1718
#ifdef DEBUG_ENABLED
1719
int pointcount = p_points.size();
1720
ERR_FAIL_COND(pointcount < 3);
1721
int color_size = p_colors.size();
1722
int uv_size = p_uvs.size();
1723
ERR_FAIL_COND(color_size != 0 && color_size != 1 && color_size != pointcount);
1724
ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount));
1725
#endif
1726
Vector<int> indices = Geometry2D::triangulate_polygon(p_points);
1727
ERR_FAIL_COND_MSG(indices.is_empty(), "Invalid polygon data, triangulation failed.");
1728
1729
Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
1730
ERR_FAIL_NULL(polygon);
1731
polygon->primitive = RS::PRIMITIVE_TRIANGLES;
1732
polygon->texture = p_texture;
1733
polygon->polygon.create(indices, p_points, p_colors, p_uvs);
1734
}
1735
1736
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) {
1737
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1738
ERR_FAIL_NULL(canvas_item);
1739
1740
int vertex_count = p_points.size();
1741
ERR_FAIL_COND(vertex_count == 0);
1742
ERR_FAIL_COND(!p_colors.is_empty() && p_colors.size() != vertex_count && p_colors.size() != 1);
1743
ERR_FAIL_COND(!p_uvs.is_empty() && p_uvs.size() != vertex_count);
1744
ERR_FAIL_COND(!p_bones.is_empty() && p_bones.size() != vertex_count * 4);
1745
ERR_FAIL_COND(!p_weights.is_empty() && p_weights.size() != vertex_count * 4);
1746
1747
Item::CommandPolygon *polygon = canvas_item->alloc_command<Item::CommandPolygon>();
1748
ERR_FAIL_NULL(polygon);
1749
1750
polygon->texture = p_texture;
1751
1752
polygon->polygon.create(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights, p_count);
1753
1754
polygon->primitive = RS::PRIMITIVE_TRIANGLES;
1755
}
1756
1757
void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) {
1758
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1759
ERR_FAIL_NULL(canvas_item);
1760
1761
Item::CommandTransform *tr = canvas_item->alloc_command<Item::CommandTransform>();
1762
ERR_FAIL_NULL(tr);
1763
tr->xform = p_transform;
1764
}
1765
1766
void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) {
1767
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1768
ERR_FAIL_NULL(canvas_item);
1769
ERR_FAIL_COND(!p_mesh.is_valid());
1770
1771
Item::CommandMesh *m = canvas_item->alloc_command<Item::CommandMesh>();
1772
ERR_FAIL_NULL(m);
1773
m->mesh = p_mesh;
1774
if (canvas_item->skeleton.is_valid()) {
1775
m->mesh_instance = RSG::mesh_storage->mesh_instance_create(p_mesh);
1776
RSG::mesh_storage->mesh_instance_set_skeleton(m->mesh_instance, canvas_item->skeleton);
1777
}
1778
1779
m->texture = p_texture;
1780
1781
m->transform = p_transform;
1782
m->modulate = p_modulate;
1783
}
1784
1785
void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) {
1786
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1787
ERR_FAIL_NULL(canvas_item);
1788
1789
Item::CommandParticles *part = canvas_item->alloc_command<Item::CommandParticles>();
1790
ERR_FAIL_NULL(part);
1791
part->particles = p_particles;
1792
1793
part->texture = p_texture;
1794
1795
//take the chance and request processing for them, at least once until they become visible again
1796
RSG::particles_storage->particles_request_process(p_particles);
1797
}
1798
1799
void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) {
1800
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1801
ERR_FAIL_NULL(canvas_item);
1802
1803
Item::CommandMultiMesh *mm = canvas_item->alloc_command<Item::CommandMultiMesh>();
1804
ERR_FAIL_NULL(mm);
1805
mm->multimesh = p_mesh;
1806
1807
mm->texture = p_texture;
1808
}
1809
1810
void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) {
1811
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1812
ERR_FAIL_NULL(canvas_item);
1813
1814
Item::CommandClipIgnore *ci = canvas_item->alloc_command<Item::CommandClipIgnore>();
1815
ERR_FAIL_NULL(ci);
1816
ci->ignore = p_ignore;
1817
}
1818
1819
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) {
1820
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1821
ERR_FAIL_NULL(canvas_item);
1822
1823
Item::CommandAnimationSlice *as = canvas_item->alloc_command<Item::CommandAnimationSlice>();
1824
ERR_FAIL_NULL(as);
1825
as->animation_length = p_animation_length;
1826
as->slice_begin = p_slice_begin;
1827
as->slice_end = p_slice_end;
1828
as->offset = p_offset;
1829
}
1830
1831
void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) {
1832
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1833
ERR_FAIL_NULL(canvas_item);
1834
1835
canvas_item->sort_y = p_enable;
1836
1837
_mark_ysort_dirty(canvas_item);
1838
}
1839
1840
void RendererCanvasCull::canvas_item_set_z_index(RID p_item, int p_z) {
1841
ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX);
1842
1843
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1844
ERR_FAIL_NULL(canvas_item);
1845
1846
canvas_item->z_index = p_z;
1847
}
1848
1849
void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) {
1850
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1851
ERR_FAIL_NULL(canvas_item);
1852
1853
canvas_item->z_relative = p_enable;
1854
}
1855
1856
void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) {
1857
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1858
ERR_FAIL_NULL(canvas_item);
1859
if (canvas_item->skeleton == p_skeleton) {
1860
return;
1861
}
1862
canvas_item->skeleton = p_skeleton;
1863
1864
Item::Command *c = canvas_item->commands;
1865
1866
while (c) {
1867
if (c->type == Item::Command::TYPE_MESH) {
1868
Item::CommandMesh *cm = static_cast<Item::CommandMesh *>(c);
1869
if (canvas_item->skeleton.is_valid()) {
1870
if (cm->mesh_instance.is_null()) {
1871
cm->mesh_instance = RSG::mesh_storage->mesh_instance_create(cm->mesh);
1872
}
1873
RSG::mesh_storage->mesh_instance_set_skeleton(cm->mesh_instance, canvas_item->skeleton);
1874
} else {
1875
if (cm->mesh_instance.is_valid()) {
1876
RSG::mesh_storage->mesh_instance_free(cm->mesh_instance);
1877
cm->mesh_instance = RID();
1878
}
1879
}
1880
}
1881
c = c->next;
1882
}
1883
}
1884
1885
void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
1886
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1887
ERR_FAIL_NULL(canvas_item);
1888
if (p_enable && (canvas_item->copy_back_buffer == nullptr)) {
1889
canvas_item->copy_back_buffer = memnew(RendererCanvasRender::Item::CopyBackBuffer);
1890
}
1891
if (!p_enable && (canvas_item->copy_back_buffer != nullptr)) {
1892
memdelete(canvas_item->copy_back_buffer);
1893
canvas_item->copy_back_buffer = nullptr;
1894
}
1895
1896
if (p_enable) {
1897
canvas_item->copy_back_buffer->rect = p_rect;
1898
canvas_item->copy_back_buffer->full = p_rect == Rect2();
1899
}
1900
}
1901
1902
void RendererCanvasCull::canvas_item_clear(RID p_item) {
1903
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1904
ERR_FAIL_NULL(canvas_item);
1905
1906
canvas_item->clear();
1907
1908
#ifdef DEBUG_ENABLED
1909
if (debug_redraw) {
1910
canvas_item->debug_redraw_time = debug_redraw_time;
1911
}
1912
#endif
1913
}
1914
1915
void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) {
1916
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1917
ERR_FAIL_NULL(canvas_item);
1918
1919
canvas_item->index = p_index;
1920
1921
if (canvas_item_owner.owns(canvas_item->parent)) {
1922
Item *canvas_item_parent = canvas_item_owner.get_or_null(canvas_item->parent);
1923
canvas_item_parent->children_order_dirty = true;
1924
return;
1925
}
1926
1927
Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
1928
if (canvas) {
1929
canvas->children_order_dirty = true;
1930
return;
1931
}
1932
}
1933
1934
void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) {
1935
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1936
ERR_FAIL_NULL(canvas_item);
1937
1938
canvas_item->material = p_material;
1939
_item_queue_update(canvas_item, true);
1940
}
1941
1942
void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) {
1943
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1944
ERR_FAIL_NULL(canvas_item);
1945
1946
canvas_item->use_parent_material = p_enable;
1947
_item_queue_update(canvas_item, true);
1948
}
1949
1950
void RendererCanvasCull::canvas_item_set_instance_shader_parameter(RID p_item, const StringName &p_parameter, const Variant &p_value) {
1951
Item *item = canvas_item_owner.get_or_null(p_item);
1952
ERR_FAIL_NULL(item);
1953
1954
item->instance_uniforms.set(item->self, p_parameter, p_value);
1955
}
1956
1957
Variant RendererCanvasCull::canvas_item_get_instance_shader_parameter(RID p_item, const StringName &p_parameter) const {
1958
const Item *item = const_cast<RendererCanvasCull *>(this)->canvas_item_owner.get_or_null(p_item);
1959
ERR_FAIL_NULL_V(item, Variant());
1960
1961
return item->instance_uniforms.get(p_parameter);
1962
}
1963
1964
Variant RendererCanvasCull::canvas_item_get_instance_shader_parameter_default_value(RID p_item, const StringName &p_parameter) const {
1965
const Item *item = const_cast<RendererCanvasCull *>(this)->canvas_item_owner.get_or_null(p_item);
1966
ERR_FAIL_NULL_V(item, Variant());
1967
1968
return item->instance_uniforms.get_default(p_parameter);
1969
}
1970
1971
void RendererCanvasCull::canvas_item_get_instance_shader_parameter_list(RID p_item, List<PropertyInfo> *p_parameters) const {
1972
ERR_FAIL_NULL(p_parameters);
1973
const Item *item = const_cast<RendererCanvasCull *>(this)->canvas_item_owner.get_or_null(p_item);
1974
ERR_FAIL_NULL(item);
1975
const_cast<RendererCanvasCull *>(this)->update_dirty_items();
1976
1977
item->instance_uniforms.get_property_list(*p_parameters);
1978
}
1979
1980
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) {
1981
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
1982
ERR_FAIL_NULL(canvas_item);
1983
1984
if (p_enable) {
1985
if (!canvas_item->visibility_notifier) {
1986
canvas_item->visibility_notifier = visibility_notifier_allocator.alloc();
1987
}
1988
canvas_item->visibility_notifier->area = p_area;
1989
canvas_item->visibility_notifier->enter_callable = p_enter_callable;
1990
canvas_item->visibility_notifier->exit_callable = p_exit_callable;
1991
1992
} else {
1993
if (canvas_item->visibility_notifier) {
1994
visibility_notifier_allocator.free(canvas_item->visibility_notifier);
1995
canvas_item->visibility_notifier = nullptr;
1996
}
1997
}
1998
}
1999
2000
void RendererCanvasCull::canvas_item_set_debug_redraw(bool p_enabled) {
2001
debug_redraw = p_enabled;
2002
RSG::canvas_render->set_debug_redraw(p_enabled, debug_redraw_time, debug_redraw_color);
2003
}
2004
2005
bool RendererCanvasCull::canvas_item_get_debug_redraw() const {
2006
return debug_redraw;
2007
}
2008
2009
void RendererCanvasCull::canvas_item_set_interpolated(RID p_item, bool p_interpolated) {
2010
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
2011
ERR_FAIL_NULL(canvas_item);
2012
canvas_item->interpolated = p_interpolated;
2013
}
2014
2015
void RendererCanvasCull::canvas_item_reset_physics_interpolation(RID p_item) {
2016
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
2017
ERR_FAIL_NULL(canvas_item);
2018
canvas_item->xform_prev = canvas_item->xform_curr;
2019
}
2020
2021
// Useful especially for origin shifting.
2022
void RendererCanvasCull::canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) {
2023
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
2024
ERR_FAIL_NULL(canvas_item);
2025
canvas_item->xform_prev = p_transform * canvas_item->xform_prev;
2026
canvas_item->xform_curr = p_transform * canvas_item->xform_curr;
2027
}
2028
2029
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) {
2030
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
2031
ERR_FAIL_NULL(canvas_item);
2032
2033
if (p_mode == RS::CANVAS_GROUP_MODE_DISABLED) {
2034
if (canvas_item->canvas_group != nullptr) {
2035
memdelete(canvas_item->canvas_group);
2036
canvas_item->canvas_group = nullptr;
2037
}
2038
} else {
2039
if (canvas_item->canvas_group == nullptr) {
2040
canvas_item->canvas_group = memnew(RendererCanvasRender::Item::CanvasGroup);
2041
}
2042
canvas_item->canvas_group->mode = p_mode;
2043
canvas_item->canvas_group->fit_empty = p_fit_empty;
2044
canvas_item->canvas_group->fit_margin = p_fit_margin;
2045
canvas_item->canvas_group->blur_mipmaps = p_blur_mipmaps;
2046
canvas_item->canvas_group->clear_margin = p_clear_margin;
2047
}
2048
}
2049
2050
RID RendererCanvasCull::canvas_light_allocate() {
2051
return canvas_light_owner.allocate_rid();
2052
}
2053
void RendererCanvasCull::canvas_light_initialize(RID p_rid) {
2054
canvas_light_owner.initialize_rid(p_rid);
2055
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_rid);
2056
clight->light_internal = RSG::canvas_render->light_create();
2057
}
2058
2059
void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) {
2060
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2061
ERR_FAIL_NULL(clight);
2062
2063
if (clight->mode == p_mode) {
2064
return;
2065
}
2066
2067
RID canvas = clight->canvas;
2068
2069
if (canvas.is_valid()) {
2070
canvas_light_attach_to_canvas(p_light, RID());
2071
}
2072
2073
clight->mode = p_mode;
2074
2075
if (canvas.is_valid()) {
2076
canvas_light_attach_to_canvas(p_light, canvas);
2077
}
2078
}
2079
2080
void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) {
2081
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2082
ERR_FAIL_NULL(clight);
2083
2084
if (clight->canvas.is_valid()) {
2085
Canvas *canvas = canvas_owner.get_or_null(clight->canvas);
2086
if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
2087
canvas->lights.erase(clight);
2088
} else {
2089
canvas->directional_lights.erase(clight);
2090
}
2091
}
2092
2093
if (!canvas_owner.owns(p_canvas)) {
2094
p_canvas = RID();
2095
}
2096
2097
clight->canvas = p_canvas;
2098
2099
if (clight->canvas.is_valid()) {
2100
Canvas *canvas = canvas_owner.get_or_null(clight->canvas);
2101
if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) {
2102
canvas->lights.insert(clight);
2103
} else {
2104
canvas->directional_lights.insert(clight);
2105
}
2106
}
2107
}
2108
2109
void RendererCanvasCull::canvas_light_set_enabled(RID p_light, bool p_enabled) {
2110
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2111
ERR_FAIL_NULL(clight);
2112
2113
clight->enabled = p_enabled;
2114
}
2115
2116
void RendererCanvasCull::canvas_light_set_texture_scale(RID p_light, float p_scale) {
2117
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2118
ERR_FAIL_NULL(clight);
2119
2120
clight->scale = p_scale;
2121
}
2122
2123
void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) {
2124
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2125
ERR_FAIL_NULL(clight);
2126
2127
if (_interpolation_data.interpolation_enabled && clight->interpolated) {
2128
if (!clight->on_interpolate_transform_list) {
2129
_interpolation_data.canvas_light_transform_update_list_curr->push_back(p_light);
2130
clight->on_interpolate_transform_list = true;
2131
} else {
2132
DEV_ASSERT(_interpolation_data.canvas_light_transform_update_list_curr->size() > 0);
2133
}
2134
}
2135
2136
clight->xform_curr = p_transform;
2137
}
2138
2139
void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
2140
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2141
ERR_FAIL_NULL(clight);
2142
2143
if (clight->texture == p_texture) {
2144
return;
2145
}
2146
clight->texture = p_texture;
2147
clight->version++;
2148
RSG::canvas_render->light_set_texture(clight->light_internal, p_texture);
2149
}
2150
2151
void RendererCanvasCull::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) {
2152
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2153
ERR_FAIL_NULL(clight);
2154
2155
clight->texture_offset = p_offset;
2156
}
2157
2158
void RendererCanvasCull::canvas_light_set_color(RID p_light, const Color &p_color) {
2159
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2160
ERR_FAIL_NULL(clight);
2161
2162
clight->color = p_color;
2163
}
2164
2165
void RendererCanvasCull::canvas_light_set_height(RID p_light, float p_height) {
2166
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2167
ERR_FAIL_NULL(clight);
2168
2169
clight->height = p_height;
2170
}
2171
2172
void RendererCanvasCull::canvas_light_set_energy(RID p_light, float p_energy) {
2173
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2174
ERR_FAIL_NULL(clight);
2175
2176
clight->energy = p_energy;
2177
}
2178
2179
void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) {
2180
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2181
ERR_FAIL_NULL(clight);
2182
2183
clight->z_min = p_min_z;
2184
clight->z_max = p_max_z;
2185
}
2186
2187
void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) {
2188
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2189
ERR_FAIL_NULL(clight);
2190
2191
clight->layer_max = p_max_layer;
2192
clight->layer_min = p_min_layer;
2193
}
2194
2195
void RendererCanvasCull::canvas_light_set_item_cull_mask(RID p_light, int p_mask) {
2196
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2197
ERR_FAIL_NULL(clight);
2198
2199
clight->item_mask = p_mask;
2200
}
2201
2202
void RendererCanvasCull::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) {
2203
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2204
ERR_FAIL_NULL(clight);
2205
2206
clight->item_shadow_mask = p_mask;
2207
}
2208
2209
void RendererCanvasCull::canvas_light_set_directional_distance(RID p_light, float p_distance) {
2210
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2211
ERR_FAIL_NULL(clight);
2212
2213
clight->directional_distance = p_distance;
2214
}
2215
2216
void RendererCanvasCull::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) {
2217
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2218
ERR_FAIL_NULL(clight);
2219
2220
clight->blend_mode = p_mode;
2221
}
2222
2223
void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) {
2224
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2225
ERR_FAIL_NULL(clight);
2226
2227
if (clight->use_shadow == p_enabled) {
2228
return;
2229
}
2230
clight->use_shadow = p_enabled;
2231
clight->version++;
2232
RSG::canvas_render->light_set_use_shadow(clight->light_internal, clight->use_shadow);
2233
}
2234
2235
void RendererCanvasCull::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) {
2236
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2237
ERR_FAIL_NULL(clight);
2238
2239
clight->shadow_filter = p_filter;
2240
}
2241
2242
void RendererCanvasCull::canvas_light_set_shadow_color(RID p_light, const Color &p_color) {
2243
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2244
ERR_FAIL_NULL(clight);
2245
2246
clight->shadow_color = p_color;
2247
}
2248
2249
void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) {
2250
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2251
ERR_FAIL_NULL(clight);
2252
clight->shadow_smooth = p_smooth;
2253
}
2254
2255
void RendererCanvasCull::canvas_light_set_interpolated(RID p_light, bool p_interpolated) {
2256
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2257
ERR_FAIL_NULL(clight);
2258
clight->interpolated = p_interpolated;
2259
}
2260
2261
void RendererCanvasCull::canvas_light_reset_physics_interpolation(RID p_light) {
2262
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2263
ERR_FAIL_NULL(clight);
2264
clight->xform_prev = clight->xform_curr;
2265
}
2266
2267
void RendererCanvasCull::canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) {
2268
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
2269
ERR_FAIL_NULL(clight);
2270
clight->xform_prev = p_transform * clight->xform_prev;
2271
clight->xform_curr = p_transform * clight->xform_curr;
2272
}
2273
2274
RID RendererCanvasCull::canvas_light_occluder_allocate() {
2275
return canvas_light_occluder_owner.allocate_rid();
2276
}
2277
void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) {
2278
return canvas_light_occluder_owner.initialize_rid(p_rid);
2279
}
2280
2281
void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) {
2282
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2283
ERR_FAIL_NULL(occluder);
2284
2285
if (occluder->canvas.is_valid()) {
2286
Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
2287
canvas->occluders.erase(occluder);
2288
}
2289
2290
if (!canvas_owner.owns(p_canvas)) {
2291
p_canvas = RID();
2292
}
2293
2294
occluder->canvas = p_canvas;
2295
2296
if (occluder->canvas.is_valid()) {
2297
Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
2298
canvas->occluders.insert(occluder);
2299
}
2300
}
2301
2302
void RendererCanvasCull::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) {
2303
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2304
ERR_FAIL_NULL(occluder);
2305
2306
occluder->enabled = p_enabled;
2307
}
2308
2309
void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) {
2310
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2311
ERR_FAIL_NULL(occluder);
2312
2313
if (occluder->polygon.is_valid()) {
2314
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
2315
if (occluder_poly) {
2316
occluder_poly->owners.erase(occluder);
2317
}
2318
}
2319
2320
occluder->polygon = p_polygon;
2321
occluder->occluder = RID();
2322
2323
if (occluder->polygon.is_valid()) {
2324
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon);
2325
if (!occluder_poly) {
2326
occluder->polygon = RID();
2327
ERR_FAIL_NULL(occluder_poly);
2328
} else {
2329
occluder_poly->owners.insert(occluder);
2330
occluder->occluder = occluder_poly->occluder;
2331
occluder->aabb_cache = occluder_poly->aabb;
2332
occluder->cull_cache = occluder_poly->cull_mode;
2333
}
2334
}
2335
}
2336
2337
void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) {
2338
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2339
ERR_FAIL_NULL(occluder);
2340
2341
occluder->sdf_collision = p_enable;
2342
}
2343
2344
void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) {
2345
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2346
ERR_FAIL_NULL(occluder);
2347
2348
if (_interpolation_data.interpolation_enabled && occluder->interpolated) {
2349
if (!occluder->on_interpolate_transform_list) {
2350
_interpolation_data.canvas_light_occluder_transform_update_list_curr->push_back(p_occluder);
2351
occluder->on_interpolate_transform_list = true;
2352
} else {
2353
DEV_ASSERT(_interpolation_data.canvas_light_occluder_transform_update_list_curr->size() > 0);
2354
}
2355
}
2356
2357
occluder->xform_curr = p_xform;
2358
}
2359
2360
void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
2361
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2362
ERR_FAIL_NULL(occluder);
2363
2364
occluder->light_mask = p_mask;
2365
}
2366
2367
void RendererCanvasCull::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) {
2368
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2369
ERR_FAIL_NULL(occluder);
2370
occluder->interpolated = p_interpolated;
2371
}
2372
2373
void RendererCanvasCull::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) {
2374
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2375
ERR_FAIL_NULL(occluder);
2376
occluder->xform_prev = occluder->xform_curr;
2377
}
2378
2379
void RendererCanvasCull::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) {
2380
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
2381
ERR_FAIL_NULL(occluder);
2382
occluder->xform_prev = p_transform * occluder->xform_prev;
2383
occluder->xform_curr = p_transform * occluder->xform_curr;
2384
}
2385
2386
RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
2387
return canvas_light_occluder_polygon_owner.allocate_rid();
2388
}
2389
void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) {
2390
canvas_light_occluder_polygon_owner.initialize_rid(p_rid);
2391
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid);
2392
occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create();
2393
}
2394
2395
void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) {
2396
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon);
2397
ERR_FAIL_NULL(occluder_poly);
2398
2399
uint32_t pc = p_shape.size();
2400
ERR_FAIL_COND(pc < 2);
2401
2402
occluder_poly->aabb = Rect2();
2403
const Vector2 *r = p_shape.ptr();
2404
for (uint32_t i = 0; i < pc; i++) {
2405
if (i == 0) {
2406
occluder_poly->aabb.position = r[i];
2407
} else {
2408
occluder_poly->aabb.expand_to(r[i]);
2409
}
2410
}
2411
2412
RSG::canvas_render->occluder_polygon_set_shape(occluder_poly->occluder, p_shape, p_closed);
2413
2414
for (RendererCanvasRender::LightOccluderInstance *E : occluder_poly->owners) {
2415
E->aabb_cache = occluder_poly->aabb;
2416
}
2417
}
2418
2419
void RendererCanvasCull::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) {
2420
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon);
2421
ERR_FAIL_NULL(occluder_poly);
2422
occluder_poly->cull_mode = p_mode;
2423
RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode);
2424
for (RendererCanvasRender::LightOccluderInstance *E : occluder_poly->owners) {
2425
E->cull_cache = p_mode;
2426
}
2427
}
2428
2429
void RendererCanvasCull::canvas_set_shadow_texture_size(int p_size) {
2430
RSG::canvas_render->set_shadow_texture_size(p_size);
2431
}
2432
2433
RID RendererCanvasCull::canvas_texture_allocate() {
2434
return RSG::texture_storage->canvas_texture_allocate();
2435
}
2436
void RendererCanvasCull::canvas_texture_initialize(RID p_rid) {
2437
RSG::texture_storage->canvas_texture_initialize(p_rid);
2438
}
2439
2440
void RendererCanvasCull::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) {
2441
RSG::texture_storage->canvas_texture_set_channel(p_canvas_texture, p_channel, p_texture);
2442
}
2443
2444
void RendererCanvasCull::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) {
2445
RSG::texture_storage->canvas_texture_set_shading_parameters(p_canvas_texture, p_base_color, p_shininess);
2446
}
2447
2448
void RendererCanvasCull::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) {
2449
RSG::texture_storage->canvas_texture_set_texture_filter(p_canvas_texture, p_filter);
2450
}
2451
2452
void RendererCanvasCull::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) {
2453
RSG::texture_storage->canvas_texture_set_texture_repeat(p_canvas_texture, p_repeat);
2454
}
2455
2456
void RendererCanvasCull::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) {
2457
Item *ci = canvas_item_owner.get_or_null(p_item);
2458
ERR_FAIL_NULL(ci);
2459
ci->texture_filter = p_filter;
2460
}
2461
void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) {
2462
Item *ci = canvas_item_owner.get_or_null(p_item);
2463
ERR_FAIL_NULL(ci);
2464
ci->texture_repeat = p_repeat;
2465
}
2466
2467
void RendererCanvasCull::update_visibility_notifiers() {
2468
SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first();
2469
while (E) {
2470
SelfList<Item::VisibilityNotifierData> *N = E->next();
2471
2472
Item::VisibilityNotifierData *visibility_notifier = E->self();
2473
if (visibility_notifier->just_visible) {
2474
visibility_notifier->just_visible = false;
2475
2476
if (visibility_notifier->enter_callable.is_valid()) {
2477
if (RSG::threaded) {
2478
visibility_notifier->enter_callable.call_deferred();
2479
} else {
2480
visibility_notifier->enter_callable.call();
2481
}
2482
}
2483
} else {
2484
if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) {
2485
visibility_notifier_list.remove(E);
2486
2487
if (visibility_notifier->exit_callable.is_valid()) {
2488
if (RSG::threaded) {
2489
visibility_notifier->exit_callable.call_deferred();
2490
} else {
2491
visibility_notifier->exit_callable.call();
2492
}
2493
}
2494
}
2495
}
2496
2497
E = N;
2498
}
2499
}
2500
2501
Rect2 RendererCanvasCull::_debug_canvas_item_get_rect(RID p_item) {
2502
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
2503
ERR_FAIL_NULL_V(canvas_item, Rect2());
2504
return canvas_item->get_rect();
2505
}
2506
2507
void RendererCanvasCull::_item_queue_update(Item *p_item, bool p_update_dependencies) {
2508
if (p_update_dependencies) {
2509
p_item->update_dependencies = true;
2510
}
2511
2512
if (!p_item->update_item.in_list()) {
2513
_item_update_list.add(&p_item->update_item);
2514
}
2515
}
2516
2517
void RendererCanvasCull::update_dirty_items() {
2518
while (_item_update_list.first()) {
2519
_update_dirty_item(_item_update_list.first()->self());
2520
}
2521
2522
// Instance updates may affect resources.
2523
RSG::utilities->update_dirty_resources();
2524
}
2525
2526
void RendererCanvasCull::_update_dirty_item(Item *p_item) {
2527
if (p_item->update_dependencies) {
2528
RID material = p_item->material;
2529
2530
if (p_item->use_parent_material) {
2531
Item *parent = canvas_item_owner.get_or_null(p_item->parent);
2532
while (parent != nullptr) {
2533
material = parent->material;
2534
if (!parent->use_parent_material) {
2535
break;
2536
}
2537
parent = canvas_item_owner.get_or_null(parent->parent);
2538
}
2539
}
2540
2541
p_item->dependency_tracker.update_begin();
2542
2543
p_item->instance_uniforms.materials_start();
2544
2545
if (material.is_valid()) {
2546
p_item->instance_uniforms.materials_append(material);
2547
RSG::material_storage->material_update_dependency(material, &p_item->dependency_tracker);
2548
}
2549
2550
if (p_item->instance_uniforms.materials_finish(p_item->self)) {
2551
p_item->instance_allocated_shader_uniforms_offset = p_item->instance_uniforms.location();
2552
}
2553
2554
p_item->dependency_tracker.update_end();
2555
}
2556
_item_update_list.remove(&p_item->update_item);
2557
p_item->update_dependencies = false;
2558
}
2559
2560
void RendererCanvasCull::update() {
2561
update_dirty_items();
2562
}
2563
2564
bool RendererCanvasCull::free(RID p_rid) {
2565
if (canvas_owner.owns(p_rid)) {
2566
Canvas *canvas = canvas_owner.get_or_null(p_rid);
2567
ERR_FAIL_NULL_V(canvas, false);
2568
2569
while (canvas->viewports.size()) {
2570
RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.get_or_null(*canvas->viewports.begin());
2571
ERR_FAIL_NULL_V(vp, true);
2572
2573
HashMap<RID, RendererViewport::Viewport::CanvasData>::Iterator E = vp->canvas_map.find(p_rid);
2574
ERR_FAIL_COND_V(!E, true);
2575
vp->canvas_map.erase(p_rid);
2576
2577
canvas->viewports.erase(*canvas->viewports.begin());
2578
}
2579
2580
for (int i = 0; i < canvas->child_items.size(); i++) {
2581
canvas->child_items[i].item->parent = RID();
2582
}
2583
2584
for (RendererCanvasRender::Light *E : canvas->lights) {
2585
E->canvas = RID();
2586
}
2587
2588
for (RendererCanvasRender::LightOccluderInstance *E : canvas->occluders) {
2589
E->canvas = RID();
2590
}
2591
2592
canvas_owner.free(p_rid);
2593
2594
} else if (canvas_item_owner.owns(p_rid)) {
2595
Item *canvas_item = canvas_item_owner.get_or_null(p_rid);
2596
ERR_FAIL_NULL_V(canvas_item, true);
2597
_interpolation_data.notify_free_canvas_item(p_rid, *canvas_item);
2598
2599
if (canvas_item->parent.is_valid()) {
2600
if (canvas_owner.owns(canvas_item->parent)) {
2601
Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent);
2602
canvas->erase_item(canvas_item);
2603
} else if (canvas_item_owner.owns(canvas_item->parent)) {
2604
Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent);
2605
item_owner->child_items.erase(canvas_item);
2606
2607
if (item_owner->sort_y) {
2608
_mark_ysort_dirty(item_owner);
2609
}
2610
}
2611
}
2612
2613
for (int i = 0; i < canvas_item->child_items.size(); i++) {
2614
canvas_item->child_items[i]->parent = RID();
2615
}
2616
2617
if (canvas_item->visibility_notifier != nullptr) {
2618
visibility_notifier_allocator.free(canvas_item->visibility_notifier);
2619
}
2620
2621
canvas_item_set_material(canvas_item->self, RID());
2622
update_dirty_items();
2623
canvas_item->instance_uniforms.free(canvas_item->self);
2624
2625
if (canvas_item->canvas_group != nullptr) {
2626
memdelete(canvas_item->canvas_group);
2627
canvas_item->canvas_group = nullptr;
2628
}
2629
2630
canvas_item_owner.free(p_rid);
2631
2632
} else if (canvas_light_owner.owns(p_rid)) {
2633
RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid);
2634
ERR_FAIL_NULL_V(canvas_light, true);
2635
_interpolation_data.notify_free_canvas_light(p_rid, *canvas_light);
2636
2637
if (canvas_light->canvas.is_valid()) {
2638
Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas);
2639
if (canvas) {
2640
canvas->lights.erase(canvas_light);
2641
}
2642
}
2643
2644
RSG::canvas_render->free(canvas_light->light_internal);
2645
2646
canvas_light_owner.free(p_rid);
2647
2648
} else if (canvas_light_occluder_owner.owns(p_rid)) {
2649
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid);
2650
ERR_FAIL_NULL_V(occluder, true);
2651
_interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder);
2652
2653
if (occluder->polygon.is_valid()) {
2654
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
2655
if (occluder_poly) {
2656
occluder_poly->owners.erase(occluder);
2657
}
2658
}
2659
2660
if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) {
2661
Canvas *canvas = canvas_owner.get_or_null(occluder->canvas);
2662
canvas->occluders.erase(occluder);
2663
}
2664
2665
canvas_light_occluder_owner.free(p_rid);
2666
2667
} else if (canvas_light_occluder_polygon_owner.owns(p_rid)) {
2668
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid);
2669
ERR_FAIL_NULL_V(occluder_poly, true);
2670
RSG::canvas_render->free(occluder_poly->occluder);
2671
2672
while (occluder_poly->owners.size()) {
2673
(*occluder_poly->owners.begin())->polygon = RID();
2674
occluder_poly->owners.remove(occluder_poly->owners.begin());
2675
}
2676
2677
canvas_light_occluder_polygon_owner.free(p_rid);
2678
} else {
2679
return false;
2680
}
2681
2682
return true;
2683
}
2684
2685
template <typename T>
2686
void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) {
2687
LocalVector<RID> owned = p_owner.get_owned_list();
2688
if (owned.size()) {
2689
if (owned.size() == 1) {
2690
WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type));
2691
} else {
2692
WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
2693
}
2694
for (const RID &rid : owned) {
2695
free(rid);
2696
}
2697
}
2698
}
2699
2700
void RendererCanvasCull::finalize() {
2701
_free_rids(canvas_owner, "Canvas");
2702
_free_rids(canvas_item_owner, "CanvasItem");
2703
_free_rids(canvas_light_owner, "CanvasLight");
2704
_free_rids(canvas_light_occluder_owner, "CanvasLightOccluder");
2705
_free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon");
2706
}
2707
2708
void RendererCanvasCull::tick() {
2709
if (_interpolation_data.interpolation_enabled) {
2710
update_interpolation_tick(true);
2711
}
2712
}
2713
2714
void RendererCanvasCull::update_interpolation_tick(bool p_process) {
2715
#define GODOT_UPDATE_INTERPOLATION_TICK(m_list_prev, m_list_curr, m_type, m_owner_list) \
2716
/* Detect any that were on the previous transform list that are no longer active. */ \
2717
for (unsigned int n = 0; n < _interpolation_data.m_list_prev->size(); n++) { \
2718
const RID &rid = (*_interpolation_data.m_list_prev)[n]; \
2719
m_type *item = m_owner_list.get_or_null(rid); \
2720
/* no longer active? (either the instance deleted or no longer being transformed) */ \
2721
if (item && !item->on_interpolate_transform_list) { \
2722
item->xform_prev = item->xform_curr; \
2723
} \
2724
} \
2725
/* and now for any in the transform list (being actively interpolated), */ \
2726
/* keep the previous transform value up to date and ready for next tick */ \
2727
if (p_process) { \
2728
for (unsigned int n = 0; n < _interpolation_data.m_list_curr->size(); n++) { \
2729
const RID &rid = (*_interpolation_data.m_list_curr)[n]; \
2730
m_type *item = m_owner_list.get_or_null(rid); \
2731
if (item) { \
2732
item->xform_prev = item->xform_curr; \
2733
item->on_interpolate_transform_list = false; \
2734
} \
2735
} \
2736
} \
2737
SWAP(_interpolation_data.m_list_curr, _interpolation_data.m_list_prev); \
2738
_interpolation_data.m_list_curr->clear();
2739
2740
GODOT_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner);
2741
GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RendererCanvasRender::Light, canvas_light_owner);
2742
GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RendererCanvasRender::LightOccluderInstance, canvas_light_occluder_owner);
2743
2744
#undef GODOT_UPDATE_INTERPOLATION_TICK
2745
}
2746
2747
void RendererCanvasCull::InterpolationData::notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item) {
2748
r_canvas_item.on_interpolate_transform_list = false;
2749
2750
if (!interpolation_enabled) {
2751
return;
2752
}
2753
2754
// If the instance was on any of the lists, remove.
2755
canvas_item_transform_update_list_curr->erase_multiple_unordered(p_rid);
2756
canvas_item_transform_update_list_prev->erase_multiple_unordered(p_rid);
2757
}
2758
2759
void RendererCanvasCull::InterpolationData::notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light) {
2760
r_canvas_light.on_interpolate_transform_list = false;
2761
2762
if (!interpolation_enabled) {
2763
return;
2764
}
2765
2766
// If the instance was on any of the lists, remove.
2767
canvas_light_transform_update_list_curr->erase_multiple_unordered(p_rid);
2768
canvas_light_transform_update_list_prev->erase_multiple_unordered(p_rid);
2769
}
2770
2771
void RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder) {
2772
r_canvas_light_occluder.on_interpolate_transform_list = false;
2773
2774
if (!interpolation_enabled) {
2775
return;
2776
}
2777
2778
// If the instance was on any of the lists, remove.
2779
canvas_light_occluder_transform_update_list_curr->erase_multiple_unordered(p_rid);
2780
canvas_light_occluder_transform_update_list_prev->erase_multiple_unordered(p_rid);
2781
}
2782
2783
RendererCanvasCull::RendererCanvasCull() {
2784
_canvas_cull_singleton = this;
2785
2786
z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
2787
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
2788
2789
disable_scale = false;
2790
2791
debug_redraw_time = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "debug/canvas_items/debug_redraw_time", PROPERTY_HINT_RANGE, "0.1,2,0.001,or_greater"), 1.0);
2792
debug_redraw_color = GLOBAL_DEF(PropertyInfo(Variant::COLOR, "debug/canvas_items/debug_redraw_color"), Color(1.0, 0.2, 0.2, 0.5));
2793
}
2794
2795
RendererCanvasCull::~RendererCanvasCull() {
2796
memfree(z_list);
2797
memfree(z_last_list);
2798
_canvas_cull_singleton = nullptr;
2799
}
2800
2801