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