--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shader.c Wed Nov 08 23:17:07 2023 +0100 @@ -0,0 +1,139 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright 2023 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "ascension/shader.h" +#include "ascension/files.h" +#include "ascension/error.h" + +#include <GL/glew.h> + +AscShaderProgram ASC_SHADER_FONT; + + +AscShader asc_shader_compile(unsigned int type, + char const *code, + int length) { + GLuint id = glCreateShader(type); + if (id == 0) { + asc_error("glCreateShader failed"); + return (AscShader) {0}; + } + + GLint success; + glShaderSource(id, 1, &code, &length); + glCompileShader(id); + glGetShaderiv(id, GL_COMPILE_STATUS, &success); + if (success) { + asc_dprintf("Shader %u compiled", id); + return (AscShader) {id}; + } else { + char *log = malloc(1024); + glGetShaderInfoLog(id, 1024, NULL, log); + glDeleteShader(id); + asc_error(log); + free(log); + return (AscShader) {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}; + } + + GLint success; + GLint id = glCreateProgram(); + if (id <= 0) { + asc_error("glCreateProgram failed"); + return (AscShaderProgram) {0}; + } + glAttachShader(id, vertex.id); + glAttachShader(id, fragment.id); + glLinkProgram(id); + glGetProgramiv(id, GL_LINK_STATUS, &success); + glDetachShader(id, vertex.id); + glDetachShader(id, fragment.id); + if (success) { + asc_dprintf("Shader Program %u linked (vtf: %u, frag: %u)", id, vertex.id, fragment.id); + return (AscShaderProgram) {id}; + } else { + char *log = malloc(1024); + glGetProgramInfoLog(id, 1024, NULL, log); + glDeleteShader(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); + glDeleteProgram(program.id); + } + program.id = 0; +} + +static AscShaderProgram asc_shader_compile_link_discard( + 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); + return prog; +} + +void asc_shader_initialize_predefined(void) { + ASC_SHADER_FONT = asc_shader_compile_link_discard("shader/font_vtx.glsl", "shader/font_frag.glsl"); +} + +void asc_shader_destroy_predefined(void) { + asc_shader_program_destroy(ASC_SHADER_FONT); +} \ No newline at end of file