Support full-screen custom postprocessing

Works just like the viewport one, except the configuration goes in
shaders/global.pp instead. The player uniforms aren't available.
This commit is contained in:
Andrei Alexeyev 2019-08-09 21:42:04 +03:00
parent 2fb8b1672b
commit b88fc4ad2e
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
9 changed files with 181 additions and 10 deletions

View file

@ -262,6 +262,7 @@ static void main_post_vfsinit(CallChainResult ccr) {
load_resources();
gamepad_init();
progress_load();
video_post_init();
set_transition(TransLoader, 0, FADE_TIME*2);

View file

@ -85,6 +85,7 @@ taisei_src = files(
'transition.c',
'version.c',
'video.c',
'video_postprocess.c',
)
if get_option('objpools')

View file

@ -184,7 +184,7 @@ void postprocess_unload(PostprocessShader **list) {
list_foreach(list, delete_shader, NULL);
}
void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw, double width, double height) {
void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw, double width, double height, void *arg) {
if(!ppshaders) {
return;
}
@ -201,7 +201,7 @@ void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareF
r_shader_ptr(s);
if(prepare) {
prepare(fbos->back, s);
prepare(fbos->back, s, arg);
}
for(PostprocessShaderUniform *u = pps->uniforms; u; u = u->next) {

View file

@ -40,14 +40,14 @@ struct PostprocessShaderUniform {
uint elements;
};
typedef void (*PostprocessDrawFuncPtr)(Framebuffer* fb, double w, double h);
typedef void (*PostprocessPrepareFuncPtr)(Framebuffer* fb, ShaderProgram *prog);
typedef void (*PostprocessDrawFuncPtr)(Framebuffer *fb, double w, double h);
typedef void (*PostprocessPrepareFuncPtr)(Framebuffer *fb, ShaderProgram *prog, void *arg);
char* postprocess_path(const char *path);
PostprocessShader* postprocess_load(const char *path, uint flags);
void postprocess_unload(PostprocessShader **list);
void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw, double width, double height);
void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw, double width, double height, void *arg);
/*
* Glue for resources api

View file

@ -583,7 +583,7 @@ static inline bool should_draw_stage_bg(void) {
int render_delay = 1.25*ATTACK_START_DELAY; // hand tuned... not ideal
if(global.boss->current->type == AT_ExtraSpell)
render_delay = 0;
return (
!global.boss
|| !global.boss->current
@ -921,7 +921,7 @@ void stage_draw_overlay(void) {
r_state_pop();
}
static void postprocess_prepare(Framebuffer *fb, ShaderProgram *s) {
static void postprocess_prepare(Framebuffer *fb, ShaderProgram *s, void *arg) {
r_uniform_int("frames", global.frames);
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
r_uniform_vec2("player", creal(global.plr.pos), VIEWPORT_H - cimag(global.plr.pos));
@ -1082,11 +1082,12 @@ void stage_draw_scene(StageInfo *stage) {
postprocess_prepare,
draw_framebuffer_tex,
VIEWPORT_W,
VIEWPORT_H
VIEWPORT_H,
NULL
);
// prepare for 2D rendering into the main framebuffer (actual screen)
r_framebuffer(NULL);
r_framebuffer(video_get_screen_framebuffer());
set_ortho(SCREEN_W, SCREEN_H);
// draw viewport contents
@ -1819,7 +1820,7 @@ void stage_draw_hud(void) {
float red = 0.5*exp(-0.5*(global.frames-global.boss->lastdamageframe)); // hit indicator
if(red > 1)
red = 0;
r_draw_sprite(&(SpriteParams) {
.sprite = "boss_indicator",
.shader = "sprite_default",

View file

@ -15,6 +15,7 @@
#include "renderer/api.h"
#include "util/pngcruft.h"
#include "taskmanager.h"
#include "video_postprocess.h"
Video video;
@ -23,6 +24,8 @@ typedef struct ScreenshotTaskData {
Pixmap image;
} ScreenshotTaskData;
static VideoPostProcess *v_postprocess;
VideoCapabilityState (*video_query_capability)(VideoCapability cap);
static VideoCapabilityState video_query_capability_generic(VideoCapability cap) {
@ -726,7 +729,13 @@ void video_init(void) {
log_info("Video subsystem initialized");
}
void video_post_init(void) {
v_postprocess = video_postprocess_init();
r_framebuffer(video_get_screen_framebuffer());
}
void video_shutdown(void) {
video_postprocess_shutdown(v_postprocess);
events_unregister_handler(video_handle_window_event);
events_unregister_handler(video_handle_config_event);
SDL_DestroyWindow(video.window);
@ -735,7 +744,30 @@ void video_shutdown(void) {
SDL_VideoQuit();
}
Framebuffer *video_get_screen_framebuffer(void) {
return video_postprocess_get_framebuffer(v_postprocess);
}
void video_swap_buffers(void) {
Framebuffer *pp_fb = video_postprocess_render(v_postprocess);
if(pp_fb) {
r_flush_sprites();
r_state_push();
r_mat_mode(MM_PROJECTION);
r_mat_push();
set_ortho(SCREEN_W, SCREEN_H);
r_mat_mode(MM_MODELVIEW);
r_framebuffer(NULL);
r_shader_standard();
r_color3(1, 1, 1);
draw_framebuffer_tex(pp_fb, SCREEN_W, SCREEN_H);
r_framebuffer_clear(pp_fb, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
r_mat_mode(MM_PROJECTION);
r_mat_pop();
r_state_pop();
}
r_swap(video.window);
// XXX: Unfortunately, there seems to be no reliable way to sync this up with events

View file

@ -44,6 +44,7 @@ typedef enum VideoBackend {
VIDEO_BACKEND_SWITCH,
} VideoBackend;
// TODO make this struct private
typedef struct {
VideoMode *modes;
SDL_Window *window;
@ -70,6 +71,7 @@ typedef enum VideoCapabilityState {
extern Video video;
void video_init(void);
void video_post_init(void);
void video_shutdown(void);
void video_set_mode(uint display, uint w, uint h, bool fs, bool resizable);
void video_set_fullscreen(bool fullscreen);
@ -84,5 +86,6 @@ uint video_num_displays(void);
uint video_current_display(void);
void video_set_display(uint idx);
const char *video_display_name(uint id) attr_returns_nonnull;
Framebuffer *video_get_screen_framebuffer(void);
#endif // IGUARD_video_h

110
src/video_postprocess.c Normal file
View file

@ -0,0 +1,110 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "events.h"
#include "log.h"
#include "resource/postprocess.h"
#include "util/graphics.h"
#include "video.h"
#include "video_postprocess.h"
struct VideoPostProcess {
FBPair framebuffers;
PostprocessShader *pp_pipeline;
int frames;
};
static bool video_postprocess_resize_event(SDL_Event *e, void *arg) {
VideoPostProcess *vpp = arg;
float w, h;
video_get_viewport_size(&w, &h);
fbpair_resize_all(&vpp->framebuffers, w, h);
fbpair_viewport(&vpp->framebuffers, 0, 0, w, h);
return false;
}
VideoPostProcess *video_postprocess_init(void) {
PostprocessShader *pps = get_resource_data(RES_POSTPROCESS, "global", RESF_OPTIONAL | RESF_PERMANENT | RESF_PRELOAD);
if(!pps) {
return NULL;
}
VideoPostProcess *vpp = calloc(1, sizeof(*vpp));
vpp->pp_pipeline = pps;
FBAttachmentConfig a = { 0 };
a.attachment = FRAMEBUFFER_ATTACH_COLOR0;
a.tex_params.anisotropy = 1;
a.tex_params.filter.mag = TEX_FILTER_LINEAR;
a.tex_params.filter.min = TEX_FILTER_LINEAR;
a.tex_params.mipmap_mode = TEX_MIPMAP_MANUAL;
a.tex_params.mipmaps = 1;
a.tex_params.type = TEX_TYPE_RGB_8;
a.tex_params.wrap.s = TEX_WRAP_MIRROR;
a.tex_params.wrap.t = TEX_WRAP_MIRROR;
float w, h;
video_get_viewport_size(&w, &h);
a.tex_params.width = w;
a.tex_params.height = h;
fbpair_create(&vpp->framebuffers, 1, &a, "Global postprocess");
fbpair_viewport(&vpp->framebuffers, 0, 0, w, h);
r_framebuffer_clear(vpp->framebuffers.back, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
r_framebuffer_clear(vpp->framebuffers.front, CLEAR_ALL, RGBA(0, 0, 0, 0), 1);
events_register_handler(&(EventHandler) {
.proc = video_postprocess_resize_event,
.priority = EPRIO_SYSTEM,
.arg = vpp,
.event_type = MAKE_TAISEI_EVENT(TE_VIDEO_MODE_CHANGED),
});
return vpp;
}
void video_postprocess_shutdown(VideoPostProcess *vpp) {
if(vpp) {
events_unregister_handler(video_postprocess_resize_event);
fbpair_destroy(&vpp->framebuffers);
free(vpp);
}
}
Framebuffer *video_postprocess_get_framebuffer(VideoPostProcess *vpp) {
return vpp ? vpp->framebuffers.front : NULL;
}
static void postprocess_prepare(Framebuffer *fb, ShaderProgram *s, void *arg) {
VideoPostProcess *vpp = arg;
r_uniform_int("frames", vpp->frames);
r_uniform_vec2("viewport", SCREEN_W, SCREEN_H);
}
Framebuffer *video_postprocess_render(VideoPostProcess *vpp) {
if(!vpp) {
return NULL;
}
postprocess(
vpp->pp_pipeline,
&vpp->framebuffers,
postprocess_prepare,
draw_framebuffer_tex,
SCREEN_W,
SCREEN_H,
vpp
);
++vpp->frames;
return vpp->framebuffers.front;
}

23
src/video_postprocess.h Normal file
View file

@ -0,0 +1,23 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_video_postprocess_h
#define IGUARD_video_postprocess_h
#include "taisei.h"
#include "renderer/api.h"
typedef struct VideoPostProcess VideoPostProcess;
VideoPostProcess *video_postprocess_init(void);
void video_postprocess_shutdown(VideoPostProcess *vpp);
Framebuffer *video_postprocess_get_framebuffer(VideoPostProcess *vpp);
Framebuffer *video_postprocess_render(VideoPostProcess *vpp);
#endif // IGUARD_video_postprocess_h