aboutsummaryrefslogtreecommitdiff
path: root/src/core/core.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-06-27 10:18:39 -0700
committer3gg <3gg@shellblade.net>2025-06-27 10:18:39 -0700
commitbd57f345ed9dbed1d81683e48199626de2ea9044 (patch)
tree4221f2f2a7ad2244d2e93052bd68187ec91b8ea9 /src/core/core.c
parent9a82ce0083437a4f9f58108b2c23b957d2249ad8 (diff)
Restructure projectHEADmain
Diffstat (limited to 'src/core/core.c')
-rw-r--r--src/core/core.c429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/core/core.c b/src/core/core.c
new file mode 100644
index 0000000..90038c6
--- /dev/null
+++ b/src/core/core.c
@@ -0,0 +1,429 @@
1#include "core_impl.h"
2
3#include "gl_util.h"
4
5// #include <log/log.h>
6
7#include <assert.h>
8
9void gfx_init_gfxcore(GfxCore* gfxcore) {
10 assert(gfxcore);
11
12 mempool_make(&gfxcore->buffers);
13 mempool_make(&gfxcore->framebuffers);
14 mempool_make(&gfxcore->geometries);
15 mempool_make(&gfxcore->renderbuffers);
16 mempool_make(&gfxcore->shaders);
17 mempool_make(&gfxcore->shader_programs);
18 mempool_make(&gfxcore->textures);
19
20 mempool_make(&gfxcore->shader_cache);
21 mempool_make(&gfxcore->program_cache);
22
23 glEnable(GL_CULL_FACE);
24 glFrontFace(GL_CCW);
25 glCullFace(GL_BACK);
26
27 glEnable(GL_DEPTH_TEST);
28
29 // Filter cubemaps across their faces to avoid seams.
30 // https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap
31 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
32}
33
34// Conveniently destroy any objects that have not been destroyed by the
35// application.
36void gfx_del_gfxcore(GfxCore* gfxcore) {
37 assert(gfxcore);
38
39 mempool_foreach(&gfxcore->buffers, buffer, { gfx_del_buffer(buffer); });
40
41 mempool_foreach(&gfxcore->framebuffers, framebuffer, {
42 gfx_del_framebuffer(framebuffer);
43 });
44
45 mempool_foreach(
46 &gfxcore->geometries, geometry, { gfx_del_geometry(geometry); });
47
48 mempool_foreach(&gfxcore->renderbuffers, renderbuffer, {
49 gfx_del_renderbuffer(renderbuffer);
50 });
51
52 mempool_foreach(
53 &gfxcore->shader_programs, prog, { gfx_del_shader_program(prog); });
54
55 mempool_foreach(&gfxcore->shaders, shader, { gfx_del_shader(shader); });
56
57 mempool_foreach(&gfxcore->textures, texture, { gfx_del_texture(texture); });
58}
59
60// -----------------------------------------------------------------------------
61// Render commands.
62// -----------------------------------------------------------------------------
63
64void gfx_start_frame(GfxCore* gfxcore) {
65 assert(gfxcore);
66
67 glViewport(
68 gfxcore->viewport.x, gfxcore->viewport.y, gfxcore->viewport.width,
69 gfxcore->viewport.height);
70 glClearColor(0, 0, 0, 0);
71 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
72
73 ASSERT_GL;
74}
75
76void gfx_end_frame(GfxCore* gfxcore) {
77 assert(gfxcore);
78 ASSERT_GL;
79}
80
81void gfx_set_viewport(GfxCore* gfxcore, int x, int y, int width, int height) {
82 assert(gfxcore);
83 gfxcore->viewport =
84 (Viewport){.x = x, .y = y, .width = width, .height = height};
85}
86
87void gfx_get_viewport(
88 GfxCore* gfxcore, int* x, int* y, int* width, int* height) {
89 assert(gfxcore);
90 assert(x);
91 assert(y);
92 assert(width);
93 assert(height);
94
95 *x = gfxcore->viewport.x;
96 *y = gfxcore->viewport.y;
97 *width = gfxcore->viewport.width;
98 *height = gfxcore->viewport.height;
99}
100
101void gfx_clear(GfxCore* gfxcore, vec4 colour) {
102 assert(gfxcore);
103
104 glClearColor(colour.x, colour.y, colour.z, colour.w);
105 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
106}
107
108void gfx_set_blending(GfxCore* gfxcore, bool enable) {
109 assert(gfxcore);
110 if (enable) {
111 glEnable(GL_BLEND);
112 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
113 } else {
114 glDisable(GL_BLEND);
115 }
116}
117
118void gfx_set_depth_mask(GfxCore* gfxcore, bool enable) {
119 assert(gfxcore);
120 glDepthMask(enable ? GL_TRUE : GL_FALSE);
121}
122
123void gfx_set_culling(GfxCore* gfxcore, bool enable) {
124 assert(gfxcore);
125 if (enable) {
126 glEnable(GL_CULL_FACE);
127 } else {
128 glDisable(GL_CULL_FACE);
129 }
130}
131
132void gfx_set_polygon_offset(GfxCore* gfxcore, float scale, float bias) {
133 assert(gfxcore);
134 if ((scale != 0.0f) || (bias != 0.0f)) {
135 glEnable(GL_POLYGON_OFFSET_FILL);
136 } else {
137 glDisable(GL_POLYGON_OFFSET_FILL);
138 }
139 glPolygonOffset(scale, bias);
140}
141
142void gfx_reset_polygon_offset(GfxCore* gfxcore) {
143 assert(gfxcore);
144 glPolygonOffset(0, 0);
145 glDisable(GL_POLYGON_OFFSET_FILL);
146}
147
148// -----------------------------------------------------------------------------
149// Buffers.
150// -----------------------------------------------------------------------------
151
152Buffer* gfx_make_buffer(GfxCore* gfxcore, const BufferDesc* desc) {
153 assert(gfxcore);
154 assert(desc);
155
156 Buffer* buffer = mempool_alloc(&gfxcore->buffers);
157 if (!gfx_init_buffer(buffer, desc)) {
158 mempool_free(&gfxcore->buffers, &buffer);
159 return 0;
160 }
161 return buffer;
162}
163
164void gfx_destroy_buffer(GfxCore* gfxcore, Buffer** buffer) {
165 assert(gfxcore);
166 assert(buffer);
167 if (*buffer) {
168 gfx_del_buffer(*buffer);
169 mempool_free(&gfxcore->buffers, buffer);
170 }
171}
172
173// -----------------------------------------------------------------------------
174// Geometry.
175// -----------------------------------------------------------------------------
176
177Geometry* gfx_make_geometry(GfxCore* gfxcore, const GeometryDesc* desc) {
178 assert(gfxcore);
179 assert(desc);
180
181 Geometry* geometry = mempool_alloc(&gfxcore->geometries);
182 if (!gfx_init_geometry(geometry, gfxcore, desc)) {
183 mempool_free(&gfxcore->geometries, &geometry);
184 return 0;
185 }
186 return geometry;
187}
188
189void gfx_destroy_geometry(GfxCore* gfxcore, Geometry** geometry) {
190 assert(gfxcore);
191 assert(geometry);
192
193 if (*geometry) {
194 gfx_del_geometry(*geometry);
195 mempool_free(&gfxcore->geometries, geometry);
196 }
197}
198
199// -----------------------------------------------------------------------------
200// Textures.
201// -----------------------------------------------------------------------------
202
203Texture* gfx_make_texture(GfxCore* gfxcore, const TextureDesc* desc) {
204 assert(gfxcore);
205 assert(desc);
206
207 Texture* texture = mempool_alloc(&gfxcore->textures);
208 if (!gfx_init_texture(texture, desc)) {
209 mempool_free(&gfxcore->textures, &texture);
210 return 0;
211 }
212 return texture;
213}
214
215void gfx_destroy_texture(GfxCore* gfxcore, Texture** texture) {
216 assert(gfxcore);
217 assert(texture);
218 assert(*texture);
219
220 if (*texture) {
221 gfx_del_texture(*texture);
222 mempool_free(&gfxcore->textures, texture);
223 }
224}
225
226// -----------------------------------------------------------------------------
227// Renderbuffers.
228// -----------------------------------------------------------------------------
229
230RenderBuffer* gfx_make_renderbuffer(
231 GfxCore* gfxcore, const RenderBufferDesc* desc) {
232 assert(gfxcore);
233 assert(desc);
234
235 RenderBuffer* renderbuffer = mempool_alloc(&gfxcore->renderbuffers);
236 if (!gfx_init_renderbuffer(renderbuffer, desc)) {
237 mempool_free(&gfxcore->renderbuffers, &renderbuffer);
238 }
239 return renderbuffer;
240}
241
242void gfx_destroy_renderbuffer(GfxCore* gfxcore, RenderBuffer** renderbuffer) {
243 assert(gfxcore);
244 assert(renderbuffer);
245 assert(*renderbuffer);
246
247 if (*renderbuffer) {
248 gfx_del_renderbuffer(*renderbuffer);
249 mempool_free(&gfxcore->renderbuffers, renderbuffer);
250 }
251}
252
253// -----------------------------------------------------------------------------
254// Framebuffers.
255// -----------------------------------------------------------------------------
256
257FrameBuffer* gfx_make_framebuffer(
258 GfxCore* gfxcore, const FrameBufferDesc* desc) {
259 assert(gfxcore);
260 assert(desc);
261
262 FrameBuffer* framebuffer = mempool_alloc(&gfxcore->framebuffers);
263 if (!gfx_init_framebuffer(framebuffer, desc)) {
264 mempool_free(&gfxcore->framebuffers, &framebuffer);
265 return 0;
266 }
267 return framebuffer;
268}
269
270void gfx_destroy_framebuffer(GfxCore* gfxcore, FrameBuffer** framebuffer) {
271 assert(gfxcore);
272 assert(framebuffer);
273 assert(*framebuffer);
274
275 if (*framebuffer) {
276 gfx_del_framebuffer(*framebuffer);
277 mempool_free(&gfxcore->framebuffers, framebuffer);
278 }
279}
280
281// -----------------------------------------------------------------------------
282// Shaders.
283// -----------------------------------------------------------------------------
284
285static uint64_t hash_shader_desc(const ShaderDesc* desc) {
286 assert(desc);
287 // Note that defines may affect shader permutations, so we need to hash those
288 // as well.
289 uint64_t hash = 0;
290 for (size_t i = 0; i < desc->num_defines; ++i) {
291 const ShaderCompilerDefine* define = &desc->defines[i];
292 hash = (((hash << 13) + sstring_hash(define->name)) << 7) +
293 sstring_hash(define->value);
294 }
295 return (hash << 17) + cstring_hash(desc->code);
296}
297
298static uint64_t hash_program_desc(const ShaderProgramDesc* desc) {
299 assert(desc);
300 return ((uint64_t)desc->vertex_shader->id << 32) |
301 (uint64_t)desc->fragment_shader->id;
302}
303
304static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) {
305 assert(cache);
306 mempool_foreach(cache, entry, {
307 if (entry->hash == hash) {
308 return entry->shader;
309 }
310 });
311 return 0;
312}
313
314static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) {
315 assert(cache);
316 mempool_foreach(cache, entry, {
317 if (entry->hash == hash) {
318 return entry->program;
319 }
320 });
321 return 0;
322}
323
324static ShaderCacheEntry* find_shader_cache_entry(
325 ShaderCache* cache, const Shader* shader) {
326 assert(cache);
327 assert(shader);
328 mempool_foreach(cache, entry, {
329 if (entry->shader == shader) {
330 return entry;
331 }
332 });
333 return 0;
334}
335
336static ShaderProgramCacheEntry* find_program_cache_entry(
337 ProgramCache* cache, const ShaderProgram* prog) {
338 assert(cache);
339 assert(prog);
340 mempool_foreach(cache, entry, {
341 if (entry->program == prog) {
342 return entry;
343 }
344 });
345 return 0;
346}
347
348Shader* gfx_make_shader(GfxCore* gfxcore, const ShaderDesc* desc) {
349 assert(gfxcore);
350 assert(desc);
351
352 // Check the shader cache first.
353 ShaderCache* cache = &gfxcore->shader_cache;
354 const uint64_t hash = hash_shader_desc(desc);
355 Shader* shader = find_cached_shader(cache, hash);
356 if (shader) {
357 // LOGD("Found cached shader with hash [%lx]", hash);
358 return shader;
359 }
360
361 shader = mempool_alloc(&gfxcore->shaders);
362 if (!shader) {
363 return 0;
364 }
365 if (!gfx_compile_shader(shader, desc)) {
366 mempool_free(&gfxcore->shaders, &shader);
367 return 0;
368 }
369 ShaderCacheEntry* entry = mempool_alloc(cache);
370 *entry = (ShaderCacheEntry){.hash = hash, .shader = shader};
371 // LOGD("Added shader with hash [%lx] to cache", hash);
372 return shader;
373}
374
375void gfx_destroy_shader(GfxCore* gfxcore, Shader** shader) {
376 assert(gfxcore);
377 assert(shader);
378
379 if (*shader) {
380 // Remove the shader from the cache.
381 ShaderCache* cache = &gfxcore->shader_cache;
382 ShaderCacheEntry* entry = find_shader_cache_entry(cache, *shader);
383 assert(entry); // Must be there, shaders can't go untracked.
384 mempool_free(cache, &entry);
385
386 gfx_del_shader(*shader);
387 mempool_free(&gfxcore->shaders, shader);
388 }
389}
390
391ShaderProgram* gfx_make_shader_program(
392 GfxCore* gfxcore, const ShaderProgramDesc* desc) {
393 assert(gfxcore);
394 assert(desc);
395
396 // Check the shader program cache first.
397 ProgramCache* cache = &gfxcore->program_cache;
398 const uint64_t hash = hash_program_desc(desc);
399 ShaderProgram* prog = find_cached_program(cache, hash);
400 if (prog) {
401 // LOGD("Found cached shader program with hash [%lx]", hash);
402 return prog;
403 }
404
405 prog = mempool_alloc(&gfxcore->shader_programs);
406 if (!gfx_build_shader_program(prog, desc)) {
407 mempool_free(&gfxcore->shader_programs, &prog);
408 return 0;
409 }
410 ShaderProgramCacheEntry* entry = mempool_alloc(cache);
411 *entry = (ShaderProgramCacheEntry){.hash = hash, .program = prog};
412 // LOGD("Added shader program with hash [%lx] to cache", hash);
413 return prog;
414}
415
416void gfx_destroy_shader_program(GfxCore* gfxcore, ShaderProgram** prog) {
417 assert(gfxcore);
418 assert(prog);
419 if (*prog) {
420 // Remove the shader program from the cache.
421 ProgramCache* cache = &gfxcore->program_cache;
422 ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog);
423 assert(entry); // Must be there, shaders can't go untracked.
424 mempool_free(cache, &entry);
425
426 gfx_del_shader_program(*prog);
427 mempool_free(&gfxcore->shader_programs, prog);
428 }
429}