diff options
author | 3gg <3gg@shellblade.net> | 2025-07-04 10:27:06 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-07-04 10:27:06 -0700 |
commit | 1ec46bead3cf87971a2329f9ef4ddde5a0c48325 (patch) | |
tree | 3f4c404467c3ad9c94265295f4aa1b97a10a9eb3 /src | |
parent | e386405ac636b7e4a41d5c03eb363e9c120ce919 (diff) |
Clarify doc
Diffstat (limited to 'src')
-rw-r--r-- | src/llr/imm_renderer.c | 260 | ||||
-rw-r--r-- | src/llr/imm_renderer_impl.h | 44 | ||||
-rw-r--r-- | src/llr/light.c (renamed from src/scene/light.c) | 6 | ||||
-rw-r--r-- | src/llr/light_impl.h (renamed from src/scene/light_impl.h) | 4 | ||||
-rw-r--r-- | src/llr/llr.c | 554 | ||||
-rw-r--r-- | src/llr/llr_impl.h | 99 | ||||
-rw-r--r-- | src/llr/material.c (renamed from src/scene/material.c) | 2 | ||||
-rw-r--r-- | src/llr/material_impl.h (renamed from src/scene/material_impl.h) | 2 | ||||
-rw-r--r-- | src/llr/mesh.c (renamed from src/scene/mesh.c) | 4 | ||||
-rw-r--r-- | src/llr/mesh_impl.h (renamed from src/scene/mesh_impl.h) | 2 |
10 files changed, 663 insertions, 314 deletions
diff --git a/src/llr/imm_renderer.c b/src/llr/imm_renderer.c deleted file mode 100644 index 4b856c9..0000000 --- a/src/llr/imm_renderer.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | #include "../renderer/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 | } | ||
diff --git a/src/llr/imm_renderer_impl.h b/src/llr/imm_renderer_impl.h deleted file mode 100644 index 5ece354..0000000 --- a/src/llr/imm_renderer_impl.h +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/renderer.h> | ||
4 | #include <gfx/sizes.h> | ||
5 | |||
6 | #include <math/mat4.h> | ||
7 | #include <math/vec3.h> | ||
8 | |||
9 | #include <stdbool.h> | ||
10 | #include <stddef.h> | ||
11 | |||
12 | typedef struct Geometry Geometry; | ||
13 | typedef struct ShaderProgram ShaderProgram; | ||
14 | |||
15 | /// Immediate mode renderer. | ||
16 | /// | ||
17 | /// Currently, the immediate mode renderer can only draw up to a maximum number | ||
18 | /// of primitives per frame. It does not adjust this number dynamically. Keeps | ||
19 | /// things simple while the extra complexity is not needed. | ||
20 | typedef struct ImmRenderer { | ||
21 | GfxCore* gfxcore; | ||
22 | ShaderProgram* shader; | ||
23 | Geometry* triangles; | ||
24 | size_t num_triangle_verts; // Number of triangle verts this frame. | ||
25 | // TODO: wireframe rendering. | ||
26 | struct { | ||
27 | bool wireframe : 1; | ||
28 | } flags; | ||
29 | vec3 triangle_verts[IMM_MAX_NUM_TRIANGLES * 3]; | ||
30 | // Matrix stack contains pre-multiplied matrices. | ||
31 | // It is also never empty. The top of the stack is an identity matrix when the | ||
32 | // stack is "empty" from the user's perspective. | ||
33 | mat4 matrix_stack[IMM_MAX_NUM_MATRICES]; | ||
34 | int stack_pointer; | ||
35 | } ImmRenderer; | ||
36 | |||
37 | /// Create a new immediate mode renderer. | ||
38 | bool imm_renderer_make(ImmRenderer*, GfxCore*); | ||
39 | |||
40 | /// Destroy the immediate mode renderer. | ||
41 | void imm_renderer_destroy(ImmRenderer*); | ||
42 | |||
43 | /// Flush draw commands. | ||
44 | void imm_renderer_flush(ImmRenderer*); | ||
diff --git a/src/scene/light.c b/src/llr/light.c index adbec8d..168f16a 100644 --- a/src/scene/light.c +++ b/src/llr/light.c | |||
@@ -1,7 +1,7 @@ | |||
1 | #include "light_impl.h" | 1 | #include "../scene/light_impl.h" |
2 | 2 | ||
3 | #include "node_impl.h" | 3 | #include "../scene/node_impl.h" |
4 | #include "scene_memory.h" | 4 | #include "../scene/scene_memory.h" |
5 | 5 | ||
6 | #include <error.h> | 6 | #include <error.h> |
7 | 7 | ||
diff --git a/src/scene/light_impl.h b/src/llr/light_impl.h index 1aa0bb4..32203c4 100644 --- a/src/scene/light_impl.h +++ b/src/llr/light_impl.h | |||
@@ -1,8 +1,8 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include <gfx/scene/light.h> | 3 | #include <../../include/gfx/llr/light.h> |
4 | 4 | ||
5 | #include "types.h" | 5 | #include "../scene/types.h" |
6 | 6 | ||
7 | typedef struct Texture Texture; | 7 | typedef struct Texture Texture; |
8 | 8 | ||
diff --git a/src/llr/llr.c b/src/llr/llr.c new file mode 100644 index 0000000..62a7c30 --- /dev/null +++ b/src/llr/llr.c | |||
@@ -0,0 +1,554 @@ | |||
1 | #include "imm_renderer_impl.h" | ||
2 | #include "light_impl.h" | ||
3 | #include "mesh_impl.h" | ||
4 | |||
5 | #include "scene/animation_impl.h" | ||
6 | |||
7 | #include <gfx/core.h> | ||
8 | #include <gfx/util/ibl.h> | ||
9 | #include <gfx/util/shader.h> | ||
10 | |||
11 | #include <math/aabb3.h> | ||
12 | |||
13 | #include <cassert.h> | ||
14 | #include <string.h> // memcpy | ||
15 | |||
16 | static const int IRRADIANCE_MAP_WIDTH = 1024; | ||
17 | static const int IRRADIANCE_MAP_HEIGHT = 1024; | ||
18 | static const int PREFILTERED_ENVIRONMENT_MAP_WIDTH = 128; | ||
19 | static const int PREFILTERED_ENVIRONMENT_MAP_HEIGHT = 128; | ||
20 | static const int BRDF_INTEGRATION_MAP_WIDTH = 512; | ||
21 | static const int BRDF_INTEGRATION_MAP_HEIGHT = 512; | ||
22 | |||
23 | /// Initialize renderer state for IBL. | ||
24 | static bool init_ibl(ImmRenderer* renderer) { | ||
25 | assert(renderer); | ||
26 | assert(!renderer->ibl); | ||
27 | assert(!renderer->brdf_integration_map); | ||
28 | |||
29 | if (!((renderer->ibl = gfx_make_ibl(renderer->gfxcore)))) { | ||
30 | return false; | ||
31 | } | ||
32 | |||
33 | if (!((renderer->brdf_integration_map = gfx_make_brdf_integration_map( | ||
34 | renderer->ibl, renderer->gfxcore, BRDF_INTEGRATION_MAP_WIDTH, | ||
35 | BRDF_INTEGRATION_MAP_HEIGHT)))) { | ||
36 | return false; | ||
37 | } | ||
38 | |||
39 | return true; | ||
40 | } | ||
41 | |||
42 | // TODO: Why is this done lazily here? Do it when the environment light is | ||
43 | // created. | ||
44 | // | ||
45 | /// Compute irradiance and prefiltered environment maps for the light if they | ||
46 | /// have not been already computed. | ||
47 | static bool set_up_environment_light( | ||
48 | ImmRenderer* renderer, EnvironmentLight* light) { | ||
49 | assert(renderer); | ||
50 | assert(light); | ||
51 | assert(renderer->ibl); | ||
52 | assert(renderer->brdf_integration_map); | ||
53 | |||
54 | if (light->irradiance_map) { | ||
55 | assert(light->prefiltered_environment_map); | ||
56 | return true; | ||
57 | } | ||
58 | |||
59 | // For convenience. | ||
60 | GfxCore* gfxcore = renderer->gfxcore; | ||
61 | |||
62 | Texture* irradiance_map = 0; | ||
63 | Texture* prefiltered_environment_map = 0; | ||
64 | |||
65 | if (!((irradiance_map = gfx_make_irradiance_map( | ||
66 | renderer->ibl, gfxcore, light->environment_map, | ||
67 | IRRADIANCE_MAP_WIDTH, IRRADIANCE_MAP_HEIGHT)))) { | ||
68 | goto cleanup; | ||
69 | } | ||
70 | |||
71 | int max_mip_level = 0; | ||
72 | if (!((prefiltered_environment_map = gfx_make_prefiltered_environment_map( | ||
73 | renderer->ibl, gfxcore, light->environment_map, | ||
74 | PREFILTERED_ENVIRONMENT_MAP_WIDTH, | ||
75 | PREFILTERED_ENVIRONMENT_MAP_HEIGHT, &max_mip_level)))) { | ||
76 | goto cleanup; | ||
77 | } | ||
78 | |||
79 | light->irradiance_map = irradiance_map; | ||
80 | light->prefiltered_environment_map = prefiltered_environment_map; | ||
81 | light->max_reflection_lod = max_mip_level; | ||
82 | |||
83 | return true; | ||
84 | |||
85 | cleanup: | ||
86 | if (irradiance_map) { | ||
87 | gfx_destroy_texture(gfxcore, &irradiance_map); | ||
88 | } | ||
89 | if (prefiltered_environment_map) { | ||
90 | gfx_destroy_texture(gfxcore, &prefiltered_environment_map); | ||
91 | } | ||
92 | return false; | ||
93 | } | ||
94 | |||
95 | static void configure_light(ImmRenderer* renderer, Light* light) { | ||
96 | assert(renderer); | ||
97 | assert(light); | ||
98 | |||
99 | // For convenience. | ||
100 | ShaderProgram* const shader = renderer->shader; | ||
101 | |||
102 | switch (light->type) { | ||
103 | case EnvironmentLightType: { | ||
104 | EnvironmentLight* env = &light->environment; | ||
105 | |||
106 | const bool initialized = set_up_environment_light(renderer, env); | ||
107 | ASSERT(initialized); | ||
108 | assert(env->environment_map); | ||
109 | assert(env->irradiance_map); | ||
110 | assert(env->prefiltered_environment_map); | ||
111 | assert(renderer->brdf_integration_map); | ||
112 | |||
113 | gfx_set_texture_uniform( | ||
114 | shader, "BRDFIntegrationMap", renderer->brdf_integration_map); | ||
115 | gfx_set_texture_uniform(shader, "Sky", env->environment_map); | ||
116 | gfx_set_texture_uniform(shader, "IrradianceMap", env->irradiance_map); | ||
117 | gfx_set_texture_uniform( | ||
118 | shader, "PrefilteredEnvironmentMap", env->prefiltered_environment_map); | ||
119 | gfx_set_float_uniform( | ||
120 | shader, "MaxReflectionLOD", (float)env->max_reflection_lod); | ||
121 | |||
122 | break; | ||
123 | } | ||
124 | default: | ||
125 | assert(false); // TODO: Implement other light types. | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static void configure_state(ImmRenderer* renderer) { | ||
131 | assert(renderer); | ||
132 | |||
133 | // Check if anything changed first so that we don't call gfx_apply_uniforms() | ||
134 | // unnecessarily. | ||
135 | const bool anything_changed = | ||
136 | renderer->camera_changed || renderer->lights_changed || | ||
137 | renderer->skeleton_changed || renderer->shader_changed; | ||
138 | if (!anything_changed) { | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | // For convenience. | ||
143 | ShaderProgram* const shader = renderer->shader; | ||
144 | |||
145 | // TODO: camera_changed is not set anywhere. Need to think how imm primitive | ||
146 | // rendering and imm mesh rendering work together. We could treat imm | ||
147 | // primitive calls like setting a new shader. | ||
148 | if (renderer->camera_changed || renderer->shader_changed) { | ||
149 | renderer->camera_changed = false; | ||
150 | |||
151 | // Set all supported camera-related uniforms. Shaders can choose which ones | ||
152 | // to use. | ||
153 | // TODO: Check to see which ones the shader actually uses and avoid | ||
154 | // computing the unnecessary matrices. | ||
155 | const mat4* const model = &renderer->matrix_stack[renderer->stack_pointer]; | ||
156 | const mat4 modelview = mat4_mul(renderer->view, *model); | ||
157 | const mat4 view_proj = mat4_mul(renderer->projection, renderer->view); | ||
158 | const mat4 mvp = mat4_mul(renderer->projection, modelview); | ||
159 | |||
160 | gfx_set_mat4_uniform(shader, "ModelMatrix", model); | ||
161 | gfx_set_mat4_uniform(shader, "Modelview", &modelview); | ||
162 | gfx_set_mat4_uniform(shader, "View", &renderer->view); | ||
163 | gfx_set_mat4_uniform(shader, "Projection", &renderer->projection); | ||
164 | gfx_set_mat4_uniform(shader, "ViewProjection", &view_proj); | ||
165 | gfx_set_mat4_uniform(shader, "MVP", &mvp); | ||
166 | gfx_set_vec3_uniform(shader, "CameraPosition", renderer->camera_position); | ||
167 | } | ||
168 | |||
169 | if (renderer->lights_changed || renderer->shader_changed) { | ||
170 | renderer->lights_changed = false; | ||
171 | |||
172 | // TODO: Could do better by only setting the lights that have actually | ||
173 | // changed. | ||
174 | // TODO: Will also need to pass the number of lights to the shader once the | ||
175 | // other light types are implemented. | ||
176 | for (int i = 0; i < renderer->num_lights; ++i) { | ||
177 | configure_light(renderer, renderer->lights[i]); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | if (renderer->skeleton_changed || renderer->shader_changed) { | ||
182 | renderer->skeleton_changed = false; | ||
183 | |||
184 | gfx_set_mat4_array_uniform( | ||
185 | shader, "JointMatrices", renderer->joint_matrices, | ||
186 | renderer->num_joints); | ||
187 | } | ||
188 | |||
189 | if (renderer->shader_changed) { | ||
190 | renderer->shader_changed = false; | ||
191 | gfx_activate_shader_program(renderer->shader); | ||
192 | } | ||
193 | |||
194 | // Must be called after activating the program. | ||
195 | gfx_apply_uniforms(renderer->shader); | ||
196 | } | ||
197 | |||
198 | bool gfx_imm_make(ImmRenderer* renderer, GfxCore* gfxcore) { | ||
199 | assert(renderer); | ||
200 | assert(gfxcore); | ||
201 | |||
202 | const size_t num_triangle_verts = IMM_MAX_NUM_TRIANGLES * 3; | ||
203 | |||
204 | renderer->gfxcore = gfxcore; | ||
205 | |||
206 | renderer->triangles = gfx_make_geometry( | ||
207 | gfxcore, | ||
208 | &(GeometryDesc){.type = Triangles, | ||
209 | .buffer_usage = BufferDynamic, | ||
210 | .num_verts = num_triangle_verts, | ||
211 | .positions3d = (BufferView3d){ | ||
212 | .size_bytes = num_triangle_verts * sizeof(vec3)}}); | ||
213 | if (!renderer->triangles) { | ||
214 | goto cleanup; | ||
215 | } | ||
216 | |||
217 | renderer->imm_shader = gfx_make_immediate_mode_shader(gfxcore); | ||
218 | if (!renderer->imm_shader) { | ||
219 | goto cleanup; | ||
220 | } | ||
221 | renderer->shader = renderer->imm_shader; | ||
222 | |||
223 | if (!init_ibl(renderer)) { | ||
224 | goto cleanup; | ||
225 | } | ||
226 | |||
227 | gfx_imm_load_identity(renderer); | ||
228 | gfx_imm_set_colour(renderer, vec4_make(0.0f, 0.0f, 0.0f, 1.0f)); | ||
229 | |||
230 | return true; | ||
231 | |||
232 | cleanup: | ||
233 | gfx_imm_destroy(renderer); | ||
234 | return false; | ||
235 | } | ||
236 | |||
237 | void gfx_imm_destroy(ImmRenderer* renderer) { | ||
238 | assert(renderer); | ||
239 | assert(renderer->gfxcore); | ||
240 | |||
241 | if (renderer->triangles) { | ||
242 | gfx_destroy_geometry(renderer->gfxcore, &renderer->triangles); | ||
243 | // TODO: Could also destroy the geometry's buffers here. | ||
244 | } | ||
245 | |||
246 | if (renderer->imm_shader) { | ||
247 | gfx_destroy_shader_program(renderer->gfxcore, &renderer->imm_shader); | ||
248 | } | ||
249 | |||
250 | if (renderer->brdf_integration_map) { | ||
251 | gfx_destroy_texture(renderer->gfxcore, &renderer->brdf_integration_map); | ||
252 | } | ||
253 | |||
254 | // TODO: Do this once the IBL from the scene renderer is gone. | ||
255 | if (renderer->ibl) { | ||
256 | // gfx_destroy_ibl(renderer->gfxcore, &renderer->ibl); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void gfx_imm_flush(ImmRenderer* renderer) { | ||
261 | assert(renderer); | ||
262 | |||
263 | if (renderer->num_triangle_verts > 0) { | ||
264 | configure_state(renderer); | ||
265 | |||
266 | gfx_update_geometry( | ||
267 | renderer->triangles, | ||
268 | &(GeometryDesc){ | ||
269 | .num_verts = renderer->num_triangle_verts, | ||
270 | .positions3d = (BufferView3d){ | ||
271 | .data = renderer->triangle_verts, | ||
272 | .size_bytes = renderer->num_triangle_verts * sizeof(vec3)} | ||
273 | }); | ||
274 | |||
275 | gfx_apply_uniforms(renderer->shader); | ||
276 | gfx_render_geometry(renderer->triangles); | ||
277 | |||
278 | renderer->num_triangle_verts = 0; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | void gfx_imm_set_shader(ImmRenderer* renderer, ShaderProgram* shader) { | ||
283 | assert(renderer); | ||
284 | assert(shader); | ||
285 | |||
286 | // TODO: It would probably be best to make the imm renderer work in terms of a | ||
287 | // new LLR renderer. Otherwise we need to constantly flush stuff everywhere | ||
288 | // "just in case". This would still allow the imm to render meshes with | ||
289 | // lighting etc. We just need to create an actual Mesh out of the 'triangles' | ||
290 | // Geometry that imm currently has. The change would greatly simplify the | ||
291 | // implementation of this otherwise coupled LLR-IMM renderer. | ||
292 | // Need to decide where to put the matrix stack manipulation. Might be good | ||
293 | // to move to the LLR. (Currently, manipulating the stack causes an imm | ||
294 | // flush, but that's because we have coupled imm with stack manipulation, | ||
295 | // which the new design seems like would address.) | ||
296 | gfx_imm_flush(renderer); | ||
297 | |||
298 | // It's important to not set shader_changed unnecessarily, since that would | ||
299 | // re-trigger the setting of uniforms. | ||
300 | if (renderer->shader != shader) { | ||
301 | renderer->shader = shader; | ||
302 | renderer->shader_changed = true; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | void gfx_imm_start(ImmRenderer* renderer) { | ||
307 | assert(renderer); | ||
308 | |||
309 | // Shader uniforms are applied lazily. | ||
310 | // TODO: In the event that gfx_activate_shader_program() activates uniforms | ||
311 | // automatically for convenience, call an overload here that doesn't do so. | ||
312 | gfx_activate_shader_program(renderer->shader); | ||
313 | } | ||
314 | |||
315 | void gfx_imm_end(ImmRenderer* renderer) { | ||
316 | assert(renderer); | ||
317 | |||
318 | gfx_imm_flush(renderer); | ||
319 | gfx_deactivate_shader_program(renderer->shader); | ||
320 | |||
321 | // TODO: Should we clear all of the render state here as well? At least set | ||
322 | // the 'changed' variables to false, for example. | ||
323 | } | ||
324 | |||
325 | void gfx_imm_push_light(ImmRenderer* renderer, Light* light) { | ||
326 | assert(renderer); | ||
327 | assert(light); | ||
328 | assert(renderer->num_lights >= 0); | ||
329 | ASSERT(renderer->num_lights < IMM_MAX_NUM_LIGHTS); | ||
330 | |||
331 | renderer->lights[renderer->num_lights++] = light; | ||
332 | renderer->lights_changed = true; | ||
333 | } | ||
334 | |||
335 | void gfx_imm_pop_light(ImmRenderer* renderer) { | ||
336 | assert(renderer); | ||
337 | ASSERT(renderer->num_lights > 0); | ||
338 | |||
339 | renderer->lights[--renderer->num_lights] = 0; | ||
340 | renderer->lights_changed = true; | ||
341 | } | ||
342 | |||
343 | void gfx_imm_set_skeleton( | ||
344 | ImmRenderer* renderer, const Anima* anima, const Skeleton* skeleton) { | ||
345 | assert(renderer); | ||
346 | assert(anima); | ||
347 | assert(skeleton); | ||
348 | assert(skeleton->num_joints <= GFX_MAX_NUM_JOINTS); | ||
349 | |||
350 | for (size_t i = 0; i < skeleton->num_joints; ++i) { | ||
351 | const joint_idx joint_index = skeleton->joints[i]; | ||
352 | const Joint* joint = &anima->joints[joint_index]; | ||
353 | renderer->joint_matrices[i] = joint->joint_matrix; | ||
354 | } | ||
355 | renderer->num_joints = skeleton->num_joints; | ||
356 | renderer->skeleton_changed = true; | ||
357 | } | ||
358 | |||
359 | void gfx_imm_unset_skeleton(ImmRenderer* renderer) { | ||
360 | assert(renderer); | ||
361 | |||
362 | renderer->num_joints = 0; | ||
363 | renderer->skeleton_changed = true; | ||
364 | } | ||
365 | |||
366 | void gfx_imm_render_mesh(ImmRenderer* renderer, const Mesh* mesh) { | ||
367 | assert(renderer); | ||
368 | assert(mesh); | ||
369 | assert(mesh->geometry); | ||
370 | assert(mesh->material); | ||
371 | |||
372 | configure_state(renderer); | ||
373 | gfx_render_geometry(mesh->geometry); | ||
374 | } | ||
375 | |||
376 | void gfx_imm_draw_triangles( | ||
377 | ImmRenderer* renderer, const vec3 verts[], size_t num_triangles) { | ||
378 | assert(renderer); | ||
379 | assert(verts); | ||
380 | const size_t new_verts = num_triangles * 3; | ||
381 | assert( | ||
382 | renderer->num_triangle_verts + new_verts < (IMM_MAX_NUM_TRIANGLES * 3)); | ||
383 | |||
384 | memcpy( | ||
385 | renderer->triangle_verts + renderer->num_triangle_verts, verts, | ||
386 | new_verts * sizeof(vec3)); | ||
387 | |||
388 | renderer->num_triangle_verts += new_verts; | ||
389 | } | ||
390 | |||
391 | void gfx_imm_draw_triangle(ImmRenderer* renderer, const vec3 verts[3]) { | ||
392 | gfx_imm_draw_triangles(renderer, verts, 1); | ||
393 | } | ||
394 | |||
395 | void gfx_imm_draw_aabb2(ImmRenderer* renderer, aabb2 box) { | ||
396 | assert(renderer); | ||
397 | |||
398 | // clang-format off | ||
399 | const vec3 verts[4] = { | ||
400 | vec3_make(box.min.x, box.min.y, 0), // 3 ---- 2 | ||
401 | vec3_make(box.max.x, box.min.y, 0), // | | | ||
402 | vec3_make(box.max.x, box.max.y, 0), // | | | ||
403 | vec3_make(box.min.x, box.max.y, 0)}; // 0 ---- 1 | ||
404 | // clang-format on | ||
405 | |||
406 | #define tri(i0, i1, i2) verts[i0], verts[i1], verts[i2] | ||
407 | const vec3 tris[6] = {tri(0, 1, 2), tri(0, 2, 3)}; | ||
408 | #undef tri | ||
409 | |||
410 | gfx_imm_draw_triangles(renderer, tris, 2); | ||
411 | } | ||
412 | |||
413 | void gfx_imm_draw_aabb3(ImmRenderer* renderer, aabb3 box) { | ||
414 | assert(renderer); | ||
415 | |||
416 | // clang-format off | ||
417 | const vec3 vertices[8] = { | ||
418 | vec3_make(box.min.x, box.min.y, box.max.z), // 7 ----- 6 | ||
419 | vec3_make(box.max.x, box.min.y, box.max.z), // / /| | ||
420 | vec3_make(box.max.x, box.max.y, box.max.z), // 3 ----- 2 | | ||
421 | vec3_make(box.min.x, box.max.y, box.max.z), // | | | | ||
422 | vec3_make(box.min.x, box.min.y, box.min.z), // | 4 ----- 5 | ||
423 | vec3_make(box.max.x, box.min.y, box.min.z), // |/ |/ | ||
424 | vec3_make(box.max.x, box.max.y, box.min.z), // 0 ----- 1 | ||
425 | vec3_make(box.min.x, box.max.y, box.min.z)}; | ||
426 | // clang-format on | ||
427 | |||
428 | gfx_imm_draw_box3(renderer, vertices); | ||
429 | } | ||
430 | |||
431 | void gfx_imm_draw_box3(ImmRenderer* renderer, const vec3 vertices[8]) { | ||
432 | assert(renderer); | ||
433 | assert(vertices); | ||
434 | |||
435 | // 7 ----- 6 | ||
436 | // / /| | ||
437 | // 3 ----- 2 | | ||
438 | // | | | | ||
439 | // | 4 ----- 5 | ||
440 | // |/ |/ | ||
441 | // 0 ----- 1 | ||
442 | |||
443 | #define tri(i0, i1, i2) vertices[i0], vertices[i1], vertices[i2] | ||
444 | const vec3 tris[36] = { | ||
445 | // Front. | ||
446 | tri(0, 1, 2), tri(0, 2, 3), | ||
447 | // Right. | ||
448 | tri(1, 5, 6), tri(1, 6, 2), | ||
449 | // Back. | ||
450 | tri(5, 4, 7), tri(5, 7, 6), | ||
451 | // Left. | ||
452 | tri(4, 0, 03), tri(4, 3, 7), | ||
453 | // Top. | ||
454 | tri(3, 2, 6), tri(3, 6, 7), | ||
455 | // Bottom. | ||
456 | tri(0, 4, 5), tri(0, 5, 1)}; | ||
457 | |||
458 | gfx_imm_draw_triangles(renderer, tris, 12); | ||
459 | } | ||
460 | |||
461 | void gfx_imm_set_colour(ImmRenderer* renderer, vec4 colour) { | ||
462 | assert(renderer); | ||
463 | assert(renderer->shader); | ||
464 | |||
465 | gfx_imm_flush(renderer); | ||
466 | |||
467 | gfx_set_vec4_uniform(renderer->shader, "Colour", colour); | ||
468 | } | ||
469 | |||
470 | // Load the top of the matrix stack into the shader. | ||
471 | static void update_shader_model_matrix(ImmRenderer* renderer) { | ||
472 | assert(renderer); | ||
473 | |||
474 | gfx_imm_flush(renderer); | ||
475 | |||
476 | gfx_set_mat4_uniform( | ||
477 | renderer->shader, "Model", | ||
478 | &renderer->matrix_stack[renderer->stack_pointer]); | ||
479 | } | ||
480 | |||
481 | void gfx_imm_load_identity(ImmRenderer* renderer) { | ||
482 | assert(renderer); | ||
483 | |||
484 | renderer->matrix_stack[0] = mat4_id(); | ||
485 | renderer->stack_pointer = 0; | ||
486 | update_shader_model_matrix(renderer); | ||
487 | } | ||
488 | |||
489 | void gfx_imm_push_matrix(ImmRenderer* renderer, const mat4* matrix) { | ||
490 | assert(renderer); | ||
491 | assert(matrix); | ||
492 | assert(renderer->stack_pointer >= 0); | ||
493 | ASSERT(renderer->stack_pointer < IMM_MAX_NUM_MATRICES); | ||
494 | |||
495 | renderer->stack_pointer += 1; | ||
496 | renderer->matrix_stack[renderer->stack_pointer] = | ||
497 | mat4_mul(*matrix, renderer->matrix_stack[renderer->stack_pointer - 1]); | ||
498 | |||
499 | update_shader_model_matrix(renderer); | ||
500 | } | ||
501 | |||
502 | void gfx_imm_pop_matrix(ImmRenderer* renderer) { | ||
503 | assert(renderer); | ||
504 | ASSERT(renderer->stack_pointer > 0); | ||
505 | |||
506 | // For debugging, zero out the matrix stack as matrices are popped out. | ||
507 | memset( | ||
508 | &renderer->matrix_stack[renderer->stack_pointer], 0, | ||
509 | sizeof(renderer->matrix_stack[0])); | ||
510 | renderer->stack_pointer -= 1; | ||
511 | |||
512 | update_shader_model_matrix(renderer); | ||
513 | } | ||
514 | |||
515 | void gfx_imm_translate(ImmRenderer* renderer, vec3 offset) { | ||
516 | assert(renderer); | ||
517 | |||
518 | const mat4 mat = mat4_translate(offset); | ||
519 | gfx_imm_push_matrix(renderer, &mat); | ||
520 | } | ||
521 | |||
522 | void gfx_imm_set_model_matrix(ImmRenderer* renderer, const mat4* model) { | ||
523 | assert(renderer); | ||
524 | assert(model); | ||
525 | |||
526 | gfx_imm_flush(renderer); | ||
527 | |||
528 | renderer->matrix_stack[0] = *model; | ||
529 | renderer->stack_pointer = 0; | ||
530 | update_shader_model_matrix(renderer); | ||
531 | } | ||
532 | |||
533 | void gfx_imm_set_camera(ImmRenderer* renderer, const Camera* camera) { | ||
534 | assert(renderer); | ||
535 | assert(renderer->shader); | ||
536 | |||
537 | gfx_imm_flush(renderer); | ||
538 | |||
539 | const mat4 view = spatial3_inverse_transform(&camera->spatial); | ||
540 | // const mat4 view_proj = mat4_mul(camera->projection, view); | ||
541 | // gfx_imm_set_view_projection_matrix(renderer, &view_proj); | ||
542 | renderer->view = view; | ||
543 | renderer->projection = camera->projection; | ||
544 | renderer->camera_changed = true; | ||
545 | } | ||
546 | |||
547 | // void gfx_imm_set_view_projection_matrix( | ||
548 | // ImmRenderer* renderer, const mat4* view_proj) { | ||
549 | // assert(renderer); | ||
550 | // assert(renderer->shader); | ||
551 | // | ||
552 | // gfx_imm_flush(renderer); | ||
553 | // gfx_set_mat4_uniform(renderer->shader, "ViewProjection", view_proj); | ||
554 | // } | ||
diff --git a/src/llr/llr_impl.h b/src/llr/llr_impl.h new file mode 100644 index 0000000..5ccabd1 --- /dev/null +++ b/src/llr/llr_impl.h | |||
@@ -0,0 +1,99 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/llr/llr.h> | ||
4 | #include <gfx/sizes.h> | ||
5 | |||
6 | #include <math/mat4.h> | ||
7 | #include <math/vec3.h> | ||
8 | |||
9 | #include <stdbool.h> | ||
10 | #include <stddef.h> | ||
11 | |||
12 | typedef struct Geometry Geometry; | ||
13 | typedef struct GfxCore GfxCore; | ||
14 | typedef struct IBL IBL; | ||
15 | typedef struct Material Material; | ||
16 | typedef struct ShaderProgram ShaderProgram; | ||
17 | typedef struct Texture Texture; | ||
18 | |||
19 | /// Immediate mode renderer. | ||
20 | /// | ||
21 | /// The renderer caches state changes in memory and only programs the underlying | ||
22 | /// shader program when a draw call is issued and if anything has changed. This | ||
23 | /// keeps the number of graphics API calls to a minimum, but requires tracking | ||
24 | /// state changes. The 'changed' booleans below fulfill this purpose, and | ||
25 | /// indicate whether a given state has changed since the last draw call. | ||
26 | /// | ||
27 | /// The renderer must combine state changes accordingly. For example, if only | ||
28 | /// the lights have changed, then it is sufficient to update light uniforms in | ||
29 | /// the current shader program. On the other hand, if the shader program has | ||
30 | /// changed, then the renderer must reconfigure it from scratch and set light | ||
31 | /// uniforms, camera uniforms, etc. | ||
32 | /// | ||
33 | /// Note that the shader program API has its own level of caching as well, so | ||
34 | /// reconfiguration at the level of the renderer does not result in the | ||
35 | /// worst-case set of graphics API calls. | ||
36 | /// | ||
37 | /// Currently, the immediate mode renderer can only draw up to a maximum number | ||
38 | /// of primitives per frame. It does not adjust this number dynamically. Keeps | ||
39 | /// things simple while the extra complexity is not needed. | ||
40 | /// TODO: Flush the buffer when it reaches its maximum size to remove this | ||
41 | /// constraint. | ||
42 | typedef struct ImmRenderer { | ||
43 | GfxCore* gfxcore; | ||
44 | |||
45 | vec3 camera_position; | ||
46 | mat4 view; // Camera view matrix. | ||
47 | mat4 projection; // Camera projection matrix. | ||
48 | bool camera_changed; // Whether the camera parameters have changed. | ||
49 | |||
50 | // ------------------------------------------- | ||
51 | // Immediate-mode rendering of scene elements. | ||
52 | |||
53 | IBL* ibl; | ||
54 | Texture* brdf_integration_map; | ||
55 | |||
56 | ShaderProgram* shader; // Active shader. Not owned. | ||
57 | bool shader_changed; // Whether the shader has changed. | ||
58 | |||
59 | // Lights are not const because environment lights store lazily-computed | ||
60 | // irradiance maps. | ||
61 | Light* lights[IMM_MAX_NUM_LIGHTS]; // Lights stack. | ||
62 | int num_lights; // Number of lights enabled at a given point in time. It | ||
63 | // points to one past the top of the stack. | ||
64 | bool lights_changed; // Whether the lights have changed. | ||
65 | |||
66 | bool skeleton_changed; | ||
67 | size_t num_joints; | ||
68 | mat4 joint_matrices[GFX_MAX_NUM_JOINTS]; | ||
69 | |||
70 | // --------------------------------------- | ||
71 | // Immediate-mode rendering of primitives. | ||
72 | |||
73 | ShaderProgram* imm_shader; // Immediate-mode shader program for primitives. | ||
74 | Geometry* triangles; | ||
75 | size_t num_triangle_verts; // Number of triangle verts this frame. | ||
76 | // TODO: wireframe rendering. | ||
77 | struct { | ||
78 | bool wireframe : 1; | ||
79 | } flags; | ||
80 | vec3 triangle_verts[IMM_MAX_NUM_TRIANGLES * 3]; | ||
81 | |||
82 | // ------------- | ||
83 | // Matrix stack. | ||
84 | |||
85 | // The matrix stack contains pre-multiplied matrices. | ||
86 | // It is also never empty. The top of the stack is an identity matrix when the | ||
87 | // stack is "empty" from the user's perspective. | ||
88 | mat4 matrix_stack[IMM_MAX_NUM_MATRICES]; | ||
89 | int stack_pointer; // Points to the top of the stack. | ||
90 | } ImmRenderer; | ||
91 | |||
92 | /// Create a new immediate mode renderer. | ||
93 | bool gfx_imm_make(ImmRenderer*, GfxCore*); | ||
94 | |||
95 | /// Destroy the immediate mode renderer. | ||
96 | void gfx_imm_destroy(ImmRenderer*); | ||
97 | |||
98 | /// Flush draw commands. | ||
99 | void gfx_imm_flush(ImmRenderer*); | ||
diff --git a/src/scene/material.c b/src/llr/material.c index 3248243..47cb45f 100644 --- a/src/scene/material.c +++ b/src/llr/material.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include "material_impl.h" | 1 | #include "material_impl.h" |
2 | 2 | ||
3 | #include "scene_memory.h" | 3 | #include "../scene/scene_memory.h" |
4 | 4 | ||
5 | #include <gfx/core.h> | 5 | #include <gfx/core.h> |
6 | 6 | ||
diff --git a/src/scene/material_impl.h b/src/llr/material_impl.h index a6aa95b..f27bf4d 100644 --- a/src/scene/material_impl.h +++ b/src/llr/material_impl.h | |||
@@ -1,6 +1,6 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include <gfx/scene/material.h> | 3 | #include <../../include/gfx/llr/material.h> |
4 | 4 | ||
5 | typedef struct ShaderProgram ShaderProgram; | 5 | typedef struct ShaderProgram ShaderProgram; |
6 | 6 | ||
diff --git a/src/scene/mesh.c b/src/llr/mesh.c index 1a93bed..ae75d8c 100644 --- a/src/scene/mesh.c +++ b/src/llr/mesh.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include "mesh_impl.h" | 1 | #include "../scene/mesh_impl.h" |
2 | 2 | ||
3 | #include "scene_memory.h" | 3 | #include "../scene/scene_memory.h" |
4 | 4 | ||
5 | #include <assert.h> | 5 | #include <assert.h> |
6 | 6 | ||
diff --git a/src/scene/mesh_impl.h b/src/llr/mesh_impl.h index 560b77e..47ff525 100644 --- a/src/scene/mesh_impl.h +++ b/src/llr/mesh_impl.h | |||
@@ -1,6 +1,6 @@ | |||
1 | #pragma once | 1 | #pragma once |
2 | 2 | ||
3 | #include <gfx/scene/mesh.h> | 3 | #include <../../include/gfx/llr/mesh.h> |
4 | 4 | ||
5 | typedef struct Mesh { | 5 | typedef struct Mesh { |
6 | const Geometry* geometry; | 6 | const Geometry* geometry; |