Refactor framebuffer-related stuff (#130)
* Renderer: rename render targets to framebuffers * Refactor framebuffer pair helper and some of the video API * Remove hardcoded dimensions from draw_framebuffer_tex * Make viewport a per-framebuffer property rather than a global one * Handle config updates via the events system. React to viewport fg/bg quality change requests.
This commit is contained in:
parent
3f82ce892c
commit
b16f402040
57 changed files with 953 additions and 772 deletions
|
@ -164,14 +164,6 @@ Music* get_music(const char *name) {
|
|||
return get_resource_data(RES_BGM, name, RESF_OPTIONAL);
|
||||
}
|
||||
|
||||
static void sfx_cfg_volume_callback(ConfigIndex idx, ConfigValue v) {
|
||||
audio_backend_set_sfx_volume(config_set_float(idx, v.f));
|
||||
}
|
||||
|
||||
static void bgm_cfg_volume_callback(ConfigIndex idx, ConfigValue v) {
|
||||
audio_backend_set_bgm_volume(config_set_float(idx, v.f));
|
||||
}
|
||||
|
||||
static bool store_sfx_volume(const char *key, const char *val, void *data) {
|
||||
int vol = atoi(val);
|
||||
|
||||
|
@ -300,14 +292,32 @@ void start_bgm(const char *name) {
|
|||
log_info("Started %s", (current_bgm.title ? current_bgm.title : current_bgm.name));
|
||||
}
|
||||
|
||||
static bool audio_config_updated(SDL_Event *evt, void *arg) {
|
||||
ConfigValue *val = evt->user.data1;
|
||||
|
||||
switch(evt->user.code) {
|
||||
case CONFIG_SFX_VOLUME:
|
||||
audio_backend_set_sfx_volume(val->f);
|
||||
break;
|
||||
|
||||
case CONFIG_BGM_VOLUME:
|
||||
audio_backend_set_bgm_volume(val->f);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void audio_init(void) {
|
||||
load_config_files();
|
||||
audio_backend_init();
|
||||
config_set_callback(CONFIG_SFX_VOLUME, sfx_cfg_volume_callback);
|
||||
config_set_callback(CONFIG_BGM_VOLUME, bgm_cfg_volume_callback);
|
||||
events_register_handler(&(EventHandler) {
|
||||
audio_config_updated, NULL, EPRIO_SYSTEM, MAKE_TAISEI_EVENT(TE_CONFIG_UPDATED)
|
||||
});
|
||||
}
|
||||
|
||||
void audio_shutdown(void) {
|
||||
events_unregister_handler(audio_config_updated);
|
||||
audio_backend_shutdown();
|
||||
ht_destroy(&sfx_volumes);
|
||||
}
|
||||
|
|
118
src/config.c
118
src/config.c
|
@ -17,7 +17,7 @@
|
|||
static bool config_initialized = false;
|
||||
|
||||
CONFIGDEFS_EXPORT ConfigEntry configdefs[] = {
|
||||
#define CONFIGDEF(type,entryname,default,ufield) {type, entryname, {.ufield = default}, NULL},
|
||||
#define CONFIGDEF(type,entryname,default,ufield) { type, entryname, { .ufield = default } },
|
||||
#define CONFIGDEF_KEYBINDING(id,entryname,default) CONFIGDEF(CONFIG_TYPE_KEYBINDING, entryname, default, i)
|
||||
#define CONFIGDEF_GPKEYBINDING(id,entryname,default) CONFIGDEF(CONFIG_TYPE_GPKEYBINDING, entryname, default, i)
|
||||
#define CONFIGDEF_INT(id,entryname,default) CONFIGDEF(CONFIG_TYPE_INT, entryname, default, i)
|
||||
|
@ -66,12 +66,60 @@ void config_init(void) {
|
|||
|
||||
static void config_delete_unknown_entries(void);
|
||||
|
||||
static void config_copy_value(ConfigEntryType type, ConfigValue *dst, ConfigValue src) {
|
||||
switch(type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
case CONFIG_TYPE_KEYBINDING:
|
||||
case CONFIG_TYPE_GPKEYBINDING:
|
||||
dst->i = src.i;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_FLOAT:
|
||||
dst->f = src.f;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
stralloc(&dst->s, src.s);
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static int config_compare_values(ConfigEntryType type, ConfigValue val0, ConfigValue val1) {
|
||||
switch(type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
case CONFIG_TYPE_KEYBINDING:
|
||||
case CONFIG_TYPE_GPKEYBINDING:
|
||||
return (val0.i > val1.i) - (val0.i < val1.i);
|
||||
|
||||
case CONFIG_TYPE_FLOAT:
|
||||
return (val0.f > val1.f) - (val0.f < val1.f);
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
return strcmp(val0.s, val1.s);
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void config_free_value(ConfigEntryType type, ConfigValue *val) {
|
||||
switch(type) {
|
||||
case CONFIG_TYPE_STRING:
|
||||
free(val->s);
|
||||
val->s = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void config_shutdown(void) {
|
||||
for(ConfigEntry *e = configdefs; e->name; ++e) {
|
||||
if(e->type == CONFIG_TYPE_STRING) {
|
||||
free(e->val.s);
|
||||
e->val.s = NULL;
|
||||
}
|
||||
config_free_value(e->type, &e->val);
|
||||
}
|
||||
|
||||
config_delete_unknown_entries();
|
||||
|
@ -152,58 +200,16 @@ KeyIndex config_key_from_gamepad_button(int btn) {
|
|||
|
||||
static void config_set_val(ConfigIndex idx, ConfigValue v) {
|
||||
ConfigEntry *e = config_get(idx);
|
||||
ConfigCallback callback = e->callback;
|
||||
bool difference = true;
|
||||
|
||||
switch(e->type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
case CONFIG_TYPE_KEYBINDING:
|
||||
case CONFIG_TYPE_GPKEYBINDING:
|
||||
difference = e->val.i != v.i;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_FLOAT:
|
||||
difference = e->val.f != v.f;
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
difference = strcmp(e->val.s, v.s);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!difference) {
|
||||
if(!config_compare_values(e->type, e->val, v)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(callback) {
|
||||
e->callback = NULL;
|
||||
callback(idx, v);
|
||||
e->callback = callback;
|
||||
return;
|
||||
}
|
||||
|
||||
#define PRINTVAL(t) log_debug("%s:" #t " = %" #t, e->name, e->val.t);
|
||||
|
||||
switch(e->type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
case CONFIG_TYPE_KEYBINDING:
|
||||
case CONFIG_TYPE_GPKEYBINDING:
|
||||
e->val.i = v.i;
|
||||
PRINTVAL(i)
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_FLOAT:
|
||||
e->val.f = v.f;
|
||||
PRINTVAL(f)
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
stralloc(&e->val.s, v.s);
|
||||
PRINTVAL(s)
|
||||
break;
|
||||
}
|
||||
|
||||
#undef PRINTVAL
|
||||
ConfigValue oldv = { 0 };
|
||||
config_copy_value(e->type, &oldv, e->val);
|
||||
config_copy_value(e->type, &e->val, v);
|
||||
events_emit(TE_CONFIG_UPDATED, idx, &e->val, &oldv);
|
||||
config_free_value(e->type, &oldv);
|
||||
}
|
||||
|
||||
int config_set_int(ConfigIndex idx, int val) {
|
||||
|
@ -224,12 +230,6 @@ char* config_set_str(ConfigIndex idx, const char *val) {
|
|||
return config_get_str(idx);
|
||||
}
|
||||
|
||||
void config_set_callback(ConfigIndex idx, ConfigCallback callback) {
|
||||
ConfigEntry *e = config_get(idx);
|
||||
assert(e->callback == NULL);
|
||||
e->callback = callback;
|
||||
}
|
||||
|
||||
static ConfigEntry* config_get_unknown_entry(const char *name) {
|
||||
ConfigEntry *e;
|
||||
ConfigEntryList *l;
|
||||
|
|
|
@ -177,13 +177,10 @@ typedef union ConfigValue {
|
|||
char *s;
|
||||
} ConfigValue;
|
||||
|
||||
typedef void (*ConfigCallback)(ConfigIndex, ConfigValue);
|
||||
|
||||
typedef struct ConfigEntry {
|
||||
ConfigEntryType type;
|
||||
char *name;
|
||||
ConfigValue val;
|
||||
ConfigCallback callback;
|
||||
} ConfigEntry;
|
||||
|
||||
#define CONFIG_LOAD_BUFSIZE 256
|
||||
|
@ -199,7 +196,6 @@ void config_init(void);
|
|||
void config_shutdown(void);
|
||||
void config_load(void);
|
||||
void config_save(void);
|
||||
void config_set_callback(ConfigIndex idx, ConfigCallback callback);
|
||||
|
||||
#ifndef DEBUG
|
||||
#define CONFIG_RAWACCESS
|
||||
|
|
24
src/events.c
24
src/events.c
|
@ -71,7 +71,6 @@ static bool events_invoke_handler(SDL_Event *event, EventHandler *handler) {
|
|||
|
||||
if(!handler->event_type || handler->event_type == event->type) {
|
||||
bool result = handler->proc(event, handler->arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -261,6 +260,7 @@ void events_pause_keyrepeat(void) {
|
|||
*/
|
||||
|
||||
static bool events_handler_quit(SDL_Event *event, void *arg);
|
||||
static bool events_handler_config(SDL_Event *event, void *arg);
|
||||
static bool events_handler_keyrepeat_workaround(SDL_Event *event, void *arg);
|
||||
static bool events_handler_clipboard(SDL_Event *event, void *arg);
|
||||
static bool events_handler_hotkeys(SDL_Event *event, void *arg);
|
||||
|
@ -270,6 +270,7 @@ static bool events_handler_key_up(SDL_Event *event, void *arg);
|
|||
|
||||
static EventHandler default_handlers[] = {
|
||||
{ .proc = events_handler_quit, .priority = EPRIO_SYSTEM, .event_type = SDL_QUIT },
|
||||
{ .proc = events_handler_config, .priority = EPRIO_SYSTEM, .event_type = 0 },
|
||||
{ .proc = events_handler_keyrepeat_workaround, .priority = EPRIO_CAPTURE, .event_type = 0 },
|
||||
{ .proc = events_handler_clipboard, .priority = EPRIO_CAPTURE, .event_type = SDL_KEYDOWN },
|
||||
{ .proc = events_handler_hotkeys, .priority = EPRIO_HOTKEYS, .event_type = SDL_KEYDOWN },
|
||||
|
@ -296,6 +297,27 @@ static bool events_handler_quit(SDL_Event *event, void *arg) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool events_handler_config(SDL_Event *event, void *arg) {
|
||||
if(event->type != MAKE_TAISEI_EVENT(TE_CONFIG_UPDATED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigValue *val = event->user.data1;
|
||||
|
||||
switch(event->user.code) {
|
||||
case CONFIG_GAMEPAD_ENABLED:
|
||||
// TODO: Refactor gamepad code so that we don't have to do this.
|
||||
if(val->i) {
|
||||
gamepad_init();
|
||||
} else {
|
||||
gamepad_shutdown();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool events_handler_keyrepeat_workaround(SDL_Event *event, void *arg) {
|
||||
hrtime_t timenow = time_get();
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ typedef enum {
|
|||
TE_INVALID = -1,
|
||||
|
||||
TE_FRAME,
|
||||
|
||||
TE_RESOURCE_ASYNC_LOADED,
|
||||
TE_CONFIG_UPDATED,
|
||||
|
||||
#define TE_MENU_FIRST TE_MENU_CURSOR_UP
|
||||
TE_MENU_CURSOR_UP,
|
||||
|
|
109
src/fbo.c
109
src/fbo.c
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "fbo.h"
|
||||
#include "global.h"
|
||||
#include "util.h"
|
||||
|
||||
// TODO: rename and move this
|
||||
Resources resources;
|
||||
|
||||
static void init_fbo(FBO *fbo, uint width, uint height, TextureType type) {
|
||||
Texture *rgba = calloc(1, sizeof(Texture));
|
||||
Texture *depth = calloc(1, sizeof(Texture));
|
||||
|
||||
r_texture_create(rgba, &(TextureParams) {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.type = type,
|
||||
});
|
||||
|
||||
r_texture_create(depth, &(TextureParams) {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.type = TEX_TYPE_DEPTH,
|
||||
});
|
||||
|
||||
r_target_create(fbo);
|
||||
r_target_attach(fbo, rgba, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
r_target_attach(fbo, depth, RENDERTARGET_ATTACHMENT_DEPTH);
|
||||
|
||||
log_debug("FBO %p: w=%i, h=%i", (void*)fbo, width, height);
|
||||
}
|
||||
|
||||
static void delete_tex(Texture *tex) {
|
||||
r_texture_destroy(tex);
|
||||
free(tex);
|
||||
}
|
||||
|
||||
static void delete_fbo(FBO *fbo) {
|
||||
delete_tex(r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_COLOR0));
|
||||
delete_tex(r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_DEPTH));
|
||||
r_target_destroy(fbo);
|
||||
}
|
||||
|
||||
static void reinit_fbo(FBO *fbo, float scale, TextureType type) {
|
||||
scale = sanitize_scale(scale);
|
||||
uint w = VIEWPORT_W * scale;
|
||||
uint h = VIEWPORT_H * scale;
|
||||
|
||||
Texture *rgba;
|
||||
|
||||
if(fbo->impl) {
|
||||
rgba = r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
} else {
|
||||
rgba = NULL;
|
||||
}
|
||||
|
||||
if(!rgba) {
|
||||
init_fbo(fbo, w, h, type);
|
||||
} else if(w != rgba->w || h != rgba->h) {
|
||||
delete_fbo(fbo);
|
||||
init_fbo(fbo, w, h, type);
|
||||
}
|
||||
}
|
||||
|
||||
static void swap_fbos(FBO **fbo1, FBO **fbo2) {
|
||||
FBO *temp = *fbo1;
|
||||
*fbo1 = *fbo2;
|
||||
*fbo2 = temp;
|
||||
}
|
||||
|
||||
void init_fbo_pair(FBOPair *pair, float scale, TextureType type) {
|
||||
pair->front = pair->_private.targets+0;
|
||||
pair->back = pair->_private.targets+1;
|
||||
|
||||
reinit_fbo(pair->front, scale, type);
|
||||
reinit_fbo(pair->back, scale, type);
|
||||
}
|
||||
|
||||
void delete_fbo_pair(FBOPair *pair) {
|
||||
delete_fbo(pair->front);
|
||||
delete_fbo(pair->back);
|
||||
}
|
||||
|
||||
void swap_fbo_pair(FBOPair *pair) {
|
||||
swap_fbos(&pair->front, &pair->back);
|
||||
}
|
||||
|
||||
void draw_fbo(FBO *fbo) {
|
||||
CullFaceMode cull_saved = r_cull_current();
|
||||
r_cull(CULL_FRONT);
|
||||
|
||||
r_mat_push();
|
||||
r_texture_ptr(0, r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_COLOR0));
|
||||
r_mat_scale(VIEWPORT_W, VIEWPORT_H, 1);
|
||||
r_mat_translate(0.5, 0.5, 0);
|
||||
r_mat_scale(1, -1, 1);
|
||||
r_draw_quad();
|
||||
r_mat_pop();
|
||||
|
||||
r_cull(cull_saved);
|
||||
}
|
48
src/fbo.h
48
src/fbo.h
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
|
||||
typedef RenderTarget FBO;
|
||||
|
||||
typedef struct FBOPair {
|
||||
/*
|
||||
* Rule of thumb:
|
||||
* 1. Bind back buffer;
|
||||
* 2. Draw front buffer;
|
||||
* 3. Call swap_fbo_pair;
|
||||
* 4. Rinse, repeat.
|
||||
*/
|
||||
|
||||
FBO *front;
|
||||
FBO *back;
|
||||
|
||||
struct {
|
||||
FBO targets[2];
|
||||
} _private;
|
||||
} FBOPair;
|
||||
|
||||
void init_fbo_pair(FBOPair *pair, float scale, TextureType type);
|
||||
void delete_fbo_pair(FBOPair *pair);
|
||||
void swap_fbo_pair(FBOPair *pair);
|
||||
|
||||
void draw_fbo(FBO *fbo);
|
||||
|
||||
// TODO: rename and move this
|
||||
typedef struct Resources {
|
||||
struct {
|
||||
FBOPair bg;
|
||||
FBOPair fg;
|
||||
FBOPair rgba;
|
||||
} fbo_pairs;
|
||||
} Resources;
|
||||
|
||||
extern Resources resources;
|
|
@ -198,31 +198,7 @@ static int gamepad_find_device(char *guid_out, size_t guid_out_sz, int *out_loca
|
|||
return -1;
|
||||
}
|
||||
|
||||
static void gamepad_cfg_enabled_callback(ConfigIndex idx, ConfigValue v) {
|
||||
config_set_int(idx, v.i);
|
||||
|
||||
if(v.i) {
|
||||
gamepad_init();
|
||||
} else {
|
||||
gamepad_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
static void gamepad_setup_cfg_callbacks(void) {
|
||||
static bool done = false;
|
||||
|
||||
if(done) {
|
||||
return;
|
||||
}
|
||||
|
||||
done = true;
|
||||
|
||||
config_set_callback(CONFIG_GAMEPAD_ENABLED, gamepad_cfg_enabled_callback);
|
||||
}
|
||||
|
||||
void gamepad_init(void) {
|
||||
gamepad_setup_cfg_callbacks();
|
||||
|
||||
if(!config_get_int(CONFIG_GAMEPAD_ENABLED) || gamepad.initialized) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ void init_global(CLIAction *cli) {
|
|||
tsrand_init(&global.rand_visual, time(0));
|
||||
tsrand_switch(&global.rand_visual);
|
||||
|
||||
memset(&resources, 0, sizeof(Resources));
|
||||
memset(&global.replay, 0, sizeof(Replay));
|
||||
|
||||
global.replaymode = REPLAY_RECORD;
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "list.h"
|
||||
#include "refs.h"
|
||||
#include "config.h"
|
||||
#include "fbo.h"
|
||||
#include "resource/resource.h"
|
||||
#include "replay.h"
|
||||
#include "random.h"
|
||||
|
@ -53,9 +52,6 @@ enum {
|
|||
RESX = 800,
|
||||
RESY = 600,
|
||||
|
||||
SCREEN_W = 800,
|
||||
SCREEN_H = 600,
|
||||
|
||||
VIEWPORT_X = 40,
|
||||
VIEWPORT_Y = 20,
|
||||
VIEWPORT_W = 480,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "options.h"
|
||||
#include "common.h"
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
|
||||
void set_player(MenuData *m, void *p) {
|
||||
progress.game_settings.character = (CharacterID)(uintptr_t)p;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "ending.h"
|
||||
#include "credits.h"
|
||||
#include "mainmenu.h"
|
||||
#include "video.h"
|
||||
|
||||
static void start_game_internal(MenuData *menu, StageInfo *info, bool difficulty_menu) {
|
||||
MenuData m;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "options.h"
|
||||
#include "common.h"
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
|
||||
// FIXME: put this into the menu struct somehow (drawdata is a bad system)
|
||||
static Color diff_color;
|
||||
|
|
|
@ -137,10 +137,6 @@ void create_ingame_menu_replay(MenuData *m) {
|
|||
void draw_ingame_menu_bg(MenuData *menu, float f) {
|
||||
float rad = f*IMENU_BLUR;
|
||||
|
||||
r_target(NULL);
|
||||
video_set_viewport();
|
||||
set_ortho(SCREEN_W, SCREEN_H);
|
||||
|
||||
r_shader("ingame_menu");
|
||||
r_uniform_float("rad", rad);
|
||||
r_uniform_float("phase", menu->frames / 100.0);
|
||||
|
@ -154,6 +150,8 @@ void update_ingame_menu(MenuData *menu) {
|
|||
}
|
||||
|
||||
void draw_ingame_menu(MenuData *menu) {
|
||||
set_ortho(SCREEN_W, SCREEN_H);
|
||||
|
||||
r_mat_push();
|
||||
|
||||
draw_ingame_menu_bg(menu, 1.0-menu_fade(menu));
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "replay.h"
|
||||
#include "plrmodes.h"
|
||||
#include "common.h"
|
||||
#include "video.h"
|
||||
|
||||
static void do_save_replay(Replay *rpy) {
|
||||
char strtime[FILENAME_TIMESTAMP_MIN_BUF_SIZE], *name;
|
||||
|
|
|
@ -58,7 +58,6 @@ taisei_src = files(
|
|||
'enemy.c',
|
||||
'entity.c',
|
||||
'events.c',
|
||||
'fbo.c',
|
||||
'framerate.c',
|
||||
'gamepad.c',
|
||||
'global.c',
|
||||
|
|
11
src/player.c
11
src/player.c
|
@ -15,6 +15,7 @@
|
|||
#include "plrmodes.h"
|
||||
#include "stage.h"
|
||||
#include "stagetext.h"
|
||||
#include "stagedraw.h"
|
||||
#include "entity.h"
|
||||
|
||||
void player_init(Player *plr) {
|
||||
|
@ -412,8 +413,8 @@ void player_realdeath(Player *plr) {
|
|||
}
|
||||
|
||||
static void player_death_effect_draw_overlay(Projectile *p, int t) {
|
||||
FBOPair *framebuffers = &resources.fbo_pairs.fg;
|
||||
r_target(framebuffers->front);
|
||||
FBPair *framebuffers = stage_get_fbpair(FBPAIR_FG);
|
||||
r_framebuffer(framebuffers->front);
|
||||
r_texture(1, "static");
|
||||
r_uniform_int("noise", 1);
|
||||
r_uniform_int("frames", global.frames);
|
||||
|
@ -421,12 +422,12 @@ static void player_death_effect_draw_overlay(Projectile *p, int t) {
|
|||
r_uniform_vec2("origin", creal(p->pos), VIEWPORT_H - cimag(p->pos));
|
||||
r_uniform_vec2("clear_origin", creal(global.plr.pos), VIEWPORT_H - cimag(global.plr.pos));
|
||||
r_uniform_vec2("viewport", VIEWPORT_W, VIEWPORT_H);
|
||||
draw_fbo(framebuffers->back);
|
||||
swap_fbo_pair(framebuffers);
|
||||
draw_framebuffer_tex(framebuffers->back, VIEWPORT_W, VIEWPORT_H);
|
||||
fbpair_swap(framebuffers);
|
||||
|
||||
// This change must propagate, hence the r_state salsa. Yes, pop then push, I know what I'm doing.
|
||||
r_state_pop();
|
||||
r_target(framebuffers->back);
|
||||
r_framebuffer(framebuffers->back);
|
||||
r_state_push();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "plrmodes.h"
|
||||
#include "marisa.h"
|
||||
#include "renderer/api.h"
|
||||
#include "stagedraw.h"
|
||||
|
||||
// args are pain
|
||||
static float global_magicstar_alpha;
|
||||
|
@ -235,6 +236,8 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
|
|||
Texture *tex0 = get_tex("part/marisa_laser0");
|
||||
Texture *tex1 = get_tex("part/marisa_laser1");
|
||||
VertexArray *varr_saved = r_vertex_array_current();
|
||||
FBPair *fbp_aux = stage_get_fbpair(FBPAIR_FG_AUX);
|
||||
FBPair *fbp_fg = stage_get_fbpair(FBPAIR_FG);
|
||||
|
||||
r_vertex_array(r_vertex_array_static_models());
|
||||
r_shader_ptr(shader);
|
||||
|
@ -242,7 +245,7 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
|
|||
r_uniform_ptr(u_clr1, 1, (float[]) { 1, 1, 1, 0.8 });
|
||||
r_uniform_ptr(u_clr_phase, 1, (float[]) { -1.5 * t/M_PI });
|
||||
r_uniform_ptr(u_clr_freq, 1, (float[]) { 10.0 });
|
||||
r_target(resources.fbo_pairs.rgba.front);
|
||||
r_framebuffer(fbp_aux->front);
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
r_clear(CLEAR_COLOR);
|
||||
r_clear_color4(0, 0, 0, 1);
|
||||
|
@ -259,9 +262,9 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
|
|||
}
|
||||
|
||||
r_blend(BLEND_ALPHA);
|
||||
r_target(resources.fbo_pairs.fg.back);
|
||||
r_framebuffer(fbp_fg->back);
|
||||
r_shader_standard();
|
||||
draw_fbo(resources.fbo_pairs.rgba.front);
|
||||
draw_framebuffer_tex(fbp_aux->front, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_ptr(shader);
|
||||
r_blend(BLEND_ADD);
|
||||
|
||||
|
|
|
@ -377,13 +377,13 @@ static int youmu_split(Enemy *e, int t) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void youmu_mirror_shader(FBO *fbo) {
|
||||
static void youmu_mirror_shader(Framebuffer *fb) {
|
||||
ShaderProgram *shader = r_shader_get("youmua_bomb");
|
||||
|
||||
double t = player_get_bomb_progress(&global.plr,0);
|
||||
r_shader_ptr(shader);
|
||||
r_uniform_float("tbomb", t);
|
||||
draw_fbo(fbo);
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
|
||||
colorfill(1,1,1,max(0,1-10*t));
|
||||
|
|
|
@ -354,29 +354,43 @@ Texture* r_texture_current(uint unit) {
|
|||
return B.texture_current(unit);
|
||||
}
|
||||
|
||||
void r_target_create(RenderTarget *target) {
|
||||
B.target_create(target);
|
||||
void r_framebuffer_create(Framebuffer *fb) {
|
||||
B.framebuffer_create(fb);
|
||||
}
|
||||
|
||||
void r_target_attach(RenderTarget *target, Texture *tex, RenderTargetAttachment attachment) {
|
||||
B.target_attach(target, tex, attachment);
|
||||
void r_framebuffer_attach(Framebuffer *fb, Texture *tex, FramebufferAttachment attachment) {
|
||||
B.framebuffer_attach(fb, tex, attachment);
|
||||
}
|
||||
|
||||
Texture* r_target_get_attachment(RenderTarget *target, RenderTargetAttachment attachment) {
|
||||
return B.target_get_attachment(target, attachment);
|
||||
Texture* r_framebuffer_get_attachment(Framebuffer *fb, FramebufferAttachment attachment) {
|
||||
return B.framebuffer_get_attachment(fb, attachment);
|
||||
}
|
||||
|
||||
void r_target_destroy(RenderTarget *target) {
|
||||
B.target_destroy(target);
|
||||
void r_framebuffer_viewport(Framebuffer *fb, int x, int y, int w, int h) {
|
||||
r_framebuffer_viewport_rect(fb, (IntRect) { x, y, w, h });
|
||||
}
|
||||
|
||||
void r_target(RenderTarget *target) {
|
||||
_r_state_touch_target();
|
||||
B.target(target);
|
||||
void r_framebuffer_viewport_rect(Framebuffer *fb, IntRect viewport) {
|
||||
assert(viewport.h > 0);
|
||||
assert(viewport.w > 0);
|
||||
B.framebuffer_viewport(fb, viewport);
|
||||
}
|
||||
|
||||
RenderTarget* r_target_current(void) {
|
||||
return B.target_current();
|
||||
void r_framebuffer_viewport_current(Framebuffer *fb, IntRect *viewport) {
|
||||
B.framebuffer_viewport_current(fb, viewport);
|
||||
}
|
||||
|
||||
void r_framebuffer_destroy(Framebuffer *fb) {
|
||||
B.framebuffer_destroy(fb);
|
||||
}
|
||||
|
||||
void r_framebuffer(Framebuffer *fb) {
|
||||
_r_state_touch_framebuffer();
|
||||
B.framebuffer(fb);
|
||||
}
|
||||
|
||||
Framebuffer * r_framebuffer_current(void) {
|
||||
return B.framebuffer_current();
|
||||
}
|
||||
|
||||
void r_vertex_buffer_create(VertexBuffer *vbuf, size_t capacity, void *data) {
|
||||
|
@ -441,15 +455,6 @@ Color r_clear_color_current(void) {
|
|||
return B.clear_color_current();
|
||||
}
|
||||
|
||||
void r_viewport_rect(IntRect rect) {
|
||||
_r_state_touch_viewport();
|
||||
B.viewport_rect(rect);
|
||||
}
|
||||
|
||||
void r_viewport_current(IntRect *out_rect) {
|
||||
B.viewport_current(out_rect);
|
||||
}
|
||||
|
||||
void r_vsync(VsyncMode mode) {
|
||||
_r_state_touch_vsync();
|
||||
B.vsync(mode);
|
||||
|
|
|
@ -21,7 +21,7 @@ typedef enum RendererFeature {
|
|||
RFEAT_DRAW_INSTANCED,
|
||||
RFEAT_DRAW_INSTANCED_BASE_INSTANCE,
|
||||
RFEAT_DEPTH_TEXTURE,
|
||||
RFEAT_RENDERTARGET_MULTIPLE_OUTPUTS,
|
||||
RFEAT_FRAMEBUFFER_MULTIPLE_OUTPUTS,
|
||||
|
||||
NUM_RFEATS,
|
||||
} RendererFeature;
|
||||
|
@ -102,22 +102,22 @@ enum {
|
|||
R_MAX_TEXUNITS = 8,
|
||||
};
|
||||
|
||||
typedef enum RenderTargetAttachment {
|
||||
RENDERTARGET_ATTACHMENT_DEPTH,
|
||||
RENDERTARGET_ATTACHMENT_COLOR0,
|
||||
RENDERTARGET_ATTACHMENT_COLOR1,
|
||||
RENDERTARGET_ATTACHMENT_COLOR2,
|
||||
RENDERTARGET_ATTACHMENT_COLOR3,
|
||||
typedef enum FramebufferAttachment {
|
||||
FRAMEBUFFER_ATTACH_DEPTH,
|
||||
FRAMEBUFFER_ATTACH_COLOR0,
|
||||
FRAMEBUFFER_ATTACH_COLOR1,
|
||||
FRAMEBUFFER_ATTACH_COLOR2,
|
||||
FRAMEBUFFER_ATTACH_COLOR3,
|
||||
|
||||
RENDERTARGET_MAX_COLOR_ATTACHMENTS = 4,
|
||||
RENDERTARGET_MAX_ATTACHMENTS = RENDERTARGET_ATTACHMENT_COLOR0 + RENDERTARGET_MAX_COLOR_ATTACHMENTS,
|
||||
} RenderTargetAttachment;
|
||||
FRAMEBUFFER_MAX_COLOR_ATTACHMENTS = 4,
|
||||
FRAMEBUFFER_MAX_ATTACHMENTS = FRAMEBUFFER_ATTACH_COLOR0 + FRAMEBUFFER_MAX_COLOR_ATTACHMENTS,
|
||||
} FramebufferAttachment;
|
||||
|
||||
typedef struct RenderTargetImpl RenderTargetImpl;
|
||||
typedef struct FramebufferImpl FramebufferImpl;
|
||||
|
||||
typedef struct RenderTarget {
|
||||
RenderTargetImpl *impl;
|
||||
} RenderTarget;
|
||||
typedef struct Framebuffer {
|
||||
FramebufferImpl *impl;
|
||||
} Framebuffer;
|
||||
|
||||
typedef enum Primitive {
|
||||
PRIM_POINTS,
|
||||
|
@ -353,8 +353,6 @@ typedef struct SpriteParams {
|
|||
vec3 vector;
|
||||
} rotation;
|
||||
|
||||
// FIXME: find a more efficient solution for this?
|
||||
// this is needed to support some color transforms, but most sprites won't use this attribute
|
||||
float custom;
|
||||
|
||||
struct {
|
||||
|
@ -415,13 +413,16 @@ void r_texture_destroy(Texture *tex) attr_nonnull(1);
|
|||
void r_texture_ptr(uint unit, Texture *tex);
|
||||
Texture* r_texture_current(uint unit);
|
||||
|
||||
void r_target_create(RenderTarget *target) attr_nonnull(1);
|
||||
void r_target_attach(RenderTarget *target, Texture *tex, RenderTargetAttachment attachment) attr_nonnull(1);
|
||||
Texture* r_target_get_attachment(RenderTarget *target, RenderTargetAttachment attachment) attr_nonnull(1);
|
||||
void r_target_destroy(RenderTarget *target) attr_nonnull(1);
|
||||
void r_framebuffer_create(Framebuffer *fb) attr_nonnull(1);
|
||||
void r_framebuffer_attach(Framebuffer *fb, Texture *tex, FramebufferAttachment attachment) attr_nonnull(1);
|
||||
Texture* r_framebuffer_get_attachment(Framebuffer *fb, FramebufferAttachment attachment) attr_nonnull(1);
|
||||
void r_framebuffer_viewport(Framebuffer *fb, int x, int y, int w, int h);
|
||||
void r_framebuffer_viewport_rect(Framebuffer *fb, IntRect viewport);
|
||||
void r_framebuffer_viewport_current(Framebuffer *fb, IntRect *viewport) attr_nonnull(2);
|
||||
void r_framebuffer_destroy(Framebuffer *fb) attr_nonnull(1);
|
||||
|
||||
void r_target(RenderTarget *target);
|
||||
RenderTarget* r_target_current(void);
|
||||
void r_framebuffer(Framebuffer *fb);
|
||||
Framebuffer* r_framebuffer_current(void);
|
||||
|
||||
void r_vertex_buffer_create(VertexBuffer *vbuf, size_t capacity, void *data) attr_nonnull(1);
|
||||
void r_vertex_buffer_destroy(VertexBuffer *vbuf) attr_nonnull(1);
|
||||
|
@ -442,9 +443,6 @@ void r_clear(ClearBufferFlags flags);
|
|||
void r_clear_color4(float r, float g, float b, float a);
|
||||
Color r_clear_color_current(void);
|
||||
|
||||
void r_viewport_rect(IntRect rect);
|
||||
void r_viewport_current(IntRect *out_rect) attr_nonnull(1);
|
||||
|
||||
void r_vsync(VsyncMode mode);
|
||||
VsyncMode r_vsync_current(void);
|
||||
|
||||
|
@ -465,6 +463,7 @@ void r_mat_perspective(float angle, float aspect, float near, float far);
|
|||
|
||||
void r_mat(MatrixMode mode, mat4 mat);
|
||||
void r_mat_current(MatrixMode mode, mat4 out_mat);
|
||||
mat4* r_mat_current_ptr(MatrixMode mode);
|
||||
|
||||
void r_shader_standard(void);
|
||||
void r_shader_standard_notex(void);
|
||||
|
@ -660,11 +659,6 @@ void r_clear_color(Color c) {
|
|||
r_clear_color4(r, g, b, a);
|
||||
}
|
||||
|
||||
static inline attr_must_inline
|
||||
void r_viewport(int x, int y, int w, int h) {
|
||||
r_viewport_rect((IntRect) { x, y, w, h });
|
||||
}
|
||||
|
||||
static inline attr_must_inline attr_nonnull(1)
|
||||
void r_draw_model(const char *model) {
|
||||
r_draw_model_ptr(get_resource_data(RES_MODEL, model, RESF_UNSAFE));
|
||||
|
|
|
@ -55,13 +55,15 @@ typedef struct RendererFuncs {
|
|||
void (*texture)(uint unit, Texture *tex);
|
||||
Texture* (*texture_current)(uint unit);
|
||||
|
||||
void (*target_create)(RenderTarget *target);
|
||||
void (*target_destroy)(RenderTarget *target);
|
||||
void (*target_attach)(RenderTarget *target, Texture *tex, RenderTargetAttachment attachment);
|
||||
Texture* (*target_get_attachment)(RenderTarget *target, RenderTargetAttachment attachment);
|
||||
void (*framebuffer_create)(Framebuffer *framebuffer);
|
||||
void (*framebuffer_destroy)(Framebuffer *framebuffer);
|
||||
void (*framebuffer_attach)(Framebuffer *framebuffer, Texture *tex, FramebufferAttachment attachment);
|
||||
void (*framebuffer_viewport)(Framebuffer *framebuffer, IntRect vp);
|
||||
void (*framebuffer_viewport_current)(Framebuffer *framebuffer, IntRect *vp);
|
||||
Texture* (*framebuffer_get_attachment)(Framebuffer *framebuffer, FramebufferAttachment attachment);
|
||||
|
||||
void (*target)(RenderTarget *target);
|
||||
RenderTarget* (*target_current)(void);
|
||||
void (*framebuffer)(Framebuffer *framebuffer);
|
||||
Framebuffer* (*framebuffer_current)(void);
|
||||
|
||||
void (*vertex_buffer_create)(VertexBuffer *vbuf, size_t capacity, void *data);
|
||||
void (*vertex_buffer_destroy)(VertexBuffer *vbuf);
|
||||
|
@ -82,9 +84,6 @@ typedef struct RendererFuncs {
|
|||
void (*clear_color4)(float r, float g, float b, float a);
|
||||
Color (*clear_color_current)(void);
|
||||
|
||||
void (*viewport_rect)(IntRect rect);
|
||||
void (*viewport_current)(IntRect *out_rect);
|
||||
|
||||
void (*vsync)(VsyncMode mode);
|
||||
VsyncMode (*vsync_current)(void);
|
||||
|
||||
|
|
|
@ -88,6 +88,11 @@ void r_mat_current(MatrixMode mode, mat4 out_mat) {
|
|||
glm_mat4_copy(*_r_matrices.indexed[mode].head, out_mat);
|
||||
}
|
||||
|
||||
mat4* r_mat_current_ptr(MatrixMode mode) {
|
||||
assert((uint)mode < sizeof(_r_matrices.indexed) / sizeof(MatrixStack));
|
||||
return _r_matrices.indexed[mode].head;
|
||||
}
|
||||
|
||||
void _r_mat_init(void) {
|
||||
matstack_reset(&_r_matrices.texture);
|
||||
matstack_reset(&_r_matrices.modelview);
|
||||
|
|
|
@ -28,9 +28,10 @@ static struct SpriteBatchState {
|
|||
Texture *tex;
|
||||
ShaderProgram *shader;
|
||||
BlendMode blend;
|
||||
RenderTarget *render_target;
|
||||
Framebuffer *framebuffer;
|
||||
CullFaceMode cull_mode;
|
||||
DepthTestFunc depth_func;
|
||||
mat4 projection CGLM_ALIGN(32);
|
||||
uint cull_enabled : 1;
|
||||
uint depth_test_enabled : 1;
|
||||
uint depth_write_enabled : 1;
|
||||
|
@ -129,23 +130,16 @@ void r_flush_sprites(void) {
|
|||
_r_sprite_batch.num_pending = 0;
|
||||
_r_sprite_batch.frame_stats.flushes++;
|
||||
|
||||
// log_warn("flush! %u", pending);
|
||||
r_state_push();
|
||||
|
||||
VertexArray *varr_saved = r_vertex_array_current();
|
||||
Texture *tex_saved = r_texture_current(0);
|
||||
ShaderProgram *prog_saved = r_shader_current();
|
||||
RenderTarget *target_saved = r_target_current();
|
||||
BlendMode blend_saved = r_blend_current();
|
||||
bool cap_deptp_test_saved = r_capability_current(RCAP_DEPTH_TEST);
|
||||
bool cap_depth_write_saved = r_capability_current(RCAP_DEPTH_WRITE);
|
||||
bool cap_cull_saved = r_capability_current(RCAP_CULL_FACE);
|
||||
DepthTestFunc depth_func_saved = r_depth_func_current();
|
||||
CullFaceMode cull_mode_saved = r_cull_current();
|
||||
r_mat_mode(MM_PROJECTION);
|
||||
r_mat_push();
|
||||
glm_mat4_copy(_r_sprite_batch.projection, *r_mat_current_ptr(MM_PROJECTION));
|
||||
|
||||
r_vertex_array(&_r_sprite_batch.varr);
|
||||
r_texture_ptr(0, _r_sprite_batch.tex);
|
||||
r_shader_ptr(_r_sprite_batch.shader);
|
||||
r_target(_r_sprite_batch.render_target);
|
||||
r_framebuffer(_r_sprite_batch.framebuffer);
|
||||
r_blend(_r_sprite_batch.blend);
|
||||
r_capability(RCAP_DEPTH_TEST, _r_sprite_batch.depth_test_enabled);
|
||||
r_capability(RCAP_DEPTH_WRITE, _r_sprite_batch.depth_write_enabled);
|
||||
|
@ -167,16 +161,8 @@ void r_flush_sprites(void) {
|
|||
r_vertex_buffer_invalidate(&_r_sprite_batch.vbuf);
|
||||
}
|
||||
|
||||
r_vertex_array(varr_saved);
|
||||
r_texture_ptr(0, tex_saved);
|
||||
r_shader_ptr(prog_saved);
|
||||
r_target(target_saved);
|
||||
r_blend(blend_saved);
|
||||
r_capability(RCAP_DEPTH_TEST, cap_deptp_test_saved);
|
||||
r_capability(RCAP_DEPTH_WRITE, cap_depth_write_saved);
|
||||
r_capability(RCAP_CULL_FACE, cap_cull_saved);
|
||||
r_depth_func(depth_func_saved);
|
||||
r_cull(cull_mode_saved);
|
||||
r_mat_pop();
|
||||
r_state_pop();
|
||||
}
|
||||
|
||||
static void _r_sprite_batch_add(Sprite *spr, const SpriteParams *params, VertexBuffer *vbuf) {
|
||||
|
@ -266,11 +252,11 @@ void r_draw_sprite(const SpriteParams *params) {
|
|||
_r_sprite_batch.shader = prog;
|
||||
}
|
||||
|
||||
RenderTarget *target = r_target_current();
|
||||
Framebuffer *fb = r_framebuffer_current();
|
||||
|
||||
if(target != _r_sprite_batch.render_target) {
|
||||
if(fb != _r_sprite_batch.framebuffer) {
|
||||
r_flush_sprites();
|
||||
_r_sprite_batch.render_target = target;
|
||||
_r_sprite_batch.framebuffer = fb;
|
||||
}
|
||||
|
||||
BlendMode blend = params->blend;
|
||||
|
@ -315,6 +301,13 @@ void r_draw_sprite(const SpriteParams *params) {
|
|||
_r_sprite_batch.cull_mode = cull_mode;
|
||||
}
|
||||
|
||||
mat4 *current_projection = r_mat_current_ptr(MM_PROJECTION);
|
||||
|
||||
if(memcmp(*current_projection, _r_sprite_batch.projection, sizeof(mat4))) {
|
||||
r_flush_sprites();
|
||||
glm_mat4_copy(*current_projection, _r_sprite_batch.projection);
|
||||
}
|
||||
|
||||
if(_r_sprite_batch.vbuf.size - _r_sprite_batch.vbuf.offset < sizeof(SpriteAttribs)) {
|
||||
if(!r_supports(RFEAT_DRAW_INSTANCED_BASE_INSTANCE)) {
|
||||
log_warn("Vertex buffer exhausted (%zu needed for next sprite, %u remaining), flush forced", sizeof(SpriteAttribs), _r_sprite_batch.vbuf.size - _r_sprite_batch.vbuf.offset);
|
||||
|
|
|
@ -100,17 +100,13 @@ void r_state_pop(void) {
|
|||
}
|
||||
|
||||
RESTORE(RSTATE_RENDERTARGET) {
|
||||
B.target(S.target);
|
||||
B.framebuffer(S.framebuffer);
|
||||
}
|
||||
|
||||
RESTORE(RSTATE_VERTEXARRAY) {
|
||||
B.vertex_array(S.varr);
|
||||
}
|
||||
|
||||
RESTORE(RSTATE_VIEWPORT) {
|
||||
B.viewport_rect(S.viewport);
|
||||
}
|
||||
|
||||
RESTORE(RSTATE_VSYNC) {
|
||||
B.vsync(S.vsync);
|
||||
}
|
||||
|
@ -181,9 +177,9 @@ void _r_state_touch_texunit(uint unit) {
|
|||
});
|
||||
}
|
||||
|
||||
void _r_state_touch_target(void) {
|
||||
void _r_state_touch_framebuffer(void) {
|
||||
TAINT(RSTATE_RENDERTARGET, {
|
||||
S.target = B.target_current();
|
||||
S.framebuffer = B.framebuffer_current();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -193,12 +189,6 @@ void _r_state_touch_vertex_array(void) {
|
|||
});
|
||||
}
|
||||
|
||||
void _r_state_touch_viewport(void) {
|
||||
TAINT(RSTATE_VIEWPORT, {
|
||||
B.viewport_current(&S.viewport);
|
||||
});
|
||||
}
|
||||
|
||||
void _r_state_touch_vsync(void) {
|
||||
TAINT(RSTATE_VSYNC, {
|
||||
S.vsync = B.vsync_current();
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
RSTATE(TEXUNITS) \
|
||||
RSTATE(RENDERTARGET) \
|
||||
RSTATE(VERTEXARRAY) \
|
||||
RSTATE(VIEWPORT) \
|
||||
RSTATE(VSYNC) \
|
||||
|
||||
typedef enum RendererStateID {
|
||||
|
@ -55,9 +54,9 @@ typedef struct RendererStateRollback {
|
|||
ShaderProgram *shader;
|
||||
// TODO uniforms
|
||||
Texture *texunits[R_MAX_TEXUNITS];
|
||||
RenderTarget *target;
|
||||
Framebuffer *framebuffer;
|
||||
// TODO framebuffer viewports, if we actually ever need to modify them at render time
|
||||
VertexArray *varr;
|
||||
IntRect viewport;
|
||||
VsyncMode vsync;
|
||||
} RendererStateRollback;
|
||||
|
||||
|
@ -71,9 +70,8 @@ void _r_state_touch_depth_func(void);
|
|||
void _r_state_touch_shader(void);
|
||||
void _r_state_touch_uniform(Uniform *uniform);
|
||||
void _r_state_touch_texunit(uint unit);
|
||||
void _r_state_touch_target(void);
|
||||
void _r_state_touch_framebuffer(void);
|
||||
void _r_state_touch_vertex_array(void);
|
||||
void _r_state_touch_viewport(void);
|
||||
void _r_state_touch_vsync(void);
|
||||
|
||||
void _r_state_init(void);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "texture.h"
|
||||
#include "shader_object.h"
|
||||
#include "shader_program.h"
|
||||
#include "render_target.h"
|
||||
#include "framebuffer.h"
|
||||
#include "vertex_buffer.h"
|
||||
#include "vertex_array.h"
|
||||
#include "../glcommon/debug.h"
|
||||
|
@ -40,9 +40,9 @@ static struct {
|
|||
} texunits;
|
||||
|
||||
struct {
|
||||
RenderTarget *active;
|
||||
RenderTarget *pending;
|
||||
} render_target;
|
||||
Framebuffer *active;
|
||||
Framebuffer *pending;
|
||||
} framebuffer;
|
||||
|
||||
struct {
|
||||
VertexArray *active;
|
||||
|
@ -92,9 +92,13 @@ static struct {
|
|||
r_capability_bits_t pending;
|
||||
} capabilities;
|
||||
|
||||
struct {
|
||||
IntRect active;
|
||||
IntRect default_framebuffer;
|
||||
} viewport;
|
||||
|
||||
vec4 color;
|
||||
vec4 clear_color;
|
||||
IntRect viewport;
|
||||
GLuint pbo;
|
||||
r_feature_bits_t features;
|
||||
|
||||
|
@ -213,7 +217,9 @@ static void gl33_init_context(SDL_Window *window) {
|
|||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glGetIntegerv(GL_VIEWPORT, &R.viewport.x);
|
||||
glGetIntegerv(GL_VIEWPORT, &R.viewport.default_framebuffer.x);
|
||||
|
||||
R.viewport.active = R.viewport.default_framebuffer;
|
||||
|
||||
r_clear_color4(0, 0, 0, 1);
|
||||
r_clear(CLEAR_ALL);
|
||||
|
@ -231,7 +237,7 @@ static void gl33_init_context(SDL_Window *window) {
|
|||
}
|
||||
|
||||
if(glext.draw_buffers) {
|
||||
R.features |= r_feature_bit(RFEAT_RENDERTARGET_MULTIPLE_OUTPUTS);
|
||||
R.features |= r_feature_bit(RFEAT_FRAMEBUFFER_MULTIPLE_OUTPUTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +259,26 @@ static void gl33_apply_capability(RendererCapability cap, bool value) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline IntRect* get_framebuffer_viewport(Framebuffer *fb) {
|
||||
if(fb == NULL) {
|
||||
return &R.viewport.default_framebuffer;
|
||||
}
|
||||
|
||||
assert(fb->impl != NULL);
|
||||
return &fb->impl->viewport;
|
||||
}
|
||||
|
||||
static void gl33_sync_viewport(void) {
|
||||
IntRect *vp = get_framebuffer_viewport(R.framebuffer.pending);
|
||||
|
||||
if(memcmp(&R.viewport.active, vp, sizeof(IntRect))) {
|
||||
R.viewport.active = *vp;
|
||||
glViewport(vp->x, vp->y, vp->w, vp->h);
|
||||
}
|
||||
}
|
||||
|
||||
static void gl33_sync_state(void) {
|
||||
|
||||
gl33_sync_capabilities();
|
||||
gl33_sync_shader();
|
||||
r_uniform("r_modelViewMatrix", 1, _r_matrices.modelview.head);
|
||||
|
@ -262,7 +287,8 @@ static void gl33_sync_state(void) {
|
|||
r_uniform("r_color", 1, R.color);
|
||||
gl33_sync_uniforms(R.progs.active);
|
||||
gl33_sync_texunits();
|
||||
gl33_sync_render_target();
|
||||
gl33_sync_framebuffer();
|
||||
gl33_sync_viewport();
|
||||
gl33_sync_vertex_array();
|
||||
gl33_sync_blend_mode();
|
||||
|
||||
|
@ -372,25 +398,25 @@ void gl33_sync_depth_test_func(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline GLuint fbo_num(RenderTarget *target) {
|
||||
if(target == NULL) {
|
||||
static inline GLuint fbo_num(Framebuffer *fb) {
|
||||
if(fb == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(target->impl != NULL);
|
||||
assert(target->impl->gl_fbo != 0);
|
||||
assert(fb->impl != NULL);
|
||||
assert(fb->impl->gl_fbo != 0);
|
||||
|
||||
return target->impl->gl_fbo;
|
||||
return fb->impl->gl_fbo;
|
||||
}
|
||||
|
||||
void gl33_sync_render_target(void) {
|
||||
if(fbo_num(R.render_target.active) != fbo_num(R.render_target.pending)) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_num(R.render_target.pending));
|
||||
R.render_target.active = R.render_target.pending;
|
||||
void gl33_sync_framebuffer(void) {
|
||||
if(fbo_num(R.framebuffer.active) != fbo_num(R.framebuffer.pending)) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo_num(R.framebuffer.pending));
|
||||
R.framebuffer.active = R.framebuffer.pending;
|
||||
}
|
||||
|
||||
if(R.render_target.active) {
|
||||
gl33_target_initialize(R.render_target.active);
|
||||
if(R.framebuffer.active) {
|
||||
gl33_framebuffer_initialize(R.framebuffer.active);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,13 +531,13 @@ void gl33_texture_deleted(Texture *tex) {
|
|||
}
|
||||
}
|
||||
|
||||
void gl33_render_target_deleted(RenderTarget *target) {
|
||||
if(R.render_target.pending == target) {
|
||||
R.render_target.pending = NULL;
|
||||
void gl33_framebuffer_deleted(Framebuffer *fb) {
|
||||
if(R.framebuffer.pending == fb) {
|
||||
R.framebuffer.pending = NULL;
|
||||
}
|
||||
|
||||
if(R.render_target.active == target) {
|
||||
R.render_target.active = NULL;
|
||||
if(R.framebuffer.active == fb) {
|
||||
R.framebuffer.active = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -719,13 +745,21 @@ static Texture* gl33_texture_current(uint unit) {
|
|||
return R.texunits.indexed[unit].tex2d.pending;
|
||||
}
|
||||
|
||||
static void gl33_target(RenderTarget *target) {
|
||||
assert(target == NULL || target->impl != NULL);
|
||||
R.render_target.pending = target;
|
||||
static void gl33_framebuffer(Framebuffer *fb) {
|
||||
assert(fb == NULL || fb->impl != NULL);
|
||||
R.framebuffer.pending = fb;
|
||||
}
|
||||
|
||||
static RenderTarget *gl33_target_current(void) {
|
||||
return R.render_target.pending;
|
||||
static Framebuffer *gl33_framebuffer_current(void) {
|
||||
return R.framebuffer.pending;
|
||||
}
|
||||
|
||||
static void gl33_framebuffer_viewport(Framebuffer *fb, IntRect vp) {
|
||||
memcpy(get_framebuffer_viewport(fb), &vp, sizeof(vp));
|
||||
}
|
||||
|
||||
static void gl33_framebuffer_viewport_current(Framebuffer *fb, IntRect *out_rect) {
|
||||
*out_rect = *get_framebuffer_viewport(fb);
|
||||
}
|
||||
|
||||
static void gl33_shader(ShaderProgram *prog) {
|
||||
|
@ -750,7 +784,7 @@ static void gl33_clear(ClearBufferFlags flags) {
|
|||
}
|
||||
|
||||
r_flush_sprites();
|
||||
gl33_sync_render_target();
|
||||
gl33_sync_framebuffer();
|
||||
glClear(mask);
|
||||
}
|
||||
|
||||
|
@ -767,21 +801,9 @@ static Color gl33_clear_color_current(void) {
|
|||
return rgba(R.clear_color[0], R.clear_color[1], R.clear_color[2], R.clear_color[3]);
|
||||
}
|
||||
|
||||
static void gl33_viewport_rect(IntRect rect) {
|
||||
if(memcmp(&R.viewport, &rect, sizeof(IntRect))) {
|
||||
r_flush_sprites(); // FIXME: have the sprite batch track this instead.
|
||||
memcpy(&R.viewport, &rect, sizeof(IntRect));
|
||||
glViewport(rect.x, rect.y, rect.w, rect.h);
|
||||
}
|
||||
}
|
||||
|
||||
static void gl33_viewport_current(IntRect *out_rect) {
|
||||
memcpy(out_rect, &R.viewport, sizeof(R.viewport));
|
||||
}
|
||||
|
||||
static void gl33_swap(SDL_Window *window) {
|
||||
r_flush_sprites();
|
||||
gl33_sync_render_target();
|
||||
gl33_sync_framebuffer();
|
||||
SDL_GL_SwapWindow(window);
|
||||
gl33_stats_post_frame();
|
||||
}
|
||||
|
@ -811,11 +833,25 @@ static DepthTestFunc gl33_depth_func_current(void) {
|
|||
}
|
||||
|
||||
static uint8_t* gl33_screenshot(uint *out_width, uint *out_height) {
|
||||
uint8_t *pixels = malloc(R.viewport.w * R.viewport.h * 3);
|
||||
uint fbo = 0;
|
||||
IntRect *vp = &R.viewport.default_framebuffer;
|
||||
|
||||
if(R.framebuffer.active != NULL) {
|
||||
fbo = R.framebuffer.active->impl->gl_fbo;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
uint8_t *pixels = malloc(vp->w * vp->h * 3);
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels(R.viewport.x, R.viewport.y, R.viewport.w, R.viewport.h, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
*out_width = R.viewport.w;
|
||||
*out_height = R.viewport.h;
|
||||
glReadPixels(vp->x, vp->y, vp->w, vp->h, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
*out_width = vp->w;
|
||||
*out_height = vp->h;
|
||||
|
||||
if(fbo != 0) {
|
||||
// FIXME: Maybe we should only ever bind FBOs to GL_DRAW_FRAMEBUFFER?
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
|
||||
}
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
|
@ -851,12 +887,14 @@ RendererBackend _r_backend_gl33 = {
|
|||
.texture_replace = gl33_texture_replace,
|
||||
.texture = gl33_texture,
|
||||
.texture_current = gl33_texture_current,
|
||||
.target_create = gl33_target_create,
|
||||
.target_destroy = gl33_target_destroy,
|
||||
.target_attach = gl33_target_attach,
|
||||
.target_get_attachment = gl33_target_get_attachment,
|
||||
.target = gl33_target,
|
||||
.target_current = gl33_target_current,
|
||||
.framebuffer_create = gl33_framebuffer_create,
|
||||
.framebuffer_destroy = gl33_framebuffer_destroy,
|
||||
.framebuffer_attach = gl33_framebuffer_attach,
|
||||
.framebuffer_get_attachment = gl33_framebuffer_get_attachment,
|
||||
.framebuffer_viewport = gl33_framebuffer_viewport,
|
||||
.framebuffer_viewport_current = gl33_framebuffer_viewport_current,
|
||||
.framebuffer = gl33_framebuffer,
|
||||
.framebuffer_current = gl33_framebuffer_current,
|
||||
.vertex_buffer_create = gl33_vertex_buffer_create,
|
||||
.vertex_buffer_destroy = gl33_vertex_buffer_destroy,
|
||||
.vertex_buffer_invalidate = gl33_vertex_buffer_invalidate,
|
||||
|
@ -872,8 +910,6 @@ RendererBackend _r_backend_gl33 = {
|
|||
.clear = gl33_clear,
|
||||
.clear_color4 = gl33_clear_color4,
|
||||
.clear_color_current = gl33_clear_color_current,
|
||||
.viewport_rect = gl33_viewport_rect,
|
||||
.viewport_current = gl33_viewport_current,
|
||||
.vsync = gl33_vsync,
|
||||
.vsync_current = gl33_vsync_current,
|
||||
.swap = gl33_swap,
|
||||
|
|
|
@ -26,7 +26,7 @@ void gl33_bind_vbo(GLuint vbo);
|
|||
void gl33_sync_shader(void);
|
||||
void gl33_sync_texunit(uint unit);
|
||||
void gl33_sync_texunits(void);
|
||||
void gl33_sync_render_target(void);
|
||||
void gl33_sync_framebuffer(void);
|
||||
void gl33_sync_vertex_array(void);
|
||||
void gl33_sync_blend_mode(void);
|
||||
void gl33_sync_cull_face_mode(void);
|
||||
|
@ -41,7 +41,7 @@ GLuint gl33_vbo_current(void);
|
|||
void gl33_vertex_buffer_deleted(VertexBuffer *vbuf);
|
||||
void gl33_vertex_array_deleted(VertexArray *varr);
|
||||
void gl33_texture_deleted(Texture *tex);
|
||||
void gl33_render_target_deleted(RenderTarget *target);
|
||||
void gl33_framebuffer_deleted(Framebuffer *fb);
|
||||
void gl33_shader_deleted(ShaderProgram *prog);
|
||||
|
||||
extern RendererBackend _r_backend_gl33;
|
||||
|
|
99
src/renderer/gl33/framebuffer.c
Normal file
99
src/renderer/gl33/framebuffer.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "framebuffer.h"
|
||||
#include "core.h"
|
||||
|
||||
static GLuint r_attachment_to_gl_attachment[] = {
|
||||
[FRAMEBUFFER_ATTACH_DEPTH] = GL_DEPTH_ATTACHMENT,
|
||||
[FRAMEBUFFER_ATTACH_COLOR0] = GL_COLOR_ATTACHMENT0,
|
||||
[FRAMEBUFFER_ATTACH_COLOR1] = GL_COLOR_ATTACHMENT1,
|
||||
[FRAMEBUFFER_ATTACH_COLOR2] = GL_COLOR_ATTACHMENT2,
|
||||
[FRAMEBUFFER_ATTACH_COLOR3] = GL_COLOR_ATTACHMENT3,
|
||||
};
|
||||
|
||||
static_assert(sizeof(r_attachment_to_gl_attachment)/sizeof(GLuint) == FRAMEBUFFER_MAX_ATTACHMENTS, "");
|
||||
|
||||
void gl33_framebuffer_create(Framebuffer *framebuffer) {
|
||||
memset(framebuffer, 0, sizeof(Framebuffer));
|
||||
framebuffer->impl = calloc(1, sizeof(FramebufferImpl));
|
||||
glGenFramebuffers(1, &framebuffer->impl->gl_fbo);
|
||||
}
|
||||
|
||||
void gl33_framebuffer_attach(Framebuffer *framebuffer, Texture *tex, FramebufferAttachment attachment) {
|
||||
assert(attachment >= 0 && attachment < FRAMEBUFFER_MAX_ATTACHMENTS);
|
||||
|
||||
GLuint gl_tex = tex ? tex->impl->gl_handle : 0;
|
||||
Framebuffer *prev_fb = r_framebuffer_current();
|
||||
|
||||
// make sure gl33_sync_framebuffer doesn't call gl33_framebuffer_initialize here
|
||||
framebuffer->impl->initialized = true;
|
||||
|
||||
r_framebuffer(framebuffer);
|
||||
gl33_sync_framebuffer();
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, r_attachment_to_gl_attachment[attachment], GL_TEXTURE_2D, gl_tex, 0);
|
||||
r_framebuffer(prev_fb);
|
||||
|
||||
framebuffer->impl->attachments[attachment] = tex;
|
||||
|
||||
// need to update draw buffers
|
||||
framebuffer->impl->initialized = false;
|
||||
}
|
||||
|
||||
Texture* gl33_framebuffer_get_attachment(Framebuffer *framebuffer, FramebufferAttachment attachment) {
|
||||
assert(framebuffer->impl != NULL);
|
||||
assert(attachment >= 0 && attachment < FRAMEBUFFER_MAX_ATTACHMENTS);
|
||||
|
||||
if(!framebuffer->impl->initialized) {
|
||||
Framebuffer *prev_fb = r_framebuffer_current();
|
||||
r_framebuffer(framebuffer);
|
||||
gl33_sync_framebuffer(); // implicitly initializes!
|
||||
r_framebuffer(prev_fb);
|
||||
}
|
||||
|
||||
return framebuffer->impl->attachments[attachment];
|
||||
}
|
||||
|
||||
void gl33_framebuffer_destroy(Framebuffer *framebuffer) {
|
||||
if(framebuffer->impl != NULL) {
|
||||
gl33_framebuffer_deleted(framebuffer);
|
||||
glDeleteFramebuffers(1, &framebuffer->impl->gl_fbo);
|
||||
free(framebuffer->impl);
|
||||
framebuffer->impl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gl33_framebuffer_initialize(Framebuffer *framebuffer) {
|
||||
if(!framebuffer->impl->initialized) {
|
||||
// NOTE: this framebuffer is guaranteed to be active at this point
|
||||
|
||||
if(glext.draw_buffers) {
|
||||
GLenum drawbufs[FRAMEBUFFER_MAX_COLOR_ATTACHMENTS];
|
||||
|
||||
for(int i = 0; i < FRAMEBUFFER_MAX_COLOR_ATTACHMENTS; ++i) {
|
||||
if(framebuffer->impl->attachments[FRAMEBUFFER_ATTACH_COLOR0 + i] != NULL) {
|
||||
drawbufs[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
} else {
|
||||
drawbufs[i] = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
glDrawBuffers(FRAMEBUFFER_MAX_COLOR_ATTACHMENTS, drawbufs);
|
||||
}
|
||||
|
||||
Color cc_saved = r_clear_color_current();
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
// NOTE: r_clear would cause an infinite recursion here
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
r_clear_color(cc_saved);
|
||||
|
||||
framebuffer->impl->initialized = true;
|
||||
}
|
||||
}
|
28
src/renderer/gl33/framebuffer.h
Normal file
28
src/renderer/gl33/framebuffer.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "../api.h"
|
||||
#include "opengl.h"
|
||||
#include "texture.h"
|
||||
|
||||
struct FramebufferImpl {
|
||||
GLuint gl_fbo;
|
||||
bool initialized;
|
||||
Texture *attachments[FRAMEBUFFER_MAX_ATTACHMENTS];
|
||||
IntRect viewport;
|
||||
};
|
||||
|
||||
void gl33_framebuffer_initialize(Framebuffer *framebuffer);
|
||||
|
||||
void gl33_framebuffer_create(Framebuffer *framebuffer);
|
||||
void gl33_framebuffer_attach(Framebuffer *framebuffer, Texture *tex, FramebufferAttachment attachment);
|
||||
Texture *gl33_framebuffer_get_attachment(Framebuffer *framebuffer, FramebufferAttachment attachment);
|
||||
void gl33_framebuffer_destroy(Framebuffer *framebuffer);
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
r_gl33_src = files(
|
||||
'core.c',
|
||||
'render_target.c',
|
||||
'framebuffer.c',
|
||||
'shader_object.c',
|
||||
'shader_program.c',
|
||||
'texture.c',
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "render_target.h"
|
||||
#include "core.h"
|
||||
|
||||
static GLuint r_attachment_to_gl_attachment[] = {
|
||||
[RENDERTARGET_ATTACHMENT_DEPTH] = GL_DEPTH_ATTACHMENT,
|
||||
[RENDERTARGET_ATTACHMENT_COLOR0] = GL_COLOR_ATTACHMENT0,
|
||||
[RENDERTARGET_ATTACHMENT_COLOR1] = GL_COLOR_ATTACHMENT1,
|
||||
[RENDERTARGET_ATTACHMENT_COLOR2] = GL_COLOR_ATTACHMENT2,
|
||||
[RENDERTARGET_ATTACHMENT_COLOR3] = GL_COLOR_ATTACHMENT3,
|
||||
};
|
||||
|
||||
static_assert(sizeof(r_attachment_to_gl_attachment)/sizeof(GLuint) == RENDERTARGET_MAX_ATTACHMENTS, "");
|
||||
|
||||
void gl33_target_create(RenderTarget *target) {
|
||||
memset(target, 0, sizeof(RenderTarget));
|
||||
target->impl = calloc(1, sizeof(RenderTargetImpl));
|
||||
glGenFramebuffers(1, &target->impl->gl_fbo);
|
||||
}
|
||||
|
||||
void gl33_target_attach(RenderTarget *target, Texture *tex, RenderTargetAttachment attachment) {
|
||||
assert(attachment >= 0 && attachment < RENDERTARGET_MAX_ATTACHMENTS);
|
||||
|
||||
GLuint gl_tex = tex ? tex->impl->gl_handle : 0;
|
||||
RenderTarget *prev_target = r_target_current();
|
||||
|
||||
// make sure gl33_sync_render_target doesn't call gl33_target_initialize here
|
||||
target->impl->initialized = true;
|
||||
|
||||
r_target(target);
|
||||
gl33_sync_render_target();
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, r_attachment_to_gl_attachment[attachment], GL_TEXTURE_2D, gl_tex, 0);
|
||||
r_target(prev_target);
|
||||
|
||||
target->impl->attachments[attachment] = tex;
|
||||
|
||||
// need to update draw buffers
|
||||
target->impl->initialized = false;
|
||||
}
|
||||
|
||||
Texture* gl33_target_get_attachment(RenderTarget *target, RenderTargetAttachment attachment) {
|
||||
assert(target->impl != NULL);
|
||||
assert(attachment >= 0 && attachment < RENDERTARGET_MAX_ATTACHMENTS);
|
||||
|
||||
if(!target->impl->initialized) {
|
||||
RenderTarget *prev_target = r_target_current();
|
||||
r_target(target);
|
||||
gl33_sync_render_target(); // implicitly initializes!
|
||||
r_target(prev_target);
|
||||
}
|
||||
|
||||
return target->impl->attachments[attachment];
|
||||
}
|
||||
|
||||
void gl33_target_destroy(RenderTarget *target) {
|
||||
if(target->impl != NULL) {
|
||||
gl33_render_target_deleted(target);
|
||||
glDeleteFramebuffers(1, &target->impl->gl_fbo);
|
||||
free(target->impl);
|
||||
target->impl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void gl33_target_initialize(RenderTarget *target) {
|
||||
if(!target->impl->initialized) {
|
||||
// NOTE: this render target is guaranteed to be active at this point
|
||||
|
||||
if(glext.draw_buffers) {
|
||||
GLenum drawbufs[RENDERTARGET_MAX_COLOR_ATTACHMENTS];
|
||||
|
||||
for(int i = 0; i < RENDERTARGET_MAX_COLOR_ATTACHMENTS; ++i) {
|
||||
if(target->impl->attachments[RENDERTARGET_ATTACHMENT_COLOR0 + i] != NULL) {
|
||||
drawbufs[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
} else {
|
||||
drawbufs[i] = GL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
glDrawBuffers(RENDERTARGET_MAX_COLOR_ATTACHMENTS, drawbufs);
|
||||
}
|
||||
|
||||
Color cc_saved = r_clear_color_current();
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
// NOTE: r_clear would cause an infinite recursion here
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
r_clear_color(cc_saved);
|
||||
|
||||
target->impl->initialized = true;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "../api.h"
|
||||
#include "opengl.h"
|
||||
#include "texture.h"
|
||||
|
||||
struct RenderTargetImpl {
|
||||
GLuint gl_fbo;
|
||||
bool initialized;
|
||||
Texture *attachments[RENDERTARGET_MAX_ATTACHMENTS];
|
||||
};
|
||||
|
||||
void gl33_target_initialize(RenderTarget *target);
|
||||
|
||||
void gl33_target_create(RenderTarget *target);
|
||||
void gl33_target_attach(RenderTarget *target, Texture *tex, RenderTargetAttachment attachment);
|
||||
Texture* gl33_target_get_attachment(RenderTarget *target, RenderTargetAttachment attachment);
|
||||
void gl33_target_destroy(RenderTarget *target);
|
|
@ -73,29 +73,48 @@ void null_texture_destroy(Texture *tex) {
|
|||
void null_texture(uint unit, Texture *tex) { }
|
||||
Texture* null_texture_current(uint unit) { return (void*)&placeholder; }
|
||||
|
||||
struct RenderTargetImpl {
|
||||
Texture *attachments[RENDERTARGET_MAX_ATTACHMENTS];
|
||||
struct FramebufferImpl {
|
||||
Texture *attachments[FRAMEBUFFER_MAX_ATTACHMENTS];
|
||||
IntRect viewport;
|
||||
};
|
||||
|
||||
void null_target_create(RenderTarget *target) {
|
||||
target->impl = calloc(1, sizeof(RenderTargetImpl));
|
||||
static IntRect default_fb_viewport;
|
||||
|
||||
void null_framebuffer_create(Framebuffer *framebuffer) {
|
||||
framebuffer->impl = calloc(1, sizeof(FramebufferImpl));
|
||||
}
|
||||
|
||||
void null_target_attach(RenderTarget *target, Texture *tex, RenderTargetAttachment attachment) {
|
||||
target->impl->attachments[attachment] = tex;
|
||||
void null_framebuffer_attach(Framebuffer *framebuffer, Texture *tex, FramebufferAttachment attachment) {
|
||||
framebuffer->impl->attachments[attachment] = tex;
|
||||
}
|
||||
|
||||
Texture* null_target_get_attachment(RenderTarget *target, RenderTargetAttachment attachment) {
|
||||
return target->impl->attachments[attachment];
|
||||
Texture* null_framebuffer_attachment(Framebuffer *framebuffer, FramebufferAttachment attachment) {
|
||||
return framebuffer->impl->attachments[attachment];
|
||||
}
|
||||
|
||||
void null_target_destroy(RenderTarget *target) {
|
||||
free(target->impl);
|
||||
memset(target, 0, sizeof(RenderTarget));
|
||||
void null_framebuffer_destroy(Framebuffer *framebuffer) {
|
||||
free(framebuffer->impl);
|
||||
memset(framebuffer, 0, sizeof(Framebuffer));
|
||||
}
|
||||
|
||||
void null_target(RenderTarget *target) { }
|
||||
RenderTarget* null_target_current(void) { return (void*)&placeholder; }
|
||||
void null_framebuffer_viewport(Framebuffer *framebuffer, IntRect vp) {
|
||||
if(framebuffer) {
|
||||
framebuffer->impl->viewport = vp;
|
||||
} else {
|
||||
default_fb_viewport = vp;
|
||||
}
|
||||
}
|
||||
|
||||
void null_framebuffer_viewport_current(Framebuffer *framebuffer, IntRect *vp) {
|
||||
if(framebuffer) {
|
||||
*vp = framebuffer->impl->viewport;
|
||||
} else {
|
||||
*vp = default_fb_viewport;
|
||||
}
|
||||
}
|
||||
|
||||
void null_framebuffer(Framebuffer *framebuffer) { }
|
||||
Framebuffer* null_framebuffer_current(void) { return (void*)&placeholder; }
|
||||
|
||||
void null_vertex_buffer_create(VertexBuffer *vbuf, size_t capacity, void *data) {
|
||||
vbuf->offset = 0;
|
||||
|
@ -140,14 +159,6 @@ void null_clear(ClearBufferFlags flags) { }
|
|||
void null_clear_color4(float r, float g, float b, float a) { }
|
||||
Color null_clear_color_current(void) { return rgba(0, 0, 0, 0); }
|
||||
|
||||
void null_viewport_rect(IntRect rect) { }
|
||||
void null_viewport_current(IntRect *out_rect) {
|
||||
out_rect->x = 0;
|
||||
out_rect->y = 0;
|
||||
out_rect->w = 800;
|
||||
out_rect->h = 600;
|
||||
}
|
||||
|
||||
void null_vsync(VsyncMode mode) { }
|
||||
VsyncMode null_vsync_current(void) { return VSYNC_NONE; }
|
||||
|
||||
|
@ -245,12 +256,14 @@ RendererBackend _r_backend_null = {
|
|||
.texture_replace = null_texture_replace,
|
||||
.texture = null_texture,
|
||||
.texture_current = null_texture_current,
|
||||
.target_create = null_target_create,
|
||||
.target_destroy = null_target_destroy,
|
||||
.target_attach = null_target_attach,
|
||||
.target_get_attachment = null_target_get_attachment,
|
||||
.target = null_target,
|
||||
.target_current = null_target_current,
|
||||
.framebuffer_create = null_framebuffer_create,
|
||||
.framebuffer_destroy = null_framebuffer_destroy,
|
||||
.framebuffer_attach = null_framebuffer_attach,
|
||||
.framebuffer_get_attachment = null_framebuffer_attachment,
|
||||
.framebuffer_viewport = null_framebuffer_viewport,
|
||||
.framebuffer_viewport_current = null_framebuffer_viewport_current,
|
||||
.framebuffer = null_framebuffer,
|
||||
.framebuffer_current = null_framebuffer_current,
|
||||
.vertex_buffer_create = null_vertex_buffer_create,
|
||||
.vertex_buffer_destroy = null_vertex_buffer_destroy,
|
||||
.vertex_buffer_invalidate = null_vertex_buffer_invalidate,
|
||||
|
@ -266,8 +279,6 @@ RendererBackend _r_backend_null = {
|
|||
.clear = null_clear,
|
||||
.clear_color4 = null_clear_color4,
|
||||
.clear_color_current = null_clear_color_current,
|
||||
.viewport_rect = null_viewport_rect,
|
||||
.viewport_current = null_viewport_current,
|
||||
.vsync = null_vsync,
|
||||
.vsync_current = null_vsync_current,
|
||||
.swap = null_swap,
|
||||
|
|
|
@ -106,7 +106,7 @@ static struct {
|
|||
FT_Library lib;
|
||||
ShaderProgram *default_shader;
|
||||
Texture render_tex;
|
||||
RenderTarget render_buf;
|
||||
Framebuffer render_buf;
|
||||
|
||||
struct {
|
||||
SDL_mutex *new_face;
|
||||
|
@ -115,19 +115,36 @@ static struct {
|
|||
} globals;
|
||||
|
||||
static double global_font_scale(void) {
|
||||
return sanitize_scale(video.quality_factor * config_get_float(CONFIG_TEXT_QUALITY));
|
||||
int w, h;
|
||||
video_get_viewport_size(&w, &h);
|
||||
return sanitize_scale(((double)h / SCREEN_H) * config_get_float(CONFIG_TEXT_QUALITY));
|
||||
}
|
||||
|
||||
static void reload_fonts(double quality);
|
||||
|
||||
static bool fonts_event(SDL_Event *event, void *arg) {
|
||||
reload_fonts(global_font_scale());
|
||||
return false;
|
||||
}
|
||||
if(!IS_TAISEI_EVENT(event->type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void fonts_quality_config_callback(ConfigIndex idx, ConfigValue v) {
|
||||
config_set_float(idx, v.f);
|
||||
reload_fonts(global_font_scale());
|
||||
switch(TAISEI_EVENT(event->type)) {
|
||||
case TE_VIDEO_MODE_CHANGED: {
|
||||
reload_fonts(global_font_scale());
|
||||
break;
|
||||
}
|
||||
|
||||
case TE_CONFIG_UPDATED: {
|
||||
if(event->user.code == CONFIG_TEXT_QUALITY) {
|
||||
ConfigValue *val = event->user.data1;
|
||||
val->f = sanitize_scale(val->f);
|
||||
reload_fonts(global_font_scale());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void try_create_mutex(SDL_mutex **mtx) {
|
||||
|
@ -147,11 +164,9 @@ static void init_fonts(void) {
|
|||
}
|
||||
|
||||
events_register_handler(&(EventHandler) {
|
||||
fonts_event, NULL, EPRIO_SYSTEM, MAKE_TAISEI_EVENT(TE_VIDEO_MODE_CHANGED)
|
||||
fonts_event, NULL, EPRIO_SYSTEM,
|
||||
});
|
||||
|
||||
config_set_callback(CONFIG_TEXT_QUALITY, fonts_quality_config_callback);
|
||||
|
||||
preload_resources(RES_FONT, RESF_PERMANENT,
|
||||
"standard",
|
||||
NULL);
|
||||
|
@ -167,8 +182,9 @@ static void init_fonts(void) {
|
|||
.height = 1024,
|
||||
});
|
||||
|
||||
r_target_create(&globals.render_buf);
|
||||
r_target_attach(&globals.render_buf, &globals.render_tex, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
r_framebuffer_create(&globals.render_buf);
|
||||
r_framebuffer_attach(&globals.render_buf, &globals.render_tex, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
r_framebuffer_viewport(&globals.render_buf, 0, 0, globals.render_tex.w, globals.render_tex.h);
|
||||
}
|
||||
|
||||
static void post_init_fonts(void) {
|
||||
|
@ -177,7 +193,7 @@ static void post_init_fonts(void) {
|
|||
|
||||
static void shutdown_fonts(void) {
|
||||
r_texture_destroy(&globals.render_tex);
|
||||
r_target_destroy(&globals.render_buf);
|
||||
r_framebuffer_destroy(&globals.render_buf);
|
||||
events_unregister_handler(fonts_event);
|
||||
FT_Done_FreeType(globals.lib);
|
||||
SDL_DestroyMutex(globals.mutex.new_face);
|
||||
|
@ -317,7 +333,7 @@ static SpriteSheet* add_spritesheet(SpriteSheetAnchor *spritesheets) {
|
|||
|
||||
// FIXME:
|
||||
//
|
||||
// This code just zeroes the texture out.
|
||||
// This code just zeroes the texture out.
|
||||
//
|
||||
// We should add an r_texture_clear function to hide this monstrosity.
|
||||
// It would also allow a non-GL backend to have a different implementation,
|
||||
|
@ -325,17 +341,17 @@ static SpriteSheet* add_spritesheet(SpriteSheetAnchor *spritesheets) {
|
|||
//
|
||||
// To future generations: if such a function is already in the renderer API,
|
||||
// but this crap is still here, please convert it.
|
||||
RenderTarget *prev_target = r_target_current();
|
||||
RenderTarget atlast_rt;
|
||||
Framebuffer *prev_fb = r_framebuffer_current();
|
||||
Framebuffer atlast_fb;
|
||||
Color cc_prev = r_clear_color_current();
|
||||
r_target_create(&atlast_rt);
|
||||
r_target_attach(&atlast_rt, &ss->tex, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
r_target(&atlast_rt);
|
||||
r_framebuffer_create(&atlast_fb);
|
||||
r_framebuffer_attach(&atlast_fb, &ss->tex, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
r_framebuffer(&atlast_fb);
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
r_clear(CLEAR_COLOR);
|
||||
r_target(prev_target);
|
||||
r_framebuffer(prev_fb);
|
||||
r_clear_color(cc_prev);
|
||||
r_target_destroy(&atlast_rt);
|
||||
r_framebuffer_destroy(&atlast_fb);
|
||||
|
||||
alist_append(spritesheets, ss);
|
||||
return ss;
|
||||
|
@ -584,8 +600,10 @@ struct rlfonts_arg {
|
|||
|
||||
attr_nonnull(1)
|
||||
static void reload_font(Font *font, double quality) {
|
||||
wipe_glyph_cache(font);
|
||||
set_font_size(font, font->base_size, quality);
|
||||
if(font->metrics.scale != quality) {
|
||||
wipe_glyph_cache(font);
|
||||
set_font_size(font, font->base_size, quality);
|
||||
}
|
||||
}
|
||||
|
||||
static void* reload_font_callback(const char *name, Resource *res, void *varg) {
|
||||
|
@ -945,11 +963,12 @@ void text_render(const char *text, Font *font, Sprite *out_sprite, BBox *out_bbo
|
|||
);
|
||||
|
||||
r_texture_replace(tex, TEX_TYPE_R, tex_new_w, tex_new_h, NULL);
|
||||
r_framebuffer_viewport(&globals.render_buf, 0, 0, tex_new_w, tex_new_h);
|
||||
}
|
||||
|
||||
r_state_push();
|
||||
|
||||
r_target(&globals.render_buf);
|
||||
r_framebuffer(&globals.render_buf);
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
r_clear(CLEAR_COLOR);
|
||||
|
||||
|
@ -967,7 +986,6 @@ void text_render(const char *text, Font *font, Sprite *out_sprite, BBox *out_bbo
|
|||
r_mat_identity();
|
||||
// XXX: y-flipped because that's how our textures are...
|
||||
r_mat_ortho(0, tex->w, 0, tex->h, -100, 100);
|
||||
r_viewport(0, 0, tex->w, tex->h);
|
||||
|
||||
r_mat_mode(MM_TEXTURE);
|
||||
r_mat_push();
|
||||
|
|
|
@ -184,7 +184,7 @@ void postprocess_unload(PostprocessShader **list) {
|
|||
list_foreach(list, delete_shader, NULL);
|
||||
}
|
||||
|
||||
void postprocess(PostprocessShader *ppshaders, FBOPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw) {
|
||||
void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw, double width, double height) {
|
||||
if(!ppshaders) {
|
||||
return;
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ void postprocess(PostprocessShader *ppshaders, FBOPair *fbos, PostprocessPrepare
|
|||
for(PostprocessShader *pps = ppshaders; pps; pps = pps->next) {
|
||||
ShaderProgram *s = pps->shader;
|
||||
|
||||
r_target(fbos->back);
|
||||
r_framebuffer(fbos->back);
|
||||
r_shader_ptr(s);
|
||||
|
||||
if(prepare) {
|
||||
|
@ -208,8 +208,8 @@ void postprocess(PostprocessShader *ppshaders, FBOPair *fbos, PostprocessPrepare
|
|||
r_uniform_ptr(u->uniform, u->elements, u->values);
|
||||
}
|
||||
|
||||
draw(fbos->front);
|
||||
swap_fbo_pair(fbos);
|
||||
draw(fbos->front, width, height);
|
||||
fbpair_swap(fbos);
|
||||
}
|
||||
|
||||
r_shader_ptr(shader_saved);
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
#include "resource.h"
|
||||
#include "shader_program.h"
|
||||
#include "fbo.h"
|
||||
#include "renderer/api.h"
|
||||
#include "util/graphics.h"
|
||||
|
||||
typedef struct PostprocessShader PostprocessShader;
|
||||
typedef struct PostprocessShaderUniform PostprocessShaderUniform;
|
||||
|
@ -38,14 +38,14 @@ struct PostprocessShaderUniform {
|
|||
uint elements;
|
||||
};
|
||||
|
||||
typedef void (*PostprocessDrawFuncPtr)(FBO*);
|
||||
typedef void (*PostprocessPrepareFuncPtr)(FBO*, ShaderProgram*);
|
||||
typedef void (*PostprocessDrawFuncPtr)(Framebuffer* fb, double w, double h);
|
||||
typedef void (*PostprocessPrepareFuncPtr)(Framebuffer* fb, ShaderProgram *prog);
|
||||
|
||||
char* postprocess_path(const char *path);
|
||||
|
||||
PostprocessShader* postprocess_load(const char *path, uint flags);
|
||||
void postprocess_unload(PostprocessShader **list);
|
||||
void postprocess(PostprocessShader *ppshaders, FBOPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw);
|
||||
void postprocess(PostprocessShader *ppshaders, FBPair *fbos, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw, double width, double height);
|
||||
|
||||
/*
|
||||
* Glue for resources api
|
||||
|
|
|
@ -67,8 +67,6 @@ typedef struct ResourceAsyncLoadData {
|
|||
void *opaque;
|
||||
} ResourceAsyncLoadData;
|
||||
|
||||
Resources resources;
|
||||
|
||||
static SDL_threadID main_thread_id; // TODO: move this somewhere else
|
||||
|
||||
static inline ResourceHandler* get_handler(ResourceType type) {
|
||||
|
@ -584,10 +582,6 @@ void free_resources(bool all) {
|
|||
return;
|
||||
}
|
||||
|
||||
delete_fbo_pair(&resources.fbo_pairs.bg);
|
||||
delete_fbo_pair(&resources.fbo_pairs.fg);
|
||||
delete_fbo_pair(&resources.fbo_pairs.rgba);
|
||||
|
||||
if(!env_get("TAISEI_NOASYNC", 0)) {
|
||||
events_unregister_handler(resource_asyncload_handler);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "hashtable.h"
|
||||
// #include "fbo.h"
|
||||
|
||||
typedef enum ResourceType {
|
||||
RES_TEXTURE,
|
||||
|
|
|
@ -171,15 +171,12 @@ static void texture_post_load(Texture *tex) {
|
|||
|
||||
ShaderProgram *shader_saved = r_shader_current();
|
||||
Texture *texture_saved = r_texture_current(0);
|
||||
RenderTarget *target_saved = r_target_current();
|
||||
Framebuffer *fb_saved = r_framebuffer_current();
|
||||
BlendMode blend_saved = r_blend_current();
|
||||
bool cullcap_saved = r_capability_current(RCAP_CULL_FACE);
|
||||
|
||||
IntRect viewport_saved;
|
||||
r_viewport_current(&viewport_saved);
|
||||
|
||||
Texture fbo_tex;
|
||||
RenderTarget fbo;
|
||||
Framebuffer fb;
|
||||
|
||||
r_blend(BLEND_NONE);
|
||||
r_disable(RCAP_CULL_FACE);
|
||||
|
@ -196,9 +193,10 @@ static void texture_post_load(Texture *tex) {
|
|||
.t = TEX_WRAP_REPEAT,
|
||||
},
|
||||
});
|
||||
r_target_create(&fbo);
|
||||
r_target_attach(&fbo, &fbo_tex, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
r_target(&fbo);
|
||||
r_framebuffer_create(&fb);
|
||||
r_framebuffer_attach(&fb, &fbo_tex, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
r_framebuffer_viewport(&fb, 0, 0, tex->w, tex->h);
|
||||
r_framebuffer(&fb);
|
||||
r_texture_ptr(0, tex);
|
||||
r_shader("texture_post_load");
|
||||
r_uniform_int("width", tex->w);
|
||||
|
@ -209,7 +207,6 @@ static void texture_post_load(Texture *tex) {
|
|||
r_mat_push();
|
||||
r_mat_identity();
|
||||
r_mat_ortho(0, tex->w, tex->h, 0, -100, 100);
|
||||
r_viewport(0, 0, tex->w, tex->h);
|
||||
r_mat_mode(MM_MODELVIEW);
|
||||
r_mat_scale(tex->w, tex->h, 1);
|
||||
r_mat_translate(0.5, 0.5, 0);
|
||||
|
@ -219,14 +216,13 @@ static void texture_post_load(Texture *tex) {
|
|||
r_mat_mode(MM_PROJECTION);
|
||||
r_mat_pop();
|
||||
r_mat_mode(MM_MODELVIEW);
|
||||
r_target(target_saved);
|
||||
r_framebuffer(fb_saved);
|
||||
r_shader_ptr(shader_saved);
|
||||
r_texture_ptr(0, texture_saved);
|
||||
r_blend(blend_saved);
|
||||
r_capability(RCAP_CULL_FACE, cullcap_saved);
|
||||
r_target_destroy(&fbo);
|
||||
r_framebuffer_destroy(&fb);
|
||||
r_texture_destroy(tex);
|
||||
r_viewport_rect(viewport_saved);
|
||||
|
||||
memcpy(tex, &fbo_tex, sizeof(fbo_tex));
|
||||
}
|
||||
|
|
|
@ -631,7 +631,7 @@ void stage_loop(StageInfo *stage) {
|
|||
|
||||
stage_objpools_alloc();
|
||||
stage_preload();
|
||||
stage_draw_preload();
|
||||
stage_draw_init();
|
||||
|
||||
uint32_t seed = (uint32_t)time(0);
|
||||
tsrand_switch(&global.rand_game);
|
||||
|
@ -696,6 +696,7 @@ void stage_loop(StageInfo *stage) {
|
|||
}
|
||||
|
||||
stage->procs->end();
|
||||
stage_draw_shutdown();
|
||||
stage_free();
|
||||
player_free(&global.plr);
|
||||
tsrand_switch(&global.rand_visual);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "boss.h"
|
||||
#include "progress.h"
|
||||
#include "difficulty.h"
|
||||
#include "fbo.h"
|
||||
#include "util/graphics.h"
|
||||
|
||||
/* taisei's strange macro language.
|
||||
*
|
||||
|
@ -56,7 +56,7 @@
|
|||
#define FROM_TO_INT_SND(snd,start,end,step,dur,istep) FROM_TO_INT(start,end,step,dur,2) { play_loop(snd); }FROM_TO_INT(start,end,step,dur,istep)
|
||||
|
||||
typedef void (*StageProc)(void);
|
||||
typedef void (*ShaderRule)(FBO*);
|
||||
typedef void (*ShaderRule)(Framebuffer *);
|
||||
|
||||
// two highest bits of uint16_t, WAY higher than the amount of spells in this game can ever possibly be
|
||||
#define STAGE_SPELL_BIT 0x8000
|
||||
|
|
201
src/stagedraw.c
201
src/stagedraw.c
|
@ -35,9 +35,11 @@ static struct {
|
|||
} color;
|
||||
} hud_text;
|
||||
|
||||
PostprocessShader *viewport_pp;
|
||||
FBPair fb_pairs[NUM_FBPAIRS];
|
||||
|
||||
bool framerate_graphs;
|
||||
bool objpool_stats;
|
||||
PostprocessShader *viewport_pp;
|
||||
|
||||
#ifdef DEBUG
|
||||
Sprite dummy;
|
||||
|
@ -50,7 +52,121 @@ static struct {
|
|||
}
|
||||
};
|
||||
|
||||
void stage_draw_preload(void) {
|
||||
static double fb_scale(void) {
|
||||
int vp_width, vp_height;
|
||||
video_get_viewport_size(&vp_width, &vp_height);
|
||||
return (double)vp_height / SCREEN_H;
|
||||
}
|
||||
|
||||
static void set_fb_size(StageFBPair fb_id, int *w, int *h) {
|
||||
double scale = fb_scale();
|
||||
|
||||
switch(fb_id) {
|
||||
case FBPAIR_BG:
|
||||
scale *= config_get_float(CONFIG_BG_QUALITY);
|
||||
break;
|
||||
|
||||
default:
|
||||
scale *= config_get_float(CONFIG_FG_QUALITY);
|
||||
break;
|
||||
}
|
||||
|
||||
scale = sanitize_scale(scale);
|
||||
*w = round(VIEWPORT_W * scale);
|
||||
*h = round(VIEWPORT_H * scale);
|
||||
}
|
||||
|
||||
static void update_fb_size(StageFBPair fb_id) {
|
||||
int w, h;
|
||||
set_fb_size(fb_id, &w, &h);
|
||||
fbpair_resize_all(stagedraw.fb_pairs + fb_id, w, h);
|
||||
fbpair_viewport(stagedraw.fb_pairs + fb_id, 0, 0, w, h);
|
||||
}
|
||||
|
||||
static bool stage_draw_event(SDL_Event *e, void *arg) {
|
||||
if(!IS_TAISEI_EVENT(e->type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(TAISEI_EVENT(e->type)) {
|
||||
case TE_VIDEO_MODE_CHANGED: {
|
||||
for(uint i = 0; i < NUM_FBPAIRS; ++i) {
|
||||
update_fb_size(i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TE_CONFIG_UPDATED: {
|
||||
switch(e->user.code) {
|
||||
case CONFIG_FG_QUALITY: {
|
||||
update_fb_size(FBPAIR_FG);
|
||||
update_fb_size(FBPAIR_FG_AUX);
|
||||
break;
|
||||
}
|
||||
|
||||
case CONFIG_BG_QUALITY: {
|
||||
update_fb_size(FBPAIR_BG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void stage_draw_setup_framebuffers(void) {
|
||||
int fg_width, fg_height, bg_width, bg_height;
|
||||
FBAttachmentConfig a[2], *a_color, *a_depth;
|
||||
memset(a, 0, sizeof(a));
|
||||
|
||||
a_color = &a[0];
|
||||
a_depth = &a[1];
|
||||
|
||||
a_color->attachment = FRAMEBUFFER_ATTACH_COLOR0;
|
||||
a_depth->attachment = FRAMEBUFFER_ATTACH_DEPTH;
|
||||
|
||||
set_fb_size(FBPAIR_FG, &fg_width, &fg_height);
|
||||
set_fb_size(FBPAIR_BG, &bg_width, &bg_height);
|
||||
|
||||
// Set up some parameters shared by all attachments
|
||||
TextureParams tex_common = {
|
||||
.filter.upscale = TEX_FILTER_LINEAR,
|
||||
.filter.downscale = TEX_FILTER_LINEAR,
|
||||
.wrap.s = TEX_WRAP_MIRROR,
|
||||
.wrap.t = TEX_WRAP_MIRROR,
|
||||
};
|
||||
|
||||
memcpy(&a_color->tex_params, &tex_common, sizeof(tex_common));
|
||||
memcpy(&a_depth->tex_params, &tex_common, sizeof(tex_common));
|
||||
|
||||
// Foreground: 1 RGB texture per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGB;
|
||||
a_color->tex_params.width = fg_width;
|
||||
a_color->tex_params.height = fg_height;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_FG, 1, a);
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_FG, 0, 0, fg_width, fg_height);
|
||||
|
||||
// Foreground auxiliary: 1 RGBA texture per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGBA;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_FG_AUX, 1, a);
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_FG_AUX, 0, 0, fg_width, fg_height);
|
||||
|
||||
// Background: 1 RGB texture + depth per FB
|
||||
a_color->tex_params.type = TEX_TYPE_RGB;
|
||||
a_color->tex_params.width = bg_width;
|
||||
a_color->tex_params.height = bg_height;
|
||||
a_depth->tex_params.type = TEX_TYPE_DEPTH;
|
||||
a_depth->tex_params.width = bg_width;
|
||||
a_depth->tex_params.height = bg_height;
|
||||
fbpair_create(stagedraw.fb_pairs + FBPAIR_BG, 2, a);
|
||||
fbpair_viewport(stagedraw.fb_pairs + FBPAIR_BG, 0, 0, bg_width, bg_height);
|
||||
}
|
||||
|
||||
void stage_draw_init(void) {
|
||||
preload_resources(RES_POSTPROCESS, RESF_OPTIONAL,
|
||||
"viewport",
|
||||
NULL);
|
||||
|
@ -107,6 +223,25 @@ void stage_draw_preload(void) {
|
|||
stagedraw.dummy.w = 1;
|
||||
stagedraw.dummy.h = 1;
|
||||
#endif
|
||||
|
||||
stage_draw_setup_framebuffers();
|
||||
|
||||
events_register_handler(&(EventHandler) {
|
||||
stage_draw_event, NULL, EPRIO_SYSTEM,
|
||||
});
|
||||
}
|
||||
|
||||
void stage_draw_shutdown(void) {
|
||||
events_unregister_handler(stage_draw_event);
|
||||
|
||||
for(uint i = 0; i < NUM_FBPAIRS; ++i) {
|
||||
fbpair_destroy(stagedraw.fb_pairs + i);
|
||||
}
|
||||
}
|
||||
|
||||
FBPair* stage_get_fbpair(StageFBPair id) {
|
||||
assert(id >= 0 && id < NUM_FBPAIRS);
|
||||
return stagedraw.fb_pairs + id;
|
||||
}
|
||||
|
||||
static void stage_draw_collision_areas(void) {
|
||||
|
@ -171,15 +306,15 @@ static void stage_draw_collision_areas(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static void apply_shader_rules(ShaderRule *shaderrules, FBOPair *fbos) {
|
||||
static void apply_shader_rules(ShaderRule *shaderrules, FBPair *fbos) {
|
||||
if(!shaderrules) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(ShaderRule *rule = shaderrules; *rule; ++rule) {
|
||||
r_target(fbos->back);
|
||||
r_framebuffer(fbos->back);
|
||||
(*rule)(fbos->front);
|
||||
swap_fbo_pair(fbos);
|
||||
fbpair_swap(fbos);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -265,7 +400,7 @@ static inline bool should_draw_stage_bg(void) {
|
|||
);
|
||||
}
|
||||
|
||||
static void apply_bg_shaders(ShaderRule *shaderrules, FBOPair *fbos) {
|
||||
static void apply_bg_shaders(ShaderRule *shaderrules, FBPair *fbos) {
|
||||
Boss *b = global.boss;
|
||||
if(b && b->current && b->current->draw_rule) {
|
||||
int t = global.frames - b->current->starttime;
|
||||
|
@ -276,11 +411,11 @@ static void apply_bg_shaders(ShaderRule *shaderrules, FBOPair *fbos) {
|
|||
apply_shader_rules(shaderrules, fbos);
|
||||
}
|
||||
|
||||
r_target(fbos->back);
|
||||
draw_fbo(fbos->front);
|
||||
r_framebuffer(fbos->back);
|
||||
draw_framebuffer_tex(fbos->front, VIEWPORT_W, VIEWPORT_H);
|
||||
draw_spellbg(t);
|
||||
swap_fbo_pair(fbos);
|
||||
r_target(fbos->back);
|
||||
fbpair_swap(fbos);
|
||||
r_framebuffer(fbos->back);
|
||||
|
||||
complex pos = b->pos;
|
||||
float ratio = (float)VIEWPORT_H/VIEWPORT_W;
|
||||
|
@ -317,9 +452,9 @@ static void apply_bg_shaders(ShaderRule *shaderrules, FBOPair *fbos) {
|
|||
r_shader_standard();
|
||||
}
|
||||
|
||||
draw_fbo(fbos->front);
|
||||
swap_fbo_pair(fbos);
|
||||
r_target(NULL);
|
||||
draw_framebuffer_tex(fbos->front, VIEWPORT_W, VIEWPORT_H);
|
||||
fbpair_swap(fbos);
|
||||
r_framebuffer(NULL);
|
||||
r_shader_standard();
|
||||
} else if(should_draw_stage_bg()) {
|
||||
set_ortho(VIEWPORT_W, VIEWPORT_H);
|
||||
|
@ -362,9 +497,9 @@ static void apply_zoom_shader(void) {
|
|||
}
|
||||
|
||||
static void stage_render_bg(StageInfo *stage) {
|
||||
r_target(resources.fbo_pairs.bg.back);
|
||||
Texture *bg_tex = r_target_get_attachment(resources.fbo_pairs.bg.back, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
r_viewport(0, 0, bg_tex->w, bg_tex->h);
|
||||
FBPair *background = stage_get_fbpair(FBPAIR_BG);
|
||||
|
||||
r_framebuffer(background->back);
|
||||
r_clear(CLEAR_ALL);
|
||||
|
||||
if(should_draw_stage_bg()) {
|
||||
|
@ -373,10 +508,10 @@ static void stage_render_bg(StageInfo *stage) {
|
|||
r_enable(RCAP_DEPTH_TEST);
|
||||
stage->procs->draw();
|
||||
r_mat_pop();
|
||||
swap_fbo_pair(&resources.fbo_pairs.bg);
|
||||
fbpair_swap(background);
|
||||
}
|
||||
|
||||
apply_bg_shaders(stage->procs->shader_rules, &resources.fbo_pairs.bg);
|
||||
apply_bg_shaders(stage->procs->shader_rules, background);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -418,7 +553,7 @@ static void stage_draw_objects(void) {
|
|||
stagetext_draw();
|
||||
}
|
||||
|
||||
static void postprocess_prepare(FBO *fbo, ShaderProgram *s) {
|
||||
static void postprocess_prepare(Framebuffer *fb, ShaderProgram *s) {
|
||||
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));
|
||||
|
@ -434,7 +569,7 @@ void stage_draw_foreground(void) {
|
|||
// confer video_update_quality to understand why this is fach. fach is equal to facw up to roundoff error.
|
||||
float scale = fach;
|
||||
|
||||
// draw the foreground FBO
|
||||
// draw the foreground Framebuffer
|
||||
r_mat_push();
|
||||
r_mat_scale(1/facw,1/fach,1);
|
||||
r_mat_translate(floorf(facw*VIEWPORT_X), floorf(fach*VIEWPORT_Y), 0);
|
||||
|
@ -452,7 +587,7 @@ void stage_draw_foreground(void) {
|
|||
global.shake_view = global.shake_view_fade = 0;
|
||||
}
|
||||
}
|
||||
draw_fbo(resources.fbo_pairs.fg.front);
|
||||
draw_framebuffer_tex(stage_get_fbpair(FBPAIR_FG)->front, VIEWPORT_W, VIEWPORT_H);
|
||||
r_mat_pop();
|
||||
}
|
||||
|
||||
|
@ -463,6 +598,9 @@ void stage_draw_scene(StageInfo *stage) {
|
|||
bool key_nobg = false;
|
||||
#endif
|
||||
|
||||
FBPair *background = stage_get_fbpair(FBPAIR_BG);
|
||||
FBPair *foreground = stage_get_fbpair(FBPAIR_FG);
|
||||
|
||||
bool draw_bg = !config_get_int(CONFIG_NO_STAGEBG) && !key_nobg;
|
||||
|
||||
if(draw_bg) {
|
||||
|
@ -471,9 +609,7 @@ void stage_draw_scene(StageInfo *stage) {
|
|||
}
|
||||
|
||||
// prepare for 2D rendering into the game viewport framebuffer
|
||||
r_target(resources.fbo_pairs.fg.back);
|
||||
Texture *fg_tex = r_target_get_attachment(resources.fbo_pairs.fg.back, RENDERTARGET_ATTACHMENT_COLOR0);
|
||||
r_viewport(0, 0, fg_tex->w, fg_tex->h);
|
||||
r_framebuffer(foreground->back);
|
||||
set_ortho(VIEWPORT_W, VIEWPORT_H);
|
||||
r_disable(RCAP_DEPTH_TEST);
|
||||
|
||||
|
@ -484,7 +620,7 @@ void stage_draw_scene(StageInfo *stage) {
|
|||
}
|
||||
|
||||
// draw the 3D background
|
||||
draw_fbo(resources.fbo_pairs.bg.front);
|
||||
draw_framebuffer_tex(background->front, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
// disable boss background distortion
|
||||
r_shader_standard();
|
||||
|
@ -501,28 +637,29 @@ void stage_draw_scene(StageInfo *stage) {
|
|||
stage_draw_objects();
|
||||
|
||||
// everything drawn, now apply postprocessing
|
||||
swap_fbo_pair(&resources.fbo_pairs.fg);
|
||||
fbpair_swap(foreground);
|
||||
|
||||
// stage postprocessing
|
||||
apply_shader_rules(global.stage->procs->postprocess_rules, &resources.fbo_pairs.fg);
|
||||
apply_shader_rules(global.stage->procs->postprocess_rules, foreground);
|
||||
|
||||
// bomb effects shader if present and player bombing
|
||||
if(global.frames - global.plr.recovery < 0 && global.plr.mode->procs.bomb_shader) {
|
||||
ShaderRule rules[] = { global.plr.mode->procs.bomb_shader, NULL };
|
||||
apply_shader_rules(rules, &resources.fbo_pairs.fg);
|
||||
apply_shader_rules(rules, foreground);
|
||||
}
|
||||
|
||||
// custom postprocessing
|
||||
postprocess(
|
||||
stagedraw.viewport_pp,
|
||||
&resources.fbo_pairs.fg,
|
||||
foreground,
|
||||
postprocess_prepare,
|
||||
draw_fbo
|
||||
draw_framebuffer_tex,
|
||||
VIEWPORT_W,
|
||||
VIEWPORT_H
|
||||
);
|
||||
|
||||
// prepare for 2D rendering into the main framebuffer (actual screen)
|
||||
r_target(NULL);
|
||||
video_set_viewport();
|
||||
r_framebuffer(NULL);
|
||||
set_ortho(SCREEN_W, SCREEN_H);
|
||||
|
||||
// draw the game viewport and HUD
|
||||
|
|
|
@ -10,9 +10,20 @@
|
|||
#include "taisei.h"
|
||||
|
||||
#include "stage.h"
|
||||
#include "util/graphics.h"
|
||||
|
||||
void stage_draw_preload(void);
|
||||
typedef enum StageFBPair {
|
||||
FBPAIR_BG,
|
||||
FBPAIR_FG,
|
||||
FBPAIR_FG_AUX,
|
||||
NUM_FBPAIRS,
|
||||
} StageFBPair;
|
||||
|
||||
void stage_draw_init(void);
|
||||
void stage_draw_shutdown(void);
|
||||
void stage_draw_hud(void);
|
||||
void stage_draw_foreground(void);
|
||||
void stage_draw_scene(StageInfo *stage);
|
||||
bool stage_should_draw_particle(Projectile *p);
|
||||
|
||||
FBPair* stage_get_fbpair(StageFBPair id) attr_returns_nonnull;
|
||||
|
|
|
@ -150,7 +150,7 @@ static vec3 **stage1_smoke_pos(vec3 p, float maxrange) {
|
|||
return linear3dpos(p, maxrange/2.0, q, r);
|
||||
}
|
||||
|
||||
static void stage1_fog(FBO *fbo) {
|
||||
static void stage1_fog(Framebuffer *fb) {
|
||||
r_shader("zbuf_fog");
|
||||
r_uniform_int("tex", 0);
|
||||
r_uniform_int("depth", 1);
|
||||
|
@ -159,8 +159,8 @@ static void stage1_fog(FBO *fbo) {
|
|||
r_uniform_float("end", 0.8);
|
||||
r_uniform_float("exponent", 3.0);
|
||||
r_uniform_float("sphereness", 0.2);
|
||||
r_texture_ptr(1, r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_DEPTH));
|
||||
draw_fbo(fbo);
|
||||
r_texture_ptr(1, r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ static vec3 **stage2_bg_grass_pos2(vec3 pos, float maxrange) {
|
|||
return linear3dpos(pos, maxrange, p, r);
|
||||
}
|
||||
|
||||
static void stage2_fog(FBO *fbo) {
|
||||
static void stage2_fog(Framebuffer *fb) {
|
||||
r_shader("zbuf_fog");
|
||||
r_uniform_int("tex", 0);
|
||||
r_uniform_int("depth", 2);
|
||||
|
@ -159,17 +159,17 @@ static void stage2_fog(FBO *fbo) {
|
|||
r_uniform_float("end", 0.8);
|
||||
r_uniform_float("exponent", 3.0);
|
||||
r_uniform_float("sphereness", 0);
|
||||
r_texture_ptr(2, r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_DEPTH));
|
||||
draw_fbo(fbo);
|
||||
r_texture_ptr(2, r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
static void stage2_bloom(FBO *fbo) {
|
||||
static void stage2_bloom(Framebuffer *fb) {
|
||||
r_shader("bloom");
|
||||
r_uniform_int("samples", 10);
|
||||
r_uniform_float("intensity", 0.05);
|
||||
r_uniform_float("radius", 0.03);
|
||||
draw_fbo(fbo);
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
|
|
|
@ -97,16 +97,16 @@ static void stage3_bg_tunnel_draw(vec3 pos) {
|
|||
r_mat_pop();
|
||||
}
|
||||
|
||||
static void stage3_tunnel(FBO *fbo) {
|
||||
static void stage3_tunnel(Framebuffer *fb) {
|
||||
r_shader("tunnel");
|
||||
r_uniform_vec3("color", stgstate.clr_r, stgstate.clr_g, stgstate.clr_b);
|
||||
r_uniform_float("mixfactor", stgstate.clr_mixfactor);
|
||||
r_texture_ptr(2, r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_DEPTH));
|
||||
draw_fbo(fbo);
|
||||
r_texture_ptr(2, r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
static void stage3_fog(FBO *fbo) {
|
||||
static void stage3_fog(Framebuffer *fb) {
|
||||
r_shader("zbuf_fog");
|
||||
r_uniform_int("tex", 0);
|
||||
r_uniform_int("depth", 2);
|
||||
|
@ -115,12 +115,12 @@ static void stage3_fog(FBO *fbo) {
|
|||
r_uniform_float("end", 0.8);
|
||||
r_uniform_float("exponent", stgstate.fog_exp/2);
|
||||
r_uniform_float("sphereness", 0);
|
||||
r_texture_ptr(2, r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_DEPTH));
|
||||
draw_fbo(fbo);
|
||||
r_texture_ptr(2, r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
static void stage3_glitch(FBO *fbo) {
|
||||
static void stage3_glitch(Framebuffer *fb) {
|
||||
float strength;
|
||||
|
||||
if(global.boss && global.boss->current && ATTACK_IS_SPELL(global.boss->current->type) && !strcmp(global.boss->name, "Scuttle")) {
|
||||
|
@ -138,7 +138,7 @@ static void stage3_glitch(FBO *fbo) {
|
|||
r_color4(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
draw_fbo(fbo);
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ struct stage4_spells_s stage4_spells = {
|
|||
},
|
||||
};
|
||||
|
||||
static void stage4_fog(FBO *fbo) {
|
||||
static void stage4_fog(Framebuffer *fb) {
|
||||
float f = 0;
|
||||
int redtime = 5100 + STAGE4_MIDBOSS_MUSIC_TIME;
|
||||
|
||||
|
@ -80,8 +80,8 @@ static void stage4_fog(FBO *fbo) {
|
|||
r_uniform_float("end", 0.8);
|
||||
r_uniform_float("exponent", 4.0);
|
||||
r_uniform_float("sphereness", 0);
|
||||
r_texture_ptr(2, r_target_get_attachment(fbo, RENDERTARGET_ATTACHMENT_DEPTH));
|
||||
draw_fbo(fbo);
|
||||
r_texture_ptr(2, r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
|
||||
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
|
||||
r_shader_standard();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <stdlib.h>
|
||||
#include "global.h"
|
||||
#include "util/glm.h"
|
||||
#include "video.h"
|
||||
|
||||
Stage3D stage_3d_context;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "util/env.h"
|
||||
#include "util/geometry.h"
|
||||
// #include "util/glm.h"
|
||||
#include "util/graphics.h"
|
||||
// #include "util/graphics.h"
|
||||
#include "util/io.h"
|
||||
#include "util/kvparser.h"
|
||||
#include "util/miscmath.h"
|
||||
|
|
92
src/util/fbpair.c
Normal file
92
src/util/fbpair.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "fbpair.h"
|
||||
#include "global.h"
|
||||
#include "util.h"
|
||||
|
||||
static void fbpair_create_fb(Framebuffer *fb, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
r_framebuffer_create(fb);
|
||||
|
||||
for(uint i = 0; i < num_attachments; ++i) {
|
||||
Texture *tex = calloc(1, sizeof(Texture));
|
||||
r_texture_create(tex, &attachments[i].tex_params);
|
||||
r_framebuffer_attach(fb, tex, attachments[i].attachment);
|
||||
}
|
||||
}
|
||||
|
||||
static void fbpair_destroy_fb(Framebuffer *fb) {
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
Texture *tex = r_framebuffer_get_attachment(fb, i);
|
||||
|
||||
if(tex != NULL) {
|
||||
r_texture_destroy(tex);
|
||||
free(tex);
|
||||
}
|
||||
}
|
||||
|
||||
r_framebuffer_destroy(fb);
|
||||
}
|
||||
|
||||
static void fbpair_resize_fb(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height) {
|
||||
Texture *tex = r_framebuffer_get_attachment(fb, attachment);
|
||||
|
||||
if(tex == NULL || (tex->w == width && tex->h == height)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: We could render a rescaled version of the old texture contents here
|
||||
|
||||
r_texture_replace(tex, tex->type, width, height, NULL);
|
||||
r_state_push();
|
||||
r_framebuffer(fb);
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
r_clear(CLEAR_ALL);
|
||||
r_state_pop();
|
||||
}
|
||||
|
||||
void fbpair_create(FBPair *pair, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
assert(num_attachments > 0 && num_attachments <= FRAMEBUFFER_MAX_ATTACHMENTS);
|
||||
memset(pair, 0, sizeof(*pair));
|
||||
fbpair_create_fb(*(void**)&pair->front = pair->framebuffers + 0, num_attachments, attachments);
|
||||
fbpair_create_fb(*(void**)&pair->back = pair->framebuffers + 1, num_attachments, attachments);
|
||||
}
|
||||
|
||||
void fbpair_destroy(FBPair *pair) {
|
||||
fbpair_destroy_fb(pair->framebuffers + 0);
|
||||
fbpair_destroy_fb(pair->framebuffers + 1);
|
||||
}
|
||||
|
||||
void fbpair_swap(FBPair *pair) {
|
||||
void *tmp = pair->front;
|
||||
*(void**)&pair->front = pair->back;
|
||||
*(void**)&pair->back = tmp;
|
||||
}
|
||||
|
||||
void fbpair_resize(FBPair *pair, FramebufferAttachment attachment, uint width, uint height) {
|
||||
fbpair_resize_fb(pair->framebuffers + 0, attachment, width, height);
|
||||
fbpair_resize_fb(pair->framebuffers + 1, attachment, width, height);
|
||||
}
|
||||
|
||||
void fbpair_resize_all(FBPair *pair, uint width, uint height) {
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
fbpair_resize(pair, i, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void fbpair_viewport(FBPair *pair, int x, int y, int w, int h) {
|
||||
r_framebuffer_viewport(pair->front, x, y, w, h);
|
||||
r_framebuffer_viewport(pair->back, x, y, w, h);
|
||||
}
|
||||
|
||||
void fbpair_viewport_rect(FBPair *pair, IntRect vp) {
|
||||
r_framebuffer_viewport_rect(pair->front, vp);
|
||||
r_framebuffer_viewport_rect(pair->back, vp);
|
||||
}
|
40
src/util/fbpair.h
Normal file
40
src/util/fbpair.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
|
||||
typedef struct FBPair {
|
||||
/*
|
||||
* Rule of thumb:
|
||||
* 1. Bind back buffer;
|
||||
* 2. Draw front buffer;
|
||||
* 3. Call fbpair_swap;
|
||||
* 4. Rinse, repeat.
|
||||
*/
|
||||
|
||||
Framebuffer *const front;
|
||||
Framebuffer *const back;
|
||||
|
||||
Framebuffer framebuffers[2];
|
||||
} FBPair;
|
||||
|
||||
typedef struct FBAttachmentConfig {
|
||||
FramebufferAttachment attachment;
|
||||
TextureParams tex_params;
|
||||
} FBAttachmentConfig;
|
||||
|
||||
void fbpair_create(FBPair *pair, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) attr_nonnull(1, 3);
|
||||
void fbpair_resize(FBPair *pair, FramebufferAttachment attachment, uint width, uint height) attr_nonnull(1);
|
||||
void fbpair_resize_all(FBPair *pair, uint width, uint height) attr_nonnull(1);
|
||||
void fbpair_destroy(FBPair *pair) attr_nonnull(1);
|
||||
void fbpair_swap(FBPair *pair) attr_nonnull(1);
|
||||
void fbpair_viewport(FBPair *pair, int x, int y, int w, int h) attr_nonnull(1);
|
||||
void fbpair_viewport_rect(FBPair *pair, IntRect vp) attr_nonnull(1);
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "graphics.h"
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
|
||||
void set_ortho(float w, float h) {
|
||||
r_mat_mode(MM_PROJECTION);
|
||||
|
@ -98,3 +99,17 @@ void draw_stars(int x, int y, int numstars, int numfrags, int maxstars, int maxf
|
|||
r_shader_ptr(prog_saved);
|
||||
}
|
||||
|
||||
void draw_framebuffer_tex(Framebuffer *fb, double width, double height) {
|
||||
CullFaceMode cull_saved = r_cull_current();
|
||||
r_cull(CULL_FRONT);
|
||||
|
||||
r_mat_push();
|
||||
r_texture_ptr(0, r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_COLOR0));
|
||||
r_mat_scale(width, height, 1);
|
||||
r_mat_translate(0.5, 0.5, 0);
|
||||
r_mat_scale(1, -1, 1);
|
||||
r_draw_quad();
|
||||
r_mat_pop();
|
||||
|
||||
r_cull(cull_saved);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "fbpair.h"
|
||||
|
||||
void set_ortho(float w, float h);
|
||||
void colorfill(float r, float g, float b, float a);
|
||||
void fade_out(float f);
|
||||
void draw_stars(int x, int y, int numstars, int numfrags, int maxstars, int maxfrags, float alpha, float star_width);
|
||||
void draw_framebuffer_tex(Framebuffer *fb, double width, double height);
|
||||
|
|
|
@ -3,6 +3,7 @@ util_src = files(
|
|||
'assert.c',
|
||||
'crap.c',
|
||||
'env.c',
|
||||
'fbpair.c',
|
||||
'geometry.c',
|
||||
'graphics.c',
|
||||
'io.c',
|
||||
|
|
116
src/video.c
116
src/video.c
|
@ -27,10 +27,12 @@ typedef struct ScreenshotTaskData {
|
|||
|
||||
static void video_add_mode(int width, int height) {
|
||||
if(video.modes) {
|
||||
int i; for(i = 0; i < video.mcount; ++i) {
|
||||
VideoMode *m = &(video.modes[i]);
|
||||
if(m->width == width && m->height == height)
|
||||
for(uint i = 0; i < video.mcount; ++i) {
|
||||
VideoMode *m = video.modes + i;
|
||||
|
||||
if(m->width == width && m->height == height) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,10 +62,16 @@ void video_get_viewport_size(int *width, int *height) {
|
|||
*height = h;
|
||||
}
|
||||
|
||||
void video_set_viewport(void) {
|
||||
int w, h;
|
||||
video_get_viewport_size(&w,&h);
|
||||
r_viewport((video.current.width - w) / 2, (video.current.height - h) / 2, w, h);
|
||||
void video_get_viewport(IntRect *vp) {
|
||||
video_get_viewport_size(&vp->w, &vp->h);
|
||||
vp->x = (video.current.width - vp->w) / 2;
|
||||
vp->y = (video.current.height - vp->h) / 2;
|
||||
}
|
||||
|
||||
static void video_set_viewport(void) {
|
||||
IntRect vp;
|
||||
video_get_viewport(&vp);
|
||||
r_framebuffer_viewport_rect(NULL, vp);
|
||||
}
|
||||
|
||||
static void video_update_vsync(void) {
|
||||
|
@ -77,23 +85,6 @@ static void video_update_vsync(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void video_update_quality(void) {
|
||||
int vw, vh;
|
||||
video_get_viewport_size(&vw, &vh);
|
||||
float q = (float)vh / SCREEN_H;
|
||||
video.quality_factor = q;
|
||||
|
||||
float fg = q * config_get_float(CONFIG_FG_QUALITY);
|
||||
float bg = q * config_get_float(CONFIG_BG_QUALITY);
|
||||
float text = q * config_get_float(CONFIG_TEXT_QUALITY);
|
||||
|
||||
log_debug("q:%f, fg:%f, bg:%f, text:%f", q, fg, bg, text);
|
||||
|
||||
init_fbo_pair(&resources.fbo_pairs.bg, bg, TEX_TYPE_RGB);
|
||||
init_fbo_pair(&resources.fbo_pairs.fg, fg, TEX_TYPE_RGB);
|
||||
init_fbo_pair(&resources.fbo_pairs.rgba, fg, TEX_TYPE_RGBA);
|
||||
}
|
||||
|
||||
static uint32_t get_fullscreen_flag(void) {
|
||||
if(config_get_int(CONFIG_FULLSCREEN_DESKTOP)) {
|
||||
return SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
|
@ -120,10 +111,7 @@ static void video_update_mode_settings(void) {
|
|||
SDL_ShowCursor(false);
|
||||
video_update_vsync();
|
||||
SDL_GetWindowSize(video.window, &video.current.width, &video.current.height);
|
||||
video.real.width = video.current.width;
|
||||
video.real.height = video.current.height;
|
||||
video_set_viewport();
|
||||
video_update_quality();
|
||||
events_emit(TE_VIDEO_MODE_CHANGED, 0, NULL, NULL);
|
||||
|
||||
if(video_is_fullscreen() && !config_get_int(CONFIG_FULLSCREEN_DESKTOP)) {
|
||||
|
@ -344,29 +332,6 @@ bool video_can_change_resolution(void) {
|
|||
return !video_is_fullscreen() || !config_get_int(CONFIG_FULLSCREEN_DESKTOP);
|
||||
}
|
||||
|
||||
static void video_cfg_fullscreen_callback(ConfigIndex idx, ConfigValue v) {
|
||||
video_set_mode(
|
||||
config_get_int(CONFIG_VID_WIDTH),
|
||||
config_get_int(CONFIG_VID_HEIGHT),
|
||||
config_set_int(idx, v.i),
|
||||
config_get_int(CONFIG_VID_RESIZABLE)
|
||||
);
|
||||
}
|
||||
|
||||
static void video_cfg_vsync_callback(ConfigIndex idx, ConfigValue v) {
|
||||
config_set_int(idx, v.i);
|
||||
video_update_vsync();
|
||||
}
|
||||
|
||||
static void video_cfg_resizable_callback(ConfigIndex idx, ConfigValue v) {
|
||||
SDL_SetWindowResizable(video.window, config_set_int(idx, v.i));
|
||||
}
|
||||
|
||||
static void video_quality_callback(ConfigIndex idx, ConfigValue v) {
|
||||
config_set_float(idx, v.f);
|
||||
video_update_quality();
|
||||
}
|
||||
|
||||
static void video_init_sdl(void) {
|
||||
// XXX: workaround for an SDL bug: https://bugzilla.libsdl.org/show_bug.cgi?id=4127
|
||||
SDL_SetHintWithPriority(SDL_HINT_FRAMEBUFFER_ACCELERATION, "0", SDL_HINT_OVERRIDE);
|
||||
|
@ -429,10 +394,10 @@ static void video_init_sdl(void) {
|
|||
}
|
||||
|
||||
static void video_handle_resize(int w, int h) {
|
||||
log_debug("%ix%i --> %ix%i", video.current.width, video.current.height, w, h);
|
||||
video.current.width = w;
|
||||
video.current.height = h;
|
||||
video_set_viewport();
|
||||
video_update_quality();
|
||||
events_emit(TE_VIDEO_MODE_CHANGED, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
|
@ -452,12 +417,34 @@ static bool video_handle_window_event(SDL_Event *event, void *arg) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool video_handle_config_event(SDL_Event *evt, void *arg) {
|
||||
ConfigValue *val = evt->user.data1;
|
||||
|
||||
switch(evt->user.code) {
|
||||
case CONFIG_FULLSCREEN:
|
||||
video_set_mode(
|
||||
config_get_int(CONFIG_VID_WIDTH),
|
||||
config_get_int(CONFIG_VID_HEIGHT),
|
||||
val->i,
|
||||
config_get_int(CONFIG_VID_RESIZABLE)
|
||||
);
|
||||
break;
|
||||
|
||||
case CONFIG_VID_RESIZABLE:
|
||||
SDL_SetWindowResizable(video.window, val->i);
|
||||
break;
|
||||
|
||||
case CONFIG_VSYNC:
|
||||
video_update_vsync();
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void video_init(void) {
|
||||
bool fullscreen_available = false;
|
||||
|
||||
memset(&video, 0, sizeof(video));
|
||||
memset(&resources.fbo_pairs, 0, sizeof(resources.fbo_pairs));
|
||||
|
||||
video_init_sdl();
|
||||
log_info("Using driver '%s'", SDL_GetCurrentVideoDriver());
|
||||
|
||||
|
@ -487,6 +474,7 @@ void video_init(void) {
|
|||
// This is required for some multihead setups.
|
||||
VideoMode common_modes[] = {
|
||||
{RESX, RESY},
|
||||
{SCREEN_W, SCREEN_H},
|
||||
|
||||
{640, 480},
|
||||
{800, 600},
|
||||
|
@ -513,24 +501,24 @@ void video_init(void) {
|
|||
config_get_int(CONFIG_VID_RESIZABLE)
|
||||
);
|
||||
|
||||
config_set_callback(CONFIG_FULLSCREEN, video_cfg_fullscreen_callback);
|
||||
config_set_callback(CONFIG_VSYNC, video_cfg_vsync_callback);
|
||||
config_set_callback(CONFIG_VID_RESIZABLE, video_cfg_resizable_callback);
|
||||
config_set_callback(CONFIG_FG_QUALITY, video_quality_callback);
|
||||
config_set_callback(CONFIG_BG_QUALITY, video_quality_callback);
|
||||
|
||||
EventHandler h = {
|
||||
events_register_handler(&(EventHandler) {
|
||||
.proc = video_handle_window_event,
|
||||
.priority = EPRIO_SYSTEM,
|
||||
.event_type = SDL_WINDOWEVENT,
|
||||
};
|
||||
});
|
||||
|
||||
events_register_handler(&(EventHandler) {
|
||||
.proc = video_handle_config_event,
|
||||
.priority = EPRIO_SYSTEM,
|
||||
.event_type = MAKE_TAISEI_EVENT(TE_CONFIG_UPDATED),
|
||||
});
|
||||
|
||||
events_register_handler(&h);
|
||||
log_info("Video subsystem initialized");
|
||||
}
|
||||
|
||||
void video_shutdown(void) {
|
||||
events_unregister_handler(video_handle_window_event);
|
||||
events_unregister_handler(video_handle_config_event);
|
||||
SDL_DestroyWindow(video.window);
|
||||
r_shutdown();
|
||||
free(video.modes);
|
||||
|
@ -538,7 +526,7 @@ void video_shutdown(void) {
|
|||
}
|
||||
|
||||
void video_swap_buffers(void) {
|
||||
r_target(NULL);
|
||||
r_framebuffer(NULL);
|
||||
r_swap(video.window);
|
||||
r_clear(CLEAR_COLOR);
|
||||
}
|
||||
|
|
16
src/video.h
16
src/video.h
|
@ -9,8 +9,8 @@
|
|||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#define WINDOW_TITLE "Taisei Project"
|
||||
#define VIDEO_ASPECT_RATIO ((double)SCREEN_W/SCREEN_H)
|
||||
// FIXME: This is just for IntRect, which probably should be placed elsewhere.
|
||||
#include "util/geometry.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
|
@ -18,6 +18,14 @@
|
|||
#define WINFLAGS_IS_FAKE_FULLSCREEN(f) (WINFLAGS_IS_FULLSCREEN(f) == SDL_WINDOW_FULLSCREEN_DESKTOP)
|
||||
#define WINFLAGS_IS_REAL_FULLSCREEN(f) (WINFLAGS_IS_FULLSCREEN(f) == SDL_WINDOW_FULLSCREEN)
|
||||
|
||||
#define WINDOW_TITLE "Taisei Project"
|
||||
#define VIDEO_ASPECT_RATIO ((double)SCREEN_W/SCREEN_H)
|
||||
|
||||
enum {
|
||||
SCREEN_W = 800,
|
||||
SCREEN_H = 600,
|
||||
};
|
||||
|
||||
typedef struct VideoMode {
|
||||
int width;
|
||||
int height;
|
||||
|
@ -28,9 +36,7 @@ typedef struct {
|
|||
int mcount;
|
||||
VideoMode intended;
|
||||
VideoMode current;
|
||||
VideoMode real;
|
||||
SDL_Window *window;
|
||||
float quality_factor;
|
||||
} Video;
|
||||
|
||||
extern Video video;
|
||||
|
@ -38,8 +44,8 @@ extern Video video;
|
|||
void video_init(void);
|
||||
void video_shutdown(void);
|
||||
void video_set_mode(int w, int h, bool fs, bool resizable);
|
||||
void video_get_viewport(IntRect *vp);
|
||||
void video_get_viewport_size(int *width, int *height);
|
||||
void video_set_viewport(void);
|
||||
bool video_is_fullscreen(void);
|
||||
bool video_is_resizable(void);
|
||||
bool video_can_change_resolution(void);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue