1/**************************************************************************/
2/* canvas_item.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 "canvas_item.h"
32
33#include "core/object/message_queue.h"
34#include "scene/2d/canvas_group.h"
35#include "scene/main/canvas_layer.h"
36#include "scene/main/window.h"
37#include "scene/resources/canvas_item_material.h"
38#include "scene/resources/font.h"
39#include "scene/resources/multimesh.h"
40#include "scene/resources/style_box.h"
41#include "scene/resources/world_2d.h"
42#include "scene/scene_string_names.h"
43
44#ifdef TOOLS_ENABLED
45bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
46 if (_edit_use_rect()) {
47 return _edit_get_rect().has_point(p_point);
48 } else {
49 return p_point.length() < p_tolerance;
50 }
51}
52
53Transform2D CanvasItem::_edit_get_transform() const {
54 return Transform2D(_edit_get_rotation(), _edit_get_position() + _edit_get_pivot());
55}
56#endif
57
58bool CanvasItem::is_visible_in_tree() const {
59 ERR_READ_THREAD_GUARD_V(false);
60 return visible && parent_visible_in_tree;
61}
62
63void CanvasItem::_propagate_visibility_changed(bool p_parent_visible_in_tree) {
64 parent_visible_in_tree = p_parent_visible_in_tree;
65 if (!visible) {
66 return;
67 }
68
69 _handle_visibility_change(p_parent_visible_in_tree);
70}
71
72void CanvasItem::set_visible(bool p_visible) {
73 ERR_MAIN_THREAD_GUARD;
74 if (visible == p_visible) {
75 return;
76 }
77
78 visible = p_visible;
79
80 if (!parent_visible_in_tree) {
81 notification(NOTIFICATION_VISIBILITY_CHANGED);
82 return;
83 }
84
85 _handle_visibility_change(p_visible);
86}
87
88void CanvasItem::_handle_visibility_change(bool p_visible) {
89 RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible);
90 notification(NOTIFICATION_VISIBILITY_CHANGED);
91
92 if (p_visible) {
93 queue_redraw();
94 } else {
95 emit_signal(SceneStringNames::get_singleton()->hidden);
96 }
97
98 _block();
99 for (int i = 0; i < get_child_count(); i++) {
100 CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i));
101
102 if (c) { // Should the top_levels stop propagation? I think so, but...
103 c->_propagate_visibility_changed(p_visible);
104 }
105 }
106 _unblock();
107}
108
109void CanvasItem::show() {
110 ERR_MAIN_THREAD_GUARD;
111 set_visible(true);
112}
113
114void CanvasItem::hide() {
115 ERR_MAIN_THREAD_GUARD;
116 set_visible(false);
117}
118
119bool CanvasItem::is_visible() const {
120 ERR_READ_THREAD_GUARD_V(false);
121 return visible;
122}
123
124CanvasItem *CanvasItem::current_item_drawn = nullptr;
125CanvasItem *CanvasItem::get_current_item_drawn() {
126 return current_item_drawn;
127}
128
129void CanvasItem::_redraw_callback() {
130 if (!is_inside_tree()) {
131 pending_update = false;
132 return;
133 }
134
135 RenderingServer::get_singleton()->canvas_item_clear(get_canvas_item());
136 //todo updating = true - only allow drawing here
137 if (is_visible_in_tree()) {
138 drawing = true;
139 current_item_drawn = this;
140 notification(NOTIFICATION_DRAW);
141 emit_signal(SceneStringNames::get_singleton()->draw);
142 GDVIRTUAL_CALL(_draw);
143 current_item_drawn = nullptr;
144 drawing = false;
145 }
146 //todo updating = false
147 pending_update = false; // don't change to false until finished drawing (avoid recursive update)
148}
149
150Transform2D CanvasItem::get_global_transform_with_canvas() const {
151 ERR_READ_THREAD_GUARD_V(Transform2D());
152 if (canvas_layer) {
153 return canvas_layer->get_final_transform() * get_global_transform();
154 } else if (is_inside_tree()) {
155 return get_viewport()->get_canvas_transform() * get_global_transform();
156 } else {
157 return get_global_transform();
158 }
159}
160
161Transform2D CanvasItem::get_screen_transform() const {
162 ERR_READ_THREAD_GUARD_V(Transform2D());
163 ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
164 return get_viewport()->get_popup_base_transform() * get_global_transform_with_canvas();
165}
166
167Transform2D CanvasItem::get_global_transform() const {
168 ERR_READ_THREAD_GUARD_V(Transform2D());
169
170 if (_is_global_invalid()) {
171 // This code can enter multiple times from threads if dirty, this is expected.
172 const CanvasItem *pi = get_parent_item();
173 Transform2D new_global;
174 if (pi) {
175 new_global = pi->get_global_transform() * get_transform();
176 } else {
177 new_global = get_transform();
178 }
179
180 global_transform = new_global;
181 _set_global_invalid(false);
182 }
183
184 return global_transform;
185}
186
187void CanvasItem::_set_global_invalid(bool p_invalid) const {
188 if (is_group_processing()) {
189 if (p_invalid) {
190 global_invalid.mt.set();
191 } else {
192 global_invalid.mt.clear();
193 }
194 } else {
195 global_invalid.st = p_invalid;
196 }
197}
198
199void CanvasItem::_top_level_raise_self() {
200 if (!is_inside_tree()) {
201 return;
202 }
203
204 if (canvas_layer) {
205 RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, canvas_layer->get_sort_index());
206 } else {
207 RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_viewport()->gui_get_canvas_sort_index());
208 }
209}
210
211void CanvasItem::_enter_canvas() {
212 // Resolves to nullptr if the node is top_level.
213 CanvasItem *parent_item = get_parent_item();
214
215 if (get_parent()) {
216 get_viewport()->canvas_parent_mark_dirty(get_parent());
217 }
218
219 if (parent_item) {
220 canvas_layer = parent_item->canvas_layer;
221 RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, parent_item->get_canvas_item());
222 RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, visibility_layer);
223 } else {
224 Node *n = this;
225
226 canvas_layer = nullptr;
227
228 while (n) {
229 canvas_layer = Object::cast_to<CanvasLayer>(n);
230 if (canvas_layer) {
231 break;
232 }
233 if (Object::cast_to<Viewport>(n)) {
234 break;
235 }
236 n = n->get_parent();
237 }
238
239 RID canvas;
240 if (canvas_layer) {
241 canvas = canvas_layer->get_canvas();
242 } else {
243 canvas = get_viewport()->find_world_2d()->get_canvas();
244 }
245
246 RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
247 RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, visibility_layer);
248
249 canvas_group = "_root_canvas" + itos(canvas.get_id());
250
251 add_to_group(canvas_group);
252 if (canvas_layer) {
253 canvas_layer->reset_sort_index();
254 } else {
255 get_viewport()->gui_reset_canvas_sort_index();
256 }
257 }
258
259 pending_update = false;
260 queue_redraw();
261
262 notification(NOTIFICATION_ENTER_CANVAS);
263}
264
265void CanvasItem::_exit_canvas() {
266 notification(NOTIFICATION_EXIT_CANVAS, true); //reverse the notification
267 RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, RID());
268 canvas_layer = nullptr;
269 if (canvas_group != StringName()) {
270 remove_from_group(canvas_group);
271 canvas_group = StringName();
272 }
273}
274
275void CanvasItem::_notification(int p_what) {
276 ERR_MAIN_THREAD_GUARD;
277
278 switch (p_what) {
279 case NOTIFICATION_ENTER_TREE: {
280 ERR_FAIL_COND(!is_inside_tree());
281
282 Node *parent = get_parent();
283 if (parent) {
284 CanvasItem *ci = Object::cast_to<CanvasItem>(parent);
285
286 if (ci) {
287 parent_visible_in_tree = ci->is_visible_in_tree();
288 C = ci->children_items.push_back(this);
289 } else {
290 CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent);
291
292 if (cl) {
293 parent_visible_in_tree = cl->is_visible();
294 } else {
295 // Look for a window.
296 Viewport *viewport = nullptr;
297
298 while (parent) {
299 viewport = Object::cast_to<Viewport>(parent);
300 if (viewport) {
301 break;
302 }
303 parent = parent->get_parent();
304 }
305
306 ERR_FAIL_NULL(viewport);
307
308 window = Object::cast_to<Window>(viewport);
309 if (window) {
310 window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
311 parent_visible_in_tree = window->is_visible();
312 } else {
313 parent_visible_in_tree = true;
314 }
315 }
316 }
317 }
318
319 _enter_canvas();
320
321 RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, is_visible_in_tree()); // The visibility of the parent may change.
322 if (is_visible_in_tree()) {
323 notification(NOTIFICATION_VISIBILITY_CHANGED); // Considered invisible until entered.
324 }
325
326 _update_texture_filter_changed(false);
327 _update_texture_repeat_changed(false);
328
329 if (!block_transform_notify && !xform_change.in_list()) {
330 get_tree()->xform_change_list.add(&xform_change);
331 }
332
333 if (get_viewport()) {
334 get_parent()->connect(SNAME("child_order_changed"), callable_mp(get_viewport(), &Viewport::canvas_parent_mark_dirty).bind(get_parent()), CONNECT_REFERENCE_COUNTED);
335 }
336
337 } break;
338 case NOTIFICATION_EXIT_TREE: {
339 if (xform_change.in_list()) {
340 get_tree()->xform_change_list.remove(&xform_change);
341 }
342 _exit_canvas();
343 if (C) {
344 Object::cast_to<CanvasItem>(get_parent())->children_items.erase(C);
345 C = nullptr;
346 }
347 if (window) {
348 window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
349 window = nullptr;
350 }
351 _set_global_invalid(true);
352 parent_visible_in_tree = false;
353
354 if (get_viewport()) {
355 get_parent()->disconnect(SNAME("child_order_changed"), callable_mp(get_viewport(), &Viewport::canvas_parent_mark_dirty).bind(get_parent()));
356 }
357 } break;
358
359 case NOTIFICATION_VISIBILITY_CHANGED: {
360 emit_signal(SceneStringNames::get_singleton()->visibility_changed);
361 } break;
362 case NOTIFICATION_WORLD_2D_CHANGED: {
363 _exit_canvas();
364 _enter_canvas();
365 } break;
366 case NOTIFICATION_PARENTED: {
367 // The node is not inside the tree during this notification.
368 _notify_transform();
369 } break;
370 }
371}
372
373void CanvasItem::update_draw_order() {
374 ERR_MAIN_THREAD_GUARD;
375
376 if (!is_inside_tree()) {
377 return;
378 }
379
380 if (canvas_group != StringName()) {
381 get_tree()->call_group_flags(SceneTree::GROUP_CALL_UNIQUE | SceneTree::GROUP_CALL_DEFERRED, canvas_group, "_top_level_raise_self");
382 } else {
383 ERR_FAIL_NULL_MSG(get_parent_item(), "Moved child is in incorrect state (no canvas group, no canvas item parent).");
384 RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
385 }
386}
387
388void CanvasItem::_window_visibility_changed() {
389 _propagate_visibility_changed(window->is_visible());
390}
391
392void CanvasItem::queue_redraw() {
393 ERR_THREAD_GUARD; // Calling from thread is safe.
394 if (!is_inside_tree()) {
395 return;
396 }
397 if (pending_update) {
398 return;
399 }
400
401 pending_update = true;
402
403 MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback));
404}
405
406void CanvasItem::move_to_front() {
407 ERR_MAIN_THREAD_GUARD;
408 if (!get_parent()) {
409 return;
410 }
411 get_parent()->move_child(this, -1);
412}
413
414void CanvasItem::set_modulate(const Color &p_modulate) {
415 ERR_THREAD_GUARD;
416 if (modulate == p_modulate) {
417 return;
418 }
419
420 modulate = p_modulate;
421 RenderingServer::get_singleton()->canvas_item_set_modulate(canvas_item, modulate);
422}
423
424Color CanvasItem::get_modulate() const {
425 ERR_READ_THREAD_GUARD_V(Color());
426 return modulate;
427}
428
429Color CanvasItem::get_modulate_in_tree() const {
430 ERR_READ_THREAD_GUARD_V(Color());
431 Color final_modulate = modulate;
432 CanvasItem *parent_item = get_parent_item();
433 while (parent_item) {
434 final_modulate *= parent_item->get_modulate();
435 parent_item = parent_item->get_parent_item();
436 }
437 return final_modulate;
438}
439
440void CanvasItem::set_as_top_level(bool p_top_level) {
441 ERR_MAIN_THREAD_GUARD;
442 if (top_level == p_top_level) {
443 return;
444 }
445
446 if (!is_inside_tree()) {
447 top_level = p_top_level;
448 _notify_transform();
449 return;
450 }
451
452 _exit_canvas();
453 top_level = p_top_level;
454 _top_level_changed();
455 _enter_canvas();
456
457 _notify_transform();
458}
459
460void CanvasItem::_top_level_changed() {
461 // Inform children that top_level status has changed on a parent.
462 int children = get_child_count();
463 for (int i = 0; i < children; i++) {
464 CanvasItem *child = Object::cast_to<CanvasItem>(get_child(i));
465 if (child) {
466 child->_top_level_changed_on_parent();
467 }
468 }
469}
470
471void CanvasItem::_top_level_changed_on_parent() {
472 // Inform children that top_level status has changed on a parent.
473 _top_level_changed();
474}
475
476bool CanvasItem::is_set_as_top_level() const {
477 return top_level;
478}
479
480CanvasItem *CanvasItem::get_parent_item() const {
481 ERR_READ_THREAD_GUARD_V(nullptr);
482 if (top_level) {
483 return nullptr;
484 }
485
486 return Object::cast_to<CanvasItem>(get_parent());
487}
488
489void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
490 ERR_THREAD_GUARD;
491 if (self_modulate == p_self_modulate) {
492 return;
493 }
494
495 self_modulate = p_self_modulate;
496 RenderingServer::get_singleton()->canvas_item_set_self_modulate(canvas_item, self_modulate);
497}
498
499Color CanvasItem::get_self_modulate() const {
500 ERR_READ_THREAD_GUARD_V(Color());
501 return self_modulate;
502}
503
504void CanvasItem::set_light_mask(int p_light_mask) {
505 ERR_THREAD_GUARD;
506 if (light_mask == p_light_mask) {
507 return;
508 }
509
510 light_mask = p_light_mask;
511 RS::get_singleton()->canvas_item_set_light_mask(canvas_item, p_light_mask);
512}
513
514int CanvasItem::get_light_mask() const {
515 ERR_READ_THREAD_GUARD_V(0);
516 return light_mask;
517}
518
519void CanvasItem::item_rect_changed(bool p_size_changed) {
520 ERR_MAIN_THREAD_GUARD;
521 if (p_size_changed) {
522 queue_redraw();
523 }
524 emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
525}
526
527void CanvasItem::set_z_index(int p_z) {
528 ERR_THREAD_GUARD;
529 ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN);
530 ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX);
531 z_index = p_z;
532 RS::get_singleton()->canvas_item_set_z_index(canvas_item, z_index);
533 update_configuration_warnings();
534}
535
536void CanvasItem::set_z_as_relative(bool p_enabled) {
537 ERR_THREAD_GUARD;
538 if (z_relative == p_enabled) {
539 return;
540 }
541 z_relative = p_enabled;
542 RS::get_singleton()->canvas_item_set_z_as_relative_to_parent(canvas_item, p_enabled);
543}
544
545bool CanvasItem::is_z_relative() const {
546 ERR_READ_THREAD_GUARD_V(false);
547 return z_relative;
548}
549
550int CanvasItem::get_z_index() const {
551 ERR_READ_THREAD_GUARD_V(0);
552 return z_index;
553}
554
555int CanvasItem::get_effective_z_index() const {
556 ERR_READ_THREAD_GUARD_V(0);
557 int effective_z_index = z_index;
558 if (is_z_relative()) {
559 CanvasItem *p = get_parent_item();
560 if (p) {
561 effective_z_index += p->get_effective_z_index();
562 }
563 }
564 return effective_z_index;
565}
566
567void CanvasItem::set_y_sort_enabled(bool p_enabled) {
568 ERR_THREAD_GUARD;
569 y_sort_enabled = p_enabled;
570 RS::get_singleton()->canvas_item_set_sort_children_by_y(canvas_item, y_sort_enabled);
571}
572
573bool CanvasItem::is_y_sort_enabled() const {
574 ERR_READ_THREAD_GUARD_V(false);
575 return y_sort_enabled;
576}
577
578void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash, bool p_aligned) {
579 ERR_THREAD_GUARD;
580 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
581 ERR_FAIL_COND(p_dash <= 0.0);
582
583 float length = (p_to - p_from).length();
584 Vector2 step = p_dash * (p_to - p_from).normalized();
585
586 if (length < p_dash || step == Vector2()) {
587 RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
588 return;
589 }
590
591 int steps = (p_aligned) ? Math::ceil(length / p_dash) : Math::floor(length / p_dash);
592 if (steps % 2 == 0) {
593 steps--;
594 }
595
596 Point2 off = p_from;
597 if (p_aligned) {
598 off += (p_to - p_from).normalized() * (length - steps * p_dash) / 2.0;
599 }
600
601 Vector<Vector2> points;
602 points.resize(steps + 1);
603 for (int i = 0; i < steps; i += 2) {
604 points.write[i] = (i == 0) ? p_from : off;
605 points.write[i + 1] = (p_aligned && i == steps - 1) ? p_to : (off + step);
606 off += step * 2;
607 }
608
609 Vector<Color> colors = { p_color };
610
611 RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, points, colors, p_width);
612}
613
614void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, bool p_antialiased) {
615 ERR_THREAD_GUARD;
616 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
617
618 RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
619}
620
621void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
622 ERR_THREAD_GUARD;
623 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
624
625 Vector<Color> colors = { p_color };
626 RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased);
627}
628
629void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
630 ERR_THREAD_GUARD;
631 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
632
633 RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
634}
635
636void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
637 ERR_THREAD_GUARD;
638 Vector<Point2> points;
639 points.resize(p_point_count);
640 Point2 *points_ptr = points.ptrw();
641
642 // Clamp angle difference to full circle so arc won't overlap itself.
643 const real_t delta_angle = CLAMP(p_end_angle - p_start_angle, -Math_TAU, Math_TAU);
644 for (int i = 0; i < p_point_count; i++) {
645 real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
646 points_ptr[i] = p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius;
647 }
648
649 draw_polyline(points, p_color, p_width, p_antialiased);
650}
651
652void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
653 ERR_THREAD_GUARD;
654 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
655
656 Vector<Color> colors = { p_color };
657 RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
658}
659
660void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
661 ERR_THREAD_GUARD;
662 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
663
664 RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
665}
666
667void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
668 ERR_THREAD_GUARD;
669 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
670
671 Rect2 rect = p_rect.abs();
672
673 if (p_filled) {
674 if (p_width != -1.0) {
675 WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
676 }
677
678 RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, rect, p_color);
679 } else if (p_width >= rect.size.width || p_width >= rect.size.height) {
680 RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, rect.grow(0.5f * p_width), p_color);
681 } else {
682 Vector<Vector2> points;
683 points.resize(5);
684 points.write[0] = rect.position;
685 points.write[1] = rect.position + Vector2(rect.size.x, 0);
686 points.write[2] = rect.position + rect.size;
687 points.write[3] = rect.position + Vector2(0, rect.size.y);
688 points.write[4] = rect.position;
689
690 Vector<Color> colors = { p_color };
691
692 RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, points, colors, p_width);
693 }
694}
695
696void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
697 ERR_THREAD_GUARD;
698 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
699
700 RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
701}
702
703void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate) {
704 ERR_THREAD_GUARD;
705 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
706
707 ERR_FAIL_COND(p_texture.is_null());
708
709 p_texture->draw(canvas_item, p_pos, p_modulate, false);
710}
711
712void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) {
713 ERR_THREAD_GUARD;
714 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
715
716 ERR_FAIL_COND(p_texture.is_null());
717 p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose);
718}
719
720void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
721 ERR_THREAD_GUARD;
722 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
723 ERR_FAIL_COND(p_texture.is_null());
724 p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv);
725}
726
727void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range, double p_scale) {
728 ERR_THREAD_GUARD;
729 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
730 ERR_FAIL_COND(p_texture.is_null());
731 RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range, p_scale);
732}
733
734void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) {
735 ERR_THREAD_GUARD;
736 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
737 ERR_FAIL_COND(p_texture.is_null());
738 RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate);
739}
740
741void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
742 ERR_THREAD_GUARD;
743 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
744
745 ERR_FAIL_COND(p_style_box.is_null());
746
747 p_style_box->draw(canvas_item, p_rect);
748}
749
750void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
751 ERR_THREAD_GUARD;
752 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
753
754 RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
755 RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid);
756}
757
758void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
759 ERR_THREAD_GUARD;
760 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
761
762 Transform2D xform(p_rot, p_offset);
763 xform.scale_basis(p_scale);
764 RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, xform);
765}
766
767void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
768 ERR_THREAD_GUARD;
769 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
770
771 RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
772}
773void CanvasItem::draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
774 ERR_THREAD_GUARD;
775 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
776
777 RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, p_animation_length, p_slice_begin, p_slice_end, p_offset);
778}
779
780void CanvasItem::draw_end_animation() {
781 ERR_THREAD_GUARD;
782 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
783
784 RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, 1, 0, 2, 0);
785}
786
787void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
788 ERR_THREAD_GUARD;
789 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
790
791 RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
792
793 RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid);
794}
795
796void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
797 ERR_THREAD_GUARD;
798 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
799
800 Vector<Color> colors = { p_color };
801 RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
802 RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid);
803}
804
805void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) {
806 ERR_THREAD_GUARD;
807 ERR_FAIL_COND(p_mesh.is_null());
808 RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
809
810 RenderingServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid);
811}
812
813void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture) {
814 ERR_THREAD_GUARD;
815 ERR_FAIL_COND(p_multimesh.is_null());
816 RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
817 RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
818}
819
820void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
821 ERR_THREAD_GUARD;
822 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
823 ERR_FAIL_COND(p_font.is_null());
824
825 p_font->draw_string(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_modulate, p_jst_flags, p_direction, p_orientation);
826}
827
828void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
829 ERR_THREAD_GUARD;
830 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
831 ERR_FAIL_COND(p_font.is_null());
832
833 p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_max_lines, p_modulate, p_brk_flags, p_jst_flags, p_direction, p_orientation);
834}
835
836void CanvasItem::draw_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
837 ERR_THREAD_GUARD;
838 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
839 ERR_FAIL_COND(p_font.is_null());
840
841 p_font->draw_string_outline(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_size, p_modulate, p_jst_flags, p_direction, p_orientation);
842}
843
844void CanvasItem::draw_multiline_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
845 ERR_THREAD_GUARD;
846 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
847 ERR_FAIL_COND(p_font.is_null());
848
849 p_font->draw_multiline_string_outline(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_max_lines, p_size, p_modulate, p_brk_flags, p_jst_flags, p_direction, p_orientation);
850}
851
852void CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, const Color &p_modulate) const {
853 ERR_THREAD_GUARD;
854 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
855 ERR_FAIL_COND(p_char.length() != 1);
856 ERR_FAIL_COND(p_font.is_null());
857
858 p_font->draw_char(canvas_item, p_pos, p_char[0], p_font_size, p_modulate);
859}
860
861void CanvasItem::draw_char_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, int p_size, const Color &p_modulate) const {
862 ERR_THREAD_GUARD;
863 ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
864 ERR_FAIL_COND(p_char.length() != 1);
865 ERR_FAIL_COND(p_font.is_null());
866
867 p_font->draw_char_outline(canvas_item, p_pos, p_char[0], p_font_size, p_size, p_modulate);
868}
869
870void CanvasItem::_notify_transform_deferred() {
871 if (is_inside_tree() && notify_transform && !xform_change.in_list()) {
872 get_tree()->xform_change_list.add(&xform_change);
873 }
874}
875
876void CanvasItem::_notify_transform(CanvasItem *p_node) {
877 /* This check exists to avoid re-propagating the transform
878 * notification down the tree on dirty nodes. It provides
879 * optimization by avoiding redundancy (nodes are dirty, will get the
880 * notification anyway).
881 */
882
883 if (/*p_node->xform_change.in_list() &&*/ p_node->_is_global_invalid()) {
884 return; //nothing to do
885 }
886
887 p_node->_set_global_invalid(true);
888
889 if (p_node->notify_transform && !p_node->xform_change.in_list()) {
890 if (!p_node->block_transform_notify) {
891 if (p_node->is_inside_tree()) {
892 if (is_accessible_from_caller_thread()) {
893 get_tree()->xform_change_list.add(&p_node->xform_change);
894 } else {
895 // Should be rare, but still needs to be handled.
896 MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred));
897 }
898 }
899 }
900 }
901
902 for (CanvasItem *ci : p_node->children_items) {
903 if (ci->top_level) {
904 continue;
905 }
906 _notify_transform(ci);
907 }
908}
909
910Rect2 CanvasItem::get_viewport_rect() const {
911 ERR_READ_THREAD_GUARD_V(Rect2());
912 ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
913 return get_viewport()->get_visible_rect();
914}
915
916RID CanvasItem::get_canvas() const {
917 ERR_READ_THREAD_GUARD_V(RID());
918 ERR_FAIL_COND_V(!is_inside_tree(), RID());
919
920 if (canvas_layer) {
921 return canvas_layer->get_canvas();
922 } else {
923 return get_viewport()->find_world_2d()->get_canvas();
924 }
925}
926
927ObjectID CanvasItem::get_canvas_layer_instance_id() const {
928 ERR_READ_THREAD_GUARD_V(ObjectID());
929 if (canvas_layer) {
930 return canvas_layer->get_instance_id();
931 } else {
932 return ObjectID();
933 }
934}
935
936CanvasItem *CanvasItem::get_top_level() const {
937 ERR_READ_THREAD_GUARD_V(nullptr);
938 CanvasItem *ci = const_cast<CanvasItem *>(this);
939 while (!ci->top_level && Object::cast_to<CanvasItem>(ci->get_parent())) {
940 ci = Object::cast_to<CanvasItem>(ci->get_parent());
941 }
942
943 return ci;
944}
945
946Ref<World2D> CanvasItem::get_world_2d() const {
947 ERR_READ_THREAD_GUARD_V(Ref<World2D>());
948 ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
949
950 CanvasItem *tl = get_top_level();
951
952 if (tl->get_viewport()) {
953 return tl->get_viewport()->find_world_2d();
954 } else {
955 return Ref<World2D>();
956 }
957}
958
959RID CanvasItem::get_viewport_rid() const {
960 ERR_READ_THREAD_GUARD_V(RID());
961 ERR_FAIL_COND_V(!is_inside_tree(), RID());
962 return get_viewport()->get_viewport_rid();
963}
964
965void CanvasItem::set_block_transform_notify(bool p_enable) {
966 ERR_THREAD_GUARD;
967 block_transform_notify = p_enable;
968}
969
970bool CanvasItem::is_block_transform_notify_enabled() const {
971 ERR_READ_THREAD_GUARD_V(false);
972 return block_transform_notify;
973}
974
975void CanvasItem::set_draw_behind_parent(bool p_enable) {
976 ERR_THREAD_GUARD;
977 if (behind == p_enable) {
978 return;
979 }
980 behind = p_enable;
981 RenderingServer::get_singleton()->canvas_item_set_draw_behind_parent(canvas_item, behind);
982}
983
984bool CanvasItem::is_draw_behind_parent_enabled() const {
985 ERR_READ_THREAD_GUARD_V(false);
986 return behind;
987}
988
989void CanvasItem::set_material(const Ref<Material> &p_material) {
990 ERR_THREAD_GUARD;
991 material = p_material;
992 RID rid;
993 if (material.is_valid()) {
994 rid = material->get_rid();
995 }
996 RS::get_singleton()->canvas_item_set_material(canvas_item, rid);
997 notify_property_list_changed(); //properties for material exposed
998}
999
1000void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
1001 ERR_THREAD_GUARD;
1002 use_parent_material = p_use_parent_material;
1003 RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
1004}
1005
1006bool CanvasItem::get_use_parent_material() const {
1007 ERR_READ_THREAD_GUARD_V(false);
1008 return use_parent_material;
1009}
1010
1011Ref<Material> CanvasItem::get_material() const {
1012 ERR_READ_THREAD_GUARD_V(Ref<Material>());
1013 return material;
1014}
1015
1016Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
1017 ERR_READ_THREAD_GUARD_V(Vector2());
1018 ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
1019
1020 Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
1021
1022 return local_matrix.xform(screen_point);
1023}
1024
1025Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
1026 ERR_READ_THREAD_GUARD_V(Ref<InputEvent>());
1027 ERR_FAIL_COND_V(p_event.is_null(), p_event);
1028 ERR_FAIL_COND_V(!is_inside_tree(), p_event);
1029
1030 return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse());
1031}
1032
1033Vector2 CanvasItem::get_global_mouse_position() const {
1034 ERR_READ_THREAD_GUARD_V(Vector2());
1035 ERR_FAIL_NULL_V(get_viewport(), Vector2());
1036 return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
1037}
1038
1039Vector2 CanvasItem::get_local_mouse_position() const {
1040 ERR_READ_THREAD_GUARD_V(Vector2());
1041 ERR_FAIL_NULL_V(get_viewport(), Vector2());
1042
1043 return get_global_transform().affine_inverse().xform(get_global_mouse_position());
1044}
1045
1046void CanvasItem::force_update_transform() {
1047 ERR_THREAD_GUARD;
1048 ERR_FAIL_COND(!is_inside_tree());
1049 if (!xform_change.in_list()) {
1050 return;
1051 }
1052
1053 get_tree()->xform_change_list.remove(&xform_change);
1054
1055 notification(NOTIFICATION_TRANSFORM_CHANGED);
1056}
1057
1058void CanvasItem::_validate_property(PropertyInfo &p_property) const {
1059 if (hide_clip_children && p_property.name == "clip_children") {
1060 p_property.usage = PROPERTY_USAGE_NONE;
1061 }
1062}
1063
1064void CanvasItem::_bind_methods() {
1065 ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self);
1066
1067#ifdef TOOLS_ENABLED
1068 ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state);
1069 ClassDB::bind_method(D_METHOD("_edit_get_state"), &CanvasItem::_edit_get_state);
1070 ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
1071 ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
1072 ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
1073 ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
1074 ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
1075 ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
1076 ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
1077 ClassDB::bind_method(D_METHOD("_edit_set_rotation", "degrees"), &CanvasItem::_edit_set_rotation);
1078 ClassDB::bind_method(D_METHOD("_edit_get_rotation"), &CanvasItem::_edit_get_rotation);
1079 ClassDB::bind_method(D_METHOD("_edit_use_rotation"), &CanvasItem::_edit_use_rotation);
1080 ClassDB::bind_method(D_METHOD("_edit_set_pivot", "pivot"), &CanvasItem::_edit_set_pivot);
1081 ClassDB::bind_method(D_METHOD("_edit_get_pivot"), &CanvasItem::_edit_get_pivot);
1082 ClassDB::bind_method(D_METHOD("_edit_use_pivot"), &CanvasItem::_edit_use_pivot);
1083 ClassDB::bind_method(D_METHOD("_edit_get_transform"), &CanvasItem::_edit_get_transform);
1084#endif
1085
1086 ClassDB::bind_method(D_METHOD("get_canvas_item"), &CanvasItem::get_canvas_item);
1087
1088 ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasItem::set_visible);
1089 ClassDB::bind_method(D_METHOD("is_visible"), &CanvasItem::is_visible);
1090 ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &CanvasItem::is_visible_in_tree);
1091 ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show);
1092 ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide);
1093
1094 ClassDB::bind_method(D_METHOD("queue_redraw"), &CanvasItem::queue_redraw);
1095 ClassDB::bind_method(D_METHOD("move_to_front"), &CanvasItem::move_to_front);
1096
1097 ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level);
1098 ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level);
1099
1100 ClassDB::bind_method(D_METHOD("set_light_mask", "light_mask"), &CanvasItem::set_light_mask);
1101 ClassDB::bind_method(D_METHOD("get_light_mask"), &CanvasItem::get_light_mask);
1102
1103 ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &CanvasItem::set_modulate);
1104 ClassDB::bind_method(D_METHOD("get_modulate"), &CanvasItem::get_modulate);
1105
1106 ClassDB::bind_method(D_METHOD("set_self_modulate", "self_modulate"), &CanvasItem::set_self_modulate);
1107 ClassDB::bind_method(D_METHOD("get_self_modulate"), &CanvasItem::get_self_modulate);
1108
1109 ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &CanvasItem::set_z_index);
1110 ClassDB::bind_method(D_METHOD("get_z_index"), &CanvasItem::get_z_index);
1111
1112 ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &CanvasItem::set_z_as_relative);
1113 ClassDB::bind_method(D_METHOD("is_z_relative"), &CanvasItem::is_z_relative);
1114
1115 ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &CanvasItem::set_y_sort_enabled);
1116 ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &CanvasItem::is_y_sort_enabled);
1117
1118 ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
1119 ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
1120
1121 ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(-1.0), DEFVAL(false));
1122 ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(-1.0), DEFVAL(2.0), DEFVAL(true));
1123 ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(-1.0), DEFVAL(false));
1124 ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(-1.0), DEFVAL(false));
1125 ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(-1.0), DEFVAL(false));
1126 ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(-1.0));
1127 ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(-1.0));
1128 ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(-1.0));
1129 ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
1130 ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)));
1131 ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
1132 ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true));
1133 ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0), DEFVAL(1.0));
1134 ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)));
1135 ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
1136 ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()));
1137 ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
1138 ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
1139 ClassDB::bind_method(D_METHOD("draw_string", "font", "pos", "text", "alignment", "width", "font_size", "modulate", "justification_flags", "direction", "orientation"), &CanvasItem::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
1140 ClassDB::bind_method(D_METHOD("draw_multiline_string", "font", "pos", "text", "alignment", "width", "font_size", "max_lines", "modulate", "brk_flags", "justification_flags", "direction", "orientation"), &CanvasItem::draw_multiline_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
1141 ClassDB::bind_method(D_METHOD("draw_string_outline", "font", "pos", "text", "alignment", "width", "font_size", "size", "modulate", "justification_flags", "direction", "orientation"), &CanvasItem::draw_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
1142 ClassDB::bind_method(D_METHOD("draw_multiline_string_outline", "font", "pos", "text", "alignment", "width", "font_size", "max_lines", "size", "modulate", "brk_flags", "justification_flags", "direction", "orientation"), &CanvasItem::draw_multiline_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
1143 ClassDB::bind_method(D_METHOD("draw_char", "font", "pos", "char", "font_size", "modulate"), &CanvasItem::draw_char, DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)));
1144 ClassDB::bind_method(D_METHOD("draw_char_outline", "font", "pos", "char", "font_size", "size", "modulate"), &CanvasItem::draw_char_outline, DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)));
1145 ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1, 1)));
1146 ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture"), &CanvasItem::draw_multimesh);
1147 ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform, DEFVAL(0.0), DEFVAL(Size2(1.0, 1.0)));
1148 ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
1149 ClassDB::bind_method(D_METHOD("draw_animation_slice", "animation_length", "slice_begin", "slice_end", "offset"), &CanvasItem::draw_animation_slice, DEFVAL(0.0));
1150 ClassDB::bind_method(D_METHOD("draw_end_animation"), &CanvasItem::draw_end_animation);
1151 ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform);
1152 ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform);
1153 ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas);
1154 ClassDB::bind_method(D_METHOD("get_viewport_transform"), &CanvasItem::get_viewport_transform);
1155 ClassDB::bind_method(D_METHOD("get_viewport_rect"), &CanvasItem::get_viewport_rect);
1156 ClassDB::bind_method(D_METHOD("get_canvas_transform"), &CanvasItem::get_canvas_transform);
1157 ClassDB::bind_method(D_METHOD("get_screen_transform"), &CanvasItem::get_screen_transform);
1158 ClassDB::bind_method(D_METHOD("get_local_mouse_position"), &CanvasItem::get_local_mouse_position);
1159 ClassDB::bind_method(D_METHOD("get_global_mouse_position"), &CanvasItem::get_global_mouse_position);
1160 ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasItem::get_canvas);
1161 ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
1162 //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
1163
1164 ClassDB::bind_method(D_METHOD("set_material", "material"), &CanvasItem::set_material);
1165 ClassDB::bind_method(D_METHOD("get_material"), &CanvasItem::get_material);
1166
1167 ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
1168 ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
1169
1170 ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &CanvasItem::set_notify_local_transform);
1171 ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &CanvasItem::is_local_transform_notification_enabled);
1172
1173 ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &CanvasItem::set_notify_transform);
1174 ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &CanvasItem::is_transform_notification_enabled);
1175
1176 ClassDB::bind_method(D_METHOD("force_update_transform"), &CanvasItem::force_update_transform);
1177
1178 ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
1179 ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
1180
1181 ClassDB::bind_method(D_METHOD("set_visibility_layer", "layer"), &CanvasItem::set_visibility_layer);
1182 ClassDB::bind_method(D_METHOD("get_visibility_layer"), &CanvasItem::get_visibility_layer);
1183 ClassDB::bind_method(D_METHOD("set_visibility_layer_bit", "layer", "enabled"), &CanvasItem::set_visibility_layer_bit);
1184 ClassDB::bind_method(D_METHOD("get_visibility_layer_bit", "layer"), &CanvasItem::get_visibility_layer_bit);
1185
1186 ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &CanvasItem::set_texture_filter);
1187 ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasItem::get_texture_filter);
1188
1189 ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
1190 ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
1191
1192 ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode);
1193 ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode);
1194
1195 GDVIRTUAL_BIND(_draw);
1196
1197 ADD_GROUP("Visibility", "");
1198 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
1199 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
1200 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
1201 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
1202 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
1203 ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only,Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode");
1204 ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
1205 ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_layer", PROPERTY_HINT_LAYERS_2D_RENDER), "set_visibility_layer", "get_visibility_layer");
1206
1207 ADD_GROUP("Ordering", "");
1208 ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
1209 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative");
1210 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sort_enabled"), "set_y_sort_enabled", "is_y_sort_enabled");
1211
1212 ADD_GROUP("Texture", "texture_");
1213 ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
1214 ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
1215
1216 ADD_GROUP("Material", "");
1217 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material");
1218 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
1219 // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
1220
1221 ADD_SIGNAL(MethodInfo("draw"));
1222 ADD_SIGNAL(MethodInfo("visibility_changed"));
1223 ADD_SIGNAL(MethodInfo("hidden"));
1224 ADD_SIGNAL(MethodInfo("item_rect_changed"));
1225
1226 BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
1227 BIND_CONSTANT(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
1228 BIND_CONSTANT(NOTIFICATION_DRAW);
1229 BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
1230 BIND_CONSTANT(NOTIFICATION_ENTER_CANVAS);
1231 BIND_CONSTANT(NOTIFICATION_EXIT_CANVAS);
1232 BIND_CONSTANT(NOTIFICATION_WORLD_2D_CHANGED);
1233
1234 BIND_ENUM_CONSTANT(TEXTURE_FILTER_PARENT_NODE);
1235 BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST);
1236 BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR);
1237 BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
1238 BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
1239 BIND_ENUM_CONSTANT(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC);
1240 BIND_ENUM_CONSTANT(TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC);
1241 BIND_ENUM_CONSTANT(TEXTURE_FILTER_MAX);
1242
1243 BIND_ENUM_CONSTANT(TEXTURE_REPEAT_PARENT_NODE);
1244 BIND_ENUM_CONSTANT(TEXTURE_REPEAT_DISABLED);
1245 BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
1246 BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
1247 BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
1248
1249 BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED);
1250 BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY);
1251 BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW);
1252 BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX);
1253}
1254
1255Transform2D CanvasItem::get_canvas_transform() const {
1256 ERR_READ_THREAD_GUARD_V(Transform2D());
1257 ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
1258
1259 if (canvas_layer) {
1260 return canvas_layer->get_final_transform();
1261 } else if (Object::cast_to<CanvasItem>(get_parent())) {
1262 return Object::cast_to<CanvasItem>(get_parent())->get_canvas_transform();
1263 } else {
1264 return get_viewport()->get_canvas_transform();
1265 }
1266}
1267
1268Transform2D CanvasItem::get_viewport_transform() const {
1269 ERR_READ_THREAD_GUARD_V(Transform2D());
1270 ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
1271
1272 if (canvas_layer) {
1273 return get_viewport()->get_final_transform() * canvas_layer->get_final_transform();
1274 } else {
1275 return get_viewport()->get_final_transform() * get_viewport()->get_canvas_transform();
1276 }
1277}
1278
1279void CanvasItem::set_notify_local_transform(bool p_enable) {
1280 ERR_THREAD_GUARD;
1281 notify_local_transform = p_enable;
1282}
1283
1284bool CanvasItem::is_local_transform_notification_enabled() const {
1285 ERR_READ_THREAD_GUARD_V(false);
1286 return notify_local_transform;
1287}
1288
1289void CanvasItem::set_notify_transform(bool p_enable) {
1290 ERR_THREAD_GUARD;
1291 if (notify_transform == p_enable) {
1292 return;
1293 }
1294
1295 notify_transform = p_enable;
1296
1297 if (notify_transform && is_inside_tree()) {
1298 // This ensures that invalid globals get resolved, so notifications can be received.
1299 _ALLOW_DISCARD_ get_global_transform();
1300 }
1301}
1302
1303bool CanvasItem::is_transform_notification_enabled() const {
1304 ERR_READ_THREAD_GUARD_V(false);
1305 return notify_transform;
1306}
1307
1308int CanvasItem::get_canvas_layer() const {
1309 ERR_READ_THREAD_GUARD_V(0);
1310 if (canvas_layer) {
1311 return canvas_layer->get_layer();
1312 } else {
1313 return 0;
1314 }
1315}
1316
1317void CanvasItem::set_visibility_layer(uint32_t p_visibility_layer) {
1318 ERR_THREAD_GUARD;
1319 visibility_layer = p_visibility_layer;
1320 RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, p_visibility_layer);
1321}
1322
1323uint32_t CanvasItem::get_visibility_layer() const {
1324 ERR_READ_THREAD_GUARD_V(0);
1325 return visibility_layer;
1326}
1327
1328void CanvasItem::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable) {
1329 ERR_THREAD_GUARD;
1330 ERR_FAIL_UNSIGNED_INDEX(p_visibility_layer, 32);
1331 if (p_enable) {
1332 set_visibility_layer(visibility_layer | (1 << p_visibility_layer));
1333 } else {
1334 set_visibility_layer(visibility_layer & (~(1 << p_visibility_layer)));
1335 }
1336}
1337
1338bool CanvasItem::get_visibility_layer_bit(uint32_t p_visibility_layer) const {
1339 ERR_READ_THREAD_GUARD_V(0);
1340 ERR_FAIL_UNSIGNED_INDEX_V(p_visibility_layer, 32, false);
1341 return (visibility_layer & (1 << p_visibility_layer));
1342}
1343
1344void CanvasItem::_refresh_texture_filter_cache() const {
1345 if (!is_inside_tree()) {
1346 return;
1347 }
1348
1349 if (texture_filter == TEXTURE_FILTER_PARENT_NODE) {
1350 CanvasItem *parent_item = get_parent_item();
1351 if (parent_item) {
1352 texture_filter_cache = parent_item->texture_filter_cache;
1353 } else {
1354 texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
1355 }
1356 } else {
1357 texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
1358 }
1359}
1360
1361void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
1362 if (!is_inside_tree()) {
1363 return;
1364 }
1365 _refresh_texture_filter_cache();
1366
1367 RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
1368 queue_redraw();
1369
1370 if (p_propagate) {
1371 for (CanvasItem *E : children_items) {
1372 if (!E->top_level && E->texture_filter == TEXTURE_FILTER_PARENT_NODE) {
1373 E->_update_texture_filter_changed(true);
1374 }
1375 }
1376 }
1377}
1378
1379void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
1380 ERR_MAIN_THREAD_GUARD; // Goes down in the tree, so only main thread can set.
1381 ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
1382 if (texture_filter == p_texture_filter) {
1383 return;
1384 }
1385 texture_filter = p_texture_filter;
1386 _update_texture_filter_changed(true);
1387 notify_property_list_changed();
1388}
1389
1390CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
1391 ERR_READ_THREAD_GUARD_V(TEXTURE_FILTER_NEAREST);
1392 return texture_filter;
1393}
1394
1395void CanvasItem::_refresh_texture_repeat_cache() const {
1396 if (!is_inside_tree()) {
1397 return;
1398 }
1399
1400 if (texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
1401 CanvasItem *parent_item = get_parent_item();
1402 if (parent_item) {
1403 texture_repeat_cache = parent_item->texture_repeat_cache;
1404 } else {
1405 texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
1406 }
1407 } else {
1408 texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
1409 }
1410}
1411
1412void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
1413 if (!is_inside_tree()) {
1414 return;
1415 }
1416 _refresh_texture_repeat_cache();
1417
1418 RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
1419 queue_redraw();
1420 if (p_propagate) {
1421 for (CanvasItem *E : children_items) {
1422 if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) {
1423 E->_update_texture_repeat_changed(true);
1424 }
1425 }
1426 }
1427}
1428
1429void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
1430 ERR_MAIN_THREAD_GUARD; // Goes down in the tree, so only main thread can set.
1431 ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
1432 if (texture_repeat == p_texture_repeat) {
1433 return;
1434 }
1435 texture_repeat = p_texture_repeat;
1436 _update_texture_repeat_changed(true);
1437 notify_property_list_changed();
1438}
1439
1440void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
1441 ERR_THREAD_GUARD;
1442 ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
1443
1444 if (clip_children_mode == p_clip_mode) {
1445 return;
1446 }
1447 clip_children_mode = p_clip_mode;
1448
1449 if (Object::cast_to<CanvasGroup>(this) != nullptr) {
1450 //avoid accidental bugs, make this not work on CanvasGroup
1451 return;
1452 }
1453
1454 RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
1455}
1456CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
1457 ERR_READ_THREAD_GUARD_V(CLIP_CHILDREN_DISABLED);
1458 return clip_children_mode;
1459}
1460
1461CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
1462 ERR_READ_THREAD_GUARD_V(TEXTURE_REPEAT_DISABLED);
1463 return texture_repeat;
1464}
1465
1466CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() const {
1467 ERR_READ_THREAD_GUARD_V(TEXTURE_FILTER_NEAREST);
1468 _refresh_texture_filter_cache();
1469 return (TextureFilter)texture_filter_cache;
1470}
1471
1472CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() const {
1473 ERR_READ_THREAD_GUARD_V(TEXTURE_REPEAT_DISABLED);
1474 _refresh_texture_repeat_cache();
1475 return (TextureRepeat)texture_repeat_cache;
1476}
1477
1478CanvasItem::CanvasItem() :
1479 xform_change(this) {
1480 canvas_item = RenderingServer::get_singleton()->canvas_item_create();
1481}
1482
1483CanvasItem::~CanvasItem() {
1484 ERR_FAIL_NULL(RenderingServer::get_singleton());
1485 RenderingServer::get_singleton()->free(canvas_item);
1486}
1487
1488///////////////////////////////////////////////////////////////////
1489
1490void CanvasTexture::set_diffuse_texture(const Ref<Texture2D> &p_diffuse) {
1491 ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_diffuse.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
1492 diffuse_texture = p_diffuse;
1493
1494 RID tex_rid = diffuse_texture.is_valid() ? diffuse_texture->get_rid() : RID();
1495 RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE, tex_rid);
1496 emit_changed();
1497}
1498Ref<Texture2D> CanvasTexture::get_diffuse_texture() const {
1499 return diffuse_texture;
1500}
1501
1502void CanvasTexture::set_normal_texture(const Ref<Texture2D> &p_normal) {
1503 ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_normal.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
1504 normal_texture = p_normal;
1505 RID tex_rid = normal_texture.is_valid() ? normal_texture->get_rid() : RID();
1506 RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_NORMAL, tex_rid);
1507}
1508Ref<Texture2D> CanvasTexture::get_normal_texture() const {
1509 return normal_texture;
1510}
1511
1512void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
1513 ERR_FAIL_COND_MSG(Object::cast_to<CanvasTexture>(p_specular.ptr()) != nullptr, "Can't self-assign a CanvasTexture");
1514 specular_texture = p_specular;
1515 RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID();
1516 RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid);
1517}
1518
1519Ref<Texture2D> CanvasTexture::get_specular_texture() const {
1520 return specular_texture;
1521}
1522
1523void CanvasTexture::set_specular_color(const Color &p_color) {
1524 specular = p_color;
1525 RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
1526}
1527
1528Color CanvasTexture::get_specular_color() const {
1529 return specular;
1530}
1531
1532void CanvasTexture::set_specular_shininess(real_t p_shininess) {
1533 shininess = p_shininess;
1534 RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
1535}
1536
1537real_t CanvasTexture::get_specular_shininess() const {
1538 return shininess;
1539}
1540
1541void CanvasTexture::set_texture_filter(CanvasItem::TextureFilter p_filter) {
1542 texture_filter = p_filter;
1543 RS::get_singleton()->canvas_texture_set_texture_filter(canvas_texture, RS::CanvasItemTextureFilter(p_filter));
1544}
1545CanvasItem::TextureFilter CanvasTexture::get_texture_filter() const {
1546 return texture_filter;
1547}
1548
1549void CanvasTexture::set_texture_repeat(CanvasItem::TextureRepeat p_repeat) {
1550 texture_repeat = p_repeat;
1551 RS::get_singleton()->canvas_texture_set_texture_repeat(canvas_texture, RS::CanvasItemTextureRepeat(p_repeat));
1552}
1553CanvasItem::TextureRepeat CanvasTexture::get_texture_repeat() const {
1554 return texture_repeat;
1555}
1556
1557int CanvasTexture::get_width() const {
1558 if (diffuse_texture.is_valid()) {
1559 return diffuse_texture->get_width();
1560 } else {
1561 return 1;
1562 }
1563}
1564int CanvasTexture::get_height() const {
1565 if (diffuse_texture.is_valid()) {
1566 return diffuse_texture->get_height();
1567 } else {
1568 return 1;
1569 }
1570}
1571
1572bool CanvasTexture::is_pixel_opaque(int p_x, int p_y) const {
1573 if (diffuse_texture.is_valid()) {
1574 return diffuse_texture->is_pixel_opaque(p_x, p_y);
1575 } else {
1576 return false;
1577 }
1578}
1579
1580bool CanvasTexture::has_alpha() const {
1581 if (diffuse_texture.is_valid()) {
1582 return diffuse_texture->has_alpha();
1583 } else {
1584 return false;
1585 }
1586}
1587
1588Ref<Image> CanvasTexture::get_image() const {
1589 if (diffuse_texture.is_valid()) {
1590 return diffuse_texture->get_image();
1591 } else {
1592 return Ref<Image>();
1593 }
1594}
1595
1596RID CanvasTexture::get_rid() const {
1597 return canvas_texture;
1598}
1599
1600void CanvasTexture::_bind_methods() {
1601 ClassDB::bind_method(D_METHOD("set_diffuse_texture", "texture"), &CanvasTexture::set_diffuse_texture);
1602 ClassDB::bind_method(D_METHOD("get_diffuse_texture"), &CanvasTexture::get_diffuse_texture);
1603
1604 ClassDB::bind_method(D_METHOD("set_normal_texture", "texture"), &CanvasTexture::set_normal_texture);
1605 ClassDB::bind_method(D_METHOD("get_normal_texture"), &CanvasTexture::get_normal_texture);
1606
1607 ClassDB::bind_method(D_METHOD("set_specular_texture", "texture"), &CanvasTexture::set_specular_texture);
1608 ClassDB::bind_method(D_METHOD("get_specular_texture"), &CanvasTexture::get_specular_texture);
1609
1610 ClassDB::bind_method(D_METHOD("set_specular_color", "color"), &CanvasTexture::set_specular_color);
1611 ClassDB::bind_method(D_METHOD("get_specular_color"), &CanvasTexture::get_specular_color);
1612
1613 ClassDB::bind_method(D_METHOD("set_specular_shininess", "shininess"), &CanvasTexture::set_specular_shininess);
1614 ClassDB::bind_method(D_METHOD("get_specular_shininess"), &CanvasTexture::get_specular_shininess);
1615
1616 ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &CanvasTexture::set_texture_filter);
1617 ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasTexture::get_texture_filter);
1618
1619 ClassDB::bind_method(D_METHOD("set_texture_repeat", "repeat"), &CanvasTexture::set_texture_repeat);
1620 ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasTexture::get_texture_repeat);
1621
1622 ADD_GROUP("Diffuse", "diffuse_");
1623 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "diffuse_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_diffuse_texture", "get_diffuse_texture");
1624 ADD_GROUP("NormalMap", "normal_");
1625 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_normal_texture", "get_normal_texture");
1626 ADD_GROUP("Specular", "specular_");
1627 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "specular_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_specular_texture", "get_specular_texture");
1628 ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
1629 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "specular_shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular_shininess", "get_specular_shininess");
1630 ADD_GROUP("Texture", "texture_");
1631 ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
1632 ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
1633}
1634
1635CanvasTexture::CanvasTexture() {
1636 canvas_texture = RS::get_singleton()->canvas_texture_create();
1637}
1638CanvasTexture::~CanvasTexture() {
1639 ERR_FAIL_NULL(RenderingServer::get_singleton());
1640 RS::get_singleton()->free(canvas_texture);
1641}
1642