1 /*
2  * This software is licensed under the terms of the MIT License.
3  * See COPYING for further information.
4  * ---
5  * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6  * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7  */
8 
9 #ifndef IGUARD_renderer_api_h
10 #define IGUARD_renderer_api_h
11 
12 #include "taisei.h"
13 
14 #include "util.h"
15 #include "util/pixmap.h"
16 #include "color.h"
17 #include "common/shaderlib/shaderlib.h"
18 #include "resource/resource.h"
19 
20 typedef struct Texture Texture;
21 typedef struct Framebuffer Framebuffer;
22 typedef struct VertexBuffer VertexBuffer;
23 typedef struct VertexArray VertexArray;
24 typedef struct IndexBuffer IndexBuffer;
25 typedef struct ShaderObject ShaderObject;
26 typedef struct ShaderProgram ShaderProgram;
27 typedef struct Sprite Sprite;
28 typedef struct Model Model;
29 
30 enum {
31 	R_DEBUG_LABEL_SIZE = 128,
32 	R_NUM_SPRITE_AUX_TEXTURES = 3,
33 };
34 
35 typedef enum RendererFeature {
36 	RFEAT_DRAW_INSTANCED,
37 	RFEAT_DRAW_INSTANCED_BASE_INSTANCE,
38 	RFEAT_DEPTH_TEXTURE,
39 	RFEAT_FRAMEBUFFER_MULTIPLE_OUTPUTS,
40 	RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN,
41 
42 	NUM_RFEATS,
43 } RendererFeature;
44 
45 typedef uint_fast8_t r_feature_bits_t;
46 
47 typedef enum RendererCapability {
48 	RCAP_DEPTH_TEST,
49 	RCAP_DEPTH_WRITE,
50 	RCAP_CULL_FACE,
51 
52 	NUM_RCAPS
53 } RendererCapability;
54 
55 typedef uint_fast8_t r_capability_bits_t;
56 
57 typedef enum TextureType {
58 	// NOTE: whichever is placed first here is considered the "default" where applicable.
59 	TEX_TYPE_RGBA_8,
60 	TEX_TYPE_RGB_8,
61 	TEX_TYPE_RG_8,
62 	TEX_TYPE_R_8,
63 
64 	TEX_TYPE_RGBA_16,
65 	TEX_TYPE_RGB_16,
66 	TEX_TYPE_RG_16,
67 	TEX_TYPE_R_16,
68 
69 	TEX_TYPE_RGBA_16_FLOAT,
70 	TEX_TYPE_RGB_16_FLOAT,
71 	TEX_TYPE_RG_16_FLOAT,
72 	TEX_TYPE_R_16_FLOAT,
73 
74 	TEX_TYPE_RGBA_32_FLOAT,
75 	TEX_TYPE_RGB_32_FLOAT,
76 	TEX_TYPE_RG_32_FLOAT,
77 	TEX_TYPE_R_32_FLOAT,
78 
79 	TEX_TYPE_DEPTH_8,
80 	TEX_TYPE_DEPTH_16,
81 	TEX_TYPE_DEPTH_24,
82 	TEX_TYPE_DEPTH_32,
83 	TEX_TYPE_DEPTH_16_FLOAT,
84 	TEX_TYPE_DEPTH_32_FLOAT,
85 
86 	TEX_TYPE_RGBA = TEX_TYPE_RGBA_8,
87 	TEX_TYPE_RGB = TEX_TYPE_RGB_8,
88 	TEX_TYPE_RG = TEX_TYPE_RG_8,
89 	TEX_TYPE_R = TEX_TYPE_R_8,
90 	TEX_TYPE_DEPTH = TEX_TYPE_DEPTH_8,
91 } TextureType;
92 
93 typedef enum TextureFilterMode {
94 	// NOTE: whichever is placed first here is considered the "default" where applicable.
95 	TEX_FILTER_LINEAR,
96 	TEX_FILTER_LINEAR_MIPMAP_NEAREST,
97 	TEX_FILTER_LINEAR_MIPMAP_LINEAR,
98 	TEX_FILTER_NEAREST,
99 	TEX_FILTER_NEAREST_MIPMAP_NEAREST,
100 	TEX_FILTER_NEAREST_MIPMAP_LINEAR,
101 } TextureFilterMode;
102 
103 typedef enum TextureWrapMode {
104 	// NOTE: whichever is placed first here is considered the "default" where applicable.
105 	TEX_WRAP_REPEAT,
106 	TEX_WRAP_MIRROR,
107 	TEX_WRAP_CLAMP,
108 } TextureWrapMode;
109 
110 typedef enum TextureMipmapMode {
111 	TEX_MIPMAP_MANUAL,
112 	TEX_MIPMAP_AUTO,
113 } TextureMipmapMode;
114 
115 enum {
116 	TEX_ANISOTROPY_DEFAULT = 1,
117 	// TEX_MIPMAPS_MAX = ((uint)(-1)),
118 	// pedantic out-of-range warning
119 	#define TEX_MIPMAPS_MAX ((uint)(-1))
120 };
121 
122 typedef struct TextureParams {
123 	uint width;
124 	uint height;
125 	TextureType type;
126 
127 	struct {
128 		TextureFilterMode mag;
129 		TextureFilterMode min;
130 	} filter;
131 
132 	struct {
133 		TextureWrapMode s;
134 		TextureWrapMode t;
135 	} wrap;
136 
137 	uint anisotropy;
138 	uint mipmaps;
139 	TextureMipmapMode mipmap_mode;
140 	bool stream;
141 } attr_designated_init TextureParams;
142 
143 typedef enum FramebufferAttachment {
144 	FRAMEBUFFER_ATTACH_DEPTH,
145 	FRAMEBUFFER_ATTACH_COLOR0,
146 	FRAMEBUFFER_ATTACH_COLOR1,
147 	FRAMEBUFFER_ATTACH_COLOR2,
148 	FRAMEBUFFER_ATTACH_COLOR3,
149 
150 	FRAMEBUFFER_MAX_COLOR_ATTACHMENTS = 4,
151 	FRAMEBUFFER_MAX_ATTACHMENTS = FRAMEBUFFER_ATTACH_COLOR0 + FRAMEBUFFER_MAX_COLOR_ATTACHMENTS,
152 } FramebufferAttachment;
153 
154 typedef enum Primitive {
155 	PRIM_POINTS,
156 	PRIM_LINE_STRIP,
157 	PRIM_LINE_LOOP,
158 	PRIM_LINES,
159 	PRIM_TRIANGLE_STRIP,
160 	PRIM_TRIANGLES,
161 } Primitive;
162 
163 typedef enum VertexAttribType {
164 	VA_FLOAT,
165 	VA_BYTE,
166 	VA_UBYTE,
167 	VA_SHORT,
168 	VA_USHORT,
169 	VA_INT,
170 	VA_UINT,
171 } VertexAttribType;
172 
173 typedef struct VertexAttribTypeInfo {
174 	size_t size;
175 	size_t alignment;
176 } VertexAttribTypeInfo;
177 
178 typedef enum VertexAttribConversion {
179 	VA_CONVERT_FLOAT,
180 	VA_CONVERT_FLOAT_NORMALIZED,
181 	VA_CONVERT_INT,
182 } VertexAttribConversion;
183 
184 typedef struct VertexAttribSpec {
185 	uint8_t elements;
186 	VertexAttribType type;
187 	VertexAttribConversion coversion;
188 	uint divisor;
189 } VertexAttribSpec;
190 
191 typedef struct VertexAttribFormat {
192 	VertexAttribSpec spec;
193 	size_t stride;
194 	size_t offset;
195 	uint attachment;
196 } VertexAttribFormat;
197 
198 typedef struct GenericModelVertex {
199 	float position[3];
200 	float normal[3];
201 
202 	struct {
203 		float s;
204 		float t;
205 	} uv;
206 } GenericModelVertex;
207 
208 typedef enum UniformType {
209 	UNIFORM_FLOAT,
210 	UNIFORM_VEC2,
211 	UNIFORM_VEC3,
212 	UNIFORM_VEC4,
213 	UNIFORM_INT,
214 	UNIFORM_IVEC2,
215 	UNIFORM_IVEC3,
216 	UNIFORM_IVEC4,
217 	UNIFORM_SAMPLER,
218 	UNIFORM_MAT3,
219 	UNIFORM_MAT4,
220 	UNIFORM_UNKNOWN,
221 } UniformType;
222 
223 typedef struct UniformTypeInfo {
224 	// Refers to vector elements, not array elements.
225 	uint8_t elements;
226 	uint8_t element_size;
227 } UniformTypeInfo;
228 
229 typedef struct Uniform Uniform;
230 
231 typedef enum ClearBufferFlags {
232 	CLEAR_COLOR = (1 << 0),
233 	CLEAR_DEPTH = (1 << 1),
234 
235 	CLEAR_ALL = CLEAR_COLOR | CLEAR_DEPTH,
236 } ClearBufferFlags;
237 
238 // Blend modes API based on the SDL one.
239 
240 typedef enum BlendModeComponent {
241 	BLENDCOMP_COLOR_OP  = 0x00,
242 	BLENDCOMP_SRC_COLOR = 0x04,
243 	BLENDCOMP_DST_COLOR = 0x08,
244 	BLENDCOMP_ALPHA_OP  = 0x10,
245 	BLENDCOMP_SRC_ALPHA = 0x14,
246 	BLENDCOMP_DST_ALPHA = 0x18,
247 } BlendModeComponent;
248 
249 #define BLENDMODE_COMPOSE(src_color, dst_color, color_op, src_alpha, dst_alpha, alpha_op) \
250 	( \
251 		((uint32_t) color_op  << BLENDCOMP_COLOR_OP ) | \
252 		((uint32_t) src_color << BLENDCOMP_SRC_COLOR) | \
253 		((uint32_t) dst_color << BLENDCOMP_DST_COLOR) | \
254 		((uint32_t) alpha_op  << BLENDCOMP_ALPHA_OP ) | \
255 		((uint32_t) src_alpha << BLENDCOMP_SRC_ALPHA) | \
256 		((uint32_t) dst_alpha << BLENDCOMP_DST_ALPHA)   \
257 	)
258 
259 #define BLENDMODE_COMPONENT(mode, comp) \
260 	(((uint32_t) mode >> (uint32_t) comp) & 0xF)
261 
262 typedef enum BlendOp {
263 	BLENDOP_ADD     = 0x1, // dst + src
264 	BLENDOP_SUB     = 0x2, // dst - src
265 	BLENDOP_REV_SUB = 0x3, // src - dst
266 	BLENDOP_MIN     = 0x4, // min(dst, src)
267 	BLENDOP_MAX     = 0x5, // max(dst, src)
268 } BlendOp;
269 
270 typedef enum BlendFactor {
271 	BLENDFACTOR_ZERO          = 0x1,  //      0,      0,      0,      0
272 	BLENDFACTOR_ONE           = 0x2,  //      1,      1,      1,      1
273 	BLENDFACTOR_SRC_COLOR     = 0x3,  //   srcR,   srcG,   srcB,   srcA
274 	BLENDFACTOR_INV_SRC_COLOR = 0x4,  // 1-srcR, 1-srcG, 1-srcB, 1-srcA
275 	BLENDFACTOR_SRC_ALPHA     = 0x5,  //   srcA,   srcA,   srcA,   srcA
276 	BLENDFACTOR_INV_SRC_ALPHA = 0x6,  // 1-srcA, 1-srcA, 1-srcA, 1-srcA
277 	BLENDFACTOR_DST_COLOR     = 0x7,  //   dstR,   dstG,   dstB,   dstA
278 	BLENDFACTOR_INV_DST_COLOR = 0x8,  // 1-dstR, 1-dstG, 1-dstB, 1-dstA
279 	BLENDFACTOR_DST_ALPHA     = 0x9,  //   dstA,   dstA,   dstA,   dstA
280 	BLENDFACTOR_INV_DST_ALPHA = 0xA,  // 1-dstA, 1-dstA, 1-dstA, 1-dstA
281 } BlendFactor;
282 
283 typedef enum BlendMode {
284 	BLEND_NONE = BLENDMODE_COMPOSE(
285 		BLENDFACTOR_ONE, BLENDFACTOR_ZERO, BLENDOP_ADD,
286 		BLENDFACTOR_ONE, BLENDFACTOR_ZERO, BLENDOP_ADD
287 	),
288 
289 	BLEND_ALPHA = BLENDMODE_COMPOSE(
290 		BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_INV_SRC_ALPHA, BLENDOP_ADD,
291 		BLENDFACTOR_ONE,       BLENDFACTOR_INV_SRC_ALPHA, BLENDOP_ADD
292 	),
293 
294 	BLEND_PREMUL_ALPHA = BLENDMODE_COMPOSE(
295 		BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA, BLENDOP_ADD,
296 		BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA, BLENDOP_ADD
297 	),
298 
299 	_BLEND_ADD = BLENDMODE_COMPOSE(
300 		BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_ONE, BLENDOP_ADD,
301 		BLENDFACTOR_ZERO,      BLENDFACTOR_ONE, BLENDOP_ADD
302 	),
303 
304 	BLEND_SUB = BLENDMODE_COMPOSE(
305 		BLENDFACTOR_SRC_ALPHA, BLENDFACTOR_ONE, BLENDOP_REV_SUB,
306 		BLENDFACTOR_ZERO,      BLENDFACTOR_ONE, BLENDOP_REV_SUB
307 	),
308 
309 	BLEND_MOD = BLENDMODE_COMPOSE(
310 		BLENDFACTOR_ZERO, BLENDFACTOR_SRC_COLOR, BLENDOP_ADD,
311 		BLENDFACTOR_ZERO, BLENDFACTOR_ONE,       BLENDOP_ADD
312 	),
313 } BlendMode;
314 
315 attr_deprecated("Use BLEND_PREMUL_ALPHA and a color with alpha == 0 instead")
316 static const BlendMode BLEND_ADD = _BLEND_ADD;
317 
318 typedef struct UnpackedBlendModePart {
319 	BlendOp op;
320 	BlendFactor src;
321 	BlendFactor dst;
322 } UnpackedBlendModePart;
323 
324 typedef struct UnpackedBlendMode {
325 	UnpackedBlendModePart color;
326 	UnpackedBlendModePart alpha;
327 } UnpackedBlendMode;
328 
329 typedef enum CullFaceMode {
330 	CULL_FRONT  = 0x1,
331 	CULL_BACK   = 0x2,
332 	CULL_BOTH   = CULL_FRONT | CULL_BACK,
333 } CullFaceMode;
334 
335 typedef enum DepthTestFunc {
336 	DEPTH_NEVER,
337 	DEPTH_ALWAYS,
338 	DEPTH_EQUAL,
339 	DEPTH_NOTEQUAL,
340 	DEPTH_LESS,
341 	DEPTH_LEQUAL,
342 	DEPTH_GREATER,
343 	DEPTH_GEQUAL,
344 } DepthTestFunc;
345 
346 typedef enum VsyncMode {
347 	VSYNC_NONE,
348 	VSYNC_NORMAL,
349 	VSYNC_ADAPTIVE,
350 } VsyncMode;
351 
352 typedef union ShaderCustomParams {
353 	float vector[4];
354 	Color color;
355 } ShaderCustomParams;
356 
357 typedef struct SpriteStateParams {
358 	Texture *primary_texture;
359 	Texture *aux_textures[R_NUM_SPRITE_AUX_TEXTURES];
360 	BlendMode blend;
361 	ShaderProgram *shader;
362 } SpriteStateParams;
363 
364 typedef struct SpriteScaleParams {
365 	union {
366 		float x;
367 		float both;
368 	};
369 
370 	float y;
371 } SpriteScaleParams;
372 
373 typedef struct SpriteRotationParams {
374 	vec3 vector;
375 	float angle;
376 } SpriteRotationParams;
377 
378 typedef struct SpriteFlipParams {
379 	unsigned char x : 1;
380 	unsigned char y : 1;
381 } SpriteFlipParams;
382 
383 typedef struct SpriteParams {
384 	const char *sprite;
385 	Sprite *sprite_ptr;
386 
387 	const char *shader;
388 	ShaderProgram *shader_ptr;
389 
390 	Texture *aux_textures[R_NUM_SPRITE_AUX_TEXTURES];
391 	const Color *color;
392 	const ShaderCustomParams *shader_params;
393 
394 	BlendMode blend;
395 
396 	FloatOffset pos;
397 	SpriteScaleParams scale;
398 	SpriteRotationParams rotation;
399 	SpriteFlipParams flip;
400 } SpriteParams;
401 
402 // Matches vertex buffer layout
403 typedef struct SpriteInstanceAttribs {
404 	mat4 mv_transform;
405 	mat4 tex_transform;
406 
407 	union {
408 		FloatRect texrect;
409 		vec4 texrect_vec4;
410 	};
411 
412 	Color rgba;
413 	FloatExtent sprite_size;
414 	ShaderCustomParams custom;
415 
416 	// offsetof(end_of_fields) == size without padding.
417 	char end_of_fields;
418 } SpriteInstanceAttribs;
419 
420 /*
421  * Creates an SDL window with proper flags, and, if needed, sets up a rendering context associated with it.
422  * Must be called before anything else.
423  */
424 
425 SDL_Window* r_create_window(const char *title, int x, int y, int w, int h, uint32_t flags)
426 	attr_nonnull(1) attr_nodiscard;
427 
428 /*
429  *	TODO: Document these, and put them in an order that makes a little bit of sense.
430  */
431 
432 void r_init(void);
433 void r_post_init(void);
434 void r_shutdown(void);
435 const char *r_backend_name(void);
436 
437 r_feature_bits_t r_features(void);
438 
439 r_capability_bits_t r_capabilities_current(void);
440 void r_capabilities(r_capability_bits_t newcaps);
441 
442 void r_capability(RendererCapability cap, bool value);
443 bool r_capability_current(RendererCapability cap);
444 
445 void r_color4(float r, float g, float b, float a);
446 const Color* r_color_current(void);
447 
448 void r_blend(BlendMode mode);
449 BlendMode r_blend_current(void);
450 
451 void r_cull(CullFaceMode mode);
452 CullFaceMode r_cull_current(void);
453 
454 void r_depth_func(DepthTestFunc func);
455 DepthTestFunc r_depth_func_current(void);
456 
457 bool r_shader_language_supported(const ShaderLangInfo *lang, ShaderLangInfo *out_alternative) attr_nonnull(1);
458 
459 ShaderObject* r_shader_object_compile(ShaderSource *source) attr_nonnull(1);
460 void r_shader_object_destroy(ShaderObject *shobj) attr_nonnull(1);
461 void r_shader_object_set_debug_label(ShaderObject *shobj, const char *label) attr_nonnull(1);
462 const char* r_shader_object_get_debug_label(ShaderObject *shobj) attr_nonnull(1);
463 
464 ShaderProgram* r_shader_program_link(uint num_objects, ShaderObject *shobjs[num_objects]) attr_nonnull(2);
465 void r_shader_program_destroy(ShaderProgram *prog);
466 void r_shader_program_set_debug_label(ShaderProgram *prog, const char *label) attr_nonnull(1);
467 const char* r_shader_program_get_debug_label(ShaderProgram *prog) attr_nonnull(1);
468 
469 void r_shader_ptr(ShaderProgram *prog) attr_nonnull(1);
470 ShaderProgram* r_shader_current(void) attr_returns_nonnull;
471 
472 Uniform* _r_shader_uniform(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash) attr_nonnull(1, 2);
473 UniformType r_uniform_type(Uniform *uniform);
474 void r_uniform_ptr_unsafe(Uniform *uniform, uint offset, uint count, void *data);
475 
476 #define _R_UNIFORM_GENERIC(suffix, uniform, ...) (_Generic((uniform), \
477 	char* : _r_uniform_##suffix, \
478 	const char* : _r_uniform_##suffix, \
479 	Uniform* : _r_uniform_ptr_##suffix \
480 ))(uniform, __VA_ARGS__)
481 
482 void _r_uniform_ptr_float(Uniform *uniform, float value);
483 void _r_uniform_float(const char *uniform, float value) attr_nonnull(1);
484 #define r_uniform_float(uniform, ...) _R_UNIFORM_GENERIC(float, uniform, __VA_ARGS__)
485 
486 void _r_uniform_ptr_float_array(Uniform *uniform, uint offset, uint count, float elements[count]) attr_nonnull(4);
487 void _r_uniform_float_array(const char *uniform, uint offset, uint count, float elements[count]) attr_nonnull(1, 4);
488 #define r_uniform_float_array(uniform, ...) _R_UNIFORM_GENERIC(float_array, uniform, __VA_ARGS__)
489 
490 void _r_uniform_ptr_vec2(Uniform *uniform, float x, float y) attr_nonnull(1);
491 void _r_uniform_vec2(const char *uniform, float x, float y) attr_nonnull(1);
492 #define r_uniform_vec2(uniform, ...) _R_UNIFORM_GENERIC(vec2, uniform, __VA_ARGS__)
493 
494 void _r_uniform_ptr_vec2_vec(Uniform *uniform, vec2_noalign value) attr_nonnull(2);
495 void _r_uniform_vec2_vec(const char *uniform, vec2_noalign value) attr_nonnull(1, 2);
496 #define r_uniform_vec2_vec(uniform, ...) _R_UNIFORM_GENERIC(vec2_vec, uniform, __VA_ARGS__)
497 
498 void _r_uniform_ptr_vec2_complex(Uniform *uniform, cmplx value);
499 void _r_uniform_vec2_complex(const char *uniform, cmplx value) attr_nonnull(1);
500 #define r_uniform_vec2_complex(uniform, ...) _R_UNIFORM_GENERIC(vec2_complex, uniform, __VA_ARGS__)
501 
502 void _r_uniform_ptr_vec2_array(Uniform *uniform, uint offset, uint count, vec2_noalign elements[count]) attr_nonnull(4);
503 void _r_uniform_vec2_array(const char *uniform, uint offset, uint count, vec2_noalign elements[count]) attr_nonnull(1, 4);
504 #define r_uniform_vec2_array(uniform, ...) _R_UNIFORM_GENERIC(vec2_array, uniform, __VA_ARGS__)
505 
506 void _r_uniform_ptr_vec2_array_complex(Uniform *uniform, uint offset, uint count, cmplx elements[count]) attr_nonnull(4);
507 void _r_uniform_vec2_array_complex(const char *uniform, uint offset, uint count, cmplx elements[count]) attr_nonnull(1, 4);
508 #define r_uniform_vec2_array_complex(uniform, ...) _R_UNIFORM_GENERIC(vec2_array_complex, uniform, __VA_ARGS__)
509 
510 void _r_uniform_ptr_vec3(Uniform *uniform, float x, float y, float z);
511 void _r_uniform_vec3(const char *uniform, float x, float y, float z) attr_nonnull(1);
512 #define r_uniform_vec3(uniform, ...) _R_UNIFORM_GENERIC(vec3, uniform, __VA_ARGS__)
513 
514 void _r_uniform_ptr_vec3_vec(Uniform *uniform, vec3_noalign value) attr_nonnull(2);
515 void _r_uniform_vec3_vec(const char *uniform, vec3_noalign value) attr_nonnull(1, 2);
516 #define r_uniform_vec3_vec(uniform, ...) _R_UNIFORM_GENERIC(vec3_vec, uniform, __VA_ARGS__)
517 
518 void _r_uniform_ptr_vec3_rgb(Uniform *uniform, const Color *rgb) attr_nonnull(2);
519 void _r_uniform_vec3_rgb(const char *uniform, const Color *rgb) attr_nonnull(1, 2);
520 #define r_uniform_vec3_rgb(uniform, ...) _R_UNIFORM_GENERIC(vec3_rgb, uniform, __VA_ARGS__)
521 
522 void _r_uniform_ptr_vec3_array(Uniform *uniform, uint offset, uint count, vec3_noalign elements[count]) attr_nonnull(4);
523 void _r_uniform_vec3_array(const char *uniform, uint offset, uint count, vec3_noalign elements[count]) attr_nonnull(1, 4);
524 #define r_uniform_vec3_array(uniform, ...) _R_UNIFORM_GENERIC(vec3_array, uniform, __VA_ARGS__)
525 
526 void _r_uniform_ptr_vec4(Uniform *uniform, float x, float y, float z, float w);
527 void _r_uniform_vec4(const char *uniform, float x, float y, float z, float w) attr_nonnull(1);
528 #define r_uniform_vec4(uniform, ...) _R_UNIFORM_GENERIC(vec4, uniform, __VA_ARGS__)
529 
530 void _r_uniform_ptr_vec4_vec(Uniform *uniform, vec4_noalign value) attr_nonnull(2);
531 void _r_uniform_vec4_vec(const char *uniform, vec4_noalign value) attr_nonnull(1, 2);
532 #define r_uniform_vec4_vec(uniform, ...) _R_UNIFORM_GENERIC(vec4_vec, uniform, __VA_ARGS__)
533 
534 void _r_uniform_ptr_vec4_rgba(Uniform *uniform, const Color *rgba) attr_nonnull(2);
535 void _r_uniform_vec4_rgba(const char *uniform, const Color *rgba) attr_nonnull(1, 2);
536 #define r_uniform_vec4_rgba(uniform, ...) _R_UNIFORM_GENERIC(vec4_rgba, uniform, __VA_ARGS__)
537 
538 void _r_uniform_ptr_vec4_array(Uniform *uniform, uint offset, uint count, vec4_noalign elements[count]) attr_nonnull(4);
539 void _r_uniform_vec4_array(const char *uniform, uint offset, uint count, vec4_noalign elements[count]) attr_nonnull(1, 4);
540 #define r_uniform_vec4_array(uniform, ...) _R_UNIFORM_GENERIC(vec4_array, uniform, __VA_ARGS__)
541 
542 void _r_uniform_ptr_mat3(Uniform *uniform, mat3_noalign value) attr_nonnull(2);
543 void _r_uniform_mat3(const char *uniform, mat3_noalign value) attr_nonnull(1, 2);
544 #define r_uniform_mat3(uniform, ...) _R_UNIFORM_GENERIC(mat3, uniform, __VA_ARGS__)
545 
546 void _r_uniform_ptr_mat3_array(Uniform *uniform, uint offset, uint count, mat3_noalign elements[count]) attr_nonnull(4);
547 void _r_uniform_mat3_array(const char *uniform, uint offset, uint count, mat3_noalign elements[count]) attr_nonnull(1, 4);
548 #define r_uniform_mat3_array(uniform, ...) _R_UNIFORM_GENERIC(mat3_array, uniform, __VA_ARGS__)
549 
550 void _r_uniform_ptr_mat4(Uniform *uniform, mat4_noalign value) attr_nonnull(2);
551 void _r_uniform_mat4(const char *uniform, mat4_noalign value) attr_nonnull(1, 2);
552 #define r_uniform_mat4(uniform, ...) _R_UNIFORM_GENERIC(mat4, uniform, __VA_ARGS__)
553 
554 void _r_uniform_ptr_mat4_array(Uniform *uniform, uint offset, uint count, mat4_noalign elements[count]) attr_nonnull(4);
555 void _r_uniform_mat4_array(const char *uniform, uint offset, uint count, mat4_noalign elements[count]) attr_nonnull(1, 4);
556 #define r_uniform_mat4_array(uniform, ...) _R_UNIFORM_GENERIC(mat4_array, uniform, __VA_ARGS__)
557 
558 void _r_uniform_ptr_int(Uniform *uniform, int value);
559 void _r_uniform_int(const char *uniform, int value) attr_nonnull(1);
560 #define r_uniform_int(uniform, ...) _R_UNIFORM_GENERIC(int, uniform, __VA_ARGS__)
561 
562 void _r_uniform_ptr_int_array(Uniform *uniform, uint offset, uint count, int elements[count]) attr_nonnull(4);
563 void _r_uniform_int_array(const char *uniform, uint offset, uint count, int elements[count]) attr_nonnull(1, 4);
564 #define r_uniform_int_array(uniform, ...) _R_UNIFORM_GENERIC(int_array, uniform, __VA_ARGS__)
565 
566 void _r_uniform_ptr_ivec2(Uniform *uniform, int x, int y);
567 void _r_uniform_ivec2(const char *uniform, int x, int y) attr_nonnull(1);
568 #define r_uniform_ivec2(uniform, ...) _R_UNIFORM_GENERIC(ivec2, uniform, __VA_ARGS__)
569 
570 void _r_uniform_ptr_ivec2_vec(Uniform *uniform, ivec2_noalign value) attr_nonnull(2);
571 void _r_uniform_ivec2_vec(const char *uniform, ivec2_noalign value) attr_nonnull(1, 2);
572 #define r_uniform_ivec2_vec(uniform, ...) _R_UNIFORM_GENERIC(ivec2_vec, uniform, __VA_ARGS__)
573 
574 void _r_uniform_ptr_ivec2_array(Uniform *uniform, uint offset, uint count, ivec2_noalign elements[count]) attr_nonnull(4);
575 void _r_uniform_ivec2_array(const char *uniform, uint offset, uint count, ivec2_noalign elements[count]) attr_nonnull(1, 4);
576 #define r_uniform_ivec2_array(uniform, ...) _R_UNIFORM_GENERIC(ivec2_array, uniform, __VA_ARGS__)
577 
578 void _r_uniform_ptr_ivec3(Uniform *uniform, int x, int y, int z);
579 void _r_uniform_ivec3(const char *uniform, int x, int y, int z) attr_nonnull(1);
580 #define r_uniform_ivec3(uniform, ...) _R_UNIFORM_GENERIC(ivec3, uniform, __VA_ARGS__)
581 
582 void _r_uniform_ptr_ivec3_vec(Uniform *uniform, ivec3_noalign value) attr_nonnull(2);
583 void _r_uniform_ivec3_vec(const char *uniform, ivec3_noalign value) attr_nonnull(1, 2);
584 #define r_uniform_ivec3_vec(uniform, ...) _R_UNIFORM_GENERIC(ivec3_vec, uniform, __VA_ARGS__)
585 
586 void _r_uniform_ptr_ivec3_array(Uniform *uniform, uint offset, uint count, ivec3_noalign elements[count]) attr_nonnull(4);
587 void _r_uniform_ivec3_array(const char *uniform, uint offset, uint count, ivec3_noalign elements[count]) attr_nonnull(1, 4);
588 #define r_uniform_ivec3_array(uniform, ...) _R_UNIFORM_GENERIC(ivec3_array, uniform, __VA_ARGS__)
589 
590 void _r_uniform_ptr_ivec4(Uniform *uniform, int x, int y, int z, int w);
591 void _r_uniform_ivec4(const char *uniform, int x, int y, int z, int w) attr_nonnull(1);
592 #define r_uniform_ivec4(uniform, ...) _R_UNIFORM_GENERIC(ivec4, uniform, __VA_ARGS__)
593 
594 void _r_uniform_ptr_ivec4_vec(Uniform *uniform, ivec4_noalign value) attr_nonnull(2);
595 void _r_uniform_ivec4_vec(const char *uniform, ivec4_noalign value) attr_nonnull(1, 2);
596 #define r_uniform_ivec4_vec(uniform, ...) _R_UNIFORM_GENERIC(ivec4_vec, uniform, __VA_ARGS__)
597 
598 void _r_uniform_ptr_ivec4_array(Uniform *uniform, uint offset, uint count, ivec4_noalign elements[count]) attr_nonnull(4);
599 void _r_uniform_ivec4_array(const char *uniform, uint offset, uint count, ivec4_noalign elements[count]) attr_nonnull(1, 4);
600 #define r_uniform_ivec4_array(uniform, ...) _R_UNIFORM_GENERIC(ivec4_array, uniform, __VA_ARGS__)
601 
602 void _r_uniform_ptr_sampler_ptr(Uniform *uniform, Texture *tex) attr_nonnull(2);
603 void _r_uniform_sampler_ptr(const char *uniform, Texture *tex) attr_nonnull(1, 2);
604 void _r_uniform_ptr_sampler(Uniform *uniform, const char *tex) attr_nonnull(2);
605 void _r_uniform_sampler(const char *uniform, const char *tex) attr_nonnull(1, 2);
606 #define r_uniform_sampler(uniform, tex) (_Generic((uniform), \
607 	char*         : _Generic((tex), \
608 			char*       : _r_uniform_sampler, \
609 			const char* : _r_uniform_sampler, \
610 			Texture*    : _r_uniform_sampler_ptr \
611 	), \
612 	const char*   : _Generic((tex), \
613 			char*       : _r_uniform_sampler, \
614 			const char* : _r_uniform_sampler, \
615 			Texture*    : _r_uniform_sampler_ptr \
616 	), \
617 	Uniform*      : _Generic((tex), \
618 			char*       : _r_uniform_ptr_sampler, \
619 			const char* : _r_uniform_ptr_sampler, \
620 			Texture*    : _r_uniform_ptr_sampler_ptr \
621 	) \
622 ))(uniform, tex)
623 
624 void _r_uniform_ptr_sampler_array_ptr(Uniform *uniform, uint offset, uint count, Texture *values[count]) attr_nonnull(4);
625 void _r_uniform_sampler_array_ptr(const char *uniform, uint offset, uint count, Texture *values[count]) attr_nonnull(1, 4);
626 void _r_uniform_ptr_sampler_array(Uniform *uniform, uint offset, uint count, const char *values[count]) attr_nonnull(4);
627 void _r_uniform_sampler_array(const char *uniform, uint offset, uint count, const char *values[count]) attr_nonnull(4);
628 #define r_uniform_sampler_array(uniform, offset, count, values) (_Generic(uniform, \
629 	char*        : _Generic((values), \
630 			char**    : _r_uniform_sampler_array, \
631 			Texture** : _r_uniform_sampler_array_ptr \
632 	), \
633 	const char*  : _Generic((values), \
634 			char**    : _r_uniform_sampler_array, \
635 			Texture** : _r_uniform_sampler_array_ptr \
636 	), \
637 	Uniform*     : _Generic((values), \
638 			char**    : _r_uniform_ptr_sampler_array, \
639 			Texture** : _r_uniform_ptr_sampler_array_ptr \
640 	) \
641 ))(uniform, offset, count, values)
642 
643 void r_draw(VertexArray *varr, Primitive prim, uint firstvert, uint count, uint instances, uint base_instance);
644 void r_draw_indexed(VertexArray *varr, Primitive prim, uint firstidx, uint count, uint instances, uint base_instance);
645 
646 Texture* r_texture_create(const TextureParams *params) attr_nonnull(1);
647 void r_texture_get_size(Texture *tex, uint mipmap, uint *width, uint *height) attr_nonnull(1);
648 uint r_texture_get_width(Texture *tex, uint mipmap) attr_nonnull(1);
649 uint r_texture_get_height(Texture *tex, uint mipmap) attr_nonnull(1);
650 void r_texture_get_params(Texture *tex, TextureParams *params) attr_nonnull(1, 2);
651 const char* r_texture_get_debug_label(Texture *tex) attr_nonnull(1);
652 void r_texture_set_debug_label(Texture *tex, const char *label) attr_nonnull(1);
653 void r_texture_set_filter(Texture *tex, TextureFilterMode fmin, TextureFilterMode fmag) attr_nonnull(1);
654 void r_texture_set_wrap(Texture *tex, TextureWrapMode ws, TextureWrapMode wt) attr_nonnull(1);
655 void r_texture_fill(Texture *tex, uint mipmap, const Pixmap *image_data) attr_nonnull(1, 3);
656 void r_texture_fill_region(Texture *tex, uint mipmap, uint x, uint y, const Pixmap *image_data) attr_nonnull(1, 5);
657 void r_texture_invalidate(Texture *tex) attr_nonnull(1);
658 void r_texture_clear(Texture *tex, const Color *clr) attr_nonnull(1, 2);
659 void r_texture_destroy(Texture *tex) attr_nonnull(1);
660 
661 Framebuffer* r_framebuffer_create(void);
662 const char* r_framebuffer_get_debug_label(Framebuffer *fb) attr_nonnull(1);
663 void r_framebuffer_set_debug_label(Framebuffer *fb, const char* label) attr_nonnull(1);
664 void r_framebuffer_attach(Framebuffer *fb, Texture *tex, uint mipmap, FramebufferAttachment attachment) attr_nonnull(1);
665 Texture* r_framebuffer_get_attachment(Framebuffer *fb, FramebufferAttachment attachment) attr_nonnull(1);
666 uint r_framebuffer_get_attachment_mipmap(Framebuffer *fb, FramebufferAttachment attachment) attr_nonnull(1);
667 void r_framebuffer_viewport(Framebuffer *fb, float x, float y, float w, float h);
668 void r_framebuffer_viewport_rect(Framebuffer *fb, FloatRect viewport);
669 void r_framebuffer_viewport_current(Framebuffer *fb, FloatRect *viewport) attr_nonnull(2);
670 void r_framebuffer_destroy(Framebuffer *fb) attr_nonnull(1);
671 void r_framebuffer_clear(Framebuffer *fb, ClearBufferFlags flags, const Color *colorval, float depthval);
672 IntExtent r_framebuffer_get_size(Framebuffer *fb);
673 
674 void r_framebuffer(Framebuffer *fb);
675 Framebuffer* r_framebuffer_current(void);
676 
677 VertexBuffer* r_vertex_buffer_create(size_t capacity, void *data);
678 const char* r_vertex_buffer_get_debug_label(VertexBuffer *vbuf) attr_nonnull(1);
679 void r_vertex_buffer_set_debug_label(VertexBuffer *vbuf, const char* label) attr_nonnull(1);
680 void r_vertex_buffer_destroy(VertexBuffer *vbuf) attr_nonnull(1);
681 void r_vertex_buffer_invalidate(VertexBuffer *vbuf) attr_nonnull(1);
682 SDL_RWops* r_vertex_buffer_get_stream(VertexBuffer *vbuf) attr_nonnull(1);
683 
684 IndexBuffer* r_index_buffer_create(size_t max_elements);
685 size_t r_index_buffer_get_capacity(IndexBuffer *ibuf) attr_nonnull(1);
686 const char* r_index_buffer_get_debug_label(IndexBuffer *ibuf) attr_nonnull(1);
687 void r_index_buffer_set_debug_label(IndexBuffer *ibuf, const char *label) attr_nonnull(1);
688 void r_index_buffer_set_offset(IndexBuffer *ibuf, size_t offset) attr_nonnull(1);
689 size_t r_index_buffer_get_offset(IndexBuffer *ibuf) attr_nonnull(1);
690 void r_index_buffer_add_indices(IndexBuffer *ibuf, uint index_ofs, size_t num_indices, uint indices[num_indices]) attr_nonnull(1, 4);
691 void r_index_buffer_destroy(IndexBuffer *ibuf) attr_nonnull(1);
692 
693 VertexArray* r_vertex_array_create(void);
694 const char* r_vertex_array_get_debug_label(VertexArray *varr) attr_nonnull(1);
695 void r_vertex_array_set_debug_label(VertexArray *varr, const char* label) attr_nonnull(1);
696 void r_vertex_array_destroy(VertexArray *varr) attr_nonnull(1);
697 void r_vertex_array_attach_vertex_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) attr_nonnull(1, 2);
698 VertexBuffer* r_vertex_array_get_vertex_attachment(VertexArray *varr, uint attachment)  attr_nonnull(1);
699 void r_vertex_array_attach_index_buffer(VertexArray *varr, IndexBuffer *ibuf) attr_nonnull(1);
700 IndexBuffer* r_vertex_array_get_index_attachment(VertexArray *varr)  attr_nonnull(1);
701 void r_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]) attr_nonnull(1, 3);
702 
703 void r_model_add_static(Model *out_mdl, Primitive prim, size_t num_vertices, GenericModelVertex vertices[num_vertices], uint indices[num_vertices]);
704 
705 void r_vsync(VsyncMode mode);
706 VsyncMode r_vsync_current(void);
707 
708 void r_swap(SDL_Window *window);
709 
710 bool r_screenshot(Pixmap *dest) attr_nodiscard attr_nonnull(1);
711 
712 void r_mat_mv_push(void);
713 void r_mat_mv_push_premade(mat4 mat);
714 void r_mat_mv_push_identity(void);
715 void r_mat_mv_pop(void);
716 void r_mat_mv(mat4 mat);
717 void r_mat_mv_current(mat4 out_mat);
718 mat4 *r_mat_mv_current_ptr(void);
719 void r_mat_mv_identity(void);
720 void r_mat_mv_translate_v(vec3 v);
721 void r_mat_mv_rotate_v(float angle, vec3 v);
722 void r_mat_mv_scale_v(vec3 v);
723 
724 void r_mat_proj_push(void);
725 void r_mat_proj_push_premade(mat4 mat);
726 void r_mat_proj_push_identity(void);
727 void r_mat_proj_push_ortho_ex(float left, float right, float bottom, float top, float near, float far);
728 void r_mat_proj_push_ortho(float width, float height);
729 void r_mat_proj_push_perspective(float angle, float aspect, float near, float far);
730 void r_mat_proj_pop(void);
731 void r_mat_proj(mat4 mat);
732 void r_mat_proj_current(mat4 out_mat);
733 mat4 *r_mat_proj_current_ptr(void);
734 void r_mat_proj_identity(void);
735 void r_mat_proj_translate_v(vec3 v);
736 void r_mat_proj_rotate_v(float angle, vec3 v);
737 void r_mat_proj_scale_v(vec3 v);
738 void r_mat_proj_ortho(float left, float right, float bottom, float top, float near, float far);
739 void r_mat_proj_perspective(float angle, float aspect, float near, float far);
740 
741 void r_mat_tex_push(void);
742 void r_mat_tex_push_premade(mat4 mat);
743 void r_mat_tex_push_identity(void);
744 void r_mat_tex_pop(void);
745 void r_mat_tex(mat4 mat);
746 void r_mat_tex_current(mat4 out_mat);
747 mat4 *r_mat_tex_current_ptr(void);
748 void r_mat_tex_identity(void);
749 void r_mat_tex_translate_v(vec3 v);
750 void r_mat_tex_rotate_v(float angle, vec3 v);
751 void r_mat_tex_scale_v(vec3 v);
752 
753 void r_shader_standard(void);
754 void r_shader_standard_notex(void);
755 
756 VertexBuffer* r_vertex_buffer_static_models(void) attr_returns_nonnull;
757 VertexArray* r_vertex_array_static_models(void) attr_returns_nonnull;
758 
759 void r_state_push(void);
760 void r_state_pop(void);
761 
762 void r_draw_quad(void);
763 void r_draw_quad_instanced(uint instances);
764 void r_draw_model_ptr(Model *model, uint instances, uint base_instance) attr_nonnull(1);
765 void r_draw_sprite(const SpriteParams *params) attr_nonnull(1);
766 
767 void r_sprite_batch_prepare_state(const SpriteStateParams *stp);
768 void r_sprite_batch_add_instance(const SpriteInstanceAttribs *attribs);
769 
770 void r_flush_sprites(void);
771 
772 BlendMode r_blend_compose(
773 	BlendFactor src_color, BlendFactor dst_color, BlendOp color_op,
774 	BlendFactor src_alpha, BlendFactor dst_alpha, BlendOp alpha_op
775 );
776 
777 uint32_t r_blend_component(BlendMode mode, BlendModeComponent component);
778 void r_blend_unpack(BlendMode mode, UnpackedBlendMode *dest) attr_nonnull(2);
779 
780 const UniformTypeInfo* r_uniform_type_info(UniformType type) attr_returns_nonnull;
781 const VertexAttribTypeInfo* r_vertex_attrib_type_info(VertexAttribType type);
782 
783 VertexAttribFormat* r_vertex_attrib_format_interleaved(
784 	size_t nattribs,
785 	VertexAttribSpec specs[nattribs],
786 	VertexAttribFormat formats[nattribs],
787 	uint attachment
788 ) attr_nonnull(2, 3);
789 
790 /*
791  * Small convenience wrappers
792  */
793 
794 INLINE
r_enable(RendererCapability cap)795 void r_enable(RendererCapability cap) {
796 	r_capability(cap, true);
797 }
798 
799 INLINE
r_disable(RendererCapability cap)800 void r_disable(RendererCapability cap) {
801 	r_capability(cap, false);
802 }
803 
804 INLINE
r_shader_get(const char * name)805 ShaderProgram* r_shader_get(const char *name) {
806 	return get_resource_data(RES_SHADER_PROGRAM, name, RESF_DEFAULT | RESF_UNSAFE);
807 }
808 
809 INLINE
r_shader_get_optional(const char * name)810 ShaderProgram* r_shader_get_optional(const char *name) {
811 	return get_resource_data(RES_SHADER_PROGRAM, name, RESF_OPTIONAL | RESF_UNSAFE);
812 }
813 
814 INLINE
r_texture_get(const char * name)815 Texture* r_texture_get(const char *name) {
816 	return get_resource_data(RES_TEXTURE, name, RESF_DEFAULT | RESF_UNSAFE);
817 }
818 
819 #pragma GCC diagnostic push
820 #pragma GCC diagnostic ignored "-Wdeprecated"
821 
r_mat_mv_translate(float x,float y,float z)822 INLINE void r_mat_mv_translate(float x, float y, float z) { r_mat_mv_translate_v((vec3) { x, y, z }); }
r_mat_proj_translate(float x,float y,float z)823 INLINE void r_mat_proj_translate(float x, float y, float z) { r_mat_proj_translate_v((vec3) { x, y, z }); }
r_mat_tex_translate(float x,float y,float z)824 INLINE void r_mat_tex_translate(float x, float y, float z) { r_mat_tex_translate_v((vec3) { x, y, z }); }
825 
r_mat_mv_rotate(float angle,float nx,float ny,float nz)826 INLINE void r_mat_mv_rotate(float angle, float nx, float ny, float nz) { r_mat_mv_rotate_v(angle, (vec3) { nx, ny, nz }); }
r_mat_proj_rotate(float angle,float nx,float ny,float nz)827 INLINE void r_mat_proj_rotate(float angle, float nx, float ny, float nz) { r_mat_proj_rotate_v(angle, (vec3) { nx, ny, nz }); }
r_mat_tex_rotate(float angle,float nx,float ny,float nz)828 INLINE void r_mat_tex_rotate(float angle, float nx, float ny, float nz) { r_mat_tex_rotate_v(angle, (vec3) { nx, ny, nz }); }
829 
r_mat_mv_scale(float sx,float sy,float sz)830 INLINE void r_mat_mv_scale(float sx, float sy, float sz) { r_mat_mv_scale_v((vec3) { sx, sy, sz }); }
r_mat_proj_scale(float sx,float sy,float sz)831 INLINE void r_mat_proj_scale(float sx, float sy, float sz) { r_mat_proj_scale_v((vec3) { sx, sy, sz }); }
r_mat_tex_scale(float sx,float sy,float sz)832 INLINE void r_mat_tex_scale(float sx, float sy, float sz) { r_mat_tex_scale_v((vec3) { sx, sy, sz }); }
833 
834 #pragma GCC diagnostic pop
835 
836 INLINE
r_color(const Color * c)837 void r_color(const Color *c) {
838 	r_color4(c->r, c->g, c->b, c->a);
839 }
840 
841 INLINE
r_color3(float r,float g,float b)842 void r_color3(float r, float g, float b) {
843 	r_color4(r, g, b, 1.0);
844 }
845 
846 INLINE attr_nonnull(1)
r_shader(const char * prog)847 void r_shader(const char *prog) {
848 	r_shader_ptr(r_shader_get(prog));
849 }
850 
851 INLINE
r_shader_uniform(ShaderProgram * prog,const char * name)852 Uniform* r_shader_uniform(ShaderProgram *prog, const char *name) {
853 	return _r_shader_uniform(prog, name, ht_str2ptr_hash(name));
854 }
855 
856 INLINE
r_shader_current_uniform(const char * name)857 Uniform* r_shader_current_uniform(const char *name) {
858 	return r_shader_uniform(r_shader_current(), name);
859 }
860 
861 INLINE
r_clear(ClearBufferFlags flags,const Color * colorval,float depthval)862 void r_clear(ClearBufferFlags flags, const Color *colorval, float depthval) {
863 	r_framebuffer_clear(r_framebuffer_current(), flags, colorval, depthval);
864 }
865 
866 INLINE attr_nonnull(1)
r_draw_model(const char * model)867 void r_draw_model(const char *model) {
868 	r_draw_model_ptr(get_resource_data(RES_MODEL, model, RESF_UNSAFE), 0, 0);
869 }
870 
871 INLINE attr_nonnull(1)
r_draw_model_instanced(const char * model,uint instances,uint base_instance)872 void r_draw_model_instanced(const char *model, uint instances, uint base_instance) {
873 	r_draw_model_ptr(get_resource_data(RES_MODEL, model, RESF_UNSAFE), instances, base_instance);
874 }
875 
876 INLINE
r_capability_bit(RendererCapability cap)877 r_capability_bits_t r_capability_bit(RendererCapability cap) {
878 	r_capability_bits_t idx = cap;
879 	assert(idx < NUM_RCAPS);
880 	return (1 << idx);
881 }
882 
883 INLINE
r_feature_bit(RendererFeature feat)884 r_feature_bits_t r_feature_bit(RendererFeature feat) {
885 	r_feature_bits_t idx = feat;
886 	assert(idx < NUM_RFEATS);
887 	return (1 << idx);
888 }
889 
890 INLINE
r_supports(RendererFeature feature)891 bool r_supports(RendererFeature feature) {
892 	return r_features() & r_feature_bit(feature);
893 }
894 
895 #endif // IGUARD_renderer_api_h
896