diff options
author | 2016-07-03 19:23:03 +0200 | |
---|---|---|
committer | 2016-07-03 19:42:52 +0200 | |
commit | be230d16e57d948a990d16f06d4da11cfea97701 (patch) | |
tree | 74a5345cac0506bb97494b79ab7900fb1fbf4a98 /video/out/opengl/user_shaders.c | |
parent | 5b6cce2b735951f82b707c3d3625f99bc6d6da09 (diff) |
vo_opengl: move eval_szexpr to user_shaders.c
This moves some of the bulky user-shader specific logic into the file
dedicated to it. Rather than expose video.c state, variable lookup is
now done via a simulated closure.
Diffstat (limited to 'video/out/opengl/user_shaders.c')
-rw-r--r-- | video/out/opengl/user_shaders.c | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/video/out/opengl/user_shaders.c b/video/out/opengl/user_shaders.c index 8f915a56e3..112012f04f 100644 --- a/video/out/opengl/user_shaders.c +++ b/video/out/opengl/user_shaders.c @@ -16,6 +16,7 @@ */ #include <ctype.h> +#include <assert.h> #include "user_shaders.h" @@ -69,6 +70,94 @@ static bool parse_rpn_szexpr(struct bstr line, struct szexp out[MAX_SZEXP_SIZE]) return true; } +// Returns whether successful. 'result' is left untouched on failure +bool eval_szexpr(struct mp_log *log, void *priv, + bool (*lookup)(void *priv, struct bstr var, float size[2]), + struct szexp expr[MAX_SZEXP_SIZE], float *result) +{ + float stack[MAX_SZEXP_SIZE] = {0}; + int idx = 0; // points to next element to push + + for (int i = 0; i < MAX_SZEXP_SIZE; i++) { + switch (expr[i].tag) { + case SZEXP_END: + goto done; + + case SZEXP_CONST: + // Since our SZEXPs are bound by MAX_SZEXP_SIZE, it should be + // impossible to overflow the stack + assert(idx < MAX_SZEXP_SIZE); + stack[idx++] = expr[i].val.cval; + continue; + + case SZEXP_OP1: + if (idx < 1) { + mp_warn(log, "Stack underflow in RPN expression!\n"); + return false; + } + + switch (expr[i].val.op) { + case SZEXP_OP_NOT: stack[idx-1] = !stack[idx-1]; break; + default: abort(); + } + continue; + + case SZEXP_OP2: + if (idx < 2) { + mp_warn(log, "Stack underflow in RPN expression!\n"); + return false; + } + + // Pop the operands in reverse order + float op2 = stack[--idx]; + float op1 = stack[--idx]; + float res = 0.0; + switch (expr[i].val.op) { + case SZEXP_OP_ADD: res = op1 + op2; break; + case SZEXP_OP_SUB: res = op1 - op2; break; + case SZEXP_OP_MUL: res = op1 * op2; break; + case SZEXP_OP_DIV: res = op1 / op2; break; + case SZEXP_OP_GT: res = op1 > op2; break; + case SZEXP_OP_LT: res = op1 < op2; break; + default: abort(); + } + + if (!isfinite(res)) { + mp_warn(log, "Illegal operation in RPN expression!\n"); + return false; + } + + stack[idx++] = res; + continue; + + case SZEXP_VAR_W: + case SZEXP_VAR_H: { + struct bstr name = expr[i].val.varname; + float size[2]; + + if (!lookup(priv, name, size)) { + mp_warn(log, "Variable %.*s not found in RPN expression!\n", + BSTR_P(name)); + return false; + } + + stack[idx++] = (expr[i].tag == SZEXP_VAR_W) ? size[0] : size[1]; + continue; + } + } + } + +done: + // Return the single stack element + if (idx != 1) { + mp_warn(log, "Malformed stack after RPN expression!\n"); + return false; + } + + *result = stack[0]; + return true; +} + // Returns false if no more shaders could be parsed bool parse_user_shader_pass(struct mp_log *log, struct bstr *body, struct gl_user_shader *out) |