From 7c1edef3ac501d40e3de495b9434df71f535e9bc Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Fri, 19 Oct 2018 23:22:07 +0300 Subject: Allow multiple shaders while reducing duplication This change also stops using bie as eventually it will be replaced with a more sophisticated asset handling system which will also allow custom shaders. --- glprog.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 15 deletions(-) (limited to 'glprog.c') diff --git a/glprog.c b/glprog.c index 5019af2..2996889 100644 --- a/glprog.c +++ b/glprog.c @@ -3,23 +3,87 @@ * SPDX-License-Identifier: MIT */ #include +#include +#include +#include +#include #include "eprintf.h" #include "gl.h" #include "glprog.h" +#include "nelem.h" enum { LOGSIZE = 1024, }; -static GLuint load_shader(const struct shdrdat *shdr) +struct glprog_progs prog; + +static const struct { + GLuint type; + const char *name; + bool reqd; + const char *pre; +} langs[] = { + { GL_VERTEX_SHADER, "vert", true, +#define SH_IN(type, name) "in " #type " " #name ";\n" +#include "shaders/data.h" + }, + { GL_TESS_CONTROL_SHADER, "tesc", false, "" }, + { GL_TESS_EVALUATION_SHADER, "tese", false, "" }, + { GL_GEOMETRY_SHADER, "geom", false, "" }, + { GL_FRAGMENT_SHADER, "frag", true, +#define SH_TEX(type, name) "uniform sampler" #type " " #name ";\n" +#define SH_OUT(type, name) "out " #type " " #name ";\n" +#include "shaders/data.h" + }, +}; + +static bool readfile(char **data, size_t *size, const char *name) +{ + FILE *f; + size_t len = 0; + + assert(data != NULL); + assert(size != NULL); + assert(name != NULL); + + f = fopen(name, "rb"); + if (f == NULL) return false; + if (*size < 1024) { + *size = 1024; + *data = erealloc(*data, *size); + } + + while (true) { + size_t read = fread(*data + len, 1, *size - len, f); + len += read; + if (*size - len > 0) break; + *size *= 2; + *data = erealloc(*data, *size); + } + + *size = len; + *data = erealloc(*data, *size); + + return true; +} + +static GLuint compile(const char *src, size_t len, const char *pre, GLuint type) { GLuint id; GLint success; char log[LOGSIZE]; + static const char *common_pre = +#define SH_VER(v) "#version " v "\n" +#define SH_UNI(type, name) "uniform " #type " " #name ";\n" +#include "shaders/data.h" + ; + const char *srcs[] = { common_pre, pre, src }; + GLint lens[] = { -1, -1, len }; - id = gl_shdr_create(shdr->type); - gl_shdr_source(id, 1, &shdr->src, &shdr->len); + id = gl_shdr_create(type); + gl_shdr_source(id, NELEM(srcs), srcs, lens); gl_shdr_compile(id); gl_shdr_param(id, GL_COMPILE_STATUS, &success); @@ -31,7 +95,7 @@ static GLuint load_shader(const struct shdrdat *shdr) return id; } -void detach_shaders(GLuint prog) +static void detach_shaders(GLuint prog) { GLsizei count; GLuint shdr; @@ -40,33 +104,52 @@ void detach_shaders(GLuint prog) gl_prog_detachshdr(prog, shdr); } -GLuint glprog_load(const struct shdrdat *shdrs, const struct unidat *unis) +static void load_shader(struct shader *s, const char *path) { GLuint prog; GLint success; - char log[LOGSIZE]; + char log[LOGSIZE], *full, *src = NULL; + size_t srclen = 0, fullsz; + + assert(s != NULL); + assert(path != NULL); - assert(shdrs != NULL); + fullsz = strlen(path) + strlen("/xxxx.glsl") + 1; + assert(fullsz > strlen(path)); + full = emalloc(fullsz); prog = gl_prog_create(); - for (const struct shdrdat *s = shdrs; s->type != 0; s++) { - GLuint shdr = load_shader(s); + for (size_t i = 0; i < NELEM(langs); i++) { + GLuint shdr; + + snprintf(full, fullsz, "%s/%s.glsl", path, langs[i].name); + if (!readfile(&src, &srclen, full)) { + if (!langs[i].reqd) continue; + eprintf("Could not load shader file %s:\n", full); + } + shdr = compile(src, srclen, langs[i].pre, langs[i].type); gl_prog_attachshdr(prog, shdr); gl_shdr_del(shdr); } + free(src); + free(full); gl_prog_link(prog); gl_prog_param(prog, GL_LINK_STATUS, &success); if (!success) { gl_prog_infolog(prog, sizeof log, NULL, log); - eprintf("Failed to link program:\n%s", log); + eprintf("Failed to link program\n%s", log); } detach_shaders(prog); - if (unis == NULL) return prog; - - for (const struct unidat *u = unis; u->name != NULL; u++) - *u->loc = gl_uni_loc(prog, u->name); +#define SH_UNI(_, name) s->uni.name = gl_uni_loc(prog, #name); +#define SH_TEX(_, name) s->tex.name = gl_uni_loc(prog, #name); +#include "shaders/data.h" + s->prog = prog; +} - return prog; +void glprog_init(void) +{ +#define SH_PROG(name) load_shader(&prog.name, "shaders/" #name); +#include "shaders/data.h" } -- cgit v1.2.3-54-g00ecf