aboutsummaryrefslogtreecommitdiffstats
path: root/glprog.c
diff options
context:
space:
mode:
authorTomasz Kramkowski <tk@the-tk.com>2018-10-19 23:22:07 +0300
committerTomasz Kramkowski <tk@the-tk.com>2018-10-19 23:30:23 +0300
commit7c1edef3ac501d40e3de495b9434df71f535e9bc (patch)
treefd7f4264bdf5c30f7182a147ed9e6c7935c69bf2 /glprog.c
parent91b543a29cb8852251908a49cd120a6f7d9f2f11 (diff)
downloadfaqe-7c1edef3ac501d40e3de495b9434df71f535e9bc.tar.gz
faqe-7c1edef3ac501d40e3de495b9434df71f535e9bc.tar.xz
faqe-7c1edef3ac501d40e3de495b9434df71f535e9bc.zip
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.
Diffstat (limited to 'glprog.c')
-rw-r--r--glprog.c113
1 files changed, 98 insertions, 15 deletions
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 <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#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"
}