Add --pipe flag
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
SHELL := /bin/bash
|
||||
.SHELLFLAGS="-O extglob -c"
|
||||
.SHELLFLAGS = -O extglob -c
|
||||
|
||||
src = $(wildcard *.c)
|
||||
obj = $(src:.c=.o)
|
||||
|
||||
102
glava.c
102
glava.c
@@ -182,7 +182,12 @@ static const char* help_str =
|
||||
" appropriate backend will be used for the underlying windowing\n"
|
||||
" system.\n"
|
||||
"-a, --audio=BACKEND specifies an audio input backend to use.\n"
|
||||
"-i, --stdin[=FORMAT] specifies a format for input to be read from stdin. The input\n"
|
||||
"-p, --pipe[=FORMAT] binds a value to be read from stdin. The input my be read using\n"
|
||||
" `@name` or `@name:default` syntax within shader sources.\n"
|
||||
" A stream of inputs (each overriding the previous) must be\n"
|
||||
" assigned with the `name = value` syntax and separated by\n"
|
||||
" newline (\'\\n\') characters.\n"
|
||||
"-i, --stdin[=OLDFORMAT] specifies a format for input to be read from stdin. The input\n"
|
||||
" may be read from the STDIN macro from within shader sources.\n"
|
||||
" A stream of inputs (each overriding the previous) must be\n"
|
||||
" separated by newline (\'\\n\') characters.\n"
|
||||
@@ -200,12 +205,12 @@ static const char* help_str =
|
||||
"The BACKEND argument may be any of the following strings (for this particular build):\n"
|
||||
"%s"
|
||||
"\n"
|
||||
"The FORMAT argument must be a valid GLSL type. If `--stdin` is used without an argument,\n"
|
||||
"The OLDFORMAT argument must be a valid GLSL type. If `--stdin` is used without an argument,\n"
|
||||
"the default type is `vec4` (type used for RGBA colors)\n"
|
||||
"\n"
|
||||
GLAVA_VERSION_STRING "\n";
|
||||
|
||||
static const char* opt_str = "dhvVe:Cm:b:r:a:i::";
|
||||
static const char* opt_str = "dhvVe:Cm:b:r:a:i::p::";
|
||||
static struct option p_opts[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
@@ -216,6 +221,7 @@ static struct option p_opts[] = {
|
||||
{"force-mod", required_argument, 0, 'm'},
|
||||
{"copy-config", no_argument, 0, 'C'},
|
||||
{"backend", required_argument, 0, 'b'},
|
||||
{"pipe", optional_argument, 0, 'p'},
|
||||
{"stdin", optional_argument, 0, 'i'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
#ifdef GLAVA_DEBUG
|
||||
@@ -233,10 +239,11 @@ static void handle_term(int signum) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void append_buf(char** buf, size_t* sz_store, char* str) {
|
||||
buf = realloc(buf, ++(*sz_store) * sizeof(char*));
|
||||
buf[*sz_store - 1] = str;
|
||||
}
|
||||
#define append_buf(buf, sz_store, ...) \
|
||||
({ \
|
||||
buf = realloc(buf, ++(*sz_store) * sizeof(*buf)); \
|
||||
buf[*sz_store - 1] = __VA_ARGS__; \
|
||||
})
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -251,8 +258,10 @@ int main(int argc, char** argv) {
|
||||
const char* system_shader_paths[] = { user_path, install_path, NULL };
|
||||
int stdin_type = STDIN_TYPE_NONE;
|
||||
|
||||
char** requests = malloc(1);
|
||||
size_t requests_sz = 0;
|
||||
char** requests = malloc(1);
|
||||
size_t requests_sz = 0;
|
||||
struct rd_bind* binds = malloc(1);
|
||||
size_t binds_sz = 0;
|
||||
|
||||
bool verbose = false, copy_mode = false, desktop = false;
|
||||
|
||||
@@ -283,21 +292,77 @@ int main(int argc, char** argv) {
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
}
|
||||
case 'i': {
|
||||
case 'p': {
|
||||
if (stdin_type != STDIN_TYPE_NONE) goto conflict_error;
|
||||
char* parsed_name = NULL;
|
||||
const char* parsed_type = NULL;
|
||||
size_t in_sz = strlen(optarg);
|
||||
int sep = -1;
|
||||
for (size_t t = 0; t < in_sz; ++t) {
|
||||
switch (optarg[t]) {
|
||||
case ' ': optarg[t] = '\0'; goto after;
|
||||
case ':': sep = (int) t; break;
|
||||
}
|
||||
}
|
||||
after:
|
||||
if (sep >= 0) {
|
||||
parsed_type = strdup(optarg + sep + 1);
|
||||
optarg[sep] = '\0';
|
||||
}
|
||||
parsed_name = optarg;
|
||||
for (size_t t = 0; t < binds_sz; ++t) {
|
||||
if (!strcmp(binds[t].name, parsed_name)) {
|
||||
fprintf(stderr, "Error: attempted to re-bind pipe argument: \"%s\"\n", parsed_name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
int type = -1;
|
||||
if (parsed_type == NULL || strlen(parsed_type) == 0) {
|
||||
type = STDIN_TYPE_VEC4;
|
||||
parsed_type = bind_types[STDIN_TYPE_VEC4].n;
|
||||
} else {
|
||||
for (size_t t = 0 ; bind_types[t].n != NULL; ++t) {
|
||||
if (!strcmp(bind_types[t].n, parsed_type)) {
|
||||
type = bind_types[t].i;
|
||||
parsed_type = bind_types[t].n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == -1) {
|
||||
fprintf(stderr, "Error: Unsupported `--pipe` GLSL type: \"%s\"\n", parsed_type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
struct rd_bind bd = {
|
||||
.name = parsed_name,
|
||||
.type = type,
|
||||
.stype = parsed_type
|
||||
};
|
||||
append_buf(binds, &binds_sz, bd);
|
||||
break;
|
||||
}
|
||||
case 'i': { /* TODO: remove */
|
||||
if (binds_sz > 0) goto conflict_error;
|
||||
stdin_type = -1;
|
||||
for (size_t t = 0 ; stdin_types[t].n != NULL; ++t) {
|
||||
if (optarg == NULL) {
|
||||
stdin_type = STDIN_TYPE_VEC4;
|
||||
} else if (!strcmp(stdin_types[t].n, optarg)) {
|
||||
stdin_type = stdin_types[t].i;
|
||||
break;
|
||||
if (optarg == NULL) {
|
||||
stdin_type = STDIN_TYPE_VEC4;
|
||||
} else {
|
||||
for (size_t t = 0 ; bind_types[t].n != NULL; ++t) {
|
||||
if (!strcmp(bind_types[t].n, optarg)) {
|
||||
stdin_type = bind_types[t].i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stdin_type == -1) {
|
||||
fprintf(stderr, "Unsupported `--stdin` GLSL type: \"%s\"\n", optarg);
|
||||
fprintf(stderr, "Error: Unsupported `--stdin` GLSL type: \"%s\"\n", optarg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
conflict_error:
|
||||
fprintf(stderr, "Error: cannot use `--pipe` and `--stdin` together\n");
|
||||
exit(EXIT_FAILURE);
|
||||
#ifdef GLAVA_DEBUG
|
||||
case 'T': {
|
||||
entry = "test_rc.glsl";
|
||||
@@ -322,9 +387,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
/* Null terminate array arguments */
|
||||
append_buf(requests, &requests_sz, NULL);
|
||||
append_buf(binds, &binds_sz, (struct rd_bind) { .name = NULL });
|
||||
|
||||
rd = rd_new(system_shader_paths, entry, (const char**) requests,
|
||||
backend, stdin_type, desktop, verbose);
|
||||
backend, binds, stdin_type, desktop, verbose);
|
||||
|
||||
struct sigaction action = { .sa_handler = handle_term };
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
|
||||
116
glsl_ext.c
116
glsl_ext.c
@@ -13,6 +13,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "render.h"
|
||||
#include "glsl_ext.h"
|
||||
|
||||
#define LINE_START 0
|
||||
@@ -22,6 +23,7 @@
|
||||
#define INCLUDE 4
|
||||
#define COLOR 5
|
||||
#define DEFINE 6
|
||||
#define BIND 7
|
||||
|
||||
struct sbuf {
|
||||
char* buf;
|
||||
@@ -65,12 +67,16 @@ static void se_append(struct sbuf* sbuf, size_t elen, const char* fmt, ...) {
|
||||
}
|
||||
|
||||
#define parse_error(line, f, fmt, ...) \
|
||||
fprintf(stderr, "[%s:%d] " fmt "\n", f, (int) line, __VA_ARGS__); \
|
||||
abort()
|
||||
do { \
|
||||
fprintf(stderr, "[%s:%d] " fmt "\n", f, (int) line, __VA_ARGS__); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
#define parse_error_s(line, f, s) \
|
||||
fprintf(stderr, "[%s:%d] " s "\n", f, (int) line); \
|
||||
abort()
|
||||
#define parse_error_s(line, f, s) \
|
||||
do { \
|
||||
fprintf(stderr, "[%s:%d] " s "\n", f, (int) line); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
struct schar {
|
||||
char* buf;
|
||||
@@ -196,7 +202,8 @@ static struct schar directive(struct glsl_ext* ext, char** args,
|
||||
.cd = ext->cd,
|
||||
.cfd = ext->cfd,
|
||||
.dd = ext->dd,
|
||||
.handlers = ext->handlers
|
||||
.handlers = ext->handlers,
|
||||
.binds = ext->binds
|
||||
};
|
||||
|
||||
/* recursively process */
|
||||
@@ -306,10 +313,12 @@ void ext_process(struct glsl_ext* ext, const char* f) {
|
||||
size_t t;
|
||||
char at;
|
||||
int state = LINE_START;
|
||||
size_t macro_start_idx, arg_start_idx, cbuf_idx;
|
||||
size_t macro_start_idx, arg_start_idx, cbuf_idx, bbuf_idx;
|
||||
size_t line = 1;
|
||||
bool quoted = false, arg_start;
|
||||
bool quoted = false, arg_start, b_sep = false, b_spc = false;
|
||||
int b_br = 0;
|
||||
char cbuf[9];
|
||||
char bbuf[128];
|
||||
char** args = malloc(sizeof(char*));
|
||||
size_t args_sz = 0;
|
||||
|
||||
@@ -385,6 +394,17 @@ void ext_process(struct glsl_ext* ext, const char* f) {
|
||||
continue;
|
||||
} else goto normal_char;
|
||||
}
|
||||
case '@': {
|
||||
/* handle bind syntax */
|
||||
if (!comment && !string && ext->binds != NULL) {
|
||||
state = BIND;
|
||||
b_sep = false;
|
||||
b_spc = false;
|
||||
b_br = 0;
|
||||
bbuf_idx = 0;
|
||||
continue;
|
||||
} else goto normal_char;
|
||||
}
|
||||
case '\n':
|
||||
if (comment && comment_line) {
|
||||
comment = false;
|
||||
@@ -425,6 +445,83 @@ void ext_process(struct glsl_ext* ext, const char* f) {
|
||||
continue;
|
||||
else goto copy; /* copy character if it ended the sequence */
|
||||
}
|
||||
}
|
||||
case BIND: { /* parse bind syntax (@name:default -> __IN_name | default)*/
|
||||
switch (at) {
|
||||
default:
|
||||
if (b_br > 0) goto handle_bind; /* store characters in braces */
|
||||
else goto emit_bind; /* emit on unexpected char outside braces */
|
||||
case '(':
|
||||
if (b_sep) {
|
||||
++b_br; goto handle_bind; /* inc. brace level */
|
||||
} else goto emit_bind; /* emit if wrong context: `@sym(`, `@(` (no ':') */
|
||||
case ')':
|
||||
if (b_br <= 0 || !b_sep) goto emit_bind; /* start emitting on unexpected ')': `@sym:v)`, `@s)` */
|
||||
else {
|
||||
--b_br;
|
||||
if (b_br == 0) goto emit_bind; /* emit after reading brace contents */
|
||||
else goto handle_bind; /* continue reading if nested */
|
||||
}
|
||||
case ' ': if (b_br <= 0) b_spc = true; /* flag a non-braced space */
|
||||
case '#':
|
||||
if (b_sep) goto handle_bind; /* handle color syntax only for defaults */
|
||||
else goto emit_bind; /* if '#' is encountered, skip to emit */
|
||||
case ':': b_sep = true;
|
||||
handle_bind: /* use character for binding syntax */
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
case '0' ... '9': {
|
||||
if (b_spc && b_br <= 0)
|
||||
goto emit_bind; /* skip non-braced characters after space: `@sym:vec4 c` */
|
||||
bbuf[bbuf_idx] = at;
|
||||
++bbuf_idx;
|
||||
if (bbuf_idx >= sizeof(bbuf) - 1)
|
||||
goto emit_bind; /* start emitting if buffer was filled */
|
||||
else continue;
|
||||
}
|
||||
emit_bind: /* end binding syntax with current char */
|
||||
case '\n':
|
||||
case '\0': {
|
||||
const char* parsed_name = NULL;
|
||||
const char* parsed_default = NULL;
|
||||
bbuf[bbuf_idx] = '\0'; /* null terminate */
|
||||
int sep = -1;
|
||||
for (size_t p = 0; p < bbuf_idx; ++p)
|
||||
if (bbuf[p] == ':') sep = p;
|
||||
if (sep >= 0) {
|
||||
parsed_default = strdup(bbuf + sep + 1);
|
||||
bbuf[sep] = '\0';
|
||||
}
|
||||
parsed_name = bbuf;
|
||||
bool m = false;
|
||||
for (struct rd_bind* bd = ext->binds; bd->name != NULL; ++bd) {
|
||||
if (!strcmp(parsed_name, bd->name)) {
|
||||
se_append(&sbuf, 128, " __IN_%s ", parsed_name);
|
||||
m = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!m) {
|
||||
if (parsed_default) {
|
||||
if (parsed_default[0] == '#') {
|
||||
++parsed_default;
|
||||
float r = 0.0F, g = 0.0F, b = 0.0F, a = 1.0F;
|
||||
if (ext_parse_color(parsed_default, 2, (float*[]) { &r, &g, &b, &a })) {
|
||||
se_append(&sbuf, 64, " vec4(%.6f, %.6f, %.6f, %.6f) ", r, g, b, a);
|
||||
} else {
|
||||
parse_error(line, f, "Invalid color format '#%s' while "
|
||||
"parsing GLSL color syntax extension", parsed_default);
|
||||
}
|
||||
} else se_append(&sbuf, 260, " %s ", parsed_default);
|
||||
} else parse_error(line, f, "Unexpected `--pipe` binding name '@%s' while parsing GLSL."
|
||||
" Try assigning a default or binding the value.", parsed_name);
|
||||
}
|
||||
state = at == '\n' ? LINE_START : GLSL;
|
||||
if (bbuf_idx >= sizeof(bbuf) - 1)
|
||||
continue;
|
||||
else goto copy; /* copy character if it ended the sequence */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* emit contents from start of macro to current index and resume regular parsing*/
|
||||
#define skip_macro() \
|
||||
@@ -444,7 +541,8 @@ void ext_process(struct glsl_ext* ext, const char* f) {
|
||||
(!strncmp("#" lower, &ext->source[macro_start_idx], t - macro_start_idx) \
|
||||
|| !strncmp("#" upper, &ext->source[macro_start_idx], t - macro_start_idx))
|
||||
#define DIRECTIVE_CASE(lower, upper) \
|
||||
do { if (state == MACRO && DIRECTIVE_CMP(#lower, #upper)) { state = upper; goto prepare_arg_parse; } } while (0)
|
||||
({ if (state == MACRO && DIRECTIVE_CMP(#lower, #upper)) \
|
||||
{ state = upper; goto prepare_arg_parse; } })
|
||||
|
||||
DIRECTIVE_CASE(request, REQUEST);
|
||||
DIRECTIVE_CASE(include, INCLUDE);
|
||||
|
||||
@@ -24,11 +24,12 @@ struct glsl_ext {
|
||||
char* processed; /* OUT: null terminated processed source */
|
||||
size_t p_len; /* OUT: length of processed buffer, excluding null char */
|
||||
const char* source; /* IN: raw data passed via ext_process */
|
||||
size_t source_len; /* IN: raw source len */
|
||||
size_t source_len; /* IN: raw source len */
|
||||
const char* cd; /* IN: current directory */
|
||||
const char* cfd; /* IN: config directory, if NULL it is assumed to cd */
|
||||
const char* dd; /* IN: default directory */
|
||||
void** destruct; /* internal */
|
||||
const char* dd; /* IN: default directory */
|
||||
struct rd_bind* binds; /* OPT IN: --pipe binds */
|
||||
void** destruct; /* internal */
|
||||
size_t destruct_sz; /* internal */
|
||||
|
||||
/* IN: NULL (where the last element's 'name' member is NULL) terminated
|
||||
|
||||
161
render.c
161
render.c
@@ -20,7 +20,7 @@
|
||||
#include "xwin.h"
|
||||
#include "glsl_ext.h"
|
||||
|
||||
typeof(stdin_types) stdin_types = {
|
||||
typeof(bind_types) bind_types = {
|
||||
[STDIN_TYPE_NONE] = { .n = "NONE", .i = STDIN_TYPE_NONE },
|
||||
[STDIN_TYPE_INT] = { .n = "int", .i = STDIN_TYPE_INT },
|
||||
[STDIN_TYPE_FLOAT] = { .n = "float", .i = STDIN_TYPE_FLOAT },
|
||||
@@ -106,6 +106,7 @@ struct gl_sfbo {
|
||||
bool indirect, nativeonly;
|
||||
const char* name;
|
||||
struct gl_bind* binds;
|
||||
GLuint* pipe_uniforms;
|
||||
size_t binds_sz;
|
||||
};
|
||||
|
||||
@@ -139,6 +140,7 @@ struct gl_data {
|
||||
float* interpolate_buf[6];
|
||||
int geometry[4];
|
||||
int stdin_type;
|
||||
struct rd_bind* binds;
|
||||
#ifdef GLAVA_DEBUG
|
||||
struct {
|
||||
float r, g, b, a;
|
||||
@@ -205,6 +207,19 @@ static GLuint shaderload(const char* rpath,
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max_uniforms);
|
||||
|
||||
const GLchar* map = raw ? shader : mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
char* bind_header = malloc(1);
|
||||
bind_header[0] = '\0';
|
||||
size_t bh_idx = 0;
|
||||
|
||||
const char* fmt = "uniform %s __IN_%s;\n";
|
||||
|
||||
for (struct rd_bind* bd = gl->binds; bd->name != NULL; ++bd) {
|
||||
size_t inc = snprintf(NULL, 0, fmt, bd->stype, bd->name);
|
||||
bind_header = realloc(bind_header, bh_idx + inc + 1);
|
||||
snprintf(bind_header + bh_idx, inc + 1, fmt, bd->stype, bd->name);
|
||||
bh_idx += inc;
|
||||
}
|
||||
|
||||
static const GLchar* header_fmt =
|
||||
"#version %d\n"
|
||||
@@ -216,7 +231,8 @@ static GLuint shaderload(const char* rpath,
|
||||
"#define USE_STDIN %d\n"
|
||||
"#if USE_STDIN == 1\n"
|
||||
"uniform %s STDIN;\n"
|
||||
"#endif\n";
|
||||
"#endif\n"
|
||||
"%s";
|
||||
|
||||
struct glsl_ext ext = {
|
||||
.source = raw ? NULL : map,
|
||||
@@ -226,7 +242,8 @@ static GLuint shaderload(const char* rpath,
|
||||
.dd = defaults,
|
||||
.handlers = handlers,
|
||||
.processed = (char*) (raw ? shader : NULL),
|
||||
.p_len = raw ? s_len : 0
|
||||
.p_len = raw ? s_len : 0,
|
||||
.binds = gl->binds
|
||||
};
|
||||
|
||||
/* If this is raw input, skip processing */
|
||||
@@ -237,7 +254,8 @@ static GLuint shaderload(const char* rpath,
|
||||
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms,
|
||||
gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor,
|
||||
1, gl->premultiply_alpha ? 1 : 0,
|
||||
gl->stdin_type != STDIN_TYPE_NONE, stdin_types[gl->stdin_type].n);
|
||||
gl->stdin_type != STDIN_TYPE_NONE, bind_types[gl->stdin_type].n,
|
||||
bind_header);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
|
||||
return 0;
|
||||
@@ -753,10 +771,10 @@ static struct gl_bind_src* lookup_bind_src(const char* str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct renderer* rd_new(const char** paths, const char* entry,
|
||||
const char** requests, const char* force_backend,
|
||||
int stdin_type, bool auto_desktop,
|
||||
bool verbose) {
|
||||
struct renderer* rd_new(const char** paths, const char* entry,
|
||||
const char** requests, const char* force_backend,
|
||||
struct rd_bind* bindings, int stdin_type,
|
||||
bool auto_desktop, bool verbose) {
|
||||
|
||||
xwin_wait_for_wm();
|
||||
|
||||
@@ -806,6 +824,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F },
|
||||
.clickthrough = false,
|
||||
.stdin_type = stdin_type,
|
||||
.binds = bindings,
|
||||
#ifdef GLAVA_DEBUG
|
||||
.test_eval_color = { 0.0F, 0.0F, 0.0F, 0.0F },
|
||||
.debug_verbose = verbose
|
||||
@@ -1337,6 +1356,11 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
} while (found);
|
||||
|
||||
stages = malloc(sizeof(struct gl_sfbo) * count);
|
||||
|
||||
size_t pipe_binds_len = 0;
|
||||
|
||||
for (struct rd_bind* bd = gl->binds; bd->name != NULL; ++bd)
|
||||
++pipe_binds_len;
|
||||
|
||||
idx = 1;
|
||||
do {
|
||||
@@ -1351,12 +1375,13 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
|
||||
struct gl_sfbo* s = &stages[idx - 1];
|
||||
*s = (struct gl_sfbo) {
|
||||
.name = strdup(d->d_name),
|
||||
.shader = 0,
|
||||
.indirect = false,
|
||||
.nativeonly = false,
|
||||
.binds = malloc(1),
|
||||
.binds_sz = 0
|
||||
.name = strdup(d->d_name),
|
||||
.shader = 0,
|
||||
.indirect = false,
|
||||
.nativeonly = false,
|
||||
.binds = malloc(1),
|
||||
.binds_sz = 0,
|
||||
.pipe_uniforms = malloc(sizeof(GLuint) * pipe_binds_len)
|
||||
};
|
||||
|
||||
current = s;
|
||||
@@ -1387,6 +1412,17 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
if (gl->stdin_type != STDIN_TYPE_NONE) {
|
||||
s->stdin_uniform = glGetUniformLocation(id, "STDIN");
|
||||
}
|
||||
size_t u = 0;
|
||||
for (struct rd_bind* bd = gl->binds; bd->name != NULL; ++bd) {
|
||||
char buf[128];
|
||||
if (snprintf(buf, 128, "__IN_%s", bd->name) > 0) {
|
||||
s->pipe_uniforms[u] = glGetUniformLocation(id, buf);
|
||||
} else {
|
||||
fprintf(stderr, "failed to format binding: \"%s\"\n", bd->name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
++u;
|
||||
}
|
||||
glBindFragDataLocation(id, 1, "fragment");
|
||||
glUseProgram(0);
|
||||
}
|
||||
@@ -1575,7 +1611,15 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
|
||||
glViewport(0, 0, ww, wh);
|
||||
|
||||
static bool stdin_uniform_ready = false;
|
||||
static char stdin_buf_store[128] = {};
|
||||
static char* stdin_buf = stdin_buf_store;
|
||||
static int stdin_select = STDIN_TYPE_NONE;
|
||||
static size_t stdin_idx = 0;
|
||||
static bool stdin_uniform_ready = false;
|
||||
static size_t stdin_bind_off = 0;
|
||||
static char* stdin_name = NULL;
|
||||
static size_t stdin_name_len = 0;
|
||||
static bool pipe_eof = false;
|
||||
static union {
|
||||
bool b;
|
||||
int i;
|
||||
@@ -1583,9 +1627,7 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
} stdin_parsed;
|
||||
|
||||
/* Parse stdin data, if nessecary */
|
||||
if (gl->stdin_type != STDIN_TYPE_NONE) {
|
||||
static char stdin_buf[64] = {};
|
||||
static size_t stdin_idx = 0;
|
||||
if (!pipe_eof && (gl->stdin_type != STDIN_TYPE_NONE || gl->binds[0].name != NULL)) {
|
||||
int c, n, p;
|
||||
setvbuf(stdin, NULL, _IOLBF, 64);
|
||||
|
||||
@@ -1597,13 +1639,65 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
|
||||
for (p = 0; n > 0; ++p) {
|
||||
c = getchar();
|
||||
if (stdin_idx >= (sizeof(stdin_buf) / sizeof(*stdin_buf)) - 1)
|
||||
if (stdin_idx >= (sizeof(stdin_buf_store) / sizeof(*stdin_buf_store)) - 1)
|
||||
break;
|
||||
if (c != EOF && c != '\n')
|
||||
stdin_buf[stdin_idx++] = c;
|
||||
else {
|
||||
stdin_buf[stdin_idx] = '\0';
|
||||
switch (gl->stdin_type) {
|
||||
|
||||
stdin_select = gl->stdin_type;
|
||||
|
||||
if (gl->stdin_type == STDIN_TYPE_NONE) {
|
||||
bool v = false;
|
||||
bool valid = false;
|
||||
while (*stdin_buf == ' ') ++stdin_buf; /* advance to first char */
|
||||
for (int h = 0; stdin_buf[h] != '\0'; ++h) {
|
||||
int l;
|
||||
if (!v && stdin_buf[h] == '=') {
|
||||
for (l = h - 1; l >= 0; --l)
|
||||
if (stdin_buf[l] != ' ')
|
||||
break;
|
||||
stdin_name = stdin_buf;
|
||||
stdin_name_len = l + 1;
|
||||
v = true;
|
||||
} else if (v && stdin_buf[h] != ' ') {
|
||||
stdin_buf += h;
|
||||
for (l = strlen(stdin_buf) - 1; stdin_buf[l] == ' '; --l);
|
||||
stdin_buf[l + 1] = '\0';
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!valid && !v) {
|
||||
/* no assignment, just a default value */
|
||||
stdin_name = "";
|
||||
stdin_name_len = 0;
|
||||
valid = true;
|
||||
}
|
||||
if (!valid) {
|
||||
fprintf(stderr, "Bad assignment format for \"%s\"\n", stdin_buf);
|
||||
goto reset;
|
||||
}
|
||||
bool bound = false;
|
||||
size_t u = 0;
|
||||
for (struct rd_bind* bd = gl->binds; bd->name != NULL; ++bd) {
|
||||
if (!strncmp(bd->name, stdin_name, stdin_name_len)) {
|
||||
bound = true;
|
||||
stdin_bind_off = u;
|
||||
stdin_select = bd->type;
|
||||
break;
|
||||
}
|
||||
++u;
|
||||
}
|
||||
if (!bound) {
|
||||
fprintf(stderr, "Variable name not bound: \"%.*s\"\n",
|
||||
(int) stdin_name_len, stdin_name);
|
||||
stdin_select = STDIN_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (stdin_select) {
|
||||
case STDIN_TYPE_BOOL:
|
||||
if (!strcmp("true", stdin_buf) ||
|
||||
!strcmp("TRUE", stdin_buf) ||
|
||||
@@ -1617,6 +1711,8 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
!strcmp("0", stdin_buf)) {
|
||||
stdin_parsed.b = false;
|
||||
stdin_uniform_ready = true;
|
||||
} else {
|
||||
fprintf(stderr, "Bad format for boolean: \"%s\"\n", stdin_buf);
|
||||
}
|
||||
break;
|
||||
case STDIN_TYPE_INT:
|
||||
@@ -1658,13 +1754,16 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
&stdin_parsed.f[2], &stdin_parsed.f[3]))
|
||||
stdin_uniform_ready = true;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
reset:
|
||||
stdin_buf = stdin_buf_store;
|
||||
stdin_buf[0] = '\0';
|
||||
stdin_idx = 0;
|
||||
stdin_idx = 0;
|
||||
break;
|
||||
|
||||
if (c == EOF) {
|
||||
gl->stdin_type = STDIN_TYPE_NONE;
|
||||
pipe_eof = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -1739,29 +1838,31 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
/* Select the program associated with this pass */
|
||||
glUseProgram(current->shader);
|
||||
|
||||
/* Pass STDIN unfirom if one has been parsed */
|
||||
/* Pass uniform if one has been parsed */
|
||||
if (stdin_uniform_ready) {
|
||||
switch (gl->stdin_type) {
|
||||
GLuint handle = gl->stdin_type != STDIN_TYPE_NONE ? current->stdin_uniform :
|
||||
current->pipe_uniforms[stdin_bind_off];
|
||||
switch (stdin_select) {
|
||||
case STDIN_TYPE_BOOL:
|
||||
glUniform1i(current->stdin_uniform, (int) stdin_parsed.b);
|
||||
glUniform1i(handle, (int) stdin_parsed.b);
|
||||
break;
|
||||
case STDIN_TYPE_INT:
|
||||
glUniform1i(current->stdin_uniform, stdin_parsed.i);
|
||||
glUniform1i(handle, stdin_parsed.i);
|
||||
break;
|
||||
case STDIN_TYPE_FLOAT:
|
||||
glUniform1f(current->stdin_uniform, stdin_parsed.f[0]);
|
||||
glUniform1f(handle, stdin_parsed.f[0]);
|
||||
break;
|
||||
case STDIN_TYPE_VEC2:
|
||||
glUniform2f(current->stdin_uniform,
|
||||
glUniform2f(handle,
|
||||
stdin_parsed.f[0], stdin_parsed.f[1]);
|
||||
break;
|
||||
case STDIN_TYPE_VEC3:
|
||||
glUniform3f(current->stdin_uniform,
|
||||
glUniform3f(handle,
|
||||
stdin_parsed.f[0], stdin_parsed.f[1],
|
||||
stdin_parsed.f[2]);
|
||||
break;
|
||||
case STDIN_TYPE_VEC4:
|
||||
glUniform4f(current->stdin_uniform,
|
||||
glUniform4f(handle,
|
||||
stdin_parsed.f[0], stdin_parsed.f[1],
|
||||
stdin_parsed.f[2], stdin_parsed.f[3]);
|
||||
break;
|
||||
|
||||
16
render.h
16
render.h
@@ -5,7 +5,7 @@
|
||||
extern const struct {
|
||||
const char* n;
|
||||
int i;
|
||||
} stdin_types[];
|
||||
} bind_types[];
|
||||
|
||||
#define STDIN_TYPE_NONE 0
|
||||
#define STDIN_TYPE_INT 1
|
||||
@@ -24,16 +24,22 @@ typedef struct renderer {
|
||||
struct gl_data* gl;
|
||||
} renderer;
|
||||
|
||||
struct rd_bind {
|
||||
const char* name;
|
||||
const char* stype;
|
||||
int type;
|
||||
};
|
||||
|
||||
#ifdef GLAVA_DEBUG
|
||||
void rd_enable_test_mode(void);
|
||||
bool rd_get_test_mode (void);
|
||||
bool rd_test_evaluate (struct renderer*);
|
||||
#endif
|
||||
|
||||
struct renderer* rd_new (const char** paths, const char* entry,
|
||||
const char** requests, const char* force_backend,
|
||||
int stdin_type, bool auto_desktop,
|
||||
bool verbose);
|
||||
struct renderer* rd_new (const char** paths, const char* entry,
|
||||
const char** requests, const char* force_backend,
|
||||
struct rd_bind* bindings, int stdin_type,
|
||||
bool auto_desktop, bool verbose);
|
||||
bool rd_update (struct renderer*, float* lb, float* rb,
|
||||
size_t bsz, bool modified);
|
||||
void rd_destroy (struct renderer*);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define AMPLIFY 300
|
||||
/* Whether the current settings use the alpha channel;
|
||||
enabling this is required for alpha to function
|
||||
correctly on X11 with `"native"` transparency. */
|
||||
correctly on X11 with `"native"` transparency */
|
||||
#define USE_ALPHA 0
|
||||
/* How strong the gradient changes */
|
||||
#define GRADIENT_POWER 60
|
||||
|
||||
Reference in New Issue
Block a user