From bd57f345ed9dbed1d81683e48199626de2ea9044 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 27 Jun 2025 10:18:39 -0700 Subject: Restructure project --- src/core/core.c | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 429 insertions(+) create mode 100644 src/core/core.c (limited to 'src/core/core.c') 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 @@ +#include "core_impl.h" + +#include "gl_util.h" + +// #include + +#include + +void gfx_init_gfxcore(GfxCore* gfxcore) { + assert(gfxcore); + + mempool_make(&gfxcore->buffers); + mempool_make(&gfxcore->framebuffers); + mempool_make(&gfxcore->geometries); + mempool_make(&gfxcore->renderbuffers); + mempool_make(&gfxcore->shaders); + mempool_make(&gfxcore->shader_programs); + mempool_make(&gfxcore->textures); + + mempool_make(&gfxcore->shader_cache); + mempool_make(&gfxcore->program_cache); + + glEnable(GL_CULL_FACE); + glFrontFace(GL_CCW); + glCullFace(GL_BACK); + + glEnable(GL_DEPTH_TEST); + + // Filter cubemaps across their faces to avoid seams. + // https://www.khronos.org/opengl/wiki/Cubemap_Texture#Seamless_cubemap + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); +} + +// Conveniently destroy any objects that have not been destroyed by the +// application. +void gfx_del_gfxcore(GfxCore* gfxcore) { + assert(gfxcore); + + mempool_foreach(&gfxcore->buffers, buffer, { gfx_del_buffer(buffer); }); + + mempool_foreach(&gfxcore->framebuffers, framebuffer, { + gfx_del_framebuffer(framebuffer); + }); + + mempool_foreach( + &gfxcore->geometries, geometry, { gfx_del_geometry(geometry); }); + + mempool_foreach(&gfxcore->renderbuffers, renderbuffer, { + gfx_del_renderbuffer(renderbuffer); + }); + + mempool_foreach( + &gfxcore->shader_programs, prog, { gfx_del_shader_program(prog); }); + + mempool_foreach(&gfxcore->shaders, shader, { gfx_del_shader(shader); }); + + mempool_foreach(&gfxcore->textures, texture, { gfx_del_texture(texture); }); +} + +// ----------------------------------------------------------------------------- +// Render commands. +// ----------------------------------------------------------------------------- + +void gfx_start_frame(GfxCore* gfxcore) { + assert(gfxcore); + + glViewport( + gfxcore->viewport.x, gfxcore->viewport.y, gfxcore->viewport.width, + gfxcore->viewport.height); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ASSERT_GL; +} + +void gfx_end_frame(GfxCore* gfxcore) { + assert(gfxcore); + ASSERT_GL; +} + +void gfx_set_viewport(GfxCore* gfxcore, int x, int y, int width, int height) { + assert(gfxcore); + gfxcore->viewport = + (Viewport){.x = x, .y = y, .width = width, .height = height}; +} + +void gfx_get_viewport( + GfxCore* gfxcore, int* x, int* y, int* width, int* height) { + assert(gfxcore); + assert(x); + assert(y); + assert(width); + assert(height); + + *x = gfxcore->viewport.x; + *y = gfxcore->viewport.y; + *width = gfxcore->viewport.width; + *height = gfxcore->viewport.height; +} + +void gfx_clear(GfxCore* gfxcore, vec4 colour) { + assert(gfxcore); + + glClearColor(colour.x, colour.y, colour.z, colour.w); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void gfx_set_blending(GfxCore* gfxcore, bool enable) { + assert(gfxcore); + if (enable) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); + } +} + +void gfx_set_depth_mask(GfxCore* gfxcore, bool enable) { + assert(gfxcore); + glDepthMask(enable ? GL_TRUE : GL_FALSE); +} + +void gfx_set_culling(GfxCore* gfxcore, bool enable) { + assert(gfxcore); + if (enable) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } +} + +void gfx_set_polygon_offset(GfxCore* gfxcore, float scale, float bias) { + assert(gfxcore); + if ((scale != 0.0f) || (bias != 0.0f)) { + glEnable(GL_POLYGON_OFFSET_FILL); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + } + glPolygonOffset(scale, bias); +} + +void gfx_reset_polygon_offset(GfxCore* gfxcore) { + assert(gfxcore); + glPolygonOffset(0, 0); + glDisable(GL_POLYGON_OFFSET_FILL); +} + +// ----------------------------------------------------------------------------- +// Buffers. +// ----------------------------------------------------------------------------- + +Buffer* gfx_make_buffer(GfxCore* gfxcore, const BufferDesc* desc) { + assert(gfxcore); + assert(desc); + + Buffer* buffer = mempool_alloc(&gfxcore->buffers); + if (!gfx_init_buffer(buffer, desc)) { + mempool_free(&gfxcore->buffers, &buffer); + return 0; + } + return buffer; +} + +void gfx_destroy_buffer(GfxCore* gfxcore, Buffer** buffer) { + assert(gfxcore); + assert(buffer); + if (*buffer) { + gfx_del_buffer(*buffer); + mempool_free(&gfxcore->buffers, buffer); + } +} + +// ----------------------------------------------------------------------------- +// Geometry. +// ----------------------------------------------------------------------------- + +Geometry* gfx_make_geometry(GfxCore* gfxcore, const GeometryDesc* desc) { + assert(gfxcore); + assert(desc); + + Geometry* geometry = mempool_alloc(&gfxcore->geometries); + if (!gfx_init_geometry(geometry, gfxcore, desc)) { + mempool_free(&gfxcore->geometries, &geometry); + return 0; + } + return geometry; +} + +void gfx_destroy_geometry(GfxCore* gfxcore, Geometry** geometry) { + assert(gfxcore); + assert(geometry); + + if (*geometry) { + gfx_del_geometry(*geometry); + mempool_free(&gfxcore->geometries, geometry); + } +} + +// ----------------------------------------------------------------------------- +// Textures. +// ----------------------------------------------------------------------------- + +Texture* gfx_make_texture(GfxCore* gfxcore, const TextureDesc* desc) { + assert(gfxcore); + assert(desc); + + Texture* texture = mempool_alloc(&gfxcore->textures); + if (!gfx_init_texture(texture, desc)) { + mempool_free(&gfxcore->textures, &texture); + return 0; + } + return texture; +} + +void gfx_destroy_texture(GfxCore* gfxcore, Texture** texture) { + assert(gfxcore); + assert(texture); + assert(*texture); + + if (*texture) { + gfx_del_texture(*texture); + mempool_free(&gfxcore->textures, texture); + } +} + +// ----------------------------------------------------------------------------- +// Renderbuffers. +// ----------------------------------------------------------------------------- + +RenderBuffer* gfx_make_renderbuffer( + GfxCore* gfxcore, const RenderBufferDesc* desc) { + assert(gfxcore); + assert(desc); + + RenderBuffer* renderbuffer = mempool_alloc(&gfxcore->renderbuffers); + if (!gfx_init_renderbuffer(renderbuffer, desc)) { + mempool_free(&gfxcore->renderbuffers, &renderbuffer); + } + return renderbuffer; +} + +void gfx_destroy_renderbuffer(GfxCore* gfxcore, RenderBuffer** renderbuffer) { + assert(gfxcore); + assert(renderbuffer); + assert(*renderbuffer); + + if (*renderbuffer) { + gfx_del_renderbuffer(*renderbuffer); + mempool_free(&gfxcore->renderbuffers, renderbuffer); + } +} + +// ----------------------------------------------------------------------------- +// Framebuffers. +// ----------------------------------------------------------------------------- + +FrameBuffer* gfx_make_framebuffer( + GfxCore* gfxcore, const FrameBufferDesc* desc) { + assert(gfxcore); + assert(desc); + + FrameBuffer* framebuffer = mempool_alloc(&gfxcore->framebuffers); + if (!gfx_init_framebuffer(framebuffer, desc)) { + mempool_free(&gfxcore->framebuffers, &framebuffer); + return 0; + } + return framebuffer; +} + +void gfx_destroy_framebuffer(GfxCore* gfxcore, FrameBuffer** framebuffer) { + assert(gfxcore); + assert(framebuffer); + assert(*framebuffer); + + if (*framebuffer) { + gfx_del_framebuffer(*framebuffer); + mempool_free(&gfxcore->framebuffers, framebuffer); + } +} + +// ----------------------------------------------------------------------------- +// Shaders. +// ----------------------------------------------------------------------------- + +static uint64_t hash_shader_desc(const ShaderDesc* desc) { + assert(desc); + // Note that defines may affect shader permutations, so we need to hash those + // as well. + uint64_t hash = 0; + for (size_t i = 0; i < desc->num_defines; ++i) { + const ShaderCompilerDefine* define = &desc->defines[i]; + hash = (((hash << 13) + sstring_hash(define->name)) << 7) + + sstring_hash(define->value); + } + return (hash << 17) + cstring_hash(desc->code); +} + +static uint64_t hash_program_desc(const ShaderProgramDesc* desc) { + assert(desc); + return ((uint64_t)desc->vertex_shader->id << 32) | + (uint64_t)desc->fragment_shader->id; +} + +static Shader* find_cached_shader(ShaderCache* cache, uint64_t hash) { + assert(cache); + mempool_foreach(cache, entry, { + if (entry->hash == hash) { + return entry->shader; + } + }); + return 0; +} + +static ShaderProgram* find_cached_program(ProgramCache* cache, uint64_t hash) { + assert(cache); + mempool_foreach(cache, entry, { + if (entry->hash == hash) { + return entry->program; + } + }); + return 0; +} + +static ShaderCacheEntry* find_shader_cache_entry( + ShaderCache* cache, const Shader* shader) { + assert(cache); + assert(shader); + mempool_foreach(cache, entry, { + if (entry->shader == shader) { + return entry; + } + }); + return 0; +} + +static ShaderProgramCacheEntry* find_program_cache_entry( + ProgramCache* cache, const ShaderProgram* prog) { + assert(cache); + assert(prog); + mempool_foreach(cache, entry, { + if (entry->program == prog) { + return entry; + } + }); + return 0; +} + +Shader* gfx_make_shader(GfxCore* gfxcore, const ShaderDesc* desc) { + assert(gfxcore); + assert(desc); + + // Check the shader cache first. + ShaderCache* cache = &gfxcore->shader_cache; + const uint64_t hash = hash_shader_desc(desc); + Shader* shader = find_cached_shader(cache, hash); + if (shader) { + // LOGD("Found cached shader with hash [%lx]", hash); + return shader; + } + + shader = mempool_alloc(&gfxcore->shaders); + if (!shader) { + return 0; + } + if (!gfx_compile_shader(shader, desc)) { + mempool_free(&gfxcore->shaders, &shader); + return 0; + } + ShaderCacheEntry* entry = mempool_alloc(cache); + *entry = (ShaderCacheEntry){.hash = hash, .shader = shader}; + // LOGD("Added shader with hash [%lx] to cache", hash); + return shader; +} + +void gfx_destroy_shader(GfxCore* gfxcore, Shader** shader) { + assert(gfxcore); + assert(shader); + + if (*shader) { + // Remove the shader from the cache. + ShaderCache* cache = &gfxcore->shader_cache; + ShaderCacheEntry* entry = find_shader_cache_entry(cache, *shader); + assert(entry); // Must be there, shaders can't go untracked. + mempool_free(cache, &entry); + + gfx_del_shader(*shader); + mempool_free(&gfxcore->shaders, shader); + } +} + +ShaderProgram* gfx_make_shader_program( + GfxCore* gfxcore, const ShaderProgramDesc* desc) { + assert(gfxcore); + assert(desc); + + // Check the shader program cache first. + ProgramCache* cache = &gfxcore->program_cache; + const uint64_t hash = hash_program_desc(desc); + ShaderProgram* prog = find_cached_program(cache, hash); + if (prog) { + // LOGD("Found cached shader program with hash [%lx]", hash); + return prog; + } + + prog = mempool_alloc(&gfxcore->shader_programs); + if (!gfx_build_shader_program(prog, desc)) { + mempool_free(&gfxcore->shader_programs, &prog); + return 0; + } + ShaderProgramCacheEntry* entry = mempool_alloc(cache); + *entry = (ShaderProgramCacheEntry){.hash = hash, .program = prog}; + // LOGD("Added shader program with hash [%lx] to cache", hash); + return prog; +} + +void gfx_destroy_shader_program(GfxCore* gfxcore, ShaderProgram** prog) { + assert(gfxcore); + assert(prog); + if (*prog) { + // Remove the shader program from the cache. + ProgramCache* cache = &gfxcore->program_cache; + ShaderProgramCacheEntry* entry = find_program_cache_entry(cache, *prog); + assert(entry); // Must be there, shaders can't go untracked. + mempool_free(cache, &entry); + + gfx_del_shader_program(*prog); + mempool_free(&gfxcore->shader_programs, prog); + } +} -- cgit v1.2.3