summaryrefslogtreecommitdiff
path: root/gfx/include/gfx/render_backend.h
blob: 8d3c42b0849b536812ff2e784603bf6258b87d5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/// Render Backend.
///
/// The Render Backend creates and owns graphics objects and performs low-level
/// rendering operations.
#pragma once

#include "sizes.h"

#include <math/aabb3.h>
#include <math/fwd.h>
#include <math/mat4.h>
#include <math/vec4.h>

#include <cstring.h>

#include <stddef.h>
#include <stdint.h>

// Implementation objects.
typedef struct Buffer        Buffer;
typedef struct FrameBuffer   FrameBuffer;
typedef struct Geometry      Geometry;
typedef struct RenderBuffer  RenderBuffer;
typedef struct Shader        Shader;
typedef struct ShaderProgram ShaderProgram;
typedef struct Texture       Texture;
typedef struct RenderBackend RenderBackend;

/// Data type for vertex indices.
/// Might need U32 for bigger models.
typedef uint8_t  VertexIndex8;
typedef uint16_t VertexIndex16;
typedef uint16_t VertexCount;

/// Geometry drawing modes.
typedef enum PrimitiveType {
  Triangles,
  TriangleFan,
  TriangleStrip
} PrimitiveType;

/// Buffer usage.
typedef enum BufferUsage { BufferStatic, BufferDynamic } BufferUsage;

/// Buffer type.
typedef enum BufferType {
  BufferUntyped,
  Buffer2d,
  Buffer3d,
  Buffer4d,
  BufferFloat,
  BufferU8,
  BufferU16
} BufferType;

/// Buffer data descriptor.
typedef struct BufferDataDesc {
  union {
    const void*     data;
    const vec2*     vec2s;
    const vec3*     vec3s;
    const float*    floats;
    const uint8_t*  u8s;
    const uint16_t* u16s;
  };
  size_t count;
} BufferDataDesc;

/// Buffer descriptor.
///
/// 'count' is the number of elements in the array. For untyped buffers, this is
/// the size in bytes of the 'data' array. For other types, it is the number of
/// vec2s, vec3s, etc. in the corresponding array.
///
/// The data pointers can also be null. In such a case, a buffer of the given
/// size is created with its contents uninitialized.
///
/// TODO: Think about typed buffers (Buffer, Buffer2d, Buffer3d, BufferU8, etc).
/// Typed buffers don't work well with interleaved vertex attributes. Not sure
/// this is really worth it.
typedef struct BufferDesc {
  BufferUsage    usage;
  BufferType     type;
  BufferDataDesc data;
} BufferDesc;

/// A buffer view for vertex data (attributes or indices).
/// Either 'data' or 'buffer' must be set.
#define MAKE_BUFFER_VIEW(NAME, TYPE) \
  typedef struct NAME {              \
    const TYPE* data;                \
    Buffer*     buffer;              \
    size_t      offset_bytes;        \
    size_t      size_bytes;          \
    size_t      stride_bytes;        \
  } NAME;

/// A buffer view for untyped data.
MAKE_BUFFER_VIEW(BufferView, void)

/// A buffer view for 2D vectors.
MAKE_BUFFER_VIEW(BufferView2d, vec2)

/// A buffer view for 3D vectors.
MAKE_BUFFER_VIEW(BufferView3d, vec3)

/// A buffer view for 4D vectors.
MAKE_BUFFER_VIEW(BufferView4d, vec4)

/// A buffer view for floats.
MAKE_BUFFER_VIEW(BufferViewFloat, float)

/// A buffer view for 8-bit unsigned integers.
MAKE_BUFFER_VIEW(BufferViewU8, uint8_t)

/// A buffer view for 16-bit unsigned integers.
MAKE_BUFFER_VIEW(BufferViewU16, uint16_t)

/// A buffer view for 8-bit vertex indices.
MAKE_BUFFER_VIEW(BufferViewIdx8, uint16_t)

/// A buffer view for 16-bit vertex indices.
MAKE_BUFFER_VIEW(BufferViewIdx16, uint16_t)

/// Describes a piece of geometry.
///
/// Buffer views may point to either already-existing GPU buffers or to data in
/// host memory.
///
/// If the buffer views do not already point to GPU buffers, GPU buffers are
/// created for the geometry. The 'buffer_usage' field specifies the usage for
/// the created buffers. Use BufferStatic for static geometry and BufferDynamic
/// for dynamic geometry.
///
/// Currently we support only up to 16-bit vertex indices. Might have to change
/// this to support a larger variety of 3D models.
typedef struct GeometryDesc {
  BufferView2d positions2d;
  BufferView3d positions3d;
  BufferView3d normals;
  BufferView4d tangents;
  BufferView2d texcoords;
  struct {
    BufferViewU8  u8;
    BufferViewU16 u16;
  } joints; // uvec4.
  struct {
    BufferViewFloat floats;
    BufferViewU8    u8;
    BufferViewU16   u16;
  } weights; // vec4 or uvec4.
  BufferViewIdx8  indices8;
  BufferViewIdx16 indices16;
  VertexCount     num_verts;
  size_t          num_indices;
  PrimitiveType   type;
  BufferUsage     buffer_usage;
  aabb3           aabb;
} GeometryDesc;

/// Shader compiler define.
typedef struct ShaderCompilerDefine {
  sstring name;
  sstring value;
} ShaderCompilerDefine;

/// Shader types.
typedef enum { VertexShader, FragmentShader } ShaderType;

/// Describes a shader.
typedef struct ShaderDesc {
  ShaderType           type;
  const char*          code;
  ShaderCompilerDefine defines[GFX_MAX_SHADER_COMPILER_DEFINES];
  size_t               num_defines;
} ShaderDesc;

/// Describes a shader program.
typedef struct ShaderProgramDesc {
  const Shader* vertex_shader;
  const Shader* fragment_shader;
} ShaderProgramDesc;

/// Shader uniform type.
typedef enum {
  UniformFloat,
  UniformMat4,
  UniformTexture,
  UniformVec3,
  UniformVec4,
  UniformMat4Array
} UniformType;

/// Shader uniform.
///
/// For uniform arrays, the client must ensure that the array is still valid by
/// the time the uniform data is passed to the GPU.
typedef struct ShaderUniform {
  sstring     name;
  UniformType type;
  union {
    const Texture* texture;
    mat4           mat4;
    vec3           vec3;
    vec4           vec4;
    float          scalar;
    struct {
      size_t count;
      union {
        const mat4* values;
      };
    } array;
  } value;
} ShaderUniform;

/// Texture dimension.
typedef enum { Texture2D, TextureCubeMap } TextureDimension;

/// Texture data format.
typedef enum {
  TextureDepth,
  TextureRG16,
  TextureRG16F,
  TextureRGB8,
  TextureR11G11B10F,
  TextureRGBA8,
  TextureSRGB8,
  TextureSRGBA8
} TextureFormat;

/// Texture filtering.
typedef enum { NearestFiltering, LinearFiltering } TextureFiltering;

/// Texture wrap mode.
typedef enum { Repeat, ClampToEdge } TextureWrapping;

/// Cubemap faces.
typedef enum {
  CubemapFacePosX,
  CubemapFaceNegX,
  CubemapFacePosY,
  CubemapFaceNegY,
  CubemapFacePosZ,
  CubemapFaceNegZ
} CubemapFace;

/// Texture data descriptor.
typedef struct TextureDataDesc {
  union {
    const void* pixels;
    struct {
      const void* pixels_pos_x;
      const void* pixels_neg_x;
      const void* pixels_pos_y;
      const void* pixels_neg_y;
      const void* pixels_pos_z;
      const void* pixels_neg_z;
    } cubemap;
  };
} TextureDataDesc;

/// Describes a texture.
typedef struct TextureDesc {
  int              width;
  int              height;
  int              depth; // Not used until 3D textures are exposed.
  TextureDimension dimension;
  TextureFormat    format;
  TextureFiltering filtering;
  TextureWrapping  wrap;
  bool             mipmaps;
  TextureDataDesc  data;
} TextureDesc;

/// Describes a renderbuffer.
typedef struct RenderBufferDesc {
  int           width;
  int           height;
  TextureFormat texture_format;
} RenderBufferDesc;

/// Framebuffer attachment type.
typedef enum FrameBufferAttachmentType {
  FrameBufferNoAttachment,
  FrameBufferTexture,
  FrameBufferCubemapTexture,
  FrameBufferRenderBuffer
} FrameBufferAttachmentType;

/// Describes a framebuffer attachment.
typedef struct FrameBufferAttachment {
  FrameBufferAttachmentType type;
  union {
    struct {
      Texture* texture;
      int      mip_level;
    } texture;
    struct {
      Texture*    texture;
      int         mip_level;
      CubemapFace face;
    } cubemap;
    RenderBuffer* renderbuffer;
  };
} FrameBufferAttachment;

/// Describes a framebuffer.
typedef struct FrameBufferDesc {
  FrameBufferAttachment colour;
  FrameBufferAttachment depth;
} FrameBufferDesc;

// -----------------------------------------------------------------------------
// Render commands.
// -----------------------------------------------------------------------------

/// Start a new frame.
void gfx_start_frame(RenderBackend*);

/// End a frame.
void gfx_end_frame(RenderBackend*);

/// Set the render backend's viewport dimensions.
void gfx_set_viewport(RenderBackend*, int width, int height);

/// Get the render backend's viewport dimensions.
void gfx_get_viewport(RenderBackend*, int* width, int* height);

/// Set blending state.
void gfx_set_blending(RenderBackend*, bool enable);

/// Set depth mask.
void gfx_set_depth_mask(RenderBackend*, bool enable);

/// Set cull mode.
void gfx_set_culling(RenderBackend*, bool enable);

/// Set polygon offset.
void gfx_set_polygon_offset(RenderBackend*, float scale, float bias);

/// Reset the polygon offset.
void gfx_reset_polygon_offset(RenderBackend*);

// -----------------------------------------------------------------------------
// Buffers.
// -----------------------------------------------------------------------------

/// Create a buffer from raw data.
Buffer* gfx_make_buffer(RenderBackend*, const BufferDesc*);

/// Destroy the buffer.
void gfx_destroy_buffer(RenderBackend*, Buffer**);

/// Update the buffer's data.
void gfx_update_buffer(Buffer*, const BufferDataDesc*);

// -----------------------------------------------------------------------------
// Geometry.
// -----------------------------------------------------------------------------

/// Create geometry.
Geometry* gfx_make_geometry(RenderBackend*, const GeometryDesc*);

/// Destroy the geometry.
void gfx_destroy_geometry(RenderBackend*, Geometry**);

/// Upload new vertex data for the geometry.
///
/// This is similar to gfx_make_geometry(), but the geometry need not be
/// entirely specified.
///
/// Only the vertex attributes, vertex count, and index count set in the
/// descriptor are updated. Index data, primitive type, and other properties of
/// the geometry are not updated.
///
/// New data must be given as arrays in host memory. That is, the buffer views
/// in the descriptor must point to CPU arrays, not GPU buffers.
///
/// Note that the descriptor cannot specify a larger vertex or index count than
/// what the geometry was created with. If the geometry size or any other
/// attribute not handled by this update function needs to be changed, then a
/// new geometry must be created.
void gfx_update_geometry(Geometry*, const GeometryDesc*);

/// Render the geometry.
void gfx_render_geometry(const Geometry*);

/// Return the geometry's bounding box.
aabb3 gfx_get_geometry_aabb(const Geometry*);

// -----------------------------------------------------------------------------
// Textures.
// -----------------------------------------------------------------------------

/// Create a texture.
Texture* gfx_make_texture(RenderBackend*, const TextureDesc*);

/// Destroy the texture.
void gfx_destroy_texture(RenderBackend*, Texture**);

/// Update the texture.
void gfx_update_texture(Texture*, const TextureDataDesc*);

// -----------------------------------------------------------------------------
// Renderbuffers.
// -----------------------------------------------------------------------------

/// Create a renderbuffer.
RenderBuffer* gfx_make_renderbuffer(RenderBackend*, const RenderBufferDesc*);

/// Destroy the renderbuffer.
void gfx_destroy_renderbuffer(RenderBackend*, RenderBuffer**);

// -----------------------------------------------------------------------------
// Framebuffers.
// -----------------------------------------------------------------------------

/// Create a framebuffer.
FrameBuffer* gfx_make_framebuffer(RenderBackend*, const FrameBufferDesc*);

/// Destroy the framebuffer.
void gfx_destroy_framebuffer(RenderBackend*, FrameBuffer**);

/// Attach a colour buffer to the framebuffer.
bool gfx_framebuffer_attach_colour(FrameBuffer*, const FrameBufferAttachment*);

/// Attach a depth buffer to the framebuffer.
bool gfx_framebuffer_attach_depth(FrameBuffer*, const FrameBufferAttachment*);

/// Activate the framebuffer.
/// Subsequent draw calls write to this framebuffer.
void gfx_activate_framebuffer(const FrameBuffer*);

/// Deactivate the framebuffer.
/// Subsequent draw calls write to the default framebuffer.
void gfx_deactivate_framebuffer(const FrameBuffer*);

/// Set the framebuffer's viewport.
/// This function should be called every time the framebuffer is activated.
void gfx_framebuffer_set_viewport(
    FrameBuffer*, int x, int y, int width, int height);

// -----------------------------------------------------------------------------
// Shaders.
// -----------------------------------------------------------------------------

/// Create a shader.
Shader* gfx_make_shader(RenderBackend*, const ShaderDesc*);

/// Destroy the shader.
void gfx_destroy_shader(RenderBackend*, Shader**);

/// Create a shader program.
ShaderProgram* gfx_make_shader_program(
    RenderBackend*, const ShaderProgramDesc*);

/// Destroy the shader program.
void gfx_destroy_shader_program(RenderBackend*, ShaderProgram**);

/// Activate the shader program.
void gfx_activate_shader_program(const ShaderProgram*);

/// Deactivate the shader program.
void gfx_deactivate_shader_program(const ShaderProgram*);

/// Apply the shader program's uniform variables.
///
/// Calls to gfx_set_XYZ_uniform save the values of the uniform variables in the
/// graphics library. By calling this function, those values are passed on to
/// the graphics driver for rendering.
///
/// This function should be called after setting all of the uniform variables
/// and prior to issuing a draw call.
void gfx_apply_uniforms(const ShaderProgram*);

/// Set the texture uniform.
/// Has no effect if the shader does not contain the given uniform.
void gfx_set_texture_uniform(ShaderProgram*, const char* name, const Texture*);

/// Set the matrix uniform.
/// Has no effect if the shader does not contain the given uniform.
void gfx_set_mat4_uniform(ShaderProgram*, const char* name, const mat4*);

/// Set the vec3 uniform.
/// Has no effect if the shader does not contain the given uniform.
void gfx_set_vec3_uniform(ShaderProgram*, const char* name, vec3);

/// Set the vec4 uniform.
/// Has no effect if the shader does not contain the given uniform.
void gfx_set_vec4_uniform(ShaderProgram*, const char* name, vec4);

/// Set the float uniform.
/// Has no effect if the shader does not contain the given uniform.
void gfx_set_float_uniform(ShaderProgram*, const char* name, float value);

/// Set the matrix array uniform.
/// Has no effect if the shader does not contain the given uniform.
void gfx_set_mat4_array_uniform(
    ShaderProgram*, const char* name, const mat4*, size_t count);