add shader loading and unloading

Wed, 08 Nov 2023 23:17:07 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 08 Nov 2023 23:17:07 +0100
changeset 15
362b7659dc76
parent 14
9dbfc0031887
child 16
c5dde81b6fb2

add shader loading and unloading

shader/font_frag.glsl file | annotate | diff | comparison | revisions
shader/font_vtx.glsl file | annotate | diff | comparison | revisions
src/Makefile file | annotate | diff | comparison | revisions
src/ascension/ascension.h file | annotate | diff | comparison | revisions
src/ascension/error.h file | annotate | diff | comparison | revisions
src/ascension/files.h file | annotate | diff | comparison | revisions
src/ascension/shader.h file | annotate | diff | comparison | revisions
src/context.c file | annotate | diff | comparison | revisions
src/error.c file | annotate | diff | comparison | revisions
src/files.c file | annotate | diff | comparison | revisions
src/shader.c file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/sandbox.c file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shader/font_frag.glsl	Wed Nov 08 23:17:07 2023 +0100
@@ -0,0 +1,10 @@
+#version 400 core
+
+in vec2 texcoord;
+out vec4 fragment;
+
+uniform sampler2DRect surface;
+
+void main(void) {
+    fragment = texture(surface, texcoord);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/shader/font_vtx.glsl	Wed Nov 08 23:17:07 2023 +0100
@@ -0,0 +1,12 @@
+#version 400 core
+
+in vec2 position;
+out vec2 texcoord;
+
+uniform mat4 projection;
+uniform mat4 model;
+
+void main(void) {
+    gl_Position = projection*model*vec4(position, 0.0, 1.0);
+    texcoord = position;
+}
--- a/src/Makefile	Wed Nov 08 21:53:43 2023 +0100
+++ b/src/Makefile	Wed Nov 08 23:17:07 2023 +0100
@@ -27,7 +27,7 @@
 
 BUILD_DIR=../build/lib
 
-SRC  = context.c error.c window.c font.c
+SRC  = context.c error.c window.c font.c files.c shader.c
 
 OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o)
 
@@ -42,7 +42,7 @@
 
 $(BUILD_DIR)/context.o: context.c ascension/context.h ascension/window.h \
  ascension/datatypes.h ascension/font.h ascension/error.h \
- ascension/utils.h
+ ascension/utils.h ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
@@ -52,12 +52,21 @@
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
+$(BUILD_DIR)/files.o: files.c ascension/files.h ascension/error.h
+	@echo "Compiling $<"
+	$(CC) -o $@ $(CFLAGS) -c $<
+
 $(BUILD_DIR)/font.o: font.c ascension/font.h ascension/context.h \
  ascension/window.h ascension/datatypes.h ascension/font.h \
  ascension/error.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
+$(BUILD_DIR)/shader.o: shader.c ascension/shader.h ascension/files.h \
+ ascension/error.h
+	@echo "Compiling $<"
+	$(CC) -o $@ $(CFLAGS) -c $<
+
 $(BUILD_DIR)/window.o: window.c ascension/window.h ascension/datatypes.h \
  ascension/context.h ascension/window.h ascension/font.h \
  ascension/error.h ascension/utils.h
--- a/src/ascension/ascension.h	Wed Nov 08 21:53:43 2023 +0100
+++ b/src/ascension/ascension.h	Wed Nov 08 23:17:07 2023 +0100
@@ -28,8 +28,9 @@
 #ifndef ASCENSION_H
 #define ASCENSION_H
 
+#include "error.h"
 #include "context.h"
-#include "error.h"
+#include "shader.h"
 
 #endif /* ASCENSION_H */
 
--- a/src/ascension/error.h	Wed Nov 08 21:53:43 2023 +0100
+++ b/src/ascension/error.h	Wed Nov 08 23:17:07 2023 +0100
@@ -29,6 +29,7 @@
 #define ASCENSION_ERROR_H
 
 #include <cx/string.h>
+#include <stdio.h>
 
 void asc_error_cxstr(cxstring text);
 void asc_error_cchar(char const* text);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ascension/files.h	Wed Nov 08 23:17:07 2023 +0100
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifndef ASCENSION_FILES_H
+#define ASCENSION_FILES_H
+
+#include <cx/string.h>
+
+typedef cxstring asc_file;
+
+asc_file asc_file_mmap_rdonly(char const *filename);
+void asc_file_unmap(asc_file ptr);
+
+#endif //ASCENSION_FILES_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ascension/shader.h	Wed Nov 08 23:17:07 2023 +0100
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef ASCENSION_SHADER_H
+#define ASCENSION_SHADER_H
+
+typedef struct AscShader {
+    unsigned int id;
+} AscShader;
+
+typedef struct AscShaderProgram {
+    unsigned int id;
+    AscShader vertex;
+    AscShader fragment;
+} AscShaderProgram;
+
+
+extern AscShaderProgram ASC_SHADER_FONT;
+
+
+/**
+ * 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
+ * @param length the length of the source code
+ * @return the compiled shader
+ */
+AscShader asc_shader_compile(unsigned int type, char const *code, int length);
+
+/**
+ * Compiles a shader from the given source file.
+ *
+ * The ID of the returned shader will be zero when something went wrong.
+ * The file is mapped into memory for compilation and then unmapped again.
+ *
+ * @param type the shader type (use the GL enum)
+ * @param filename the path to the shader file
+ * @return the compiled shader
+ */
+AscShader asc_shader_compilef(unsigned int type, char const *filename);
+
+/**
+ * This function links shaders into a program.
+ *
+ * The ID of the returned program will be zero when something went wrong.
+ *
+ * @param vertex the vertex shader
+ * @param fragment the fragment shader
+ * @return a compiled program
+ */
+AscShaderProgram asc_shader_link(AscShader vertex, AscShader fragment);
+
+/**
+ * Destroys the shader.
+ *
+ * @param shader the shader
+ */
+void asc_shader_destroy(AscShader shader);
+
+/**
+ * Destroys the shader program.
+ *
+ * @param program the program
+ */
+void asc_shader_program_destroy(AscShaderProgram program);
+
+/**
+ * Initializes shaders that already come with the engine.
+ */
+void asc_shader_initialize_predefined(void);
+
+/**
+ * You do not need to do this manually.
+ *
+ * When the ascension context is destroyed, this function is called automatically.
+ * When you did not initialize the predefined shaders, this function does nothing.
+ */
+void asc_shader_destroy_predefined(void);
+
+#endif //ASCENSION_SHADER_H
--- a/src/context.c	Wed Nov 08 21:53:43 2023 +0100
+++ b/src/context.c	Wed Nov 08 23:17:07 2023 +0100
@@ -28,6 +28,7 @@
 #include "ascension/context.h"
 #include "ascension/error.h"
 #include "ascension/utils.h"
+#include "ascension/shader.h"
 
 #include <cx/linked_list.h>
 
@@ -64,7 +65,7 @@
 }
 
 void asc_context_destroy(void) {
-    // destroy data
+    asc_shader_destroy_predefined();
     for (unsigned int i = 0 ; i < ASC_MAX_WINDOWS ; i++) {
         asc_window_destroy(&asc_context.windows[i]);
     }
--- a/src/error.c	Wed Nov 08 21:53:43 2023 +0100
+++ b/src/error.c	Wed Nov 08 23:17:07 2023 +0100
@@ -43,7 +43,7 @@
     if (text.length == 0) return;
 
     // write error to debug output
-    asc_dprintf("ERROR: %*.s", (int)text.length, text.ptr);
+    asc_dprintf("ERROR: %.*s", (int)text.length, text.ptr);
 
     // write error to buffer
     CxBuffer* buf = &asc_context.error_buffer;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/files.c	Wed Nov 08 23:17:07 2023 +0100
@@ -0,0 +1,64 @@
+/*
+ * 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/files.h"
+#include "ascension/error.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+asc_file asc_file_mmap_rdonly(char const *filename) {
+    int fd = open(filename, O_RDONLY);
+    if (fd < 0) {
+        asc_dprintf("Failed to open file %s", filename);
+        return (cxstring) {NULL, 0};
+    }
+
+    struct stat statbuf;
+    int err = fstat(fd, &statbuf);
+    if (err < 0) {
+        close(fd);
+        asc_dprintf("Failed to stat file %s", filename);
+        return (cxstring) {NULL, 0};
+    }
+
+    char const *data = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    if (data == MAP_FAILED) {
+        close(fd);
+        asc_dprintf("Failed to map file %s into memory", filename);
+        return (cxstring) {NULL, 0};
+    }
+    close(fd);
+
+    return cx_strn(data, statbuf.st_size);
+}
+
+void asc_file_unmap(asc_file file) {
+    munmap((void *) file.ptr, file.length);
+}
\ No newline at end of file
--- /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
--- a/test/Makefile	Wed Nov 08 21:53:43 2023 +0100
+++ b/test/Makefile	Wed Nov 08 23:17:07 2023 +0100
@@ -39,9 +39,9 @@
 FORCE:
 
 $(BUILD_DIR)/sandbox.o: sandbox.c ../src/ascension/ascension.h \
- ../src/ascension/context.h ../src/ascension/window.h \
- ../src/ascension/datatypes.h ../src/ascension/font.h \
- ../src/ascension/error.h
+ ../src/ascension/error.h ../src/ascension/context.h \
+ ../src/ascension/window.h ../src/ascension/datatypes.h \
+ ../src/ascension/font.h ../src/ascension/shader.h
 	@echo "Compiling $<"
 	$(CC) -o $@ $(CFLAGS) -c $<
 
--- a/test/sandbox.c	Wed Nov 08 21:53:43 2023 +0100
+++ b/test/sandbox.c	Wed Nov 08 23:17:07 2023 +0100
@@ -49,7 +49,7 @@
     settings.title = "Sandbox Application";
 
     AscWindow *window = asc_window_initialize(0, &settings);
-
+    asc_shader_initialize_predefined();
     while (asc_loop_next()) {
         // quit application on any error
         if (show_message_box_on_error(window->window)) break;

mercurial