src/shader.c

changeset 15
362b7659dc76
child 16
c5dde81b6fb2
--- /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

mercurial