--- a/src/shader.c Sun Jun 08 14:57:54 2025 +0200 +++ b/src/shader.c Sun Jun 08 14:58:19 2025 +0200 @@ -87,14 +87,16 @@ * * @param shader the shader IDs to link * @param n the number of shaders - * @return a compiled program + * @param prog the struct where to store the result + * @retval zero success + * @retval non-zero failure */ -static AscShaderProgram asc_shader_link(unsigned shader[], unsigned n) { +static int asc_shader_link(unsigned shader[], unsigned n, AscShaderProgram *prog) { GLint success; GLint id = glCreateProgram(); if (id <= 0) { asc_error("glCreateProgram failed: %s", glGetError()); - return (AscShaderProgram) {0}; + return -1; } for (unsigned i = 0; i < n; i++) { glAttachShader(id, shader[i]); @@ -106,33 +108,36 @@ } if (success) { asc_dprintf("Shader Program %u linked.", id); - AscShaderProgram prog; - prog.id = id; + prog->gl_id = id; // by convention every shader shall have MVP matrices - prog.model = glGetUniformLocation(id, "model"); - prog.view = glGetUniformLocation(id, "view"); - prog.projection = glGetUniformLocation(id, "projection"); - return prog; + prog->model = glGetUniformLocation(id, "model"); + prog->view = glGetUniformLocation(id, "view"); + prog->projection = glGetUniformLocation(id, "projection"); + return 0; } else { char *log = malloc(1024); glGetProgramInfoLog(id, 1024, NULL, log); glDeleteProgram(id); asc_error("Linking shader program %u failed.\n%s", id, log); free(log); - return (AscShaderProgram) {0}; + return -1; } } -void asc_shader_program_destroy(AscShaderProgram *program) { - if (program->id > 0) { - asc_dprintf("Delete Shader Program %u", program->id); - glDeleteProgram(program->id); +void asc_shader_free(AscShaderProgram *program) { + if (program->gl_id > 0) { + asc_dprintf("Delete Shader Program %u", program->gl_id); + glDeleteProgram(program->gl_id); } - program->id = 0; + if (program->destr_func) { + program->destr_func(program); + } + cxFreeDefault(program); } -AscShaderProgram asc_shader_program_create(AscShaderCodes codes) { - unsigned shader[4]; +void *asc_shader_create(AscShaderCodes codes, size_t mem_size) { + AscShaderProgram *prog = cxZallocDefault(mem_size); + unsigned shader[2]; unsigned n = 0; if (codes.vtx) { shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx, codes.vtx_pp); @@ -140,15 +145,19 @@ if (codes.frag) { shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag, codes.frag_pp); } - const AscShaderProgram prog = asc_shader_link(shader, n); + if (asc_shader_link(shader, n, prog)) { + cxFreeDefault(prog); + prog = NULL; + } for (unsigned i = 0; i < n; i++) { + asc_dprintf("Delete shader: %u", shader[i]); glDeleteShader(shader[i]); } return prog; } -void asc_shader_program_use(const AscShaderProgram *shader, const AscCamera *camera) { - glUseProgram(shader->id); +void asc_shader_use(const AscShaderProgram *shader, const AscCamera *camera) { + glUseProgram(shader->gl_id); glUniformMatrix4fv(shader->projection, 1, GL_FALSE, camera->projection); glUniformMatrix4fv(shader->view, 1, GL_FALSE, camera->view); } @@ -185,3 +194,36 @@ cxFreeDefault(codes.vtx); cxFreeDefault(codes.frag); } + +AscShaderProgram *asc_shader_register(unsigned int id, asc_shader_create_func create_func) { + AscGLContext *glctx = asc_active_glctx; + AscShaderProgram *prog = NULL; +#ifndef NDEBUG + prog = asc_shader_lookup(id); + if (prog != NULL) { + asc_error("Shader program %u already exists. This is a bug!", id); + // still return it, so that the caller does not die immediately + return prog; + } +#endif + prog = create_func(); + prog->id = id; + cxListAdd(glctx->shaders, prog); + return prog; +} + +AscShaderProgram *asc_shader_lookup(unsigned int id) { + CxIterator iter = cxListIterator(asc_active_glctx->shaders); + cx_foreach(AscShaderProgram *, prog, iter) { + if (prog->id == id) return prog; + } + return NULL; +} + +AscShaderProgram *asc_shader_lookup_or_create(unsigned int id, asc_shader_create_func create_func) { + AscShaderProgram *prog = asc_shader_lookup(id); + if (prog == NULL) { + return asc_shader_register(id, create_func); + } + return prog; +} \ No newline at end of file