Files
korenkonder_ReDIVA/src/CRE/font.cpp
T

283 lines
8.0 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#include "font.hpp"
#include "data.hpp"
#include <map>
struct fontmap {
p_file_handler file_handler;
bool read;
prj::shared_ptr<prj::stack_allocator> alloc_handler;
font_handler handler[FONT_COUNT];
font font[FONT_COUNT];
fontmap();
~fontmap();
const font_handler* get_font_handler(int32_t index);
bool load_file();
void parse_file();
void read_file();
void set_font_handler(int32_t handler_index, int32_t font_index, bool disable_glyph_spacing = false);
};
struct font_character_file {
uint16_t id;
uint8_t halfwidth;
uint8_t pad;
uint8_t tex_column;
uint8_t tex_row;
uint8_t glyph_offset;
uint8_t glypth_width;
};
struct font_file {
int32_t map_id;
uint8_t character_advance_width;
uint8_t character_line_height;
uint8_t glyph_box_width;
uint8_t glyph_box_height;
uint8_t flags;
uint8_t column_scale_num;
uint8_t column_scale_denom;
uint8_t field_B;
uint32_t field_C;
uint32_t characters_count_per_row;
uint32_t characters_count;
uint32_t characters_offset;
};
struct fontmap_header {
uint32_t signature;
uint32_t pad;
uint32_t font_count;
uint32_t font_offsets_offset;
};
fontmap* fontmap_data;
static const font_character font_character_null = {};
font::font() : glyph_width(), glyph_height(), glyph_box_width(), glyph_box_height(),
column_scale_num(), column_scale_denom(), column_scale(), characters_count_per_row(), disable_glyph_spacing() {
sprite_id = -1;
map_id = -1;
}
font::~font() {
}
const font_character* font::get_character(wchar_t c) const {
if (c >= 0 && c < characters.size())
return &characters[c];
return &font_character_null;
}
void font::init(int32_t sprite_id, uint8_t glyph_width, uint8_t glyph_height,
uint8_t glyph_box_width, uint8_t glyph_box_height, uint8_t column_scale_num,
uint8_t column_scale_denom, int32_t map_id) {
this->sprite_id = sprite_id;
this->glyph_width = glyph_width;
this->glyph_height = glyph_height;
this->glyph_box_width = glyph_box_width;
this->glyph_box_height = glyph_box_height;
this->map_id = map_id;
set_column_scale(column_scale_num, column_scale_denom);
characters_count_per_row = 16;
if (characters.capacity() < 0x100)
characters.reserve(0x100);
font_character font_char = {};
font_char.init = true;
font_char.glyph_offset = 0;
for (int32_t i = 0; i < 0x100; i++) {
font_char.halfwidth = column_scale_denom != 1;
font_char.tex_row = (uint8_t)(i / characters_count_per_row);
font_char.tex_column = (uint8_t)(i % characters_count_per_row);
font_char.glyph_width = glyph_width;
characters.push_back(font_char);
}
}
void font::set_column_scale(uint8_t num, uint8_t denom) {
column_scale_num = num;
column_scale_denom = denom;
column_scale = (float_t)num / (float_t)denom;
}
void font_handler::set_font(const font* f, bool disable_glyph_spacing) {
font_ptr = f;
glyph_width = f->glyph_width;
glyph_height = f->glyph_height;
glyph_horizontal_spacing = 0;
glyph_vertical_spacing = 0;
disable_glyph_spacing = disable_glyph_spacing;
}
void fontmap_data_init() {
if (!fontmap_data)
fontmap_data = new fontmap;
}
const font_handler* fontmap_data_get_font_handler(int32_t index) {
return fontmap_data->get_font_handler(index);
}
bool fontmap_data_load_file() {
return fontmap_data->load_file();
}
void fontmap_data_read_file() {
fontmap_data->read_file();
}
void fontmap_data_free() {
if (fontmap_data) {
delete fontmap_data;
fontmap_data = 0;
}
}
fontmap::fontmap() : read(), handler() {
font[0].init(3348, 10, 16, 10, 16, 1, 1, -1);
font[1].init(2281, 12, 18, 14, 20, 1, 1, 12);
font[2].init(211, 24, 24, 26, 26, 1, 2, 0);
font[3].init(7365, 24, 24, 26, 26, 1, 2, 0);
font[4].init(1625, 12, 16, 14, 18, 1, 1, 5);
font[5].init(1390, 14, 20, 16, 22, 1, 1, 1);
font[6].init(1670, 14, 18, 16, 20, 1, 1, 9);
font[7].init(1602, 20, 26, 22, 28, 1, 1, 6);
font[8].init(38527, 20, 22, 22, 24, 1, 1, 14);
font[9].init(1695, 22, 22, 24, 24, 1, 1, 10);
font[10].init(1665, 22, 24, 24, 26, 1, 1, 11);
font[11].init(1391, 24, 30, 26, 32, 1, 1, 2);
font[12].init(1282, 26, 24, 28, 26, 1, 1, 3);
font[13].init(2853, 28, 40, 30, 42, 1, 1, 13);
font[14].init(8827, 28, 40, 30, 42, 1, 1, 13);
font[15].init(1283, 34, 32, 36, 34, 1, 1, 4);
font[16].init(1603, 40, 52, 42, 54, 1, 1, 7);
font[17].init(1604, 56, 46, 58, 48, 1, 1, 8);
set_font_handler(0, 0);
set_font_handler(15, 1);
set_font_handler(16, 2);
set_font_handler(17, 3);
set_font_handler(1, 4);
set_font_handler(2, 5);
set_font_handler(3, 6);
set_font_handler(4, 7);
set_font_handler(5, 8);
set_font_handler(6, 9);
set_font_handler(7, 10);
set_font_handler(8, 11);
set_font_handler(9, 12);
set_font_handler(10, 13);
set_font_handler(11, 14);
set_font_handler(12, 15);
set_font_handler(13, 16);
set_font_handler(14, 17);
}
fontmap::~fontmap() {
}
const font_handler* fontmap::get_font_handler(int32_t index) {
if (index < 0 || index >= FONT_COUNT)
index = 0;
return &handler[index];
}
bool fontmap::load_file() {
if (read)
return false;
if (file_handler.check_not_ready())
return true;
parse_file();
file_handler.reset();
read = true;
return false;
}
void fontmap::parse_file() {
size_t data = (size_t)file_handler.get_data();
fontmap_header* fmh = (fontmap_header*)data;
if (fmh->signature != reverse_endianness_uint32_t('FMH3'))
return;
std::map<int32_t, font_file*> font_map;
uint32_t* font_offsets = (uint32_t*)(data + fmh->font_offsets_offset);
for (uint32_t i = 0; i < fmh->font_count; i++) {
font_file* ff = (font_file*)(data + font_offsets[i]);
auto elem = font_map.find(ff->map_id);
if (elem != font_map.end())
elem->second = ff;
else
font_map.insert({ ff->map_id, ff });
}
for (::font& i : font) {
if (i.map_id == -1)
continue;
auto elem = font_map.find(i.map_id);
if (elem == font_map.end())
continue;
font_file* ff = elem->second;
i.set_column_scale(ff->column_scale_num, ff->column_scale_denom);
i.characters_count_per_row = ff->characters_count_per_row;
i.disable_glyph_spacing = (ff->flags & 2) != 0;
if (!ff->characters_count)
continue;
font_character_file* first_char = (font_character_file*)(data + ff->characters_offset);
font_character_file* last_char = &first_char[ff->characters_count];
font_character_file* max_char = first_char;
if (first_char != last_char)
for (font_character_file* j = first_char + 1; j != last_char; j++)
if (max_char->id < j->id)
max_char = j;
i.characters.clear();
i.characters.resize(max_char->id + 1ULL);
for (size_t k = 0; k < ff->characters_count; k++) {
font_character_file* c_f = &((font_character_file*)(data + ff->characters_offset))[k];
if (c_f->id < i.characters.size()) {
font_character* c = &i.characters.data()[c_f->id];
c->init = true;
c->halfwidth = !!c_f->halfwidth;
c->tex_column = c_f->tex_column;
c->tex_row = c_f->tex_row;
c->glyph_offset = c_f->glyph_offset;
c->glyph_width = c_f->glypth_width;
}
}
}
}
void fontmap::read_file() {
if (read)
return;
file_handler.read_file(&data_list[DATA_AFT], "rom/", "fontmap.farc", "fontmap.bin", false);
read = false;
}
void fontmap::set_font_handler(int32_t handler_index, int32_t font_index, bool disable_glyph_spacing) {
handler[handler_index].set_font(&font[font_index], disable_glyph_spacing);
}