# HG changeset patch # User Mike Becker # Date 1699481827 -3600 # Node ID 362b7659dc762d6380e62852453556d63850c5eb # Parent 9dbfc00318875f035ea88a925da02d440e9fd88e add shader loading and unloading diff -r 9dbfc0031887 -r 362b7659dc76 shader/font_frag.glsl --- /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); +} diff -r 9dbfc0031887 -r 362b7659dc76 shader/font_vtx.glsl --- /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; +} diff -r 9dbfc0031887 -r 362b7659dc76 src/Makefile --- 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 diff -r 9dbfc0031887 -r 362b7659dc76 src/ascension/ascension.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 */ diff -r 9dbfc0031887 -r 362b7659dc76 src/ascension/error.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 +#include void asc_error_cxstr(cxstring text); void asc_error_cchar(char const* text); diff -r 9dbfc0031887 -r 362b7659dc76 src/ascension/files.h --- /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 + +typedef cxstring asc_file; + +asc_file asc_file_mmap_rdonly(char const *filename); +void asc_file_unmap(asc_file ptr); + +#endif //ASCENSION_FILES_H diff -r 9dbfc0031887 -r 362b7659dc76 src/ascension/shader.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 diff -r 9dbfc0031887 -r 362b7659dc76 src/context.c --- 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 @@ -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]); } diff -r 9dbfc0031887 -r 362b7659dc76 src/error.c --- 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; diff -r 9dbfc0031887 -r 362b7659dc76 src/files.c --- /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 +#include +#include +#include + +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 diff -r 9dbfc0031887 -r 362b7659dc76 src/shader.c --- /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 + +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 diff -r 9dbfc0031887 -r 362b7659dc76 test/Makefile --- 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 $< diff -r 9dbfc0031887 -r 362b7659dc76 test/sandbox.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;