1/**************************************************************************/
2/* renderer_canvas_render.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_RENDER_H
32#define RENDERER_CANVAS_RENDER_H
33
34#include "servers/rendering_server.h"
35
36class RendererCanvasRender {
37public:
38 static RendererCanvasRender *singleton;
39
40 enum CanvasRectFlags {
41 CANVAS_RECT_REGION = 1,
42 CANVAS_RECT_TILE = 2,
43 CANVAS_RECT_FLIP_H = 4,
44 CANVAS_RECT_FLIP_V = 8,
45 CANVAS_RECT_TRANSPOSE = 16,
46 CANVAS_RECT_CLIP_UV = 32,
47 CANVAS_RECT_IS_GROUP = 64,
48 CANVAS_RECT_MSDF = 128,
49 CANVAS_RECT_LCD = 256,
50 };
51
52 struct Light {
53 bool enabled;
54 Color color;
55 Transform2D xform;
56 float height;
57 float energy;
58 float scale;
59 int z_min;
60 int z_max;
61 int layer_min;
62 int layer_max;
63 int item_mask;
64 int item_shadow_mask;
65 float directional_distance;
66 RS::CanvasLightMode mode;
67 RS::CanvasLightBlendMode blend_mode;
68 RID texture;
69 Vector2 texture_offset;
70 RID canvas;
71 bool use_shadow;
72 int shadow_buffer_size;
73 RS::CanvasLightShadowFilter shadow_filter;
74 Color shadow_color;
75 float shadow_smooth;
76
77 //void *texture_cache; // implementation dependent
78 Rect2 rect_cache;
79 Transform2D xform_cache;
80 float radius_cache; //used for shadow far plane
81 //Projection shadow_matrix_cache;
82
83 Transform2D light_shader_xform;
84 //Vector2 light_shader_pos;
85
86 Light *shadows_next_ptr = nullptr;
87 Light *filter_next_ptr = nullptr;
88 Light *next_ptr = nullptr;
89 Light *directional_next_ptr = nullptr;
90
91 RID light_internal;
92 uint64_t version;
93
94 int32_t render_index_cache;
95
96 Light() {
97 version = 0;
98 enabled = true;
99 color = Color(1, 1, 1);
100 shadow_color = Color(0, 0, 0, 0);
101 height = 0;
102 z_min = -1024;
103 z_max = 1024;
104 layer_min = 0;
105 layer_max = 0;
106 item_mask = 1;
107 scale = 1.0;
108 energy = 1.0;
109 item_shadow_mask = 1;
110 mode = RS::CANVAS_LIGHT_MODE_POINT;
111 blend_mode = RS::CANVAS_LIGHT_BLEND_MODE_ADD;
112 // texture_cache = nullptr;
113 next_ptr = nullptr;
114 directional_next_ptr = nullptr;
115 filter_next_ptr = nullptr;
116 use_shadow = false;
117 shadow_buffer_size = 2048;
118 shadow_filter = RS::CANVAS_LIGHT_FILTER_NONE;
119 shadow_smooth = 0.0;
120 render_index_cache = -1;
121 directional_distance = 10000.0;
122 }
123 };
124
125 //easier wrap to avoid mistakes
126
127 struct Item;
128
129 typedef uint64_t PolygonID;
130 virtual PolygonID request_polygon(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>()) = 0;
131 virtual void free_polygon(PolygonID p_polygon) = 0;
132
133 //also easier to wrap to avoid mistakes
134 struct Polygon {
135 PolygonID polygon_id;
136 Rect2 rect_cache;
137
138 _FORCE_INLINE_ void create(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>()) {
139 ERR_FAIL_COND(polygon_id != 0);
140 {
141 uint32_t pc = p_points.size();
142 const Vector2 *v2 = p_points.ptr();
143 rect_cache.position = *v2;
144 for (uint32_t i = 1; i < pc; i++) {
145 rect_cache.expand_to(v2[i]);
146 }
147 }
148 polygon_id = singleton->request_polygon(p_indices, p_points, p_colors, p_uvs, p_bones, p_weights);
149 }
150
151 _FORCE_INLINE_ Polygon() { polygon_id = 0; }
152 _FORCE_INLINE_ ~Polygon() {
153 if (polygon_id) {
154 singleton->free_polygon(polygon_id);
155 }
156 }
157 };
158
159 //item
160
161 struct Item {
162 //commands are allocated in blocks of 4k to improve performance
163 //and cache coherence.
164 //blocks always grow but never shrink.
165
166 struct CommandBlock {
167 enum {
168 MAX_SIZE = 4096
169 };
170 uint32_t usage;
171 uint8_t *memory = nullptr;
172 };
173
174 struct Command {
175 enum Type {
176 TYPE_RECT,
177 TYPE_NINEPATCH,
178 TYPE_POLYGON,
179 TYPE_PRIMITIVE,
180 TYPE_MESH,
181 TYPE_MULTIMESH,
182 TYPE_PARTICLES,
183 TYPE_TRANSFORM,
184 TYPE_CLIP_IGNORE,
185 TYPE_ANIMATION_SLICE,
186 };
187
188 Command *next = nullptr;
189 Type type;
190 virtual ~Command() {}
191 };
192
193 struct CommandRect : public Command {
194 Rect2 rect;
195 Color modulate;
196 Rect2 source;
197 uint16_t flags;
198 float outline;
199 float px_range;
200
201 RID texture;
202
203 CommandRect() {
204 flags = 0;
205 outline = 0;
206 px_range = 1;
207 type = TYPE_RECT;
208 }
209 };
210
211 struct CommandNinePatch : public Command {
212 Rect2 rect;
213 Rect2 source;
214 float margin[4];
215 bool draw_center;
216 Color color;
217 RS::NinePatchAxisMode axis_x;
218 RS::NinePatchAxisMode axis_y;
219
220 RID texture;
221
222 CommandNinePatch() {
223 draw_center = true;
224 type = TYPE_NINEPATCH;
225 }
226 };
227
228 struct CommandPolygon : public Command {
229 RS::PrimitiveType primitive;
230 Polygon polygon;
231
232 RID texture;
233
234 CommandPolygon() {
235 type = TYPE_POLYGON;
236 }
237 };
238
239 struct CommandPrimitive : public Command {
240 uint32_t point_count;
241 Vector2 points[4];
242 Vector2 uvs[4];
243 Color colors[4];
244
245 RID texture;
246
247 CommandPrimitive() {
248 type = TYPE_PRIMITIVE;
249 }
250 };
251
252 struct CommandMesh : public Command {
253 RID mesh;
254 Transform2D transform;
255 Color modulate;
256 RID mesh_instance;
257
258 RID texture;
259
260 CommandMesh() { type = TYPE_MESH; }
261 ~CommandMesh();
262 };
263
264 struct CommandMultiMesh : public Command {
265 RID multimesh;
266
267 RID texture;
268
269 CommandMultiMesh() { type = TYPE_MULTIMESH; }
270 };
271
272 struct CommandParticles : public Command {
273 RID particles;
274 RID texture;
275
276 CommandParticles() { type = TYPE_PARTICLES; }
277 };
278
279 struct CommandTransform : public Command {
280 Transform2D xform;
281 CommandTransform() { type = TYPE_TRANSFORM; }
282 };
283
284 struct CommandClipIgnore : public Command {
285 bool ignore;
286 CommandClipIgnore() {
287 type = TYPE_CLIP_IGNORE;
288 ignore = false;
289 }
290 };
291
292 struct CommandAnimationSlice : public Command {
293 double animation_length = 0;
294 double slice_begin = 0;
295 double slice_end = 0;
296 double offset = 0;
297
298 CommandAnimationSlice() {
299 type = TYPE_ANIMATION_SLICE;
300 }
301 };
302
303 struct ViewportRender {
304 RenderingServer *owner = nullptr;
305 void *udata = nullptr;
306 Rect2 rect;
307 };
308
309 Transform2D xform;
310 bool clip;
311 bool visible;
312 bool behind;
313 bool update_when_visible;
314
315 struct CanvasGroup {
316 RS::CanvasGroupMode mode;
317 bool fit_empty;
318 float fit_margin;
319 bool blur_mipmaps;
320 float clear_margin;
321 };
322
323 CanvasGroup *canvas_group = nullptr;
324 bool use_canvas_group = false;
325 int light_mask;
326 int z_final;
327
328 mutable bool custom_rect;
329 mutable bool rect_dirty;
330 mutable Rect2 rect;
331 RID material;
332 RID skeleton;
333
334 Item *next = nullptr;
335
336 struct CopyBackBuffer {
337 Rect2 rect;
338 Rect2 screen_rect;
339 bool full;
340 };
341 CopyBackBuffer *copy_back_buffer = nullptr;
342
343 Color final_modulate;
344 Transform2D final_transform;
345 Rect2 final_clip_rect;
346 Item *final_clip_owner = nullptr;
347 Item *material_owner = nullptr;
348 Item *canvas_group_owner = nullptr;
349 ViewportRender *vp_render = nullptr;
350 bool distance_field;
351 bool light_masked;
352
353 Rect2 global_rect_cache;
354
355 const Rect2 &get_rect() const;
356
357 Command *commands = nullptr;
358 Command *last_command = nullptr;
359 Vector<CommandBlock> blocks;
360 uint32_t current_block;
361
362 template <class T>
363 T *alloc_command() {
364 T *command = nullptr;
365 if (commands == nullptr) {
366 // As the most common use case of canvas items is to
367 // use only one command, the first is done with it's
368 // own allocation. The rest of them use blocks.
369 command = memnew(T);
370 command->next = nullptr;
371 commands = command;
372 last_command = command;
373 } else {
374 //Subsequent commands go into a block.
375
376 while (true) {
377 if (unlikely(current_block == (uint32_t)blocks.size())) {
378 // If we need more blocks, we allocate them
379 // (they won't be freed until this CanvasItem is
380 // deleted, though).
381 CommandBlock cb;
382 cb.memory = (uint8_t *)memalloc(CommandBlock::MAX_SIZE);
383 cb.usage = 0;
384 blocks.push_back(cb);
385 }
386
387 CommandBlock *c = &blocks.write[current_block];
388 size_t space_left = CommandBlock::MAX_SIZE - c->usage;
389 if (space_left < sizeof(T)) {
390 current_block++;
391 continue;
392 }
393
394 //allocate block and add to the linked list
395 void *memory = c->memory + c->usage;
396 command = memnew_placement(memory, T);
397 command->next = nullptr;
398 last_command->next = command;
399 last_command = command;
400 c->usage += sizeof(T);
401 break;
402 }
403 }
404
405 rect_dirty = true;
406 return command;
407 }
408
409 void clear() {
410 // The first one is always allocated on heap
411 // the rest go in the blocks
412 Command *c = commands;
413 while (c) {
414 Command *n = c->next;
415 if (c == commands) {
416 memdelete(commands);
417 commands = nullptr;
418 } else {
419 c->~Command();
420 }
421 c = n;
422 }
423 {
424 uint32_t cbc = MIN((current_block + 1), (uint32_t)blocks.size());
425 CommandBlock *blockptr = blocks.ptrw();
426 for (uint32_t i = 0; i < cbc; i++) {
427 blockptr[i].usage = 0;
428 }
429 }
430
431 last_command = nullptr;
432 commands = nullptr;
433 current_block = 0;
434 clip = false;
435 rect_dirty = true;
436 final_clip_owner = nullptr;
437 material_owner = nullptr;
438 light_masked = false;
439 }
440
441 RS::CanvasItemTextureFilter texture_filter;
442 RS::CanvasItemTextureRepeat texture_repeat;
443
444 Item() {
445 commands = nullptr;
446 last_command = nullptr;
447 current_block = 0;
448 light_mask = 1;
449 vp_render = nullptr;
450 next = nullptr;
451 final_clip_owner = nullptr;
452 canvas_group_owner = nullptr;
453 clip = false;
454 final_modulate = Color(1, 1, 1, 1);
455 visible = true;
456 rect_dirty = true;
457 custom_rect = false;
458 behind = false;
459 material_owner = nullptr;
460 copy_back_buffer = nullptr;
461 distance_field = false;
462 light_masked = false;
463 update_when_visible = false;
464 z_final = 0;
465 texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
466 texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
467 }
468 virtual ~Item() {
469 clear();
470 for (int i = 0; i < blocks.size(); i++) {
471 memfree(blocks[i].memory);
472 }
473 if (copy_back_buffer) {
474 memdelete(copy_back_buffer);
475 }
476 }
477 };
478
479 virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) = 0;
480
481 struct LightOccluderInstance {
482 bool enabled;
483 RID canvas;
484 RID polygon;
485 RID occluder;
486 Rect2 aabb_cache;
487 Transform2D xform;
488 Transform2D xform_cache;
489 int light_mask;
490 bool sdf_collision;
491 RS::CanvasOccluderPolygonCullMode cull_cache;
492
493 LightOccluderInstance *next = nullptr;
494
495 LightOccluderInstance() {
496 enabled = true;
497 sdf_collision = false;
498 next = nullptr;
499 light_mask = 1;
500 cull_cache = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
501 }
502 };
503
504 virtual RID light_create() = 0;
505 virtual void light_set_texture(RID p_rid, RID p_texture) = 0;
506 virtual void light_set_use_shadow(RID p_rid, bool p_enable) = 0;
507 virtual void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) = 0;
508 virtual void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) = 0;
509
510 virtual void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) = 0;
511
512 virtual RID occluder_polygon_create() = 0;
513 virtual void occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) = 0;
514 virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0;
515 virtual void set_shadow_texture_size(int p_size) = 0;
516
517 virtual bool free(RID p_rid) = 0;
518 virtual void update() = 0;
519
520 RendererCanvasRender() { singleton = this; }
521 virtual ~RendererCanvasRender() {}
522};
523
524#endif // RENDERER_CANVAS_RENDER_H
525