--- a/src/shader.c Sat Mar 01 22:55:30 2025 +0100 +++ b/src/shader.c Tue Mar 18 22:43:31 2025 +0100 @@ -26,73 +26,74 @@ */ #include "ascension/shader.h" -#include "ascension/files.h" #include "ascension/error.h" #include <GL/glew.h> #include <string.h> -AscShader asc_shader_compile(unsigned int type, - char const *code, - int length) { +/** + * Compiles a shader from the given source code. + * + * The ID of the returned shader will be zero when something went wrong. + * + * @param type the shader type (use the GL enum) + * @param code the source code + * @return the compiled shader + */ +static unsigned asc_shader_compile(unsigned int type, char const *code) { GLuint id = glCreateShader(type); if (id == 0) { asc_error("glCreateShader failed"); - return (AscShader) {0}; + return 0; } GLint success; + int length = (int) strlen(code); // must be int because of OpenGL API glShaderSource(id, 1, &code, &length); glCompileShader(id); glGetShaderiv(id, GL_COMPILE_STATUS, &success); if (success) { asc_dprintf("Shader %u compiled", id); - return (AscShader) {id}; + return id; } else { char *log = malloc(1024); glGetShaderInfoLog(id, 1024, NULL, log); glDeleteShader(id); asc_error(log); free(log); - return (AscShader) {0}; + return 0; } } -AscShader asc_shader_compilef(unsigned int type, - char const *filename) { - asc_file code = asc_file_mmap_rdonly(filename); - if (code.ptr == NULL) { - asc_error("Mapping shader file into memory failed"); - return (AscShader) {0}; - } - AscShader ret = asc_shader_compile(type, code.ptr, code.length); - asc_file_unmap(code); - return ret; -} - -AscShaderProgram asc_shader_link(AscShader vertex, - AscShader fragment) { - if (vertex.id == 0 || fragment.id == 0) { - asc_dprintf("Skip linking shader program - shaders have not been loaded correctly."); - return (AscShaderProgram) {0}; - } - +/** + * This function links shaders into a program. + * + * The ID of the returned program will be zero when something went wrong. + * + * @param shader the shader IDs to link + * @param n the number of shaders + * @return a compiled program + */ +static AscShaderProgram asc_shader_link(unsigned shader[], unsigned n) { GLint success; GLint id = glCreateProgram(); if (id <= 0) { asc_error("glCreateProgram failed"); return (AscShaderProgram) {0}; } - glAttachShader(id, vertex.id); - glAttachShader(id, fragment.id); + for (unsigned i = 0; i < n; i++) { + glAttachShader(id, shader[i]); + } glLinkProgram(id); glGetProgramiv(id, GL_LINK_STATUS, &success); - glDetachShader(id, vertex.id); - glDetachShader(id, fragment.id); + for (unsigned i = 0; i < n; i++) { + glDeleteShader(shader[i]); + } if (success) { - asc_dprintf("Shader Program %u linked (vtf: %u, frag: %u)", id, vertex.id, fragment.id); + asc_dprintf("Shader Program %u linked.", id); AscShaderProgram prog; prog.id = id; + // TODO: maybe not every program has the same uniforms prog.model = glGetUniformLocation(id, "model"); prog.view = glGetUniformLocation(id, "view"); prog.projection = glGetUniformLocation(id, "projection"); @@ -100,21 +101,13 @@ } else { char *log = malloc(1024); glGetProgramInfoLog(id, 1024, NULL, log); - glDeleteShader(id); + glDeleteProgram(id); asc_error(log); free(log); return (AscShaderProgram) {0}; } } -void asc_shader_destroy(AscShader shader) { - if (shader.id > 0) { - asc_dprintf("Delete Shader %u", shader.id); - glDeleteShader(shader.id); - } - shader.id = 0; -} - void asc_shader_program_destroy(AscShaderProgram program) { if (program.id > 0) { asc_dprintf("Delete Shader Program %u", program.id); @@ -123,12 +116,18 @@ program.id = 0; } -AscShaderProgram asc_shader_easy_compile_and_link( - char const *vtxName, char const *fragName) { - AscShader font_vtx = asc_shader_compilef(GL_VERTEX_SHADER, vtxName); - AscShader font_frag = asc_shader_compilef(GL_FRAGMENT_SHADER, fragName); - AscShaderProgram prog = asc_shader_link(font_vtx, font_frag); - asc_shader_destroy(font_vtx); - asc_shader_destroy(font_frag); +AscShaderProgram asc_shader_program_create(AscShaderCodes codes) { + unsigned shader[4]; + unsigned n = 0; + if (codes.vtx) { + shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx); + } + if (codes.frag) { + shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag); + } + const AscShaderProgram prog = asc_shader_link(shader, n); + for (unsigned i = 0; i < n; i++) { + glDeleteShader(shader[i]); + } return prog; }