| 1 | /**************************************************************************/ |
| 2 | /* renderer_canvas_cull.h */ |
| 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 | #ifndef RENDERER_CANVAS_CULL_H |
| 32 | #define RENDERER_CANVAS_CULL_H |
| 33 | |
| 34 | #include "core/templates/paged_allocator.h" |
| 35 | #include "renderer_compositor.h" |
| 36 | #include "renderer_viewport.h" |
| 37 | |
| 38 | class RendererCanvasCull { |
| 39 | public: |
| 40 | struct Item : public RendererCanvasRender::Item { |
| 41 | RID parent; // canvas it belongs to |
| 42 | List<Item *>::Element *E; |
| 43 | int z_index; |
| 44 | bool z_relative; |
| 45 | bool sort_y; |
| 46 | Color modulate; |
| 47 | Color self_modulate; |
| 48 | bool use_parent_material; |
| 49 | int index; |
| 50 | bool children_order_dirty; |
| 51 | int ysort_children_count; |
| 52 | Color ysort_modulate; |
| 53 | Transform2D ysort_xform; |
| 54 | Vector2 ysort_pos; |
| 55 | int ysort_index; |
| 56 | int ysort_parent_abs_z_index; // Absolute Z index of parent. Only populated and used when y-sorting. |
| 57 | uint32_t visibility_layer = 0xffffffff; |
| 58 | |
| 59 | Vector<Item *> child_items; |
| 60 | |
| 61 | struct VisibilityNotifierData { |
| 62 | Rect2 area; |
| 63 | Callable enter_callable; |
| 64 | Callable exit_callable; |
| 65 | bool just_visible = false; |
| 66 | uint64_t visible_in_frame = 0; |
| 67 | SelfList<VisibilityNotifierData> visible_element; |
| 68 | VisibilityNotifierData() : |
| 69 | visible_element(this) { |
| 70 | } |
| 71 | }; |
| 72 | |
| 73 | VisibilityNotifierData *visibility_notifier = nullptr; |
| 74 | |
| 75 | Item() { |
| 76 | children_order_dirty = true; |
| 77 | E = nullptr; |
| 78 | z_index = 0; |
| 79 | modulate = Color(1, 1, 1, 1); |
| 80 | self_modulate = Color(1, 1, 1, 1); |
| 81 | sort_y = false; |
| 82 | use_parent_material = false; |
| 83 | z_relative = true; |
| 84 | index = 0; |
| 85 | ysort_children_count = -1; |
| 86 | ysort_xform = Transform2D(); |
| 87 | ysort_pos = Vector2(); |
| 88 | ysort_index = 0; |
| 89 | ysort_parent_abs_z_index = 0; |
| 90 | } |
| 91 | }; |
| 92 | |
| 93 | struct ItemIndexSort { |
| 94 | _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const { |
| 95 | return p_left->index < p_right->index; |
| 96 | } |
| 97 | }; |
| 98 | |
| 99 | struct ItemPtrSort { |
| 100 | _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const { |
| 101 | if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y)) { |
| 102 | return p_left->ysort_index < p_right->ysort_index; |
| 103 | } |
| 104 | |
| 105 | return p_left->ysort_pos.y < p_right->ysort_pos.y; |
| 106 | } |
| 107 | }; |
| 108 | |
| 109 | struct LightOccluderPolygon { |
| 110 | bool active; |
| 111 | Rect2 aabb; |
| 112 | RS::CanvasOccluderPolygonCullMode cull_mode; |
| 113 | RID occluder; |
| 114 | HashSet<RendererCanvasRender::LightOccluderInstance *> owners; |
| 115 | |
| 116 | LightOccluderPolygon() { |
| 117 | active = false; |
| 118 | cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; |
| 119 | } |
| 120 | }; |
| 121 | |
| 122 | RID_Owner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner; |
| 123 | |
| 124 | RID_Owner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner; |
| 125 | |
| 126 | struct Canvas : public RendererViewport::CanvasBase { |
| 127 | HashSet<RID> viewports; |
| 128 | struct ChildItem { |
| 129 | Point2 mirror; |
| 130 | Item *item = nullptr; |
| 131 | bool operator<(const ChildItem &p_item) const { |
| 132 | return item->index < p_item.item->index; |
| 133 | } |
| 134 | }; |
| 135 | |
| 136 | HashSet<RendererCanvasRender::Light *> lights; |
| 137 | HashSet<RendererCanvasRender::Light *> directional_lights; |
| 138 | |
| 139 | HashSet<RendererCanvasRender::LightOccluderInstance *> occluders; |
| 140 | |
| 141 | bool children_order_dirty; |
| 142 | Vector<ChildItem> child_items; |
| 143 | Color modulate; |
| 144 | RID parent; |
| 145 | float parent_scale; |
| 146 | |
| 147 | int find_item(Item *p_item) { |
| 148 | for (int i = 0; i < child_items.size(); i++) { |
| 149 | if (child_items[i].item == p_item) { |
| 150 | return i; |
| 151 | } |
| 152 | } |
| 153 | return -1; |
| 154 | } |
| 155 | void erase_item(Item *p_item) { |
| 156 | int idx = find_item(p_item); |
| 157 | if (idx >= 0) { |
| 158 | child_items.remove_at(idx); |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | Canvas() { |
| 163 | modulate = Color(1, 1, 1, 1); |
| 164 | children_order_dirty = true; |
| 165 | parent_scale = 1.0; |
| 166 | } |
| 167 | }; |
| 168 | |
| 169 | mutable RID_Owner<Canvas, true> canvas_owner; |
| 170 | RID_Owner<Item, true> canvas_item_owner; |
| 171 | RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner; |
| 172 | |
| 173 | bool disable_scale; |
| 174 | bool sdf_used = false; |
| 175 | bool snapping_2d_transforms_to_pixel = false; |
| 176 | |
| 177 | PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator; |
| 178 | SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list; |
| 179 | |
| 180 | _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform); |
| 181 | |
| 182 | private: |
| 183 | void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask); |
| 184 | void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort, uint32_t canvas_cull_mask); |
| 185 | |
| 186 | static constexpr int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1; |
| 187 | |
| 188 | RendererCanvasRender::Item **z_list; |
| 189 | RendererCanvasRender::Item **z_last_list; |
| 190 | |
| 191 | public: |
| 192 | void 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, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask); |
| 193 | |
| 194 | bool was_sdf_used(); |
| 195 | |
| 196 | RID canvas_allocate(); |
| 197 | void canvas_initialize(RID p_rid); |
| 198 | |
| 199 | void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); |
| 200 | void canvas_set_modulate(RID p_canvas, const Color &p_color); |
| 201 | void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale); |
| 202 | void canvas_set_disable_scale(bool p_disable); |
| 203 | |
| 204 | RID canvas_item_allocate(); |
| 205 | void canvas_item_initialize(RID p_rid); |
| 206 | |
| 207 | void canvas_item_set_parent(RID p_item, RID p_parent); |
| 208 | |
| 209 | void canvas_item_set_visible(RID p_item, bool p_visible); |
| 210 | void canvas_item_set_light_mask(RID p_item, int p_mask); |
| 211 | |
| 212 | void canvas_item_set_visibility_layer(RID p_item, uint32_t p_layer); |
| 213 | uint32_t canvas_item_get_visibility_layer(RID p_item); |
| 214 | |
| 215 | void canvas_item_set_transform(RID p_item, const Transform2D &p_transform); |
| 216 | void canvas_item_set_clip(RID p_item, bool p_clip); |
| 217 | void canvas_item_set_distance_field_mode(RID p_item, bool p_enable); |
| 218 | void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2()); |
| 219 | void canvas_item_set_modulate(RID p_item, const Color &p_color); |
| 220 | void canvas_item_set_self_modulate(RID p_item, const Color &p_color); |
| 221 | |
| 222 | void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable); |
| 223 | |
| 224 | void canvas_item_set_update_when_visible(RID p_item, bool p_update); |
| 225 | |
| 226 | void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false); |
| 227 | void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false); |
| 228 | void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0); |
| 229 | void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color); |
| 230 | void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color); |
| 231 | void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); |
| 232 | void 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 = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false); |
| 233 | void 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 = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0); |
| 234 | void 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 = Color(1, 1, 1)); |
| 235 | void 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::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)); |
| 236 | void 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); |
| 237 | void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID()); |
| 238 | void 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 = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1); |
| 239 | void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID()); |
| 240 | void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID()); |
| 241 | void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture); |
| 242 | void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); |
| 243 | void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); |
| 244 | void canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset); |
| 245 | |
| 246 | void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); |
| 247 | void canvas_item_set_z_index(RID p_item, int p_z); |
| 248 | void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable); |
| 249 | void canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect); |
| 250 | void canvas_item_attach_skeleton(RID p_item, RID p_skeleton); |
| 251 | |
| 252 | void canvas_item_clear(RID p_item); |
| 253 | void canvas_item_set_draw_index(RID p_item, int p_index); |
| 254 | |
| 255 | void canvas_item_set_material(RID p_item, RID p_material); |
| 256 | |
| 257 | void canvas_item_set_use_parent_material(RID p_item, bool p_enable); |
| 258 | |
| 259 | void 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); |
| 260 | |
| 261 | void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); |
| 262 | |
| 263 | RID canvas_light_allocate(); |
| 264 | void canvas_light_initialize(RID p_rid); |
| 265 | |
| 266 | void canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode); |
| 267 | void canvas_light_attach_to_canvas(RID p_light, RID p_canvas); |
| 268 | void canvas_light_set_enabled(RID p_light, bool p_enabled); |
| 269 | void canvas_light_set_texture_scale(RID p_light, float p_scale); |
| 270 | void canvas_light_set_transform(RID p_light, const Transform2D &p_transform); |
| 271 | void canvas_light_set_texture(RID p_light, RID p_texture); |
| 272 | void canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset); |
| 273 | void canvas_light_set_color(RID p_light, const Color &p_color); |
| 274 | void canvas_light_set_height(RID p_light, float p_height); |
| 275 | void canvas_light_set_energy(RID p_light, float p_energy); |
| 276 | void canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z); |
| 277 | void canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer); |
| 278 | void canvas_light_set_item_cull_mask(RID p_light, int p_mask); |
| 279 | void canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask); |
| 280 | void canvas_light_set_directional_distance(RID p_light, float p_distance); |
| 281 | |
| 282 | void canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode); |
| 283 | |
| 284 | void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled); |
| 285 | void canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter); |
| 286 | void canvas_light_set_shadow_color(RID p_light, const Color &p_color); |
| 287 | void canvas_light_set_shadow_smooth(RID p_light, float p_smooth); |
| 288 | |
| 289 | RID canvas_light_occluder_allocate(); |
| 290 | void canvas_light_occluder_initialize(RID p_rid); |
| 291 | |
| 292 | void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas); |
| 293 | void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled); |
| 294 | void canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon); |
| 295 | void canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable); |
| 296 | void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform); |
| 297 | void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask); |
| 298 | |
| 299 | RID canvas_occluder_polygon_allocate(); |
| 300 | void canvas_occluder_polygon_initialize(RID p_rid); |
| 301 | |
| 302 | void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed); |
| 303 | |
| 304 | void canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode); |
| 305 | |
| 306 | void canvas_set_shadow_texture_size(int p_size); |
| 307 | |
| 308 | RID canvas_texture_allocate(); |
| 309 | void canvas_texture_initialize(RID p_rid); |
| 310 | |
| 311 | void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture); |
| 312 | void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess); |
| 313 | |
| 314 | void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter); |
| 315 | void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat); |
| 316 | |
| 317 | void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter); |
| 318 | void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat); |
| 319 | |
| 320 | void update_visibility_notifiers(); |
| 321 | |
| 322 | bool free(RID p_rid); |
| 323 | RendererCanvasCull(); |
| 324 | ~RendererCanvasCull(); |
| 325 | }; |
| 326 | |
| 327 | #endif // RENDERER_CANVAS_CULL_H |
| 328 | |