Tue, 18 Mar 2025 22:43:31 +0100
prepare code for embedding shader sources with c23 #embed
.hgignore | file | annotate | diff | comparison | revisions | |
src/Makefile | file | annotate | diff | comparison | revisions | |
src/ascension/files.h | file | annotate | diff | comparison | revisions | |
src/ascension/shader.h | file | annotate | diff | comparison | revisions | |
src/files.c | file | annotate | diff | comparison | revisions | |
src/glcontext.c | file | annotate | diff | comparison | revisions | |
src/shader.c | file | annotate | diff | comparison | revisions | |
src/shader_codes.h | file | annotate | diff | comparison | revisions | |
test/Makefile | file | annotate | diff | comparison | revisions |
--- a/.hgignore Sat Mar 01 22:55:30 2025 +0100 +++ b/.hgignore Tue Mar 18 22:43:31 2025 +0100 @@ -1,4 +1,5 @@ .idea/ nbproject/ build/ +shader/.*\.h config.mk
--- a/src/Makefile Sat Mar 01 22:55:30 2025 +0100 +++ b/src/Makefile Tue Mar 18 22:43:31 2025 +0100 @@ -27,7 +27,7 @@ BUILD_DIR=../build/lib -SRC = context.c glcontext.c error.c window.c files.c shader.c font.c text.c \ +SRC = context.c glcontext.c error.c window.c shader.c font.c text.c \ texture.c scene.c camera.c primitives.c OBJ = $(SRC:%.c=$(BUILD_DIR)/%.o) @@ -49,20 +49,17 @@ ascension/datatypes.h ascension/window.h ascension/glcontext.h \ ascension/primitives.h ascension/mesh.h ascension/shader.h \ ascension/scene.h ascension/transform.h ascension/camera.h \ - ascension/input.h ascension/ui/font.h ascension/error.h \ - ascension/utils.h + ascension/texture.h ascension/input.h ascension/ui/font.h \ + ascension/error.h ascension/utils.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< $(BUILD_DIR)/error.o: error.c ascension/context.h ascension/datatypes.h \ ascension/window.h ascension/glcontext.h ascension/primitives.h \ ascension/mesh.h ascension/shader.h ascension/scene.h \ - ascension/transform.h ascension/camera.h ascension/input.h \ - ascension/ui/font.h ascension/error.h ascension/utils.h - @echo "Compiling $<" - $(CC) -o $@ $(CFLAGS) -c $< - -$(BUILD_DIR)/files.o: files.c ascension/files.h ascension/error.h + ascension/transform.h ascension/camera.h ascension/texture.h \ + ascension/input.h ascension/ui/font.h ascension/error.h \ + ascension/utils.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< @@ -70,13 +67,14 @@ ascension/datatypes.h ascension/window.h ascension/glcontext.h \ ascension/primitives.h ascension/mesh.h ascension/shader.h \ ascension/scene.h ascension/transform.h ascension/camera.h \ - ascension/input.h ascension/ui/font.h ascension/error.h + ascension/texture.h ascension/input.h ascension/ui/font.h \ + ascension/error.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< $(BUILD_DIR)/glcontext.o: glcontext.c ascension/glcontext.h \ ascension/primitives.h ascension/mesh.h ascension/shader.h \ - ascension/error.h + ascension/error.h shader_codes.h ascension/shader.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< @@ -84,21 +82,21 @@ ascension/mesh.h ascension/error.h ascension/context.h \ ascension/datatypes.h ascension/window.h ascension/glcontext.h \ ascension/primitives.h ascension/shader.h ascension/scene.h \ - ascension/transform.h ascension/camera.h ascension/input.h \ - ascension/ui/font.h + ascension/transform.h ascension/camera.h ascension/texture.h \ + ascension/input.h ascension/ui/font.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< $(BUILD_DIR)/scene.o: scene.c ascension/scene.h ascension/datatypes.h \ - ascension/transform.h ascension/camera.h ascension/context.h \ - ascension/window.h ascension/glcontext.h ascension/primitives.h \ - ascension/mesh.h ascension/shader.h ascension/scene.h ascension/input.h \ - ascension/ui/font.h ascension/utils.h ascension/shader.h + ascension/transform.h ascension/camera.h ascension/texture.h \ + ascension/context.h ascension/window.h ascension/glcontext.h \ + ascension/primitives.h ascension/mesh.h ascension/shader.h \ + ascension/scene.h ascension/input.h ascension/ui/font.h \ + ascension/utils.h ascension/shader.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< -$(BUILD_DIR)/shader.o: shader.c ascension/shader.h ascension/files.h \ - ascension/error.h +$(BUILD_DIR)/shader.o: shader.c ascension/shader.h ascension/error.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $< @@ -120,9 +118,9 @@ $(BUILD_DIR)/window.o: window.c ascension/window.h ascension/datatypes.h \ ascension/glcontext.h ascension/primitives.h ascension/mesh.h \ ascension/shader.h ascension/scene.h ascension/transform.h \ - ascension/camera.h ascension/context.h ascension/window.h \ - ascension/input.h ascension/ui/font.h ascension/error.h \ - ascension/utils.h + ascension/camera.h ascension/texture.h ascension/context.h \ + ascension/window.h ascension/input.h ascension/ui/font.h \ + ascension/error.h ascension/utils.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $<
--- a/src/ascension/files.h Sat Mar 01 22:55:30 2025 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * 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
--- a/src/ascension/shader.h Sat Mar 01 22:55:30 2025 +0100 +++ b/src/ascension/shader.h Tue Mar 18 22:43:31 2025 +0100 @@ -28,9 +28,10 @@ #ifndef ASCENSION_SHADER_H #define ASCENSION_SHADER_H -typedef struct AscShader { - unsigned int id; -} AscShader; +typedef struct AscShaderCodes { + const char *vtx; + const char *frag; +} AscShaderCodes; typedef struct AscShaderProgram { unsigned int id; @@ -45,60 +46,20 @@ int tex; } AscShaderSprite; - /** - * 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. + * Destroys a shader program. * * @param program the program */ void asc_shader_program_destroy(AscShaderProgram program); -AscShaderProgram asc_shader_easy_compile_and_link( - char const *vtxName, - char const *fragName -); +/** + * Creates a shader program. + * + * @param codes the (zero-terminated) source codes + * @return the compiled and linked shader program + */ +AscShaderProgram asc_shader_program_create(AscShaderCodes codes); #endif //ASCENSION_SHADER_H
--- a/src/files.c Sat Mar 01 22:55:30 2025 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * 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
--- a/src/glcontext.c Sat Mar 01 22:55:30 2025 +0100 +++ b/src/glcontext.c Tue Mar 18 22:43:31 2025 +0100 @@ -48,12 +48,11 @@ cx_strfree(&buf); } +#include "shader_codes.h" + static void asc_shader_initialize_predefined(AscGLContext *ctx) { AscShaderSprite *sprite = &ctx->shader.sprite; - sprite->program = asc_shader_easy_compile_and_link( - "shader/sprite_vtx.glsl", - "shader/sprite_frag.glsl" - ); + sprite->program = asc_shader_program_create(asc_shader_codes_sprite); sprite->depth = glGetUniformLocation(sprite->program.id, "depth"); sprite->tex = glGetUniformLocation(sprite->program.id, "texture"); }
--- a/src/shader.c Sat Mar 01 22:55:30 2025 +0100 +++ b/src/shader.c Tue Mar 18 22:43:31 2025 +0100 @@ -26,73 +26,74 @@ */ #include "ascension/shader.h" -#include "ascension/files.h" #include "ascension/error.h" #include <GL/glew.h> #include <string.h> -AscShader asc_shader_compile(unsigned int type, - char const *code, - int length) { +/** + * 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 + * @return the compiled shader + */ +static unsigned asc_shader_compile(unsigned int type, char const *code) { GLuint id = glCreateShader(type); if (id == 0) { asc_error("glCreateShader failed"); - return (AscShader) {0}; + return 0; } GLint success; + int length = (int) strlen(code); // must be int because of OpenGL API glShaderSource(id, 1, &code, &length); glCompileShader(id); glGetShaderiv(id, GL_COMPILE_STATUS, &success); if (success) { asc_dprintf("Shader %u compiled", id); - return (AscShader) {id}; + return id; } else { char *log = malloc(1024); glGetShaderInfoLog(id, 1024, NULL, log); glDeleteShader(id); asc_error(log); free(log); - return (AscShader) {0}; + return 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}; - } - +/** + * This function links shaders into a program. + * + * The ID of the returned program will be zero when something went wrong. + * + * @param shader the shader IDs to link + * @param n the number of shaders + * @return a compiled program + */ +static AscShaderProgram asc_shader_link(unsigned shader[], unsigned n) { GLint success; GLint id = glCreateProgram(); if (id <= 0) { asc_error("glCreateProgram failed"); return (AscShaderProgram) {0}; } - glAttachShader(id, vertex.id); - glAttachShader(id, fragment.id); + for (unsigned i = 0; i < n; i++) { + glAttachShader(id, shader[i]); + } glLinkProgram(id); glGetProgramiv(id, GL_LINK_STATUS, &success); - glDetachShader(id, vertex.id); - glDetachShader(id, fragment.id); + for (unsigned i = 0; i < n; i++) { + glDeleteShader(shader[i]); + } if (success) { - asc_dprintf("Shader Program %u linked (vtf: %u, frag: %u)", id, vertex.id, fragment.id); + asc_dprintf("Shader Program %u linked.", id); AscShaderProgram prog; prog.id = id; + // TODO: maybe not every program has the same uniforms prog.model = glGetUniformLocation(id, "model"); prog.view = glGetUniformLocation(id, "view"); prog.projection = glGetUniformLocation(id, "projection"); @@ -100,21 +101,13 @@ } else { char *log = malloc(1024); glGetProgramInfoLog(id, 1024, NULL, log); - glDeleteShader(id); + glDeleteProgram(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); @@ -123,12 +116,18 @@ program.id = 0; } -AscShaderProgram asc_shader_easy_compile_and_link( - 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); +AscShaderProgram asc_shader_program_create(AscShaderCodes codes) { + unsigned shader[4]; + unsigned n = 0; + if (codes.vtx) { + shader[n++] = asc_shader_compile(GL_VERTEX_SHADER, codes.vtx); + } + if (codes.frag) { + shader[n++] = asc_shader_compile(GL_FRAGMENT_SHADER, codes.frag); + } + const AscShaderProgram prog = asc_shader_link(shader, n); + for (unsigned i = 0; i < n; i++) { + glDeleteShader(shader[i]); + } return prog; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shader_codes.h Tue Mar 18 22:43:31 2025 +0100 @@ -0,0 +1,61 @@ +/* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright 2025 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. + */ + +#ifdef ASC_SHADER_CODES_LOADED +#error "Shader codes are supposed to be included once!" +#endif +#define ASC_SHADER_CODES_LOADED + +#include "ascension/shader.h" + +#define asc_embed(name, file) \ + __asm__(".section .rodata\n" \ + ".global " #name "\n" \ + #name ":\n" \ + ".incbin \"" file "\"\n" \ + ".byte 0\n" \ + ); \ + extern const char name[] + +#ifdef __has_embed +const char asc_shader_code_sprite_vtx[] = { +#embed "../shader/sprite_vtx.glsl" suffix(, 0) +}; +const char asc_shader_code_sprite_frag[] = { +#embed "../shader/sprite_frag.glsl" suffix(, 0) +}; +#else +#warning "C23 support for #embed is missing - falling back to inline assembler" +asc_embed(asc_shader_code_sprite_vtx, "../shader/sprite_vtx.glsl"); +asc_embed(asc_shader_code_sprite_frag, "../shader/sprite_frag.glsl"); +#endif + +static AscShaderCodes asc_shader_codes_sprite = { + asc_shader_code_sprite_vtx, + asc_shader_code_sprite_frag +}; +
--- a/test/Makefile Sat Mar 01 22:55:30 2025 +0100 +++ b/test/Makefile Tue Mar 18 22:43:31 2025 +0100 @@ -47,10 +47,10 @@ ../src/ascension/glcontext.h ../src/ascension/primitives.h \ ../src/ascension/mesh.h ../src/ascension/shader.h \ ../src/ascension/scene.h ../src/ascension/transform.h \ - ../src/ascension/camera.h ../src/ascension/input.h \ - ../src/ascension/ui/font.h ../src/ascension/ui.h \ - ../src/ascension/ui/text.h ../src/ascension/ui/font.h \ - ../src/ascension/ui/../scene.h ../src/ascension/ui/../texture.h \ + ../src/ascension/camera.h ../src/ascension/texture.h \ + ../src/ascension/input.h ../src/ascension/ui/font.h \ + ../src/ascension/ui.h ../src/ascension/ui/text.h \ + ../src/ascension/ui/font.h ../src/ascension/ui/../scene.h \ ../src/ascension/ui/../utils.h @echo "Compiling $<" $(CC) -o $@ $(CFLAGS) -c $<