WIP rendering quality (resolution) settings.
Rewrote a lot of the stage drawing and FBO handling code. Introduced some WTFs, hence the WIP.
This commit is contained in:
parent
b3032d3712
commit
edf584b9f3
23 changed files with 478 additions and 236 deletions
|
@ -25,7 +25,7 @@ float smoothstep(float x) {
|
|||
}
|
||||
|
||||
void main(void) {
|
||||
float n = 15.;
|
||||
float n = 8.;
|
||||
vec2 pos = (vec2(gl_TexCoord[0])-origin*vec2(ratio,1.0))*n;
|
||||
pos.x /= ratio;
|
||||
pos = vec2(n*atan(pos.x,pos.y),length(pos)+n*t*0.1);
|
||||
|
|
|
@ -76,6 +76,9 @@
|
|||
CONFIGDEF_INT (NO_STAGEBG, "disable_stagebg", 0) \
|
||||
CONFIGDEF_INT (SAVE_RPY, "save_rpy", 2) \
|
||||
CONFIGDEF_INT (SPELLSTAGE_AUTORESTART, "spellpractice_restart_on_fail", 0) \
|
||||
CONFIGDEF_FLOAT (TEXT_QUALITY, "text_quality", 1.0) \
|
||||
CONFIGDEF_FLOAT (FG_QUALITY, "fg_quality", 1.0) \
|
||||
CONFIGDEF_FLOAT (BG_QUALITY, "Bg_quality", 1.0) \
|
||||
KEYDEFS \
|
||||
CONFIGDEF_INT (GAMEPAD_ENABLED, "gamepad_enabled", 0) \
|
||||
CONFIGDEF_INT (GAMEPAD_DEVICE, "gamepad_device", 0) \
|
||||
|
|
59
src/fbo.c
59
src/fbo.c
|
@ -8,15 +8,21 @@
|
|||
#include "fbo.h"
|
||||
#include "global.h"
|
||||
|
||||
void init_fbo(FBO *fbo) {
|
||||
static float sanitize_scale(float scale) {
|
||||
return clamp(scale, 0.25, 4.0);
|
||||
}
|
||||
|
||||
void init_fbo(FBO *fbo, float scale) {
|
||||
glGenTextures(1, &fbo->tex);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo->tex);
|
||||
|
||||
fbo->nw = 2;
|
||||
fbo->nh = 2;
|
||||
scale = sanitize_scale(scale);
|
||||
|
||||
while(fbo->nw < VIEWPORT_W+VIEWPORT_X) fbo->nw *= 2;
|
||||
while(fbo->nh < VIEWPORT_H+VIEWPORT_Y) fbo->nh *= 2;
|
||||
fbo->scale = ftopow2(scale);
|
||||
fbo->nw = topow2(scale * SCREEN_W);
|
||||
fbo->nh = topow2(scale * SCREEN_H);
|
||||
|
||||
log_debug("FBO %p: q=%f, w=%i, h=%i", (void*)fbo, fbo->scale, fbo->nw, fbo->nh);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
@ -44,28 +50,39 @@ void init_fbo(FBO *fbo) {
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void reinit_fbo(FBO *fbo, float scale) {
|
||||
if(fbo->scale != sanitize_scale(scale)) {
|
||||
delete_fbo(fbo);
|
||||
init_fbo(fbo, scale);
|
||||
}
|
||||
}
|
||||
|
||||
void delete_fbo(FBO *fbo) {
|
||||
glDeleteFramebuffers(1, &fbo->fbo);
|
||||
glDeleteTextures(1, &fbo->depth);
|
||||
glDeleteTextures(1, &fbo->tex);
|
||||
}
|
||||
|
||||
void draw_fbo_viewport(FBO *fbo) {
|
||||
void draw_fbo(FBO *fbo) {
|
||||
glPushMatrix();
|
||||
glTranslatef(-VIEWPORT_X,VIEWPORT_H+VIEWPORT_Y-fbo->nh,0);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glTranslatef(fbo->nw/2,fbo->nw/2,0);
|
||||
glScalef(fbo->nw, fbo->nh, 1);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, fbo->tex);
|
||||
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glDrawArrays(GL_QUADS, 4, 4);
|
||||
// glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glScalef(fbo->nw, fbo->nh, 1);
|
||||
glTranslatef(0.5, 0.5, 0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, fbo->tex);
|
||||
glDrawArrays(GL_QUADS, 4, 4);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void draw_fbo_viewport(FBO *fbo) {
|
||||
// assumption: rendering into another, identical FBO
|
||||
|
||||
glViewport(0, 0, fbo->nw * ((float)SCREEN_W/SCREEN_H), fbo->nh);
|
||||
set_ortho();
|
||||
|
||||
glPushMatrix();
|
||||
float s = (float)SCREEN_H/fbo->nh;
|
||||
glScalef(s, s, 1);
|
||||
draw_fbo(fbo);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
|
|
@ -15,12 +15,14 @@ typedef struct {
|
|||
GLuint tex;
|
||||
GLuint depth;
|
||||
|
||||
int nw,nh;
|
||||
int nw, nh;
|
||||
float scale;
|
||||
} FBO;
|
||||
|
||||
void init_fbo(FBO *fbo);
|
||||
void init_fbo(FBO *fbo, float scale);
|
||||
void reinit_fbo(FBO *fbo, float scale);
|
||||
void draw_fbo(FBO *fbo);
|
||||
void draw_fbo_viewport(FBO *fbo);
|
||||
|
||||
void delete_fbo(FBO *fbo);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "ingamemenu.h"
|
||||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include "video.h"
|
||||
|
||||
void return_to_game(MenuData *m, void *arg) {
|
||||
}
|
||||
|
@ -37,24 +38,24 @@ void draw_ingame_menu_bg(MenuData *menu, float f) {
|
|||
float rad = f*IMENU_BLUR;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
video_set_viewport();
|
||||
set_ortho();
|
||||
|
||||
Shader *shader = get_shader("ingame_menu");
|
||||
glUseProgram(shader->prog);
|
||||
|
||||
glUniform1f(uniloc(shader, "rad"), rad);
|
||||
glUniform1f(uniloc(shader, "phase"), menu->frames / 100.0);
|
||||
|
||||
draw_fbo_viewport(&resources.fsec);
|
||||
|
||||
stage_draw_foreground();
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void draw_ingame_menu(MenuData *menu) {
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_X, VIEWPORT_Y, 0);
|
||||
|
||||
draw_ingame_menu_bg(menu, 1.0-menu_fade(menu));
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_X, VIEWPORT_Y, 0);
|
||||
glTranslatef(VIEWPORT_W/2, VIEWPORT_H/4, 0);
|
||||
|
||||
draw_menu_selector(0, menu->drawdata[0], menu->drawdata[1]*2, 41, menu->frames);
|
||||
|
|
|
@ -131,6 +131,14 @@ OptionBinding* bind_scale(int cfgentry, float smin, float smax, float step) {
|
|||
return bind;
|
||||
}
|
||||
|
||||
OptionBinding* bind_quality(int cfgentry) {
|
||||
OptionBinding *bind = bind_new();
|
||||
bind->type = BT_Quality;
|
||||
bind->configentry = cfgentry;
|
||||
|
||||
return bind;
|
||||
}
|
||||
|
||||
// Returns a pointer to the first found binding that blocks input. If none found, returns NULL.
|
||||
OptionBinding* bind_getinputblocking(MenuData *m) {
|
||||
int i;
|
||||
|
@ -246,6 +254,10 @@ bool bind_resizable_dependence(void) {
|
|||
return !config_get_int(CONFIG_FULLSCREEN);
|
||||
}
|
||||
|
||||
bool bind_bgquality_dependence(void) {
|
||||
return !config_get_int(CONFIG_NO_STAGEBG);
|
||||
}
|
||||
|
||||
int bind_saverpy_get(OptionBinding *b) {
|
||||
int v = config_get_int(b->configentry);
|
||||
|
||||
|
@ -352,6 +364,20 @@ void options_sub_video(MenuData *parent, void *arg) {
|
|||
b = bind_option(CONFIG_NO_STAGEBG, bind_common_intget, bind_common_intset)
|
||||
); bind_onoff(b);
|
||||
|
||||
add_menu_separator(m);
|
||||
|
||||
add_menu_entry(m, "Stage viewport quality", do_nothing,
|
||||
b = bind_quality(CONFIG_FG_QUALITY)
|
||||
);
|
||||
|
||||
add_menu_entry(m, "Stage background quality", do_nothing,
|
||||
b = bind_quality(CONFIG_BG_QUALITY)
|
||||
); b->dependence = bind_bgquality_dependence;
|
||||
|
||||
add_menu_entry(m, "Text quality", do_nothing,
|
||||
b = bind_quality(CONFIG_TEXT_QUALITY)
|
||||
);
|
||||
|
||||
add_menu_separator(m);
|
||||
add_menu_entry(m, "Back", menu_commonaction_close, NULL);
|
||||
|
||||
|
@ -784,6 +810,13 @@ void draw_options_menu(MenuData *menu) {
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_Quality: {
|
||||
char tmp[16];
|
||||
snprintf(tmp, 16, "%i%%", (int)(100 * config_get_float(bind->configentry)));
|
||||
draw_text(AL_Right, origin, 20*i, tmp, _fonts.standard);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -929,10 +962,22 @@ static void options_input_event(EventType type, int state, void *arg) {
|
|||
case E_CursorLeft:
|
||||
play_ui_sound("generic_shot");
|
||||
if(bind) {
|
||||
if(bind->type == BT_IntValue || bind->type == BT_Resolution)
|
||||
bind_setprev(bind);
|
||||
else if(bind->type == BT_Scale) {
|
||||
config_set_float(bind->configentry, clamp(config_get_float(bind->configentry) - bind->scale_step, bind->scale_min, bind->scale_max));
|
||||
switch(bind->type) {
|
||||
case BT_IntValue:
|
||||
case BT_Resolution:
|
||||
bind_setprev(bind);
|
||||
break;
|
||||
|
||||
case BT_Scale:
|
||||
config_set_float(bind->configentry, clamp(config_get_float(bind->configentry) - bind->scale_step, bind->scale_min, bind->scale_max));
|
||||
break;
|
||||
|
||||
case BT_Quality:
|
||||
config_set_float(bind->configentry, config_get_float(bind->configentry) / 2.0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -940,10 +985,22 @@ static void options_input_event(EventType type, int state, void *arg) {
|
|||
case E_CursorRight:
|
||||
play_ui_sound("generic_shot");
|
||||
if(bind) {
|
||||
if(bind->type == BT_IntValue || bind->type == BT_Resolution)
|
||||
bind_setnext(bind);
|
||||
else if(bind->type == BT_Scale) {
|
||||
config_set_float(bind->configentry, clamp(config_get_float(bind->configentry) + bind->scale_step, bind->scale_min, bind->scale_max));
|
||||
switch(bind->type) {
|
||||
case BT_IntValue:
|
||||
case BT_Resolution:
|
||||
bind_setnext(bind);
|
||||
break;
|
||||
|
||||
case BT_Scale:
|
||||
config_set_float(bind->configentry, clamp(config_get_float(bind->configentry) + bind->scale_step, bind->scale_min, bind->scale_max));
|
||||
break;
|
||||
|
||||
case BT_Quality:
|
||||
config_set_float(bind->configentry, config_get_float(bind->configentry) * 2.0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef enum BindingType {
|
|||
BT_Scale,
|
||||
BT_GamepadKeyBinding,
|
||||
BT_GamepadAxisBinding,
|
||||
BT_Quality,
|
||||
} BindingType;
|
||||
|
||||
typedef struct OptionBinding {
|
||||
|
|
|
@ -84,19 +84,15 @@ static void replayview_freearg(void *a) {
|
|||
free(ctx);
|
||||
}
|
||||
|
||||
static void shorten(char *s, int width) {
|
||||
float sw = stringwidth(s, _fonts.standard);
|
||||
float len = strlen(s);
|
||||
float avgw = sw / len;
|
||||
int c = width / avgw, i;
|
||||
static void shorten(char *s, float width) {
|
||||
while(stringwidth(s, _fonts.standard) > width) {
|
||||
s[strlen(s) - 1] = 0;
|
||||
|
||||
if(c > len)
|
||||
return;
|
||||
|
||||
s[c+1] = 0;
|
||||
|
||||
for(i = 0; i < 3; ++i)
|
||||
s[c - i] = '.';
|
||||
int l = strlen(s);
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
s[l - i - 1] = '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void replayview_draw_stagemenu(MenuData *m) {
|
||||
|
@ -155,8 +151,8 @@ static void replayview_drawitem(void *n, int item, int cnt) {
|
|||
|
||||
for(i = 0; i < columns; ++i) {
|
||||
char tmp[128];
|
||||
int csize = sizes[i] * (SCREEN_W - 210)/columns;
|
||||
int o = 0;
|
||||
float csize = sizes[i] * (SCREEN_W - 210)/columns;
|
||||
float o = 0;
|
||||
|
||||
for(j = 0; j < i; ++j)
|
||||
o += sizes[j] * (SCREEN_W - 210)/columns;
|
||||
|
|
|
@ -281,7 +281,8 @@ void MariLaser(Projectile *p, int t) {
|
|||
return;
|
||||
|
||||
if(cimag(p->pos) - cimag(global.plr.pos) < 90) {
|
||||
glScissor(VIEWPORT_X, SCREEN_H - VIEWPORT_Y- cimag(((Enemy *)REF(p->args[1]))->pos)+1, VIEWPORT_W+VIEWPORT_X, VIEWPORT_H);
|
||||
float f = resources.fbo.fg[0].nh/(float)SCREEN_H;
|
||||
glScissor(0, resources.fbo.fg[0].nh - f * (cimag(((Enemy *)REF(p->args[1]))->pos) + 20), resources.fbo.fg[0].nw, resources.fbo.fg[0].nh);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,27 +11,38 @@
|
|||
|
||||
struct Fonts _fonts;
|
||||
|
||||
TTF_Font *load_font(char *name, int size) {
|
||||
TTF_Font* load_font(char *name, int size) {
|
||||
char *buf = strjoin(get_prefix(), name, NULL);
|
||||
size *= resources.fontren.quality;
|
||||
|
||||
TTF_Font *f = TTF_OpenFont(buf, size);
|
||||
if(!f)
|
||||
log_fatal("Failed to load font '%s'", buf);
|
||||
|
||||
log_info("Loaded '%s'", buf);
|
||||
log_info("Loaded '%s' @ %i", buf, size);
|
||||
|
||||
free(buf);
|
||||
return f;
|
||||
}
|
||||
|
||||
void fontrenderer_init(FontRenderer *f) {
|
||||
static float sanitize_scale(float scale) {
|
||||
return clamp(scale, 0.5, 4.0);
|
||||
}
|
||||
|
||||
void fontrenderer_init(FontRenderer *f, float quality) {
|
||||
quality = sanitize_scale(quality);
|
||||
f->quality = quality = ftopow2(quality);
|
||||
|
||||
int w = FONTREN_MAXW * quality;
|
||||
int h = FONTREN_MAXH * quality;
|
||||
|
||||
glGenBuffers(1,&f->pbo);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, f->pbo);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, FONTREN_MAXW*FONTREN_MAXH*4, NULL, GL_STREAM_DRAW);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, w*h*4, NULL, GL_STREAM_DRAW);
|
||||
glGenTextures(1,&f->tex.gltex);
|
||||
|
||||
f->tex.truew = FONTREN_MAXW;
|
||||
f->tex.trueh = FONTREN_MAXH;
|
||||
f->tex.truew = w;
|
||||
f->tex.trueh = h;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D,f->tex.gltex);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
|
@ -57,7 +68,7 @@ void fontrenderer_draw_prerendered(FontRenderer *f, SDL_Surface *surf) {
|
|||
glBindTexture(GL_TEXTURE_2D,f->tex.gltex);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, f->pbo);
|
||||
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, FONTREN_MAXW*FONTREN_MAXH*4, NULL, GL_STREAM_DRAW);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, f->tex.truew*f->tex.trueh*4, NULL, GL_STREAM_DRAW);
|
||||
|
||||
// the written texture zero padded to avoid bits of previously drawn text bleeding in
|
||||
int winw = surf->w+1;
|
||||
|
@ -76,32 +87,51 @@ void fontrenderer_draw_prerendered(FontRenderer *f, SDL_Surface *surf) {
|
|||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
SDL_Surface* fontrender_render(const char *text, TTF_Font *font) {
|
||||
SDL_Surface* fontrender_render(FontRenderer *f, const char *text, TTF_Font *font) {
|
||||
SDL_Surface *surf = TTF_RenderUTF8_Blended(font, text, (SDL_Color){255, 255, 255});
|
||||
|
||||
if(!surf) {
|
||||
log_fatal("TTF_RenderUTF8_Blended() failed: %s", TTF_GetError());
|
||||
}
|
||||
|
||||
if(surf->w > FONTREN_MAXW || surf->h > FONTREN_MAXH) {
|
||||
log_fatal("Text (%s %dx%d) is too big for the internal buffer (%dx%d).", text, surf->w, surf->h, FONTREN_MAXW, FONTREN_MAXH);
|
||||
if(surf->w > f->tex.truew || surf->h > f->tex.trueh) {
|
||||
log_fatal("Text (%s %dx%d) is too big for the internal buffer (%dx%d).", text, surf->w, surf->h, f->tex.truew, f->tex.trueh);
|
||||
}
|
||||
|
||||
return surf;
|
||||
}
|
||||
|
||||
void fontrenderer_draw(FontRenderer *f, const char *text, TTF_Font *font) {
|
||||
SDL_Surface *surf = fontrender_render(text, font);
|
||||
SDL_Surface *surf = fontrender_render(f, text, font);
|
||||
fontrenderer_draw_prerendered(f, surf);
|
||||
SDL_FreeSurface(surf);
|
||||
}
|
||||
|
||||
void init_fonts(void) {
|
||||
static void text_quality_callback(ConfigIndex idx, ConfigValue v) {
|
||||
reinit_fonts(v.f);
|
||||
config_set_float(idx, resources.fontren.quality);
|
||||
}
|
||||
|
||||
void init_fonts(float quality) {
|
||||
static bool callbacks_set_up = false;
|
||||
|
||||
TTF_Init();
|
||||
fontrenderer_init(&resources.fontren);
|
||||
fontrenderer_init(&resources.fontren, quality);
|
||||
_fonts.standard = load_font("gfx/LinBiolinum.ttf", 20);
|
||||
_fonts.mainmenu = load_font("gfx/immortal.ttf", 35);
|
||||
_fonts.small = load_font("gfx/LinBiolinum.ttf", 14);
|
||||
|
||||
if(!callbacks_set_up) {
|
||||
config_set_callback(CONFIG_TEXT_QUALITY, text_quality_callback);
|
||||
callbacks_set_up = true;
|
||||
}
|
||||
}
|
||||
|
||||
void reinit_fonts(float quality) {
|
||||
if(resources.fontren.quality != sanitize_scale(quality)) {
|
||||
free_fonts();
|
||||
init_fonts(quality);
|
||||
}
|
||||
}
|
||||
|
||||
void free_fonts(void) {
|
||||
|
@ -113,14 +143,16 @@ void free_fonts(void) {
|
|||
}
|
||||
|
||||
static void draw_text_texture(Alignment align, float x, float y, Texture *tex) {
|
||||
float m = 1.0 / resources.fontren.quality;
|
||||
|
||||
switch(align) {
|
||||
case AL_Center:
|
||||
break;
|
||||
case AL_Left:
|
||||
x += tex->w/2;
|
||||
x += m*tex->w/2;
|
||||
break;
|
||||
case AL_Right:
|
||||
x -= tex->w/2;
|
||||
x -= m*tex->w/2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -131,7 +163,12 @@ static void draw_text_texture(Alignment align, float x, float y, Texture *tex) {
|
|||
y += 0.5;
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
draw_texture_p(x, y, tex);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(x, y, 0);
|
||||
glScalef(m, m, 1);
|
||||
draw_texture_p(0, 0, tex);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void draw_text_prerendered(Alignment align, float x, float y, SDL_Surface *surf) {
|
||||
|
@ -157,13 +194,13 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
|
|||
int stringwidth(char *s, TTF_Font *font) {
|
||||
int w;
|
||||
TTF_SizeText(font, s, &w, NULL);
|
||||
return w;
|
||||
return w / resources.fontren.quality;
|
||||
}
|
||||
|
||||
int stringheight(char *s, TTF_Font *font) {
|
||||
int h;
|
||||
TTF_SizeText(font, s, NULL, &h);
|
||||
return h;
|
||||
return h / resources.fontren.quality;
|
||||
}
|
||||
|
||||
int charwidth(char c, TTF_Font *font) {
|
||||
|
|
|
@ -18,28 +18,31 @@ typedef enum {
|
|||
} Alignment;
|
||||
|
||||
|
||||
// Size of the buffer used by the font renderer. No text larger than this can be drawn.
|
||||
// Size of the buffer used by the font renderer at quality == 1.0.
|
||||
// No text larger than this can be drawn.
|
||||
enum {
|
||||
FONTREN_MAXW = 1024,
|
||||
FONTREN_MAXH = 512
|
||||
FONTREN_MAXH = 256,
|
||||
};
|
||||
|
||||
typedef struct FontRenderer FontRenderer;
|
||||
struct FontRenderer {
|
||||
Texture tex;
|
||||
GLuint pbo;
|
||||
float quality;
|
||||
};
|
||||
|
||||
void fontrenderer_init(FontRenderer *f);
|
||||
void fontrenderer_init(FontRenderer *f, float quality);
|
||||
void fontrenderer_free(FontRenderer *f);
|
||||
void fontrenderer_draw(FontRenderer *f, const char *text, TTF_Font *font);
|
||||
void fontrenderer_draw_prerendered(FontRenderer *f, SDL_Surface *surf);
|
||||
SDL_Surface* fontrender_render(const char *text, TTF_Font *font);
|
||||
SDL_Surface* fontrender_render(FontRenderer *f, const char *text, TTF_Font *font);
|
||||
|
||||
Texture *load_text(const char *text, TTF_Font *font);
|
||||
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font);
|
||||
void draw_text_prerendered(Alignment align, float x, float y, SDL_Surface *surf);
|
||||
void init_fonts(void);
|
||||
void init_fonts(float quality);
|
||||
void reinit_fonts(float quality);
|
||||
void free_fonts(void);
|
||||
|
||||
int stringwidth(char *s, TTF_Font *font);
|
||||
|
|
|
@ -146,7 +146,7 @@ FBO* postprocess(PostprocessShader *ppshaders, FBO *primfbo, FBO *auxfbo, Postpr
|
|||
}
|
||||
|
||||
fbonum = !fbonum;
|
||||
draw_fbo_viewport(fbos[fbonum]);
|
||||
draw(fbos[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -386,8 +386,17 @@ const char* resource_util_filename(const char *path) {
|
|||
return path;
|
||||
}
|
||||
|
||||
static void fbo_quality_callback(ConfigIndex idx, ConfigValue v) {
|
||||
FBO *fbos = idx == CONFIG_FG_QUALITY ? resources.fbo.fg : resources.fbo.bg;
|
||||
reinit_fbo(fbos+0, v.f);
|
||||
reinit_fbo(fbos+1, v.f);
|
||||
config_set_float(idx, fbos->scale);
|
||||
}
|
||||
|
||||
void load_resources(void) {
|
||||
init_fonts();
|
||||
static bool callbacks_set_up = false;
|
||||
|
||||
init_fonts(config_get_float(CONFIG_TEXT_QUALITY));
|
||||
|
||||
if(glext.draw_instanced) {
|
||||
load_shader_snippets("shader/laser_snippets", "laser_", RESF_PERMANENT);
|
||||
|
@ -395,11 +404,21 @@ void load_resources(void) {
|
|||
|
||||
menu_preload();
|
||||
|
||||
init_fbo(&resources.fbg[0]);
|
||||
init_fbo(&resources.fbg[1]);
|
||||
init_fbo(&resources.fsec);
|
||||
float fgq = config_get_float(CONFIG_FG_QUALITY);
|
||||
float bgq = config_get_float(CONFIG_BG_QUALITY);
|
||||
|
||||
init_fbo(&resources.fbo.bg[0], bgq);
|
||||
init_fbo(&resources.fbo.bg[1], bgq);
|
||||
init_fbo(&resources.fbo.fg[0], fgq);
|
||||
init_fbo(&resources.fbo.fg[1], fgq);
|
||||
|
||||
resources.stage_postprocess = postprocess_load("shader/postprocess.conf");
|
||||
|
||||
if(!callbacks_set_up) {
|
||||
config_set_callback(CONFIG_FG_QUALITY, fbo_quality_callback);
|
||||
config_set_callback(CONFIG_BG_QUALITY, fbo_quality_callback);
|
||||
callbacks_set_up = true;
|
||||
}
|
||||
}
|
||||
|
||||
void free_resources(bool all) {
|
||||
|
@ -442,9 +461,10 @@ void free_resources(bool all) {
|
|||
|
||||
postprocess_unload(&resources.stage_postprocess);
|
||||
|
||||
delete_fbo(&resources.fbg[0]);
|
||||
delete_fbo(&resources.fbg[1]);
|
||||
delete_fbo(&resources.fsec);
|
||||
delete_fbo(&resources.fbo.bg[0]);
|
||||
delete_fbo(&resources.fbo.bg[1]);
|
||||
delete_fbo(&resources.fbo.fg[0]);
|
||||
delete_fbo(&resources.fbo.fg[1]);
|
||||
|
||||
free_fonts();
|
||||
}
|
||||
|
|
|
@ -99,10 +99,13 @@ typedef struct Resource {
|
|||
|
||||
typedef struct Resources {
|
||||
ResourceHandler handlers[RES_NUMTYPES];
|
||||
FBO fbg[2];
|
||||
FBO fsec;
|
||||
PostprocessShader *stage_postprocess;
|
||||
FontRenderer fontren;
|
||||
|
||||
struct {
|
||||
FBO bg[2];
|
||||
FBO fg[2];
|
||||
} fbo;
|
||||
} Resources;
|
||||
|
||||
extern Resources resources;
|
||||
|
|
344
src/stage.c
344
src/stage.c
|
@ -482,40 +482,19 @@ void draw_hud(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void apply_bg_shaders(ShaderRule *shaderrules);
|
||||
static int apply_bg_shaders(ShaderRule *shaderrules, int fbonum);
|
||||
static void display_stage_title(StageInfo *info);
|
||||
|
||||
static void postprocess_prepare(FBO *fbo, Shader *s) {
|
||||
float w = 1.0f / fbo->nw;
|
||||
float h = 1.0f / fbo->nh;
|
||||
float w = (1.0f / fbo->nw) * fbo->scale;
|
||||
float h = (1.0f / fbo->nh) * fbo->scale;
|
||||
|
||||
glUniform1i(uniloc(s, "frames"), global.frames);
|
||||
glUniform2f(uniloc(s, "view_ofs"), VIEWPORT_X * w, VIEWPORT_Y * h);
|
||||
glUniform2f(uniloc(s, "view_scale"), VIEWPORT_W * w, VIEWPORT_H * h);
|
||||
}
|
||||
|
||||
static void stage_draw(StageInfo *stage) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbg[0].fbo);
|
||||
glViewport(0,0,SCREEN_W,SCREEN_H);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glPushMatrix();
|
||||
glTranslatef(-(VIEWPORT_X+VIEWPORT_W/2.0), -(VIEWPORT_Y+VIEWPORT_H/2.0),0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
if(!config_get_int(CONFIG_NO_STAGEBG))
|
||||
stage->procs->draw();
|
||||
|
||||
glPopMatrix();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
set_ortho();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_X,VIEWPORT_Y,0);
|
||||
|
||||
apply_bg_shaders(stage->procs->shader_rules);
|
||||
|
||||
static void stage_draw_objects(void) {
|
||||
if(global.boss) {
|
||||
glPushMatrix();
|
||||
glTranslatef(creal(global.boss->pos), cimag(global.boss->pos), 0);
|
||||
|
@ -526,20 +505,18 @@ static void stage_draw(StageInfo *stage) {
|
|||
}
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
glRotatef(global.frames*4.0, 0, 0, -1);
|
||||
|
||||
float f = 0.8+0.1*sin(global.frames/8.0);
|
||||
|
||||
if(boss_is_dying(global.boss)) {
|
||||
float t = (global.frames - global.boss->current->endtime)/(float)BOSS_DEATH_DELAY + 1;
|
||||
f -= t*(t-0.7)/(1-t);
|
||||
}
|
||||
|
||||
glScalef(f,f,f);
|
||||
|
||||
draw_texture(0,0,"boss_circle");
|
||||
|
||||
draw_texture(0, 0, "boss_circle");
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -559,51 +536,138 @@ static void stage_draw(StageInfo *stage) {
|
|||
draw_dialog(global.dialog);
|
||||
|
||||
stagetext_draw();
|
||||
|
||||
FBO *ppfbo = postprocess(resources.stage_postprocess, &resources.fsec, resources.fbg, postprocess_prepare, draw_fbo_viewport);
|
||||
|
||||
if(ppfbo != &resources.fsec) {
|
||||
// ensure that fsec is the most up to date fbo, because the ingame menu derives the background from it.
|
||||
// it would be more efficient to somehow pass ppfbo to it and avoid the copy, but this is simpler.
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fsec.fbo);
|
||||
draw_fbo_viewport(ppfbo);
|
||||
ppfbo = &resources.fsec;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
video_set_viewport();
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
if(global.shake_view) {
|
||||
glTranslatef(global.shake_view*sin(global.frames),global.shake_view*sin(global.frames+3),0);
|
||||
glScalef(1+2*global.shake_view/VIEWPORT_W,1+2*global.shake_view/VIEWPORT_H,1);
|
||||
glTranslatef(-global.shake_view,-global.shake_view,0);
|
||||
|
||||
if(global.shake_view_fade) {
|
||||
global.shake_view -= global.shake_view_fade;
|
||||
if(global.shake_view <= 0)
|
||||
global.shake_view = global.shake_view_fade = 0;
|
||||
}
|
||||
}
|
||||
|
||||
draw_fbo_viewport(ppfbo);
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
draw_hud();
|
||||
}
|
||||
|
||||
static int apply_shaderrules(ShaderRule *shaderrules, int fbonum) {
|
||||
if(!config_get_int(CONFIG_NO_STAGEBG)) {
|
||||
for(ShaderRule *rule = shaderrules; *rule; ++rule) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbg[!fbonum].fbo);
|
||||
(*rule)(fbonum);
|
||||
fbonum = !fbonum;
|
||||
static FBO* stage_render_bg(StageInfo *stage) {
|
||||
float aspect = (float)SCREEN_W/SCREEN_H;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.bg[0].fbo);
|
||||
glViewport(0, 0, resources.fbo.bg[0].nw * aspect, resources.fbo.bg[0].nh);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-(VIEWPORT_X+VIEWPORT_W/2.0), -(VIEWPORT_Y+VIEWPORT_H/2.0),0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
stage->procs->draw();
|
||||
glPopMatrix();
|
||||
|
||||
int num = apply_bg_shaders(stage->procs->shader_rules, 0);
|
||||
return &resources.fbo.bg[num];
|
||||
}
|
||||
|
||||
static void apply_zoom_shader(void);
|
||||
|
||||
void stage_draw_foreground(void) {
|
||||
float s = (float)SCREEN_H/resources.fbo.fg[0].nh;
|
||||
|
||||
// draw the foreground FBO
|
||||
glPushMatrix();
|
||||
// apply the screenshake effect
|
||||
if(global.shake_view) {
|
||||
glTranslatef(global.shake_view*sin(global.frames),global.shake_view*sin(global.frames*1.1+3),0);
|
||||
glScalef(1+2*global.shake_view/VIEWPORT_W,1+2*global.shake_view/VIEWPORT_H,1);
|
||||
glTranslatef(-global.shake_view,-global.shake_view,0);
|
||||
|
||||
if(global.shake_view_fade) {
|
||||
global.shake_view -= global.shake_view_fade;
|
||||
if(global.shake_view <= 0)
|
||||
global.shake_view = global.shake_view_fade = 0;
|
||||
}
|
||||
}
|
||||
|
||||
glScalef(s, s, 1);
|
||||
draw_fbo(&resources.fbo.fg[0]);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void stage_draw(StageInfo *stage) {
|
||||
float s = (float)SCREEN_H/resources.fbo.fg[0].nh;
|
||||
float aspect = (float)SCREEN_W/SCREEN_H;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool key_nobg = gamekeypressed(KEY_NOBACKGROUND);
|
||||
#else
|
||||
bool key_nobg = false;
|
||||
#endif
|
||||
|
||||
bool draw_bg = !config_get_int(CONFIG_NO_STAGEBG) && !key_nobg;
|
||||
FBO *fbg = NULL;
|
||||
|
||||
if(draw_bg) {
|
||||
// render the 3D background
|
||||
fbg = stage_render_bg(stage);
|
||||
}
|
||||
|
||||
return fbonum;
|
||||
// switch to foreground FBO
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.fg[0].fbo);
|
||||
glViewport(0, 0, resources.fbo.fg[0].nw * aspect, resources.fbo.fg[0].nh);
|
||||
set_ortho_ex(SCREEN_W, SCREEN_H);
|
||||
|
||||
if(draw_bg) {
|
||||
// enable boss background distortion
|
||||
if(global.boss) {
|
||||
apply_zoom_shader();
|
||||
}
|
||||
|
||||
// draw the 3D background
|
||||
glPushMatrix();
|
||||
float s2 = s * (resources.fbo.fg[0].scale / fbg->scale);
|
||||
glScalef(s2, s2, 1);
|
||||
draw_fbo(fbg);
|
||||
glPopMatrix();
|
||||
|
||||
// disable boss background distortion
|
||||
glUseProgram(0);
|
||||
|
||||
// fade the background during bomb
|
||||
if(global.frames - global.plr.recovery < 0) {
|
||||
float t = BOMB_RECOVERY - global.plr.recovery + global.frames;
|
||||
float fade = 1;
|
||||
|
||||
if(t < BOMB_RECOVERY/6)
|
||||
fade = t/BOMB_RECOVERY*6;
|
||||
|
||||
if(t > BOMB_RECOVERY/4*3)
|
||||
fade = 1-t/BOMB_RECOVERY*4 + 3;
|
||||
|
||||
glPushMatrix();
|
||||
fade_out(fade*0.6);
|
||||
glPopMatrix();
|
||||
}
|
||||
} else if(!key_nobg) {
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
// draw the 2D objects
|
||||
set_ortho_ex(s * resources.fbo.fg[0].nw * aspect, s * resources.fbo.fg[0].nh);
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_X, VIEWPORT_Y, 0);
|
||||
stage_draw_objects();
|
||||
glPopMatrix();
|
||||
|
||||
// apply custom postprocessing shaders
|
||||
FBO *ppfbo = postprocess(
|
||||
resources.stage_postprocess,
|
||||
resources.fbo.fg,
|
||||
resources.fbo.fg+1,
|
||||
postprocess_prepare,
|
||||
draw_fbo_viewport
|
||||
);
|
||||
|
||||
// update the primary foreground FBO if needed
|
||||
if(ppfbo != resources.fbo.fg) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.fg[0].fbo);
|
||||
draw_fbo_viewport(ppfbo);
|
||||
}
|
||||
|
||||
// switch to main framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
video_set_viewport();
|
||||
set_ortho();
|
||||
|
||||
// finally, draw stuff to the actual screen
|
||||
stage_draw_foreground();
|
||||
draw_hud();
|
||||
}
|
||||
|
||||
static void draw_wall_of_text(float f, const char *txt) {
|
||||
|
@ -611,16 +675,20 @@ static void draw_wall_of_text(float f, const char *txt) {
|
|||
Texture *tex = &resources.fontren.tex;
|
||||
int strw = tex->w;
|
||||
int strh = tex->h;
|
||||
|
||||
float w = SCREEN_W;
|
||||
float h = SCREEN_H;
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_W/2,VIEWPORT_H/2,0);
|
||||
glScalef(VIEWPORT_W,VIEWPORT_H,1.);
|
||||
glTranslatef(w/2, h/2, 0);
|
||||
glScalef(w, h, 1.0);
|
||||
|
||||
Shader *shader = get_shader("spellcard_walloftext");
|
||||
glUseProgram(shader->prog);
|
||||
glUniform1f(uniloc(shader, "w"), strw/(float)tex->truew);
|
||||
glUniform1f(uniloc(shader, "h"), strh/(float)tex->trueh);
|
||||
glUniform1f(uniloc(shader, "ratio"), (float)VIEWPORT_H/VIEWPORT_W);
|
||||
glUniform2f(uniloc(shader, "origin"), creal(global.boss->pos)/VIEWPORT_H,cimag(global.boss->pos)/VIEWPORT_W);
|
||||
glUniform1f(uniloc(shader, "ratio"), h/w);
|
||||
glUniform2f(uniloc(shader, "origin"), creal(global.boss->pos)/h, cimag(global.boss->pos)/w);
|
||||
glUniform1f(uniloc(shader, "t"), f);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->gltex);
|
||||
|
@ -628,11 +696,12 @@ static void draw_wall_of_text(float f, const char *txt) {
|
|||
glUseProgram(0);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void draw_spellbg(int t) {
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_X, VIEWPORT_Y, 0);
|
||||
|
||||
Boss *b = global.boss;
|
||||
b->current->draw_rule(b, t);
|
||||
|
||||
|
@ -666,22 +735,30 @@ static void draw_spellbg(int t) {
|
|||
glColor4f(1,1,1,1);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static void apply_zoom_shader(void) {
|
||||
if(config_get_int(CONFIG_NO_STAGEBG))
|
||||
return;
|
||||
|
||||
Shader *shader = get_shader("boss_zoom");
|
||||
glUseProgram(shader->prog);
|
||||
|
||||
complex fpos = VIEWPORT_H*I + conj(global.boss->pos) + (VIEWPORT_X + VIEWPORT_Y*I);
|
||||
complex pos = fpos + 15*cexp(I*global.frames/4.5);
|
||||
// XXX: no idea why this works the way it does. the VIEWPORT_X offsets are just weird.
|
||||
// i do not understand why VIEWPORT_X needs to be multiplied by M_PI (and only in the first case)
|
||||
// i found that out by trial and error, and it's most likely a coincidence and is inexact
|
||||
// the output appears correct and i don't feel like attempting to screw with the shader,
|
||||
// so i will just leave it this way until lao educates my dumb ass
|
||||
//
|
||||
// I am truly sorry.
|
||||
|
||||
complex fpos = VIEWPORT_H*I + conj(global.boss->pos) + (VIEWPORT_X*M_PI + VIEWPORT_Y*I);
|
||||
complex pos = VIEWPORT_H*I + conj(global.boss->pos) + (VIEWPORT_X + VIEWPORT_Y*I);
|
||||
pos += 15*cexp(I*global.frames/4.5);
|
||||
|
||||
glUniform2f(uniloc(shader, "blur_orig"),
|
||||
creal(pos)/resources.fbg[0].nw, cimag(pos)/resources.fbg[0].nh);
|
||||
creal(pos)/SCREEN_H, cimag(pos)/SCREEN_H);
|
||||
glUniform2f(uniloc(shader, "fix_orig"),
|
||||
creal(fpos)/resources.fbg[0].nw, cimag(fpos)/resources.fbg[0].nh);
|
||||
creal(fpos)/SCREEN_W, cimag(fpos)/SCREEN_H);
|
||||
|
||||
float spellcard_sup = 1;
|
||||
// This factor is used to surpress the effect near the start of spell cards.
|
||||
|
@ -697,9 +774,10 @@ static void apply_zoom_shader(void) {
|
|||
spellcard_sup = 1-t*t;
|
||||
}
|
||||
|
||||
glUniform1f(uniloc(shader, "blur_rad"), spellcard_sup*(0.2+0.025*sin(global.frames/15.0)));
|
||||
glUniform1f(uniloc(shader, "blur_rad"), 1.5 * spellcard_sup*(0.2+0.025*sin(global.frames/15.0)));
|
||||
glUniform1f(uniloc(shader, "rad"), 0.24);
|
||||
glUniform1f(uniloc(shader, "ratio"), (float)resources.fbg[0].nh/resources.fbg[0].nw);
|
||||
glUniform1f(uniloc(shader, "ratio"), (float)resources.fbo.bg[0].nh/resources.fbo.bg[0].nw);
|
||||
|
||||
if(global.boss->zoomcolor) {
|
||||
static float clr[4];
|
||||
parse_color_array(global.boss->zoomcolor, clr);
|
||||
|
@ -709,28 +787,50 @@ static void apply_zoom_shader(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void apply_bg_shaders(ShaderRule *shaderrules) {
|
||||
int fbonum = 0;
|
||||
static int apply_shaderrules(ShaderRule *shaderrules, int fbonum) {
|
||||
for(ShaderRule *rule = shaderrules; *rule; ++rule) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.bg[!fbonum].fbo);
|
||||
(*rule)(fbonum);
|
||||
fbonum = !fbonum;
|
||||
}
|
||||
|
||||
return fbonum;
|
||||
}
|
||||
|
||||
static int apply_bg_shaders(ShaderRule *shaderrules, int fbonum) {
|
||||
Boss *b = global.boss;
|
||||
if(b && b->current && b->current->draw_rule) {
|
||||
int t = global.frames - b->current->starttime;
|
||||
if(t < 4*ATTACK_START_DELAY || b->current->endtime)
|
||||
fbonum = apply_shaderrules(shaderrules, fbonum);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbg[!fbonum].fbo);
|
||||
int o = fbonum;
|
||||
if(t < 4*ATTACK_START_DELAY || b->current->endtime) {
|
||||
fbonum = apply_shaderrules(shaderrules, fbonum);
|
||||
}
|
||||
|
||||
if(fbonum == o) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.bg[!fbonum].fbo);
|
||||
draw_fbo_viewport(resources.fbo.bg + fbonum);
|
||||
fbonum = !fbonum;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.bg[!fbonum].fbo);
|
||||
draw_spellbg(t);
|
||||
|
||||
complex pos = VIEWPORT_H*I + conj(b->pos) + (VIEWPORT_X + VIEWPORT_Y*I);
|
||||
float ratio = (float)resources.fbg[fbonum].nh/resources.fbg[fbonum].nw;
|
||||
// XXX: this seems to fit but it makes no sense
|
||||
// just like in apply_zoom_shader
|
||||
float magic = M_PI;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbg[fbonum].fbo);
|
||||
complex pos = VIEWPORT_H*I + conj(b->pos) + (VIEWPORT_X*magic + VIEWPORT_Y*I);
|
||||
float ratio = (float)resources.fbo.bg[fbonum].nh/resources.fbo.bg[fbonum].nw;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo.bg[fbonum].fbo);
|
||||
if(t<4*ATTACK_START_DELAY) {
|
||||
Shader *shader = get_shader("spellcard_intro");
|
||||
glUseProgram(shader->prog);
|
||||
glUniform1f(uniloc(shader, "ratio"),ratio);
|
||||
glUniform2f(uniloc(shader, "origin"),
|
||||
creal(pos)/resources.fbg[fbonum].nw, cimag(pos)/resources.fbg[fbonum].nh);
|
||||
|
||||
glUniform1f(uniloc(shader, "ratio"), ratio);
|
||||
glUniform2f(uniloc(shader, "origin"), creal(pos)/SCREEN_W, cimag(pos)/SCREEN_H);
|
||||
|
||||
float delay = ATTACK_START_DELAY;
|
||||
if(b->current->type == AT_ExtraSpell)
|
||||
delay = ATTACK_START_DELAY_EXTRA;
|
||||
|
@ -741,56 +841,32 @@ static void apply_bg_shaders(ShaderRule *shaderrules) {
|
|||
int tn = global.frames - b->current->endtime;
|
||||
Shader *shader = get_shader("spellcard_outro");
|
||||
glUseProgram(shader->prog);
|
||||
float delay = ATTACK_END_DELAY;
|
||||
if(b->current->type == AT_ExtraSpell)
|
||||
delay = ATTACK_END_DELAY_EXTRA;
|
||||
|
||||
glUniform1f(uniloc(shader, "ratio"),ratio);
|
||||
glUniform2f(uniloc(shader, "origin"),
|
||||
creal(pos)/resources.fbg[fbonum].nw, cimag(pos)/resources.fbg[fbonum].nh);
|
||||
|
||||
float delay = ATTACK_END_DELAY;
|
||||
|
||||
if(boss_is_dying(b)) {
|
||||
delay = BOSS_DEATH_DELAY;
|
||||
} else if(b->current->type == AT_ExtraSpell) {
|
||||
delay = ATTACK_END_DELAY_EXTRA;
|
||||
}
|
||||
|
||||
glUniform1f(uniloc(shader, "ratio"), ratio);
|
||||
glUniform2f(uniloc(shader, "origin"), creal(pos)/SCREEN_W, cimag(pos)/SCREEN_H);
|
||||
|
||||
glUniform1f(uniloc(shader, "t"), max(0,tn/delay+1));
|
||||
|
||||
} else {
|
||||
glUseProgram(0);
|
||||
}
|
||||
draw_fbo_viewport(&resources.fbg[!fbonum]);
|
||||
|
||||
draw_fbo_viewport(&resources.fbo.bg[!fbonum]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glUseProgram(0);
|
||||
} else
|
||||
fbonum = apply_shaderrules(shaderrules, fbonum);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, resources.fsec.fbo);
|
||||
|
||||
if(global.boss) { // Boss background shader
|
||||
apply_zoom_shader();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
if(!gamekeypressed(KEY_NOBACKGROUND))
|
||||
#endif
|
||||
{
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
if(global.frames - global.plr.recovery < 0) {
|
||||
float t = BOMB_RECOVERY - global.plr.recovery + global.frames;
|
||||
float fade = 1;
|
||||
|
||||
if(t < BOMB_RECOVERY/6)
|
||||
fade = t/BOMB_RECOVERY*6;
|
||||
|
||||
if(t > BOMB_RECOVERY/4*3)
|
||||
fade = 1-t/BOMB_RECOVERY*4 + 3;
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(-30,-30,0);
|
||||
fade_out(fade*0.6);
|
||||
glPopMatrix();
|
||||
}
|
||||
return fbonum;
|
||||
}
|
||||
|
||||
static void stage_logic(void) {
|
||||
|
|
|
@ -95,6 +95,8 @@ void stage_gameover(void);
|
|||
|
||||
void stage_clear_hazards(bool force);
|
||||
|
||||
void stage_draw_foreground(void);
|
||||
|
||||
#include "stages/stage1.h"
|
||||
#include "stages/stage2.h"
|
||||
#include "stages/stage3.h"
|
||||
|
|
|
@ -103,6 +103,9 @@ Vector **stage1_smoke_pos(Vector p, float maxrange) {
|
|||
}
|
||||
|
||||
void stage1_fog(int fbonum) {
|
||||
//draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
//return;
|
||||
|
||||
Shader *shader = get_shader("zbuf_fog");
|
||||
|
||||
glUseProgram(shader->prog);
|
||||
|
@ -114,10 +117,10 @@ void stage1_fog(int fbonum) {
|
|||
glUniform1f(uniloc(shader, "exponent"),3.0);
|
||||
glUniform1f(uniloc(shader, "sphereness"),.2);
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbg[fbonum].depth);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbo.bg[fbonum].depth);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -142,10 +142,10 @@ static void stage2_fog(int fbonum) {
|
|||
glUniform1f(uniloc(shader, "exponent"),3.0);
|
||||
glUniform1f(uniloc(shader, "sphereness"),0);
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbg[fbonum].depth);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbo.bg[fbonum].depth);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ static void stage2_bloom(int fbonum) {
|
|||
glUniform1i(uniloc(shader, "samples"), 10);
|
||||
glUniform1f(uniloc(shader, "intensity"), 0.05);
|
||||
glUniform1f(uniloc(shader, "radius"), 0.03);
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,10 +71,10 @@ void stage3_tunnel(int fbonum) {
|
|||
glUseProgram(shader->prog);
|
||||
glUniform3f(uniloc(shader, "color"),stgstate.clr_r,stgstate.clr_g,stgstate.clr_b);
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbg[fbonum].depth);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbo.bg[fbonum].depth);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
@ -90,10 +90,10 @@ void stage3_fog(int fbonum) {
|
|||
glUniform1f(uniloc(shader, "exponent"), stgstate.fog_exp/2);
|
||||
glUniform1f(uniloc(shader, "sphereness"),0);
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbg[fbonum].depth);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbo.bg[fbonum].depth);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,10 @@ void stage4_fog(int fbonum) {
|
|||
glUniform1f(uniloc(shader, "exponent"),4.0);
|
||||
glUniform1f(uniloc(shader, "sphereness"),0);
|
||||
glActiveTexture(GL_TEXTURE0 + 2);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbg[fbonum].depth);
|
||||
glBindTexture(GL_TEXTURE_2D, resources.fbo.bg[fbonum].depth);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
draw_fbo_viewport(&resources.fbg[fbonum]);
|
||||
draw_fbo_viewport(&resources.fbo.bg[fbonum]);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ static StageText *textlist = NULL;
|
|||
|
||||
StageText* stagetext_add(const char *text, complex pos, Alignment align, TTF_Font *font, Color clr, int delay, int lifetime, int fadeintime, int fadeouttime) {
|
||||
StageText *t = create_element((void**)&textlist, sizeof(StageText));
|
||||
t->rendered_text = fontrender_render(text, font);
|
||||
t->rendered_text = fontrender_render(&resources.fontren, text, font);
|
||||
t->pos = pos;
|
||||
t->align = align;
|
||||
|
||||
|
@ -26,7 +26,7 @@ void stagetext_numeric_predraw(StageText *txt, int t, float a) {
|
|||
char buf[32];
|
||||
SDL_FreeSurface(txt->rendered_text);
|
||||
snprintf(buf, sizeof(buf), "%i", (int)((intptr_t)txt->custom.data1 * pow(a, 5)));
|
||||
txt->rendered_text = fontrender_render(buf, (TTF_Font*)txt->custom.data2);
|
||||
txt->rendered_text = fontrender_render(&resources.fontren, buf, (TTF_Font*)txt->custom.data2);
|
||||
}
|
||||
|
||||
StageText* stagetext_add_numeric(int n, complex pos, Alignment align, TTF_Font *font, Color clr, int delay, int lifetime, int fadeintime, int fadeouttime) {
|
||||
|
@ -90,7 +90,7 @@ static void stagetext_table_push(StageTextTable *tbl, StageText *txt, bool updat
|
|||
c->data = txt;
|
||||
|
||||
if(update_pos) {
|
||||
tbl->pos += txt->rendered_text->h * I;
|
||||
tbl->pos += txt->rendered_text->h / resources.fontren.quality * I;
|
||||
}
|
||||
|
||||
tbl->delay += 5;
|
||||
|
|
21
src/util.c
21
src/util.c
|
@ -219,6 +219,19 @@ double swing(double x, double s) {
|
|||
return x * x * ((s + 1) * x + s) / 2 + 1;
|
||||
}
|
||||
|
||||
unsigned int topow2(unsigned int x) {
|
||||
int y = 1;
|
||||
while(y < x) y *= 2;
|
||||
return y;
|
||||
}
|
||||
|
||||
float ftopow2(float x) {
|
||||
// XXX: obviously this isn't the smallest possible power of two, but for our purposes, it could as well be.
|
||||
float y = 0.0625;
|
||||
while(y < x) y *= 2;
|
||||
return y;
|
||||
}
|
||||
|
||||
//
|
||||
// gl/video utils
|
||||
//
|
||||
|
@ -258,14 +271,18 @@ bool calc_fps(FPSCounter *fps) {
|
|||
return updated;
|
||||
}
|
||||
|
||||
void set_ortho(void) {
|
||||
void set_ortho_ex(float w, float h) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, SCREEN_W, SCREEN_H, 0, -100, 100);
|
||||
glOrtho(0, w, h, 0, -100, 100);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void set_ortho(void) {
|
||||
set_ortho_ex(SCREEN_W, SCREEN_H);
|
||||
}
|
||||
|
||||
void colorfill(float r, float g, float b, float a) {
|
||||
if(a <= 0) return;
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ double approach(double v, double t, double d) __attribute__((const));
|
|||
double psin(double) __attribute__((const));
|
||||
int sign(double) __attribute__((const));
|
||||
double swing(double x, double s) __attribute__((const));
|
||||
unsigned int topow2(unsigned int x) __attribute__((const));
|
||||
float ftopow2(float x) __attribute__((const));
|
||||
|
||||
//
|
||||
// gl/video utils
|
||||
|
@ -88,6 +90,7 @@ typedef struct {
|
|||
void frame_rate(uint64_t *lasttime);
|
||||
bool calc_fps(FPSCounter *fps);
|
||||
void set_ortho(void);
|
||||
void set_ortho_ex(float w, float h);
|
||||
void colorfill(float r, float g, float b, float a);
|
||||
void fade_out(float f);
|
||||
|
||||
|
|
Loading…
Reference in a new issue