diff options
Diffstat (limited to 'src/renderer/imm_renderer.c')
-rw-r--r-- | src/renderer/imm_renderer.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/renderer/imm_renderer.c b/src/renderer/imm_renderer.c new file mode 100644 index 0000000..8cf3a10 --- /dev/null +++ b/src/renderer/imm_renderer.c | |||
@@ -0,0 +1,260 @@ | |||
1 | #include "imm_renderer_impl.h" | ||
2 | |||
3 | #include <gfx/core.h> | ||
4 | #include <gfx/util/shader.h> | ||
5 | |||
6 | #include <math/aabb3.h> | ||
7 | |||
8 | #include <assert.h> | ||
9 | #include <string.h> // memcpy | ||
10 | |||
11 | bool imm_renderer_make(ImmRenderer* renderer, GfxCore* gfxcore) { | ||
12 | assert(renderer); | ||
13 | assert(gfxcore); | ||
14 | |||
15 | const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3; | ||
16 | |||
17 | renderer->gfxcore = gfxcore; | ||
18 | |||
19 | renderer->triangles = gfx_make_geometry( | ||
20 | gfxcore, &(GeometryDesc){ | ||
21 | .type = Triangles, | ||
22 | .buffer_usage = BufferDynamic, | ||
23 | .num_verts = num_triangle_verts, | ||
24 | .positions3d = (BufferView3d){ | ||
25 | .size_bytes = num_triangle_verts * sizeof(vec3)}}); | ||
26 | if (!renderer->triangles) { | ||
27 | goto cleanup; | ||
28 | } | ||
29 | |||
30 | renderer->shader = gfx_make_immediate_mode_shader(gfxcore); | ||
31 | if (!renderer->shader) { | ||
32 | goto cleanup; | ||
33 | } | ||
34 | |||
35 | renderer->matrix_stack[0] = mat4_id(); | ||
36 | renderer->stack_pointer = 0; | ||
37 | |||
38 | gfx_imm_set_colour(renderer, vec4_make(0.0, 0.0, 0.0, 1.0)); | ||
39 | |||
40 | return true; | ||
41 | |||
42 | cleanup: | ||
43 | imm_renderer_destroy(renderer); | ||
44 | return false; | ||
45 | } | ||
46 | |||
47 | void imm_renderer_destroy(ImmRenderer* renderer) { | ||
48 | assert(renderer); | ||
49 | assert(renderer->gfxcore); | ||
50 | |||
51 | if (renderer->triangles) { | ||
52 | gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles); | ||
53 | // TODO: Could also destroy the geometry's buffers here. | ||
54 | } | ||
55 | |||
56 | if (renderer->shader) { | ||
57 | gfx_destroy_shader_program(renderer->gfxcore, &renderer->shader); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | void imm_renderer_flush(ImmRenderer* renderer) { | ||
62 | assert(renderer); | ||
63 | |||
64 | if (renderer->num_triangle_verts > 0) { | ||
65 | gfx_update_geometry( | ||
66 | renderer->triangles, | ||
67 | &(GeometryDesc){ | ||
68 | .num_verts = renderer->num_triangle_verts, | ||
69 | .positions3d = (BufferView3d){ | ||
70 | .data = renderer->triangle_verts, | ||
71 | .size_bytes = renderer->num_triangle_verts * sizeof(vec3)} | ||
72 | }); | ||
73 | |||
74 | gfx_apply_uniforms(renderer->shader); | ||
75 | gfx_render_geometry(renderer->triangles); | ||
76 | |||
77 | renderer->num_triangle_verts = 0; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | void gfx_imm_start(ImmRenderer* renderer) { | ||
82 | assert(renderer); | ||
83 | // Shader uniforms are applied lazily. | ||
84 | // TODO: In the event that gfx_activate_shader_program() activates uniforms | ||
85 | // automatically for convenience, call an overload here that doesn't do so. | ||
86 | ShaderProgram* shader = renderer->shader; | ||
87 | gfx_activate_shader_program(shader); | ||
88 | } | ||
89 | |||
90 | void gfx_imm_end(ImmRenderer* renderer) { | ||
91 | assert(renderer); | ||
92 | imm_renderer_flush(renderer); | ||
93 | gfx_deactivate_shader_program(renderer->shader); | ||
94 | } | ||
95 | |||
96 | void gfx_imm_draw_triangles( | ||
97 | ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) { | ||
98 | assert(renderer); | ||
99 | assert(verts); | ||
100 | const size_t new_verts = num_triangles * 3; | ||
101 | assert( | ||
102 | renderer->num_triangle_verts + new_verts < (IMM_MAX_NUM_TRIANGLES * 3)); | ||
103 | |||
104 | memcpy( | ||
105 | renderer->triangle_verts + renderer->num_triangle_verts, verts, | ||
106 | new_verts * sizeof(vec3)); | ||
107 | |||
108 | renderer->num_triangle_verts += new_verts; | ||
109 | } | ||
110 | |||
111 | void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) { | ||
112 | gfx_imm_draw_triangles(renderer, verts, 1); | ||
113 | } | ||
114 | |||
115 | void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) { | ||
116 | assert(renderer); | ||
117 | |||
118 | // clang-format off | ||
119 | const vec3 verts[4] = { | ||
120 | vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2 | ||
121 | vec3_make(box.max.x, box.min.y, 0), // | | | ||
122 | vec3_make(box.max.x, box.max.y, 0), // | | | ||
123 | vec3_make(box.min.x, box.max.y, 0)}; // 0 ---- 1 | ||
124 | // clang-format on | ||
125 | |||
126 | #define tri(i0, i1, i2) verts[i0], verts[i1], verts[i2] | ||
127 | const vec3 tris[6] = {tri(0, 1, 2), tri(0, 2, 3)}; | ||
128 | #undef tri | ||
129 | |||
130 | gfx_imm_draw_triangles(renderer, tris, 2); | ||
131 | } | ||
132 | |||
133 | void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) { | ||
134 | assert(renderer); | ||
135 | |||
136 | // clang-format off | ||
137 | const vec3 vertices[8] = { | ||
138 | vec3_make(box.min.x, box.min.y, box.max.z), // 7 ----- 6 | ||
139 | vec3_make(box.max.x, box.min.y, box.max.z), // / /| | ||
140 | vec3_make(box.max.x, box.max.y, box.max.z), // 3 ----- 2 | | ||
141 | vec3_make(box.min.x, box.max.y, box.max.z), // | | | | ||
142 | vec3_make(box.min.x, box.min.y, box.min.z), // | 4 ----- 5 | ||
143 | vec3_make(box.max.x, box.min.y, box.min.z), // |/ |/ | ||
144 | vec3_make(box.max.x, box.max.y, box.min.z), // 0 ----- 1 | ||
145 | vec3_make(box.min.x, box.max.y, box.min.z)}; | ||
146 | // clang-format on | ||
147 | |||
148 | gfx_imm_draw_box3(renderer, vertices); | ||
149 | } | ||
150 | |||
151 | void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]) { | ||
152 | assert(renderer); | ||
153 | assert(vertices); | ||
154 | |||
155 | // 7 ----- 6 | ||
156 | // / /| | ||
157 | // 3 ----- 2 | | ||
158 | // | | | | ||
159 | // | 4 ----- 5 | ||
160 | // |/ |/ | ||
161 | // 0 ----- 1 | ||
162 | |||
163 | #define tri(i0, i1, i2) vertices[i0], vertices[i1], vertices[i2] | ||
164 | const vec3 tris[36] = {// Front. | ||
165 | tri(0, 1, 2), tri(0, 2, 3), | ||
166 | // Right. | ||
167 | tri(1, 5, 6), tri(1, 6, 2), | ||
168 | // Back. | ||
169 | tri(5, 4, 7), tri(5, 7, 6), | ||
170 | // Left. | ||
171 | tri(4, 0, 03), tri(4, 3, 7), | ||
172 | // Top. | ||
173 | tri(3, 2, 6), tri(3, 6, 7), | ||
174 | // Bottom. | ||
175 | tri(0, 4, 5), tri(0, 5, 1)}; | ||
176 | |||
177 | gfx_imm_draw_triangles(renderer, tris, 12); | ||
178 | } | ||
179 | |||
180 | // Load the top of the matrix stack into the shader. | ||
181 | static void update_shader_model_matrix(ImmRenderer* renderer) { | ||
182 | assert(renderer); | ||
183 | imm_renderer_flush(renderer); | ||
184 | gfx_set_mat4_uniform( | ||
185 | renderer->shader, "Model", | ||
186 | &renderer->matrix_stack[renderer->stack_pointer]); | ||
187 | } | ||
188 | |||
189 | void gfx_imm_load_identity(ImmRenderer* renderer) { | ||
190 | assert(renderer); | ||
191 | renderer->matrix_stack[0] = mat4_id(); | ||
192 | renderer->stack_pointer = 0; | ||
193 | update_shader_model_matrix(renderer); | ||
194 | } | ||
195 | |||
196 | void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix) { | ||
197 | assert(renderer); | ||
198 | assert(matrix); | ||
199 | assert(renderer->stack_pointer >= 0); | ||
200 | assert(renderer->stack_pointer < IMM_MAX_NUM_MATRICES); // TODO: hard assert. | ||
201 | |||
202 | renderer->matrix_stack[renderer->stack_pointer + 1] = | ||
203 | mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer]); | ||
204 | renderer->stack_pointer += 1; | ||
205 | |||
206 | update_shader_model_matrix(renderer); | ||
207 | } | ||
208 | |||
209 | void gfx_imm_pop_matrix(ImmRenderer* renderer) { | ||
210 | assert(renderer); | ||
211 | assert(renderer->stack_pointer > 0); // TODO: hard assert. | ||
212 | |||
213 | // For debugging, zero out the matrix stack as matrices are popped out. | ||
214 | memset( | ||
215 | &renderer->matrix_stack[renderer->stack_pointer], 0, | ||
216 | sizeof(renderer->matrix_stack[0])); | ||
217 | |||
218 | renderer->stack_pointer -= 1; | ||
219 | |||
220 | update_shader_model_matrix(renderer); | ||
221 | } | ||
222 | |||
223 | void gfx_imm_translate(ImmRenderer* renderer, vec3 offset) { | ||
224 | assert(renderer); | ||
225 | const mat4 mat = mat4_translate(offset); | ||
226 | gfx_imm_push_matrix(renderer, &mat); | ||
227 | } | ||
228 | |||
229 | void gfx_imm_set_camera(ImmRenderer* renderer, const Camera* camera) { | ||
230 | assert(renderer); | ||
231 | assert(renderer->shader); | ||
232 | imm_renderer_flush(renderer); | ||
233 | const mat4 view = spatial3_inverse_transform(&camera->spatial); | ||
234 | const mat4 view_proj = mat4_mul(camera->projection, view); | ||
235 | gfx_imm_set_view_projection_matrix(renderer, &view_proj); | ||
236 | } | ||
237 | |||
238 | void gfx_imm_set_model_matrix(ImmRenderer* renderer, const mat4* model) { | ||
239 | assert(renderer); | ||
240 | assert(model); | ||
241 | imm_renderer_flush(renderer); | ||
242 | renderer->matrix_stack[0] = *model; | ||
243 | renderer->stack_pointer = 0; | ||
244 | update_shader_model_matrix(renderer); | ||
245 | } | ||
246 | |||
247 | void gfx_imm_set_view_projection_matrix( | ||
248 | ImmRenderer* renderer, const mat4* view_proj) { | ||
249 | assert(renderer); | ||
250 | assert(renderer->shader); | ||
251 | imm_renderer_flush(renderer); | ||
252 | gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj); | ||
253 | } | ||
254 | |||
255 | void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) { | ||
256 | assert(renderer); | ||
257 | assert(renderer->shader); | ||
258 | imm_renderer_flush(renderer); | ||
259 | gfx_set_vec4_uniform(renderer->shader, "Colour", colour); | ||
260 | } | ||