initial support for arbitrary overlay text
This commit is contained in:
parent
bf21e20b8b
commit
884c155193
6 changed files with 273 additions and 21 deletions
|
@ -29,6 +29,7 @@ set(SRCs
|
|||
color.c
|
||||
gamepad.c
|
||||
stage.c
|
||||
stagetext.c
|
||||
replay.c
|
||||
global.c
|
||||
events.c
|
||||
|
|
|
@ -48,17 +48,13 @@ void fontrenderer_free(FontRenderer *f) {
|
|||
glDeleteTextures(1,&f->tex.gltex);
|
||||
}
|
||||
|
||||
void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font) {
|
||||
SDL_Color clr = {255,255,255};
|
||||
SDL_Surface *surf = TTF_RenderUTF8_Blended(font, text, clr);
|
||||
if(surf == 0) {
|
||||
log_fatal("SDL_ttf: %s", TTF_GetError());
|
||||
}
|
||||
static bool fontrenderer_try_draw_prerendered(FontRenderer *f, SDL_Surface *surf) {
|
||||
assert(surf != NULL);
|
||||
|
||||
if(surf->w > FONTREN_MAXW || surf->h > FONTREN_MAXH) {
|
||||
log_fatal("Text drawn (\"%s\" %dx%d) is too big for the internal buffer (%dx%d).", text, surf->w, surf->h, FONTREN_MAXW, FONTREN_MAXH);
|
||||
return false;
|
||||
}
|
||||
|
||||
f->tex.w = surf->w;
|
||||
f->tex.h = surf->h;
|
||||
|
||||
|
@ -76,12 +72,38 @@ void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font) {
|
|||
memcpy(pixels+y*winw, ((uint8_t *)surf->pixels)+y*surf->pitch, surf->w*4);
|
||||
pixels[y*winw+surf->w]=0;
|
||||
}
|
||||
|
||||
memset(pixels+(winh-1)*winw,0,winw*4);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,winw,winh,GL_RGBA,GL_UNSIGNED_BYTE,0);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fontrenderer_draw_prerendered(FontRenderer *f, SDL_Surface *surf) {
|
||||
if(!fontrenderer_try_draw_prerendered(f, surf)) {
|
||||
log_fatal("Text drawn (<%p> %dx%d) is too big for the internal buffer (%dx%d).", (void*)surf, surf->w, surf->h, FONTREN_MAXW, FONTREN_MAXH);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface* fontrender_render(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());
|
||||
}
|
||||
|
||||
return surf;
|
||||
}
|
||||
|
||||
void fontrenderer_draw(FontRenderer *f, const char *text, TTF_Font *font) {
|
||||
SDL_Surface *surf = fontrender_render(text, font);
|
||||
|
||||
if(!fontrenderer_try_draw_prerendered(f, surf)) {
|
||||
log_fatal("Text drawn (\"%s\" %dx%d) is too big for the internal buffer (%dx%d).", text, surf->w, surf->h, FONTREN_MAXW, FONTREN_MAXH);
|
||||
}
|
||||
|
||||
SDL_FreeSurface(surf);
|
||||
}
|
||||
|
@ -103,19 +125,7 @@ void free_fonts(void) {
|
|||
TTF_Quit();
|
||||
}
|
||||
|
||||
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font) {
|
||||
char *nl;
|
||||
char *buf = malloc(strlen(text)+1);
|
||||
strcpy(buf, text);
|
||||
|
||||
if((nl = strchr(buf, '\n')) != NULL && strlen(nl) > 1) {
|
||||
draw_text(align, x, y + 20, nl+1, font);
|
||||
*nl = '\0';
|
||||
}
|
||||
|
||||
fontrenderer_draw(&resources.fontren, buf, font);
|
||||
Texture *tex = &resources.fontren.tex;
|
||||
|
||||
static void draw_text_texture(Alignment align, float x, float y, Texture *tex) {
|
||||
switch(align) {
|
||||
case AL_Center:
|
||||
break;
|
||||
|
@ -135,7 +145,25 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
|
|||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
draw_texture_p(x, y, tex);
|
||||
}
|
||||
|
||||
void draw_text_prerendered(Alignment align, float x, float y, SDL_Surface *surf) {
|
||||
fontrenderer_draw_prerendered(&resources.fontren, surf);
|
||||
draw_text_texture(align, x, y, &resources.fontren.tex);
|
||||
}
|
||||
|
||||
void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *font) {
|
||||
char *nl;
|
||||
char *buf = malloc(strlen(text)+1);
|
||||
strcpy(buf, text);
|
||||
|
||||
if((nl = strchr(buf, '\n')) != NULL && strlen(nl) > 1) {
|
||||
draw_text(align, x, y + 20, nl+1, font);
|
||||
*nl = '\0';
|
||||
}
|
||||
|
||||
fontrenderer_draw(&resources.fontren, buf, font);
|
||||
draw_text_texture(align, x, y, &resources.fontren.tex);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,13 @@ struct FontRenderer {
|
|||
|
||||
void fontrenderer_init(FontRenderer *f);
|
||||
void fontrenderer_free(FontRenderer *f);
|
||||
void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font);
|
||||
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);
|
||||
|
||||
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 free_fonts(void);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "menu/gameovermenu.h"
|
||||
#include "audio.h"
|
||||
#include "log.h"
|
||||
#include "stagetext.h"
|
||||
|
||||
static size_t numstages = 0;
|
||||
StageInfo *stages = NULL;
|
||||
|
@ -567,6 +568,8 @@ static void stage_draw(StageInfo *stage) {
|
|||
if(stage->type != STAGE_SPELL)
|
||||
draw_stage_title(stage);
|
||||
|
||||
stagetext_draw();
|
||||
|
||||
FBO *ppfbo = postprocess(resources.stage_postprocess, &resources.fsec, resources.fbg, postprocess_prepare, draw_fbo_viewport);
|
||||
|
||||
if(ppfbo != &resources.fsec) {
|
||||
|
@ -847,6 +850,8 @@ static void stage_free(void) {
|
|||
free_boss(global.boss);
|
||||
global.boss = NULL;
|
||||
}
|
||||
|
||||
stagetext_free();
|
||||
}
|
||||
|
||||
static void stage_finalize(void *arg) {
|
||||
|
@ -956,6 +961,8 @@ void stage_loop(StageInfo *stage) {
|
|||
|
||||
int transition_delay = 0;
|
||||
|
||||
// stagetext_table_test();
|
||||
|
||||
while(global.game_over <= 0) {
|
||||
if(global.game_over != GAMEOVER_TRANSITIONING) {
|
||||
if(!global.boss && !global.dialog) {
|
||||
|
|
153
src/stagetext.c
Normal file
153
src/stagetext.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
|
||||
#include "stagetext.h"
|
||||
#include "list.h"
|
||||
#include "global.h"
|
||||
|
||||
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->pos = pos;
|
||||
t->align = align;
|
||||
|
||||
t->time.spawn = global.frames + delay;
|
||||
t->time.life = lifetime + fadeouttime;
|
||||
t->time.fadein = fadeintime;
|
||||
t->time.fadeout = fadeouttime;
|
||||
|
||||
parse_color_array(clr, t->clr);
|
||||
memset(&t->custom, 0, sizeof(t->custom));
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
StageText* stagetext_add_numeric(int n, complex pos, Alignment align, TTF_Font *font, Color clr, int delay, int lifetime, int fadeintime, int fadeouttime) {
|
||||
StageText *t = stagetext_add("0", pos, align, font, clr, delay, lifetime, fadeintime, fadeouttime);
|
||||
t->custom.data1 = (void*)(intptr_t)n;
|
||||
t->custom.data2 = (void*)font;
|
||||
t->custom.predraw = stagetext_numeric_predraw;
|
||||
return t;
|
||||
}
|
||||
|
||||
static void stagetext_delete(StageText **dest, StageText *txt) {
|
||||
SDL_FreeSurface(txt->rendered_text);
|
||||
delete_element((void**)dest, txt);
|
||||
}
|
||||
|
||||
void stagetext_free(void) {
|
||||
delete_all_elements((void**)&textlist, (void (*)(void **, void *))stagetext_delete);
|
||||
}
|
||||
|
||||
static void stagetext_draw_single(StageText *txt) {
|
||||
if(global.frames < txt->time.spawn) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(global.frames > txt->time.spawn + txt->time.life) {
|
||||
stagetext_delete(&textlist, txt);
|
||||
return;
|
||||
}
|
||||
|
||||
int t = global.frames - txt->time.spawn;
|
||||
float f = 1.0 - clamp((txt->time.life - t) / (float)txt->time.fadeout, 0, clamp(t / (float)txt->time.fadein, 0, 1));
|
||||
|
||||
if(txt->custom.predraw) {
|
||||
txt->custom.predraw(txt, t, 1.0 - f);
|
||||
}
|
||||
|
||||
Shader *sha = get_shader("stagetitle");
|
||||
glUseProgram(sha->prog);
|
||||
glUniform1i(uniloc(sha, "trans"), 1);
|
||||
glUniform1f(uniloc(sha, "t"), 1.0 - f);
|
||||
glUniform3fv(uniloc(sha, "color"), 1, txt->clr);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + 1);
|
||||
glBindTexture(GL_TEXTURE_2D, get_tex("titletransition")->gltex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
draw_text_prerendered(txt->align, creal(txt->pos)+10*f*f, cimag(txt->pos)+10*f*f, txt->rendered_text);
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void stagetext_draw(void) {
|
||||
for(StageText *t = textlist, *next = NULL; t; t = next) {
|
||||
next = t->next;
|
||||
stagetext_draw_single(t);
|
||||
}
|
||||
}
|
||||
|
||||
static void stagetext_table_push(StageTextTable *tbl, StageText *txt, bool update_pos) {
|
||||
ListContainer *c = create_container(&tbl->elems);
|
||||
c->data = txt;
|
||||
|
||||
if(update_pos) {
|
||||
tbl->pos += txt->rendered_text->h * I;
|
||||
}
|
||||
|
||||
tbl->delay += 5;
|
||||
}
|
||||
|
||||
void stagetext_begin_table(StageTextTable *tbl, const char *title, Color titleclr, Color clr, double width, int delay, int lifetime, int fadeintime, int fadeouttime) {
|
||||
memset(tbl, 0, sizeof(StageTextTable));
|
||||
tbl->pos = VIEWPORT_W/2 + VIEWPORT_H/2*I;
|
||||
tbl->clr = clr;
|
||||
tbl->width = width;
|
||||
tbl->lifetime = lifetime;
|
||||
tbl->fadeintime = fadeintime;
|
||||
tbl->fadeouttime = fadeouttime;
|
||||
tbl->delay = delay;
|
||||
|
||||
StageText *txt = stagetext_add(title, tbl->pos, AL_Center, _fonts.mainmenu, titleclr, tbl->delay, lifetime, fadeintime, fadeouttime);
|
||||
stagetext_table_push(tbl, txt, true);
|
||||
}
|
||||
|
||||
void stagetext_end_table(StageTextTable *tbl) {
|
||||
complex ofs = -0.5 * I * (cimag(tbl->pos) - VIEWPORT_H/2);
|
||||
|
||||
for(ListContainer *c = tbl->elems; c; c = c->next) {
|
||||
((StageText*)c->data)->pos += ofs;
|
||||
}
|
||||
|
||||
delete_all_elements((void**)&tbl->elems, delete_element);
|
||||
}
|
||||
|
||||
static void stagetext_table_add_label(StageTextTable *tbl, const char *title) {
|
||||
StageText *txt = stagetext_add(title, tbl->pos - tbl->width * 0.5, AL_Left, _fonts.standard, tbl->clr, tbl->delay, tbl->lifetime, tbl->fadeintime, tbl->fadeouttime);
|
||||
stagetext_table_push(tbl, txt, false);
|
||||
}
|
||||
|
||||
void stagetext_table_add(StageTextTable *tbl, const char *title, const char *val) {
|
||||
stagetext_table_add_label(tbl, title);
|
||||
StageText *txt = stagetext_add(val, tbl->pos + tbl->width * 0.5, AL_Right, _fonts.standard, tbl->clr, tbl->delay, tbl->lifetime, tbl->fadeintime, tbl->fadeouttime);
|
||||
stagetext_table_push(tbl, txt, true);
|
||||
}
|
||||
|
||||
void stagetext_table_add_numeric(StageTextTable *tbl, const char *title, int n) {
|
||||
stagetext_table_add_label(tbl, title);
|
||||
StageText *txt = stagetext_add_numeric(n, tbl->pos + tbl->width * 0.5, AL_Right, _fonts.standard, tbl->clr, tbl->delay, tbl->lifetime, tbl->fadeintime, tbl->fadeouttime);
|
||||
stagetext_table_push(tbl, txt, true);
|
||||
}
|
||||
|
||||
void stagetext_table_add_separator(StageTextTable *tbl) {
|
||||
tbl->pos += I * 0.5 * stringheight("Love Live", _fonts.standard);
|
||||
}
|
||||
|
||||
void stagetext_table_test(void) {
|
||||
StageTextTable tbl;
|
||||
stagetext_begin_table(&tbl, "Test", rgb(1, 1, 1), rgb(1, 1, 1), VIEWPORT_W/2, 60, 300, 30, 60);
|
||||
stagetext_table_add(&tbl, "foo", "bar");
|
||||
stagetext_table_add(&tbl, "qwerty", "asdfg");
|
||||
stagetext_table_add(&tbl, "top", "kek");
|
||||
stagetext_table_add_separator(&tbl);
|
||||
stagetext_table_add_numeric(&tbl, "Total Score", 9000000);
|
||||
stagetext_end_table(&tbl);
|
||||
}
|
60
src/stagetext.h
Normal file
60
src/stagetext.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
|
||||
#ifndef STAGETXT_H
|
||||
#define STAGETXT_H
|
||||
|
||||
#include "util.h"
|
||||
#include "color.h"
|
||||
#include "resource/font.h"
|
||||
|
||||
typedef struct StageText StageText;
|
||||
typedef void (*StageTextPreDrawFunc)(StageText* txt, int t, float alpha);
|
||||
|
||||
typedef struct StageTextTable StageTextTable;
|
||||
|
||||
struct StageText {
|
||||
StageText *next;
|
||||
StageText *prev;
|
||||
|
||||
SDL_Surface *rendered_text;
|
||||
complex pos;
|
||||
Alignment align;
|
||||
float clr[4];
|
||||
|
||||
struct {
|
||||
int spawn;
|
||||
int life;
|
||||
int fadein;
|
||||
int fadeout;
|
||||
} time;
|
||||
|
||||
struct {
|
||||
StageTextPreDrawFunc predraw;
|
||||
void *data1;
|
||||
void *data2;
|
||||
} custom;
|
||||
};
|
||||
|
||||
void stagetext_free(void);
|
||||
void stagetext_draw(void);
|
||||
StageText* stagetext_add(const char *text, complex pos, Alignment align, TTF_Font *font, Color clr, int delay, int lifetime, int fadeintime, int fadeouttime);
|
||||
StageText* stagetext_add_numeric(int n, complex pos, Alignment align, TTF_Font *font, Color clr, int delay, int lifetime, int fadeintime, int fadeouttime);
|
||||
|
||||
struct StageTextTable {
|
||||
complex pos;
|
||||
double width;
|
||||
Color clr;
|
||||
int lifetime;
|
||||
int fadeintime;
|
||||
int fadeouttime;
|
||||
int delay;
|
||||
ListContainer *elems;
|
||||
};
|
||||
|
||||
void stagetext_begin_table(StageTextTable *tbl, const char *title, Color titleclr, Color clr, double width, int delay, int lifetime, int fadeintime, int fadeouttime);
|
||||
void stagetext_end_table(StageTextTable *tbl);
|
||||
void stagetext_table_add(StageTextTable *tbl, const char *title, const char *val);
|
||||
void stagetext_table_add_numeric(StageTextTable *tbl, const char *title, int n);
|
||||
|
||||
void stagetext_table_test(void);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue