universe@15: /* universe@15: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@15: * Copyright 2023 Mike Becker. All rights reserved. universe@15: * universe@15: * Redistribution and use in source and binary forms, with or without universe@15: * modification, are permitted provided that the following conditions are met: universe@15: * universe@15: * 1. Redistributions of source code must retain the above copyright universe@15: * notice, this list of conditions and the following disclaimer. universe@15: * universe@15: * 2. Redistributions in binary form must reproduce the above copyright universe@15: * notice, this list of conditions and the following disclaimer in the universe@15: * documentation and/or other materials provided with the distribution. universe@15: * universe@15: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@15: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@15: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@15: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@15: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@15: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@15: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@15: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@15: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@15: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@15: * POSSIBILITY OF SUCH DAMAGE. universe@15: */ universe@15: universe@15: #include "ascension/shader.h" universe@15: #include "ascension/files.h" universe@15: #include "ascension/error.h" universe@15: universe@15: #include universe@16: #include universe@15: universe@16: AscShaderFont ASC_SHADER_FONT; universe@15: universe@15: universe@15: AscShader asc_shader_compile(unsigned int type, universe@15: char const *code, universe@15: int length) { universe@15: GLuint id = glCreateShader(type); universe@15: if (id == 0) { universe@15: asc_error("glCreateShader failed"); universe@15: return (AscShader) {0}; universe@15: } universe@15: universe@15: GLint success; universe@15: glShaderSource(id, 1, &code, &length); universe@15: glCompileShader(id); universe@15: glGetShaderiv(id, GL_COMPILE_STATUS, &success); universe@15: if (success) { universe@15: asc_dprintf("Shader %u compiled", id); universe@15: return (AscShader) {id}; universe@15: } else { universe@15: char *log = malloc(1024); universe@15: glGetShaderInfoLog(id, 1024, NULL, log); universe@15: glDeleteShader(id); universe@15: asc_error(log); universe@15: free(log); universe@15: return (AscShader) {0}; universe@15: } universe@15: } universe@15: universe@15: AscShader asc_shader_compilef(unsigned int type, universe@15: char const *filename) { universe@15: asc_file code = asc_file_mmap_rdonly(filename); universe@15: if (code.ptr == NULL) { universe@15: asc_error("Mapping shader file into memory failed"); universe@15: return (AscShader) {0}; universe@15: } universe@15: AscShader ret = asc_shader_compile(type, code.ptr, code.length); universe@15: asc_file_unmap(code); universe@15: return ret; universe@15: } universe@15: universe@15: AscShaderProgram asc_shader_link(AscShader vertex, universe@15: AscShader fragment) { universe@15: if (vertex.id == 0 || fragment.id == 0) { universe@15: asc_dprintf("Skip linking shader program - shaders have not been loaded correctly."); universe@15: return (AscShaderProgram) {0}; universe@15: } universe@15: universe@15: GLint success; universe@15: GLint id = glCreateProgram(); universe@15: if (id <= 0) { universe@15: asc_error("glCreateProgram failed"); universe@15: return (AscShaderProgram) {0}; universe@15: } universe@15: glAttachShader(id, vertex.id); universe@15: glAttachShader(id, fragment.id); universe@15: glLinkProgram(id); universe@15: glGetProgramiv(id, GL_LINK_STATUS, &success); universe@15: glDetachShader(id, vertex.id); universe@15: glDetachShader(id, fragment.id); universe@15: if (success) { universe@15: asc_dprintf("Shader Program %u linked (vtf: %u, frag: %u)", id, vertex.id, fragment.id); universe@16: AscShaderProgram prog; universe@16: prog.id = id; universe@16: prog.model = glGetUniformLocation(id, "model"); universe@16: prog.view = glGetUniformLocation(id, "view"); universe@16: prog.projection = glGetUniformLocation(id, "projection"); universe@16: return prog; universe@15: } else { universe@15: char *log = malloc(1024); universe@15: glGetProgramInfoLog(id, 1024, NULL, log); universe@15: glDeleteShader(id); universe@15: asc_error(log); universe@15: free(log); universe@15: return (AscShaderProgram) {0}; universe@15: } universe@15: } universe@15: universe@15: void asc_shader_destroy(AscShader shader) { universe@15: if (shader.id > 0) { universe@15: asc_dprintf("Delete Shader %u", shader.id); universe@15: glDeleteShader(shader.id); universe@15: } universe@15: shader.id = 0; universe@15: } universe@15: universe@15: void asc_shader_program_destroy(AscShaderProgram program) { universe@15: if (program.id > 0) { universe@15: asc_dprintf("Delete Shader Program %u", program.id); universe@15: glDeleteProgram(program.id); universe@15: } universe@15: program.id = 0; universe@15: } universe@15: universe@15: static AscShaderProgram asc_shader_compile_link_discard( universe@15: char const *vtxName, char const *fragName) { universe@15: AscShader font_vtx = asc_shader_compilef(GL_VERTEX_SHADER, vtxName); universe@15: AscShader font_frag = asc_shader_compilef(GL_FRAGMENT_SHADER, fragName); universe@15: AscShaderProgram prog = asc_shader_link(font_vtx, font_frag); universe@15: asc_shader_destroy(font_vtx); universe@15: asc_shader_destroy(font_frag); universe@15: return prog; universe@15: } universe@15: universe@15: void asc_shader_initialize_predefined(void) { universe@16: ASC_SHADER_FONT.base = asc_shader_compile_link_discard("shader/font_vtx.glsl", "shader/font_frag.glsl"); universe@16: ASC_SHADER_FONT.surface = glGetUniformLocation(ASC_SHADER_FONT.base.id, "surface"); universe@15: } universe@15: universe@15: void asc_shader_destroy_predefined(void) { universe@16: asc_shader_program_destroy(ASC_SHADER_FONT.base); universe@15: }