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:
parent
2fb8b1672b
commit
b88fc4ad2e
9 changed files with 181 additions and 10 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ taisei_src = files(
|
|||
'transition.c',
|
||||
'version.c',
|
||||
'video.c',
|
||||
'video_postprocess.c',
|
||||
)
|
||||
|
||||
if get_option('objpools')
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
32
src/video.c
32
src/video.c
|
@ -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
|
||||
|
|
|
@ -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
110
src/video_postprocess.c
Normal 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
23
src/video_postprocess.h
Normal 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
|
Loading…
Reference in a new issue