Postprocessing 2: Electric Boogalo

This commit is contained in:
Andrei "Akari" Alexeyev 2017-03-27 01:42:09 +03:00
parent 8a636822eb
commit dec99650c7
7 changed files with 289 additions and 31 deletions

View file

@ -84,6 +84,7 @@ set(SRCs
resource/font.c
resource/shader.c
resource/model.c
resource/postprocess.c
rwops/rwops_zlib.c
rwops/rwops_segment.c
rwops/rwops_autobuf.c

144
src/resource/postprocess.c Normal file
View file

@ -0,0 +1,144 @@
#include <SDL.h>
#include "util.h"
#include "postprocess.h"
#include "resource.h"
static PostprocessShaderUniformFuncPtr get_uniform_func(PostprocessShaderUniformType type, int size) {
tsglUniform1fv_ptr f_funcs[] = { glUniform1fv, glUniform2fv, glUniform3fv, glUniform4fv };
tsglUniform1iv_ptr i_funcs[] = { glUniform1iv, glUniform2iv, glUniform3iv, glUniform4iv };
tsglUniform1uiv_ptr ui_funcs[] = { glUniform1uiv, glUniform2uiv, glUniform3uiv, glUniform4uiv };
PostprocessShaderUniformFuncPtr *lists[] = {
(PostprocessShaderUniformFuncPtr*) f_funcs,
(PostprocessShaderUniformFuncPtr*) i_funcs,
(PostprocessShaderUniformFuncPtr*) ui_funcs,
};
return lists[type][size - 1];
}
static void postprocess_load_callback(const char *key, const char *value, void *data) {
PostprocessShader **slist = data;
PostprocessShader *current = *slist;
if(!strcmp(key, "@shader")) {
current = create_element((void**)slist, sizeof(PostprocessShader));
current->uniforms = NULL;
current->shader = get_resource(RES_SHADER, value, RESF_PRELOAD | RESF_PERMANENT)->shader;
return;
}
if(!current) {
log_warn("Must define a @shader before key '%s'", key);
return;
}
char buf[strlen(key) + 1];
strcpy(buf, key);
char *type = buf;
char *name;
int utype;
int usize;
int asize;
int typesize;
switch(*type) {
case 'f': utype = PSU_FLOAT; typesize = sizeof(GLfloat); break;
case 'i': utype = PSU_INT; typesize = sizeof(GLint); break;
case 'u': utype = PSU_UINT; typesize = sizeof(GLuint); break;
default:
log_warn("Invalid type in key '%s'", key);
return;
}
++type;
usize = strtol(type, &type, 10);
if(usize < 1 || usize > 4) {
log_warn("Invalid uniform size %i in key '%s' (must be in range [1, 4])", usize, key);
return;
}
asize = strtol(type, &type, 10);
if(asize < 1) {
log_warn("Negative uniform amount in key '%s'", key);
return;
}
name = type;
while(isspace(*name))
++name;
PostprocessShaderUniformValuePtr vbuf;
vbuf.v = malloc(usize * asize * typesize);
for(int i = 0; i < usize * asize; ++i) {
switch(utype) {
case PSU_FLOAT: vbuf.f[i] = strtof (value, (char**)&value ); break;
case PSU_INT: vbuf.i[i] = strtol (value, (char**)&value, 10); break;
case PSU_UINT: vbuf.u[i] = strtoul (value, (char**)&value, 10); break;
}
}
PostprocessShaderUniform *uni = create_element((void**)&current->uniforms, sizeof(PostprocessShaderUniform));
uni->loc = uniloc(current->shader, name);
uni->type = utype;
uni->size = usize;
uni->amount = asize;
uni->values.v = vbuf.v;
uni->func = get_uniform_func(utype, usize);
}
PostprocessShader* postprocess_load(const char *path) {
PostprocessShader *list = NULL;
parse_keyvalue_file_cb(path, postprocess_load_callback, &list);
return list;
}
static void delete_uniform(void **dest, void *data) {
PostprocessShaderUniform *uni = data;
free(uni->values.v);
delete_element(dest, data);
}
static void delete_shader(void **dest, void *data) {
PostprocessShader *ps = data;
delete_all_elements((void**)&ps->uniforms, delete_uniform);
delete_element(dest, data);
}
void postprocess_unload(PostprocessShader **list) {
delete_all_elements((void**)list, delete_shader);
}
FBO* postprocess(PostprocessShader *ppshaders, FBO *primfbo, FBO *auxfbo, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw) {
FBO *fbos[] = { primfbo, auxfbo };
if(!ppshaders) {
return primfbo;
}
int fbonum = 1;
for(PostprocessShader *pps = ppshaders; pps; pps = pps->next) {
Shader *s = pps->shader;
glBindFramebuffer(GL_FRAMEBUFFER, fbos[fbonum]->fbo);
glUseProgram(s->prog);
prepare(fbos[fbonum], s);
for(PostprocessShaderUniform *u = pps->uniforms; u; u = u->next) {
u->func(u->loc, u->amount, u->values.v);
}
fbonum = !fbonum;
draw_fbo_viewport(fbos[fbonum]);
glUseProgram(0);
}
fbonum = !fbonum;
return fbos[fbonum];
}

View file

@ -0,0 +1,53 @@
#ifndef POSTPROCESS_H
#define POSTPROCESS_H
#include "list.h"
#include "hashtable.h"
#include "shader.h"
#include "fbo.h"
typedef struct PostprocessShader PostprocessShader;
typedef struct PostprocessShaderUniform PostprocessShaderUniform;
struct PostprocessShader {
PostprocessShader *next;
PostprocessShader *prev;
PostprocessShaderUniform *uniforms;
Shader *shader;
};
typedef enum PostprocessShaderUniformType {
PSU_FLOAT,
PSU_INT,
PSU_UINT,
} PostprocessShaderUniformType;
typedef union PostprocessShaderUniformValue {
void *v;
GLfloat *f;
GLint *i;
GLuint *u;
} PostprocessShaderUniformValuePtr;
typedef void (APIENTRY *PostprocessShaderUniformFuncPtr)(GLint, GLsizei, const GLvoid*);
struct PostprocessShaderUniform {
PostprocessShaderUniform *next;
PostprocessShaderUniform *prev;
PostprocessShaderUniformType type;
PostprocessShaderUniformValuePtr values;
PostprocessShaderUniformFuncPtr func;
int loc;
int size;
int amount;
};
typedef void (*PostprocessDrawFuncPtr)(FBO*);
typedef void (*PostprocessPrepareFuncPtr)(FBO*, Shader*);
PostprocessShader* postprocess_load(const char *path);
void postprocess_unload(PostprocessShader **list);
FBO* postprocess(PostprocessShader *ppshaders, FBO *fbo1, FBO *fbo2, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw);
#endif

View file

@ -399,6 +399,8 @@ void load_resources(void) {
init_fbo(&resources.fbg[0]);
init_fbo(&resources.fbg[1]);
init_fbo(&resources.fsec);
resources.stage_postprocess = postprocess_load("shader/postprocess.conf");
}
void free_resources(bool all) {
@ -439,6 +441,8 @@ void free_resources(bool all) {
delete_vbo(&_vbo);
postprocess_unload(&resources.stage_postprocess);
delete_fbo(&resources.fbg[0]);
delete_fbo(&resources.fbg[1]);
delete_fbo(&resources.fsec);

View file

@ -17,6 +17,7 @@
#include "shader.h"
#include "font.h"
#include "model.h"
#include "postprocess.h"
#include "hashtable.h"
#include "paths/native.h"
@ -100,6 +101,7 @@ typedef struct Resources {
ResourceHandler handlers[RES_NUMTYPES];
FBO fbg[2];
FBO fsec;
PostprocessShader *stage_postprocess;
} Resources;
extern Resources resources;

View file

@ -446,34 +446,13 @@ void draw_hud(void) {
static void apply_bg_shaders(ShaderRule *shaderrules);
static void draw_stage_title(StageInfo *info);
static void postprocess(FBO *fbo) {
static bool initialized = false;
static Shader *shader = NULL;
if(!initialized) {
Resource *res = get_resource(RES_SHADER, "postprocess", RESF_OPTIONAL | RESF_PRELOAD | RESF_PERMANENT);
if(res) {
shader = res->shader;
}
initialized = true;
}
if(!shader) {
draw_fbo_viewport(fbo);
return;
}
static void postprocess_prepare(FBO *fbo, Shader *s) {
float w = 1.0f / fbo->nw;
float h = 1.0f / fbo->nh;
glUseProgram(shader->prog);
glUniform1i(uniloc(shader, "frames"), global.frames);
glUniform2f(uniloc(shader, "view_ofs"), VIEWPORT_X * w, VIEWPORT_Y * h);
glUniform2f(uniloc(shader, "view_scale"), VIEWPORT_W * w, VIEWPORT_H * h);
draw_fbo_viewport(fbo);
glUseProgram(0);
glUniform1i(uniloc(s, "frames"), global.frames);
glUniform2f(uniloc(s, "view_ofs"), VIEWPORT_X * w, VIEWPORT_Y * h);
glUniform2f(uniloc(s, "view_scale"), VIEWPORT_W * w, VIEWPORT_H * h);
}
static void stage_draw(StageInfo *stage) {
@ -547,8 +526,11 @@ static void stage_draw(StageInfo *stage) {
if(stage->type != STAGE_SPELL)
draw_stage_title(stage);
FBO *ppfbo = postprocess(resources.stage_postprocess, &resources.fsec, resources.fbg, postprocess_prepare, draw_fbo_viewport);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
video_set_viewport();
glPushMatrix();
if(global.shake_view) {
@ -557,12 +539,10 @@ static void stage_draw(StageInfo *stage) {
glTranslatef(-global.shake_view,-global.shake_view,0);
}
postprocess(&resources.fsec);
draw_fbo_viewport(ppfbo);
glPopMatrix();
glPopMatrix();
draw_hud();
}

View file

@ -6,13 +6,15 @@
# You can force the script to pick up functions that are not directly called in the code here
force_funcs = [
force_funcs = {
'glDrawArraysInstancedEXT',
'glDrawArraysInstancedARB',
'glGetShaderiv',
'glGetShaderInfoLog',
'glGetProgramInfoLog',
]
}
force_funcs |= {"glUniform%i%sv" % (i, s) for i in range(1, 5) for s in ('f', 'i', 'ui')}
import sys, re
from pathlib import Path as P
@ -38,7 +40,7 @@ for src in srcdir.glob('**/*.c'):
for func in regex_glcall.findall(src.read_text()):
glfuncs.add(func)
glfuncs = sorted(list(glfuncs) + force_funcs)
glfuncs = sorted(list(glfuncs) + list(force_funcs))
typedefs = []
prototypes = []
@ -195,12 +197,24 @@ typedef void (GLAPIENTRY *tsglTexParameterf_ptr)(GLenum target, GLenum pname, GL
typedef void (GLAPIENTRY *tsglTexParameteri_ptr)(GLenum target, GLenum pname, GLint param);
typedef void (GLAPIENTRY *tsglTranslatef_ptr)(GLfloat x, GLfloat y, GLfloat z);
typedef void (APIENTRY *tsglUniform1f_ptr)(GLint location, GLfloat v0);
typedef void (APIENTRY *tsglUniform1fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform1i_ptr)(GLint location, GLint v0);
typedef void (APIENTRY *tsglUniform1iv_ptr)(GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRY *tsglUniform1uiv_ptr)(GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRY *tsglUniform2f_ptr)(GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRY *tsglUniform2fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform2iv_ptr)(GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRY *tsglUniform2uiv_ptr)(GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRY *tsglUniform3f_ptr)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
typedef void (APIENTRY *tsglUniform3fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform3fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform3iv_ptr)(GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRY *tsglUniform3uiv_ptr)(GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRY *tsglUniform4f_ptr)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRY *tsglUniform4fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform4fv_ptr)(GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRY *tsglUniform4iv_ptr)(GLint location, GLsizei count, const GLint *value);
typedef void (APIENTRY *tsglUniform4uiv_ptr)(GLint location, GLsizei count, const GLuint *value);
typedef void (APIENTRY *tsglUseProgram_ptr)(GLuint program);
typedef void (GLAPIENTRY *tsglVertexPointer_ptr)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLsizei height);
@ -273,12 +287,24 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#undef glTexParameteri
#undef glTranslatef
#undef glUniform1f
#undef glUniform1fv
#undef glUniform1i
#undef glUniform1iv
#undef glUniform1uiv
#undef glUniform2f
#undef glUniform2fv
#undef glUniform2iv
#undef glUniform2uiv
#undef glUniform3f
#undef glUniform3fv
#undef glUniform3fv
#undef glUniform3iv
#undef glUniform3uiv
#undef glUniform4f
#undef glUniform4fv
#undef glUniform4fv
#undef glUniform4iv
#undef glUniform4uiv
#undef glUseProgram
#undef glVertexPointer
#undef glViewport
@ -352,12 +378,24 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#define glTexParameteri tsglTexParameteri
#define glTranslatef tsglTranslatef
#define glUniform1f tsglUniform1f
#define glUniform1fv tsglUniform1fv
#define glUniform1i tsglUniform1i
#define glUniform1iv tsglUniform1iv
#define glUniform1uiv tsglUniform1uiv
#define glUniform2f tsglUniform2f
#define glUniform2fv tsglUniform2fv
#define glUniform2iv tsglUniform2iv
#define glUniform2uiv tsglUniform2uiv
#define glUniform3f tsglUniform3f
#define glUniform3fv tsglUniform3fv
#define glUniform3fv tsglUniform3fv
#define glUniform3iv tsglUniform3iv
#define glUniform3uiv tsglUniform3uiv
#define glUniform4f tsglUniform4f
#define glUniform4fv tsglUniform4fv
#define glUniform4fv tsglUniform4fv
#define glUniform4iv tsglUniform4iv
#define glUniform4uiv tsglUniform4uiv
#define glUseProgram tsglUseProgram
#define glVertexPointer tsglVertexPointer
#define glViewport tsglViewport
@ -433,12 +471,24 @@ GLDEF(glTexParameterf, tsglTexParameterf, tsglTexParameterf_ptr) \
GLDEF(glTexParameteri, tsglTexParameteri, tsglTexParameteri_ptr) \
GLDEF(glTranslatef, tsglTranslatef, tsglTranslatef_ptr) \
GLDEF(glUniform1f, tsglUniform1f, tsglUniform1f_ptr) \
GLDEF(glUniform1fv, tsglUniform1fv, tsglUniform1fv_ptr) \
GLDEF(glUniform1i, tsglUniform1i, tsglUniform1i_ptr) \
GLDEF(glUniform1iv, tsglUniform1iv, tsglUniform1iv_ptr) \
GLDEF(glUniform1uiv, tsglUniform1uiv, tsglUniform1uiv_ptr) \
GLDEF(glUniform2f, tsglUniform2f, tsglUniform2f_ptr) \
GLDEF(glUniform2fv, tsglUniform2fv, tsglUniform2fv_ptr) \
GLDEF(glUniform2iv, tsglUniform2iv, tsglUniform2iv_ptr) \
GLDEF(glUniform2uiv, tsglUniform2uiv, tsglUniform2uiv_ptr) \
GLDEF(glUniform3f, tsglUniform3f, tsglUniform3f_ptr) \
GLDEF(glUniform3fv, tsglUniform3fv, tsglUniform3fv_ptr) \
GLDEF(glUniform3fv, tsglUniform3fv, tsglUniform3fv_ptr) \
GLDEF(glUniform3iv, tsglUniform3iv, tsglUniform3iv_ptr) \
GLDEF(glUniform3uiv, tsglUniform3uiv, tsglUniform3uiv_ptr) \
GLDEF(glUniform4f, tsglUniform4f, tsglUniform4f_ptr) \
GLDEF(glUniform4fv, tsglUniform4fv, tsglUniform4fv_ptr) \
GLDEF(glUniform4fv, tsglUniform4fv, tsglUniform4fv_ptr) \
GLDEF(glUniform4iv, tsglUniform4iv, tsglUniform4iv_ptr) \
GLDEF(glUniform4uiv, tsglUniform4uiv, tsglUniform4uiv_ptr) \
GLDEF(glUseProgram, tsglUseProgram, tsglUseProgram_ptr) \
GLDEF(glVertexPointer, tsglVertexPointer, tsglVertexPointer_ptr) \
GLDEF(glViewport, tsglViewport, tsglViewport_ptr)
@ -518,12 +568,24 @@ GLAPI void GLAPIENTRY glTexParameterf( GLenum target, GLenum pname, GLfloat para
GLAPI void GLAPIENTRY glTexParameteri( GLenum target, GLenum pname, GLint param );
GLAPI void GLAPIENTRY glTranslatef( GLfloat x, GLfloat y, GLfloat z );
GLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0);
GLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform1i (GLint location, GLint v0);
GLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value);
GLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value);
GLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1);
GLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value);
GLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value);
GLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value);
GLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value);
GLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value);
GLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value);
GLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value);
GLAPI void APIENTRY glUseProgram (GLuint program);
GLAPI void GLAPIENTRY glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei height );
@ -596,12 +658,24 @@ GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei heigh
#define tsglTexParameteri glTexParameteri
#define tsglTranslatef glTranslatef
#define tsglUniform1f glUniform1f
#define tsglUniform1fv glUniform1fv
#define tsglUniform1i glUniform1i
#define tsglUniform1iv glUniform1iv
#define tsglUniform1uiv glUniform1uiv
#define tsglUniform2f glUniform2f
#define tsglUniform2fv glUniform2fv
#define tsglUniform2iv glUniform2iv
#define tsglUniform2uiv glUniform2uiv
#define tsglUniform3f glUniform3f
#define tsglUniform3fv glUniform3fv
#define tsglUniform3fv glUniform3fv
#define tsglUniform3iv glUniform3iv
#define tsglUniform3uiv glUniform3uiv
#define tsglUniform4f glUniform4f
#define tsglUniform4fv glUniform4fv
#define tsglUniform4fv glUniform4fv
#define tsglUniform4iv glUniform4iv
#define tsglUniform4uiv glUniform4uiv
#define tsglUseProgram glUseProgram
#define tsglVertexPointer glVertexPointer
#define tsglViewport glViewport