integrate fonts into the resource system (preparing for text rendering rewrite)
This commit is contained in:
parent
9d47a59d44
commit
9356f263fd
14 changed files with 203 additions and 86 deletions
3
resources/fonts/big.font
Normal file
3
resources/fonts/big.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/immortal.ttf
|
||||
size = 35
|
3
resources/fonts/hud.font
Normal file
3
resources/fonts/hud.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/Laconic_Regular.otf
|
||||
size = 19
|
3
resources/fonts/mono.font
Normal file
3
resources/fonts/mono.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/ShareTechMono-Regular.ttf
|
||||
size = 19
|
3
resources/fonts/monosmall.font
Normal file
3
resources/fonts/monosmall.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/ShareTechMono-Regular.ttf
|
||||
size = 14
|
3
resources/fonts/monotiny.font
Normal file
3
resources/fonts/monotiny.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/ShareTechMono-Regular.ttf
|
||||
size = 10
|
3
resources/fonts/small.font
Normal file
3
resources/fonts/small.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/LinBiolinum.ttf
|
||||
size = 14
|
3
resources/fonts/standard.font
Normal file
3
resources/fonts/standard.font
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
source = res/fonts/LinBiolinum.ttf
|
||||
size = 20
|
|
@ -42,7 +42,6 @@ static void taisei_shutdown(void) {
|
|||
|
||||
free_all_refs();
|
||||
free_resources(true);
|
||||
uninit_fonts();
|
||||
audio_shutdown();
|
||||
video_shutdown();
|
||||
gamepad_shutdown();
|
||||
|
@ -236,7 +235,6 @@ int main(int argc, char **argv) {
|
|||
time_init();
|
||||
init_global(&a);
|
||||
events_init();
|
||||
init_fonts();
|
||||
video_init();
|
||||
init_resources();
|
||||
r_post_init();
|
||||
|
|
|
@ -13,17 +13,18 @@
|
|||
#include "util.h"
|
||||
#include "objectpool.h"
|
||||
#include "objectpool_util.h"
|
||||
#include "video.h"
|
||||
|
||||
#define CACHE_EXPIRE_TIME 1000
|
||||
|
||||
#ifdef DEBUG
|
||||
// #define VERBOSE_CACHE_LOG
|
||||
// #define VERBOSE_CACHE_LOG
|
||||
#endif
|
||||
|
||||
#ifdef VERBOSE_CACHE_LOG
|
||||
#define CACHELOG(fmt, ...) log_debug(fmt, __VA_ARGS__)
|
||||
#define CACHELOG(fmt, ...) log_debug(fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define CACHELOG(fmt, ...)
|
||||
#define CACHELOG(fmt, ...)
|
||||
#endif
|
||||
|
||||
typedef struct CacheEntry {
|
||||
|
@ -35,7 +36,7 @@ typedef struct CacheEntry {
|
|||
uint32_t ref_time;
|
||||
|
||||
struct {
|
||||
// to simplify invalidation
|
||||
// to simplify invalidation
|
||||
Hashtable *ht;
|
||||
char *ht_key;
|
||||
} owner;
|
||||
|
@ -54,10 +55,72 @@ static FontRenderer font_renderer;
|
|||
struct Font {
|
||||
TTF_Font *ttf;
|
||||
Hashtable *cache;
|
||||
char *source_path;
|
||||
int base_size;
|
||||
};
|
||||
|
||||
struct Fonts _fonts;
|
||||
|
||||
static void fontrenderer_init(float quality);
|
||||
static void fontrenderer_free(void);
|
||||
static void reload_fonts(float quality);
|
||||
|
||||
static bool fonts_event(SDL_Event *event, void *arg) {
|
||||
reload_fonts(video.quality_factor * config_get_float(CONFIG_TEXT_QUALITY));
|
||||
return false;
|
||||
}
|
||||
|
||||
static void fonts_quality_config_callback(ConfigIndex idx, ConfigValue v) {
|
||||
config_set_float(idx, v.f);
|
||||
reload_fonts(video.quality_factor * v.f);
|
||||
}
|
||||
|
||||
static void init_fonts(void) {
|
||||
TTF_Init();
|
||||
memset(&font_renderer, 0, sizeof(font_renderer));
|
||||
cache_pool = OBJPOOL_ALLOC(CacheEntry, 512);
|
||||
fontrenderer_init(video.quality_factor * config_get_float(CONFIG_TEXT_QUALITY));
|
||||
|
||||
events_register_handler(&(EventHandler) {
|
||||
fonts_event, NULL, EPRIO_SYSTEM, MAKE_TAISEI_EVENT(TE_VIDEO_MODE_CHANGED)
|
||||
});
|
||||
|
||||
config_set_callback(CONFIG_TEXT_QUALITY, fonts_quality_config_callback);
|
||||
|
||||
preload_resources(RES_FONT, RESF_PERMANENT,
|
||||
"standard",
|
||||
"big",
|
||||
"small",
|
||||
"hud",
|
||||
"mono",
|
||||
"monosmall",
|
||||
"monotiny",
|
||||
NULL);
|
||||
|
||||
_fonts.standard = get_resource(RES_FONT, "standard", 0)->data;
|
||||
_fonts.mainmenu = get_resource(RES_FONT, "big", 0)->data;
|
||||
_fonts.small = get_resource(RES_FONT, "small", 0)->data;
|
||||
_fonts.hud = get_resource(RES_FONT, "hud", 0)->data;
|
||||
_fonts.mono = get_resource(RES_FONT, "mono", 0)->data;
|
||||
_fonts.monosmall = get_resource(RES_FONT, "monosmall", 0)->data;
|
||||
_fonts.monotiny = get_resource(RES_FONT, "monotiny", 0)->data;
|
||||
}
|
||||
|
||||
static void uninit_fonts(void) {
|
||||
events_unregister_handler(fonts_event);
|
||||
fontrenderer_free();
|
||||
TTF_Quit();
|
||||
objpool_free(cache_pool);
|
||||
}
|
||||
|
||||
static char* font_path(const char *name) {
|
||||
return strjoin(FONT_PATH_PREFIX, name, FONT_EXTENSION, NULL);
|
||||
}
|
||||
|
||||
bool check_font_path(const char *path) {
|
||||
return strstartswith(path, FONT_PATH_PREFIX) && strendswith(path, FONT_EXTENSION);
|
||||
}
|
||||
|
||||
static TTF_Font* load_ttf(char *vfspath, int size) {
|
||||
char *syspath = vfs_repr(vfspath, true);
|
||||
|
||||
|
@ -73,7 +136,7 @@ static TTF_Font* load_ttf(char *vfspath, int size) {
|
|||
TTF_Font *f = TTF_OpenFontRW(rwops, true, size);
|
||||
|
||||
if(!f) {
|
||||
log_fatal("Failed to load font '%s' @ %i: %s", syspath, size, TTF_GetError());
|
||||
log_warn("Failed to load TTF font '%s' @ %i: %s", syspath, size, TTF_GetError());
|
||||
}
|
||||
|
||||
log_info("Loaded '%s' @ %i", syspath, size);
|
||||
|
@ -82,16 +145,57 @@ static TTF_Font* load_ttf(char *vfspath, int size) {
|
|||
return f;
|
||||
}
|
||||
|
||||
static Font* load_font(char *vfspath, int size) {
|
||||
TTF_Font *ttf = load_ttf(vfspath, size);
|
||||
void* load_font_begin(const char *path, uint flags) {
|
||||
Font font;
|
||||
memset(&font, 0, sizeof(font));
|
||||
|
||||
Font *font = calloc(1, sizeof(Font));
|
||||
font->ttf = ttf;
|
||||
font->cache = hashtable_new_stringkeys();
|
||||
if(!parse_keyvalue_file_with_spec(path, (KVSpec[]){
|
||||
{ "source", .out_str = &font.source_path },
|
||||
{ "size", .out_int = &font.base_size },
|
||||
{ NULL }
|
||||
})) {
|
||||
log_warn("Failed to parse font file '%s'", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return font;
|
||||
font.ttf = load_ttf(font.source_path, font.base_size);
|
||||
|
||||
if(!font.ttf) {
|
||||
free(font.source_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
font.cache = hashtable_new_stringkeys();
|
||||
|
||||
return memdup(&font, sizeof(font));
|
||||
}
|
||||
|
||||
void* load_font_end(void *opaque, const char *path, uint flags) {
|
||||
return opaque;
|
||||
}
|
||||
|
||||
static void free_font(Font *font);
|
||||
|
||||
void unload_font(void *vfont) {
|
||||
free_font(vfont);
|
||||
}
|
||||
|
||||
ResourceHandler font_res_handler = {
|
||||
.type = RES_FONT,
|
||||
.typename = "font",
|
||||
.subdir = FONT_PATH_PREFIX,
|
||||
|
||||
.procs = {
|
||||
.init = init_fonts,
|
||||
.shutdown = uninit_fonts,
|
||||
.find = font_path,
|
||||
.check = check_font_path,
|
||||
.begin_load = load_font_begin,
|
||||
.end_load = load_font_end,
|
||||
.unload = unload_font,
|
||||
},
|
||||
};
|
||||
|
||||
static void free_cache_entry(CacheEntry *e) {
|
||||
if(!e) {
|
||||
return;
|
||||
|
@ -208,60 +312,42 @@ static SDL_Surface* fontrender_render(const char *text, Font *font) {
|
|||
return surf;
|
||||
}
|
||||
|
||||
void init_fonts(void) {
|
||||
TTF_Init();
|
||||
memset(&font_renderer, 0, sizeof(font_renderer));
|
||||
cache_pool = OBJPOOL_ALLOC(CacheEntry, 512);
|
||||
}
|
||||
static void free_font_cache(Hashtable *cache) {
|
||||
CacheEntry *e;
|
||||
|
||||
void uninit_fonts(void) {
|
||||
free_fonts();
|
||||
TTF_Quit();
|
||||
}
|
||||
|
||||
void load_fonts(float quality) {
|
||||
fontrenderer_init(quality);
|
||||
_fonts.standard = load_font("res/fonts/LinBiolinum.ttf", 20);
|
||||
_fonts.mainmenu = load_font("res/fonts/immortal.ttf", 35);
|
||||
_fonts.small = load_font("res/fonts/LinBiolinum.ttf", 14);
|
||||
_fonts.hud = load_font("res/fonts/Laconic_Regular.otf", 19);
|
||||
_fonts.mono = load_font("res/fonts/ShareTechMono-Regular.ttf", 19);
|
||||
_fonts.monosmall = load_font("res/fonts/ShareTechMono-Regular.ttf", 14);
|
||||
_fonts.monotiny = load_font("res/fonts/ShareTechMono-Regular.ttf", 10);
|
||||
}
|
||||
|
||||
void reload_fonts(float quality) {
|
||||
if(!font_renderer.quality) {
|
||||
// never loaded
|
||||
load_fonts(quality);
|
||||
return;
|
||||
}
|
||||
|
||||
if(font_renderer.quality != sanitize_scale(quality)) {
|
||||
free_fonts();
|
||||
load_fonts(quality);
|
||||
for(HashtableIterator *i = hashtable_iter(cache); hashtable_iter_next(i, 0, (void**)&e);) {
|
||||
free_cache_entry(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_font(Font *font) {
|
||||
CacheEntry *e;
|
||||
TTF_CloseFont(font->ttf);
|
||||
|
||||
for(HashtableIterator *i = hashtable_iter(font->cache); hashtable_iter_next(i, 0, (void**)&e);) {
|
||||
free_cache_entry(e);
|
||||
}
|
||||
|
||||
free_font_cache(font->cache);
|
||||
hashtable_free(font->cache);
|
||||
free(font->source_path);
|
||||
free(font);
|
||||
}
|
||||
|
||||
void free_fonts(void) {
|
||||
fontrenderer_free();
|
||||
static void reload_font(Font *font) {
|
||||
TTF_CloseFont(font->ttf);
|
||||
free_font_cache(font->cache);
|
||||
hashtable_unset_all(font->cache);
|
||||
font->ttf = load_ttf(font->source_path, font->base_size);
|
||||
}
|
||||
|
||||
Font **last = &_fonts.first + (sizeof(_fonts)/sizeof(Font*) - 1);
|
||||
for(Font **font = &_fonts.first; font <= last; ++font) {
|
||||
free_font(*font);
|
||||
static void* reload_font_callback(const char *name, Resource *res, void *varg) {
|
||||
reload_font((Font*)res->data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void reload_fonts(float quality) {
|
||||
if(font_renderer.quality == sanitize_scale(quality)) {
|
||||
return;
|
||||
}
|
||||
|
||||
fontrenderer_free();
|
||||
fontrenderer_init(quality);
|
||||
resource_for_each(RES_FONT, reload_font_callback, NULL);
|
||||
}
|
||||
|
||||
static void draw_text_line(Alignment align, float x, float y, const char *text, Font *font) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "sprite.h"
|
||||
#include "hashtable.h"
|
||||
#include "resource.h"
|
||||
|
||||
typedef enum {
|
||||
AL_Center,
|
||||
|
@ -39,13 +40,6 @@ int font_line_spacing(Font *font);
|
|||
void shorten_text_up_to_width(char *s, float width, Font *font);
|
||||
void wrap_text(char *buf, size_t bufsize, const char *src, int width, Font *font);
|
||||
|
||||
void init_fonts(void);
|
||||
void uninit_fonts(void);
|
||||
void load_fonts(float quality);
|
||||
void reload_fonts(float quality);
|
||||
void free_fonts(void);
|
||||
void update_font_cache(void);
|
||||
|
||||
extern struct Fonts {
|
||||
union {
|
||||
struct {
|
||||
|
@ -61,3 +55,8 @@ extern struct Fonts {
|
|||
Font *first;
|
||||
};
|
||||
} _fonts;
|
||||
|
||||
extern ResourceHandler font_res_handler;
|
||||
|
||||
#define FONT_PATH_PREFIX "res/fonts/"
|
||||
#define FONT_EXTENSION ".font"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "model.h"
|
||||
#include "postprocess.h"
|
||||
#include "sprite.h"
|
||||
#include "font.h"
|
||||
|
||||
#include "renderer/common/backend.h"
|
||||
|
||||
|
@ -37,6 +38,7 @@ ResourceHandler *_handlers[] = {
|
|||
[RES_MODEL] = &model_res_handler,
|
||||
[RES_POSTPROCESS] = &postprocess_res_handler,
|
||||
[RES_SPRITE] = &sprite_res_handler,
|
||||
[RES_FONT] = &font_res_handler,
|
||||
|
||||
// FIXME: these are currently handled by the renderer backend completely
|
||||
[RES_SHADER_OBJECT] = NULL,
|
||||
|
@ -415,33 +417,19 @@ void preload_resources(ResourceType type, ResourceFlags flags, const char *first
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
static void init_sdl_image(void) {
|
||||
int want_flags = IMG_INIT_JPG | IMG_INIT_PNG;
|
||||
int init_flags = IMG_Init(want_flags);
|
||||
|
||||
if((want_flags & init_flags) != want_flags) {
|
||||
log_warn(
|
||||
"SDL_image doesn't support some of the formats we want. "
|
||||
"Requested: %i, got: %i. "
|
||||
"Textures may fail to load",
|
||||
want_flags,
|
||||
init_flags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void init_resources(void) {
|
||||
main_thread_id = SDL_ThreadID();
|
||||
_handlers[RES_SHADER_OBJECT] = _r_backend.res_handlers.shader_object;
|
||||
_handlers[RES_SHADER_PROGRAM] = _r_backend.res_handlers.shader_program;
|
||||
|
||||
init_sdl_image();
|
||||
|
||||
for(int i = 0; i < RES_NUMTYPES; ++i) {
|
||||
ResourceHandler *h = get_handler(i);
|
||||
alloc_handler(h);
|
||||
}
|
||||
|
||||
main_thread_id = SDL_ThreadID();
|
||||
if(h->procs.init != NULL) {
|
||||
h->procs.init();
|
||||
}
|
||||
}
|
||||
|
||||
if(!env_get("TAISEI_NOASYNC", 0)) {
|
||||
EventHandler h = {
|
||||
|
@ -559,6 +547,10 @@ void free_resources(bool all) {
|
|||
}
|
||||
|
||||
if(all) {
|
||||
if(handler->procs.shutdown != NULL) {
|
||||
handler->procs.shutdown();
|
||||
}
|
||||
|
||||
hashtable_free(handler->private->mapping);
|
||||
free(handler->private);
|
||||
}
|
||||
|
@ -575,6 +567,4 @@ void free_resources(bool all) {
|
|||
if(!env_get("TAISEI_NOASYNC", 0)) {
|
||||
events_unregister_handler(resource_asyncload_handler);
|
||||
}
|
||||
|
||||
IMG_Quit();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ typedef enum ResourceType {
|
|||
RES_MODEL,
|
||||
RES_POSTPROCESS,
|
||||
RES_SPRITE,
|
||||
RES_FONT,
|
||||
RES_NUMTYPES,
|
||||
} ResourceType;
|
||||
|
||||
|
@ -61,6 +62,12 @@ typedef void* (*ResourceEndLoadProc)(void *opaque, const char *path, uint flags)
|
|||
// Unloads a resource, freeing all allocated to it memory.
|
||||
typedef void (*ResourceUnloadProc)(void *res);
|
||||
|
||||
// Called during resource subsystem initialization
|
||||
typedef void (*ResourceInit)(void);
|
||||
|
||||
// Called during resource subsystem shutdown
|
||||
typedef void (*ResourceShutdown)(void);
|
||||
|
||||
typedef struct ResourceHandlerPrivate ResourceHandlerPrivate;
|
||||
|
||||
typedef struct ResourceHandler {
|
||||
|
@ -76,6 +83,8 @@ typedef struct ResourceHandler {
|
|||
ResourceBeginLoadProc begin_load;
|
||||
ResourceEndLoadProc end_load;
|
||||
ResourceUnloadProc unload;
|
||||
ResourceInit init;
|
||||
ResourceShutdown shutdown;
|
||||
} procs;
|
||||
|
||||
ResourceHandlerPrivate *private;
|
||||
|
|
|
@ -20,12 +20,29 @@ static void* load_texture_begin(const char *path, uint flags);
|
|||
static void* load_texture_end(void *opaque, const char *path, uint flags);
|
||||
static void free_texture(Texture *tex);
|
||||
|
||||
static void init_sdl_image(void) {
|
||||
int want_flags = IMG_INIT_JPG | IMG_INIT_PNG;
|
||||
int init_flags = IMG_Init(want_flags);
|
||||
|
||||
if((want_flags & init_flags) != want_flags) {
|
||||
log_warn(
|
||||
"SDL_image doesn't support some of the formats we want. "
|
||||
"Requested: %i, got: %i. "
|
||||
"Textures may fail to load",
|
||||
want_flags,
|
||||
init_flags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ResourceHandler texture_res_handler = {
|
||||
.type = RES_TEXTURE,
|
||||
.typename = "texture",
|
||||
.subdir = TEX_PATH_PREFIX,
|
||||
|
||||
.procs = {
|
||||
.init = init_sdl_image,
|
||||
.shutdown = IMG_Quit,
|
||||
.find = texture_path,
|
||||
.check = check_texture_path,
|
||||
.begin_load = load_texture_begin,
|
||||
|
|
|
@ -92,8 +92,6 @@ static void video_update_quality(void) {
|
|||
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);
|
||||
|
||||
reload_fonts(text);
|
||||
}
|
||||
|
||||
static uint32_t get_fullscreen_flag(void) {
|
||||
|
@ -520,7 +518,6 @@ void video_init(void) {
|
|||
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);
|
||||
config_set_callback(CONFIG_TEXT_QUALITY, video_quality_callback);
|
||||
|
||||
EventHandler h = {
|
||||
.proc = video_handle_window_event,
|
||||
|
|
Loading…
Reference in a new issue