Split up fonts/fonts.json into different files so each font can have a string ID.

This commit is contained in:
David Benepe
2022-03-31 12:50:31 -04:00
parent ab91bcf963
commit 5fe59a2a54
11 changed files with 114 additions and 49 deletions
+3 -2
View File
@@ -965,7 +965,8 @@
"build-id": "ASSET_FONTS",
"type": "Fonts",
"folder": "fonts",
"filenames": ["fonts"]
"filenames": ["fonts"],
"font-names": [ "FunFont", "SmallFont", "BigFont", "SubtitleFont" ]
},
{
"build-id": "ASSET_BINARY_45",
@@ -1039,4 +1040,4 @@
}
]
}
}
}
+9
View File
@@ -4816,6 +4816,15 @@ typedef enum {
ASSET_PARTICLE_BEHAVIORS_74
} AssetParticleBehaviorsEnum;
/********** ASSET_FONTS **********/
typedef enum {
ASSET_FONTS_FUNFONT,
ASSET_FONTS_SMALLFONT,
ASSET_FONTS_BIGFONT,
ASSET_FONTS_SUBTITLEFONT
} AssetFontsEnum;
/********** ASSET_TTGHOSTS **********/
typedef enum {
@@ -11,7 +11,12 @@
#define SIZEOF_CHAR_NODE 8
BuildFonts::BuildFonts(std::string srcPath, std::string dstPath) {
int numberOfFonts = get_array_length_from_json(srcPath, "fonts");
std::string fontFolderPath = get_directory_from_full_path(srcPath);
std::vector<std::string> fontIds = get_array_from_section("ASSET_FONTS", "fonts-order");
int numberOfFonts = fontIds.size();
std::vector<uint8_t> out(align16(SIZEOF_FONT * numberOfFonts + SIZEOF_FONTS_HEADER));
// Write header.
@@ -19,21 +24,23 @@ BuildFonts::BuildFonts(std::string srcPath, std::string dstPath) {
// Write fonts.
for(int font = 0; font < numberOfFonts; font++) {
std::string fontPath = fontFolderPath + "/" + get_string_from_json(srcPath, "fonts", fontIds[font]);
int fontOffset = font * SIZEOF_FONT + SIZEOF_FONTS_HEADER;
insert_ascii(out, fontOffset, get_string_from_json(srcPath, "fonts", font, "name"));
write_big_endian_halfword(out, fontOffset + 0x20, get_int_from_json(srcPath, "fonts", font, "fixed-width"));
write_big_endian_halfword(out, fontOffset + 0x22, get_int_from_json(srcPath, "fonts", font, "y-offset"));
write_big_endian_halfword(out, fontOffset + 0x24, get_int_from_json(srcPath, "fonts", font, "special-character-width"));
write_big_endian_halfword(out, fontOffset + 0x26, get_int_from_json(srcPath, "fonts", font, "tab-width"));
insert_ascii(out, fontOffset + 0x28, get_string_from_json(srcPath, "fonts", font, "unknown-text"));
insert_ascii(out, fontOffset, get_string_from_json(fontPath, "name"));
write_big_endian_halfword(out, fontOffset + 0x20, get_int_from_json(fontPath, "fixed-width"));
write_big_endian_halfword(out, fontOffset + 0x22, get_int_from_json(fontPath, "y-offset"));
write_big_endian_halfword(out, fontOffset + 0x24, get_int_from_json(fontPath, "special-character-width"));
write_big_endian_halfword(out, fontOffset + 0x26, get_int_from_json(fontPath, "tab-width"));
insert_ascii(out, fontOffset + 0x28, get_string_from_json(fontPath, "unknown-text"));
int numberOfTextures = get_array_length_from_json(srcPath, "fonts", font, "textures");
int numberOfTextures = get_array_length_from_json(fontPath, "textures");
int texOffset = fontOffset + 0x40;
int texIndex = 0;
// Write texture ids.
for(; texIndex < numberOfTextures; texIndex++) {
write_big_endian_halfword(out, texOffset, get_tex_2d_index_from_build_id(get_string_from_json(srcPath, "fonts", font, "textures", texIndex)));
write_big_endian_halfword(out, texOffset, get_tex_2d_index_from_build_id(get_string_from_json(fontPath, "textures", texIndex)));
texOffset += 2;
}
// Fill rest of the space with -1.
@@ -42,14 +49,14 @@ BuildFonts::BuildFonts(std::string srcPath, std::string dstPath) {
texOffset += 2;
}
std::string encoding = get_string_from_json(srcPath, "fonts", font, "encoding", "type");
std::string encoding = get_string_from_json(fontPath, "encoding", "type");
make_uppercase(encoding);
// Write character nodes
if(encoding == "ASCII") {
write_ascii_char_nodes(out, srcPath, fontOffset + 0x100, font);
write_ascii_char_nodes(out, fontPath, fontOffset + 0x100);
} else if(encoding == "CUSTOM") {
write_custom_char_nodes(out, srcPath, fontOffset + 0x100, font);
write_custom_char_nodes(out, fontPath, fontOffset + 0x100);
} else {
display_error_and_abort("Unsupported font encoding type: \"", encoding, "\"");
}
@@ -63,18 +70,18 @@ BuildFonts::~BuildFonts() {
}
void write_char_node(std::vector<uint8_t> &out, std::string srcPath, int nodeOffset, int font, std::string &chr) {
out[nodeOffset] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "tex-index");
out[nodeOffset + 1] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "char-width");
out[nodeOffset + 2] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "offset", 0); // X offset
out[nodeOffset + 3] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "offset", 1); // Y offset
out[nodeOffset + 4] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "uv", 0); // U coordinate
out[nodeOffset + 5] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "uv", 1); // V coordinate
out[nodeOffset + 6] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "tex-size", 0); // Width
out[nodeOffset + 7] = get_int_from_json(srcPath, "fonts", font, "characters", chr, "tex-size", 1); // Height
void write_char_node(std::vector<uint8_t> &out, std::string fontPath, int nodeOffset, std::string &chr) {
out[nodeOffset] = get_int_from_json(fontPath, "characters", chr, "tex-index");
out[nodeOffset + 1] = get_int_from_json(fontPath, "characters", chr, "char-width");
out[nodeOffset + 2] = get_int_from_json(fontPath, "characters", chr, "offset", 0); // X offset
out[nodeOffset + 3] = get_int_from_json(fontPath, "characters", chr, "offset", 1); // Y offset
out[nodeOffset + 4] = get_int_from_json(fontPath, "characters", chr, "uv", 0); // U coordinate
out[nodeOffset + 5] = get_int_from_json(fontPath, "characters", chr, "uv", 1); // V coordinate
out[nodeOffset + 6] = get_int_from_json(fontPath, "characters", chr, "tex-size", 0); // Width
out[nodeOffset + 7] = get_int_from_json(fontPath, "characters", chr, "tex-size", 1); // Height
}
void BuildFonts::write_ascii_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, int font) {
void BuildFonts::write_ascii_char_nodes(std::vector<uint8_t> &out, std::string fontPath, int offset) {
for(int node = CHAR_NODE_START_OFFSET; node < CHAR_NODE_END_OFFSET; node++) {
std::string chr;
if(node == 127) {
@@ -87,20 +94,20 @@ void BuildFonts::write_ascii_char_nodes(std::vector<uint8_t> &out, std::string s
chr = (char)node;
}
int nodeOffset = offset + (node - CHAR_NODE_START_OFFSET) * SIZEOF_CHAR_NODE;
write_char_node(out, srcPath, nodeOffset, font, chr);
write_char_node(out, fontPath, nodeOffset, chr);
}
}
void BuildFonts::write_custom_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, int font) {
void BuildFonts::write_custom_char_nodes(std::vector<uint8_t> &out, std::string fontPath, int offset) {
int index = 0;
std::vector<std::string> order = get_array_from_json(srcPath, "fonts", font, "encoding", "order");
std::vector<std::string> order = get_array_from_json(fontPath, "encoding", "order");
for(std::string &chr : order) {
if(index >= NUMBER_OF_CHAR_NODES) {
std::string fontName = get_string_from_json(srcPath, "fonts", font, "name");
std::string fontName = get_string_from_json(fontPath, "name");
display_error_and_abort("Too many character nodes in ", fontName, ". The limit is ", NUMBER_OF_CHAR_NODES);
}
int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE);
write_char_node(out, srcPath, nodeOffset, font, chr);
write_char_node(out, fontPath, nodeOffset, chr);
}
// Set the rest of the nodes to show nothing.
while(index < NUMBER_OF_CHAR_NODES) {
@@ -8,6 +8,6 @@ public:
BuildFonts(std::string srcPath, std::string dstPath);
~BuildFonts();
private:
void write_ascii_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, int font);
void write_custom_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset, int font);
void write_ascii_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset);
void write_custom_char_nodes(std::vector<uint8_t> &out, std::string srcPath, int offset);
};
@@ -92,7 +92,12 @@ void BuildGameText::build_textbox(std::vector<uint8_t> &out, std::string &srcPat
if(cmdType == "Text") {
write_ascii(out, get_string_from_json(srcPath, "pages", page, cmd, "value"));
} else if(cmdType == "SetFont") {
write_basic_command(out, 3, get_int_from_json(srcPath, "pages", page, cmd, "value"));
std::string fontId = get_string_from_json(srcPath, "pages", page, cmd, "value");
int fontIndex = get_index_of_string_array_value_from_section("ASSET_FONTS", fontId, "fonts-order");
if(fontIndex == -1) {
display_error_and_abort("Could not find the font \"", fontId, "\" in the \"fonts-order\" array in asset_fonts.json.");
}
write_basic_command(out, 3, fontIndex);
} else if(cmdType == "SetBorder") {
write_basic_command_4_args(out, 4,
get_int_from_json(srcPath, "pages", page, cmd, "value", "Left"),
@@ -127,6 +127,19 @@ inline int get_array_length_from_section(std::string sectionName, FirstKey const
return json_get(*json, key, rest_keys...).length();
}
template<typename FirstKey, typename ...RestKeys>
inline int get_index_of_string_array_value_from_section(std::string sectionName, std::string value, FirstKey const& key, RestKeys const&... rest_keys) {
json::JSON *json = get_section_json(sectionName);
std::vector<std::string> arr = get_array_from_section(sectionName, key, rest_keys...);
for(int i = 0; i < arr.size(); i++) {
if(arr[i] == value) {
return i;
}
}
return -1; // Value not found in array.
}
template<typename FirstKey, typename ...RestKeys>
inline bool section_has_key(std::string sectionName, FirstKey const& key, RestKeys const&... rest_keys) {
json::JSON *json = get_section_json(sectionName);
@@ -137,4 +150,3 @@ inline bool section_has_key(std::string sectionName, FirstKey const& key, RestKe
}
@@ -297,6 +297,18 @@ void ExtractConfig::extract_asset_sections(int &romOffset) {
}
sectionOut["filename"] = filename + get_extension_from_type(type);
extractions.push_back(ExtractInfo(build_id, type, folder, filename, sectionsData[i]));
if(type == "Fonts") {
//sectionOut["fonts"] = json::Object();
sectionOut["fonts-order"] = json::Array();
for(auto& fontName : section["font-names"].ArrayRange()) {
std::string fontid = "ASSET_FONTS_" + fontName.ToString();
make_uppercase(fontid);
//sectionOut["fonts"][fontid] = fontName.ToString() + ".json";
sectionOut["fonts-order"].append(fontid);
}
}
} else if (type == "Table") {
sectionOut["for"] = section["for"];
}
@@ -323,7 +335,7 @@ void write_vanilla_warning_file(std::string baseDirectory) {
void ExtractConfig::execute_extraction() {
// These braces are important, because I want the ThreadPool to call its destructor by going out of scope.
//{
{
ThreadPool pool(std::thread::hardware_concurrency());
//ThreadPool pool(1);
@@ -352,7 +364,7 @@ void ExtractConfig::execute_extraction() {
} else if(type == "Sprites") {
ExtractSprite(key, data, outFilepath + ".json", configJSON);
} else if(type == "Fonts") {
ExtractFonts(key, data, outFilepath + ".json", configJSON);
ExtractFonts(key, data, outFilepath + ".json", folder, configJSON);
} else if(is_binary_type(type)) {
ExtractBinary(key, data, outFilepath + ".bin");
} else if(is_compressed_type(type)) {
@@ -363,7 +375,7 @@ void ExtractConfig::execute_extraction() {
}
});
}
//}
}
}
void ExtractConfig::extract() {
@@ -1,21 +1,29 @@
#include "extract_fonts.h"
ExtractFonts::ExtractFonts(std::string key, std::vector<uint8_t> data, std::string outFilepath, json::JSON &configJSON)
#define SECTION_TEXTURE_2D_INDEX 4
#define SECTION_FONTS_INDEX 44
#define GAME_FONTS_FOLDERNAME "game_fonts"
ExtractFonts::ExtractFonts(std::string key, std::vector<uint8_t> data, std::string outFilepath, std::string folder, json::JSON &configJSON)
: Extract(key, data, outFilepath) {
json::JSON out = json::Object();
out["type"] = "Fonts";
out["fonts"] = json::Array();
//out["fonts-folder"] = GAME_FONTS_FOLDERNAME;
create_directory(folder + "/" + GAME_FONTS_FOLDERNAME);
out["fonts"] = json::Object();
int numberOfFonts = get_big_endian_word(data, 0);
for(int i = 0; i < numberOfFonts; i++) {
int offset = (i * 0x400) + 4; // Offset in file for this font.
std::string fontName = get_ascii(data, offset);
std::string fontId = "ASSET_FONTS_" + fontName;
make_uppercase(fontId);
json::JSON font = json::Object();
font["name"] = get_ascii(data, offset);
font["name"] = fontName;
font["unknown-text"] = get_ascii(data, offset + 0x28);
font["fixed-width"] = get_big_endian_halfword(data, offset + 0x20);
font["y-offset"] = get_big_endian_halfword(data, offset + 0x22);
@@ -27,7 +35,8 @@ ExtractFonts::ExtractFonts(std::string key, std::vector<uint8_t> data, std::stri
int texOffset = offset + 0x40;
int16_t texIndex = get_big_endian_halfword(data, texOffset);
while(texIndex != -1) {
font["textures"].append(configJSON["assets"]["sections"][4]["child-build-ids"][texIndex]);
json::JSON textureId = configJSON["assets"]["sections"][SECTION_TEXTURE_2D_INDEX]["child-build-ids"][texIndex];
font["textures"].append(textureId);
texOffset += 2;
texIndex = get_big_endian_halfword(data, texOffset);
}
@@ -63,10 +72,15 @@ ExtractFonts::ExtractFonts(std::string key, std::vector<uint8_t> data, std::stri
font["encoding"] = json::Object();
font["encoding"]["type"] = "ASCII";
std::string fontJsonFilename = GAME_FONTS_FOLDERNAME;
fontJsonFilename += "/" + fontName + ".json";
out["fonts"][fontId] = fontJsonFilename;
out["fonts"].append(font);
write_json(font, folder + "/" + fontJsonFilename);
}
out["type"] = "Fonts";
write_json(out, outFilepath);
print_extracted();
}
@@ -4,6 +4,6 @@
class ExtractFonts : Extract {
public:
ExtractFonts(std::string key, std::vector<uint8_t> data, std::string outFilepath, json::JSON &configJSON);
ExtractFonts(std::string key, std::vector<uint8_t> data, std::string outFilepath, std::string folder, json::JSON &configJSON);
~ExtractFonts();
};
@@ -100,7 +100,7 @@ void ExtractGameText::extract_textbox(json::JSON &out, std::vector<uint8_t> &dat
break;
case 3:
cmd["command"] = "SetFont";
cmd["value"] = data[offset++];
cmd["value"] = get_string_from_section("ASSET_FONTS", "fonts-order", data[offset++]);
break;
case 4:
cmd["command"] = "SetBorder";
@@ -23,9 +23,14 @@ AssetEnumsHeader::AssetEnumsHeader(std::string dstFolder) {
std::vector<std::string> sectionOrder = get_section_order(sectionName);
write_order_section(out, sectionName, sectionOrder);
}
if(get_string_from_section(sectionName, "type") == "MenuText") {
std::string sectionType = get_string_from_section(sectionName, "type");
if(sectionType == "MenuText") {
std::vector<std::string> menuTextBuildIds = get_array_from_section(sectionName, "menu-text-build-ids");
write_order_section(out, sectionName + "_IDS", menuTextBuildIds);
} else if (sectionType == "Fonts") {
std::vector<std::string> fonts = get_array_from_section(sectionName, "fonts-order");
write_header_comment(out, sectionName);
write_order_section(out, sectionName, fonts);
}
}
out << "#endif " << std::endl;