Files
allegro_schrift/glue.c
2026-09-12 06:38:30 +00:00

199 lines
5.4 KiB
C

#define ALLEGRO_INTERNAL_UNSTABLE
#include "allegro5/allegro.h"
#include "allegro5/internal/aintern.h"
#include "allegro5/internal/aintern_vector.h"
#include "allegro5/allegro_schrift.h"
#include "allegro5/internal/aintern_font.h"
#include "allegro5/internal/aintern_dtor.h"
#include "allegro5/internal/aintern_system.h"
#include "allegro5/internal/aintern_exitfunc.h"
#include "schrift.h"
#include <stdlib.h>
ALLEGRO_DEBUG_CHANNEL("font")
#define CANI_ALLEGRO_SCHRIFT_VER 1
/* globals */
static bool ttf_inited;
// Destroys the source bitmap and replaces it with a version
// expanded downward by add no. of pixels.
ALLEGRO_BITMAP *grow_bitmap(ALLEGRO_BITMAP *bmp, uint16_t add) {
const uint32_t h = al_get_bitmap_height(bmp) + add;
ALLEGRO_BITMAP *tgt = al_get_target_bitmap();
ALLEGRO_BITMAP *grown = al_create_bitmap(al_get_bitmap_width(bmp), h);
al_set_target_bitmap(grown);
al_draw_bitmap(bmp, 0, 0, 0);
al_set_target_bitmap(tgt);
al_destroy_bitmap(bmp);
return grown;
}
ALLEGRO_FONT *al_load_ttf_font_f(ALLEGRO_FILE *file,
char const *filename, int size, int flags)
{
#define CLEANUP free(filebuf); if (gtex) al_destroy_bitmap(gtex); al_set_target_bitmap(tgt)
#define FAIL CLEANUP; return NULL
const int64_t filesize = al_fsize(file); // this should not be signed!
if (filesize < 1) {
ALLEGRO_ERROR("Can't load font %s: file is empty or unknown size.\n", filename);
return NULL;
}
void *filebuf = malloc(filesize);
SFT sft = { .flags = SFT_DOWNWARD_Y };
ALLEGRO_FONT *f = NULL;
ALLEGRO_BITMAP *gtex = NULL;
int result = 0;
ALLEGRO_BITMAP *tgt = al_get_target_bitmap();
ALLEGRO_CONFIG* system_cfg = al_get_system_config();
const char* cache_text_str =
al_get_config_value(system_cfg, "ttf", "cache_text");
if (!cache_text_str) {
ALLEGRO_ERROR("No characters defined in cache_text, no glyphs to bake!\n", filename);
FAIL;
}
// read font file
#define chunksize 1024
size_t offset = 0;
while (!al_feof(file)) {
if (al_ferror(file)) {
ALLEGRO_ERROR("Can't load font %s: error reading file.\n", filename);
FAIL;
}
offset += al_fread(file, (uint8_t*)filebuf + offset, chunksize);
}
sft.xScale = size;
sft.yScale = size;
sft.font = sft_loadmem(filebuf, filesize);
if (!sft.font) {
ALLEGRO_ERROR("Can't load font %s: schrift error, is it a valid format?\n", filename);
FAIL;
}
// convert glyphs into textures todo
gtex = al_create_bitmap(2048, 2048);
uint16_t woff = 1, hoff = 0;
al_set_target_bitmap(gtex);
al_clear_to_color(al_map_rgba(0, 0, 0, 255));
unsigned int i = 0;
while (cache_text_str[i] != '\0') {
ALLEGRO_INFO("generating glyph for %c\n", cache_text_str[i]);
SFT_Glyph glyph;
SFT_GMetrics geom;
SFT_Image img;
ALLEGRO_LOCKED_REGION *block = NULL;
if (0 > sft_lookup(&sft, cache_text_str[i], &glyph)) goto glyph_lookup_fail;
ALLEGRO_INFO("got glyph\n");
if (0 > sft_gmetrics(&sft, glyph, &geom)) goto glyph_lookup_fail;
ALLEGRO_INFO("got geom\n");
block =
al_lock_bitmap_region(gtex, woff, hoff, geom.minWidth, geom.minHeight,
ALLEGRO_PIXEL_FORMAT_SINGLE_CHANNEL_8, ALLEGRO_LOCK_WRITEONLY);
ALLEGRO_INFO("got lock\n");
img.width = geom.minWidth;
img.height = geom.minHeight;
img.pixels = block->data;
if (0 > sft_render(&sft, glyph, img)) goto glyph_lookup_fail;
ALLEGRO_INFO("got raster\n");
al_unlock_bitmap(gtex);
ALLEGRO_INFO("unlock\n");
i++; continue;
glyph_lookup_fail:
ALLEGRO_ERROR("Failure generating glyph %c in %s!\n", cache_text_str[i], filename);
FAIL;
}
// debug
al_save_bitmap("schrift_test.png", gtex);
// convert texture to bitmap font
const unsigned int ranges_size = i*2;
int ranges[ranges_size];
i = 0;
while (i < ranges_size) {
ranges[i] = (unsigned char)cache_text_str[i];
ranges[i+1] = (unsigned char)cache_text_str[i];
i++; i++;
}
f = al_grab_font_from_bitmap(gtex, ranges_size, ranges);
f->dtor_item = _al_register_destructor(_al_dtor_list, "ttf_font", f,
(void (*)(void *))al_destroy_font);
ALLEGRO_DEBUG("Font %s loaded.\n", filename);
CLEANUP;
return f;
}
ALLEGRO_FONT *al_load_ttf_font(char const *filename, int size, int flags)
{
ALLEGRO_FILE *f;
ALLEGRO_FONT *font;
ASSERT(filename);
f = al_fopen(filename, "rb");
if (!f) {
ALLEGRO_ERROR("Unable to open file for reading: %s\n", filename);
return NULL;
}
font = al_load_ttf_font_f(f, filename, size, flags);
return font;
}
bool al_init_ttf_addon(void)
{
if (ttf_inited) {
ALLEGRO_WARN("TTF addon already initialised.\n");
return true;
}
al_register_font_loader(".ttf", al_load_ttf_font);
_al_add_exit_func(al_shutdown_ttf_addon, "al_shutdown_ttf_addon");
ttf_inited = true;
return ttf_inited;
}
bool al_is_ttf_addon_initialized(void)
{
return ttf_inited;
}
void al_shutdown_ttf_addon(void)
{
if (!ttf_inited) {
ALLEGRO_ERROR("TTF addon not initialised.\n");
return;
}
al_register_font_loader(".ttf", NULL);
ttf_inited = false;
}
uint32_t al_get_allegro_ttf_version(void)
{
return CANI_ALLEGRO_SCHRIFT_VER;
}
ALLEGRO_FONT *al_load_ttf_font_stretch(char const *filename, int w, int h, int flags) {
ALLEGRO_WARN("Unimplemented function\n");
al_load_ttf_font(filename, h, flags);
}
ALLEGRO_FONT *al_load_ttf_font_stretch_f(ALLEGRO_FILE *file, char const *filename, int w, int h, int flags) {
ALLEGRO_WARN("Unimplemented function\n");
al_load_ttf_font_f(file, filename, h, flags);
}