diff --git a/common/util/FontUtils.cpp b/common/util/FontUtils.cpp index 934803921d..d59c23c9fb 100644 --- a/common/util/FontUtils.cpp +++ b/common/util/FontUtils.cpp @@ -11,6 +11,8 @@ #include #include +#include +#include #include "string_util.h" @@ -37,6 +39,319 @@ GameTextVersion get_text_version_from_name(const std::string& name) { return sTextVerEnumMap.at(name); } +static constexpr u32 utf8_hangul_syllable_base = 0xEAB080; +static constexpr int utf8_hangul_lead_consonant_amount = 19; +static constexpr int utf8_hangul_vowel_amount = 21; +static constexpr int utf8_hangul_trail_consonant_amount = 28; + +// TABLE FORMAT +// 0 - TWO-JAMO SEQ 1 +// 1 - THREE-JAMO SEQ 1 +// 2 - TWO-JAMO SEQ 2 +// 3 - THREE-JAMO SEQ 2 + +// special sequences: +// 0x389 - [Xㅜㄴ] + +static std::vector> s_unsorted_hangul_lead_consonant = { + /* ㄱ */ {0x306}, + /* ㄲ */ {0x307}, + /* ㄴ */ {0x308, 0x31f}, + /* ㄷ */ {0x309, 0x370}, + /* ㄸ */ {0x30A}, + /* ㄹ */ {0x30b, 0x372}, + /* ㅁ */ {0x30C, 0x373}, + /* ㅂ */ {0x30d}, + /* ㅃ */ {0x30e}, + /* ㅅ */ {0x320}, + /* ㅆ */ {}, + /* ㅇ */ {0x30F, 0x378}, + /* ㅈ */ {0x310, 0x379}, + /* ㅉ */ {0x311}, + /* ㅊ */ {}, + /* ㅋ */ {0x312}, + /* ㅌ */ {0x313}, + /* ㅍ */ {0x314}, + /* ㅎ */ {0x32E}, +}; + +static std::vector> s_unsorted_hangul_vowel = { + /* ㅏ */ {0x31A, 0x315}, + /* ㅐ */ {}, + /* ㅑ */ {0x316, 0x31b}, + /* ㅒ */ {}, + /* ㅓ */ {0x31D, 0x318}, + /* ㅔ */ {}, + /* ㅕ */ {0x31E, 0x319}, + /* ㅖ */ {}, + /* ㅗ */ {0x382, 0x37F}, + /* ㅘ */ {}, + /* ㅙ */ {}, + /* ㅚ */ {}, + /* ㅛ */ {0x383}, + /* ㅜ */ {}, + /* ㅝ */ {}, + /* ㅞ */ {}, + /* ㅟ */ {}, + /* ㅠ */ {}, + /* ㅡ */ {0x384}, + /* ㅢ */ {}, + /* ㅣ */ {0x31C, 0x317}, +}; + +static std::vector> s_unsorted_hangul_trail_consonant = { + /* */ {}, + /* ㄱ */ {0x3C5, 0x3FE}, + /* ㄲ */ {}, + /* ㄳ */ {}, + /* ㄴ */ {0x3C8, 0x3FF}, + /* ㄵ */ {}, + /* ㄶ */ {}, + /* ㄷ */ {}, + /* ㄹ */ {0x3CC, 0x186}, + /* ㄺ */ {}, + /* ㄻ */ {}, + /* ㄼ */ {}, + /* ㄽ */ {}, + /* ㄾ */ {}, + /* ㄿ */ {}, + /* ㅀ */ {}, + /* ㅁ */ {0x187}, + /* ㅂ */ {0x188}, + /* ㅄ */ {}, + /* ㅅ */ {0x3D5, 0x189}, + /* ㅆ */ {0x3D6, 0x18A}, + /* ㅇ */ {0x3D7, 0x3EE, 0x18B}, + /* ㅈ */ {}, + /* ㅊ */ {}, + /* ㅋ */ {}, + /* ㅌ */ {}, + /* ㅍ */ {}, + /* ㅎ */ {}, +}; + +static std::vector> s_unsorted_hangul_other = { + /* */ {}, + /* ㄱ */ {0x3C5}, + /* ㄲ */ {}, + /* ㄳ */ {}, + /* ㄴ */ {0x3C8, 0x3C8}, + /* ㄵ */ {}, + /* ㄶ */ {}, + /* ㄷ */ {}, + /* ㄹ */ {0x3CC, 0x186}, + /* ㄺ */ {}, + /* ㄻ */ {}, + /* ㄼ */ {}, + /* ㄽ */ {}, + /* ㄾ */ {}, + /* ㄿ */ {}, + /* ㅀ */ {}, + /* ㅁ */ {0x187}, + /* ㅂ */ {0x188}, + /* ㅄ */ {}, + /* ㅅ */ {0x3D5, 0x189}, + /* ㅆ */ {0x3D6, 0x18A}, + /* ㅇ */ {0x3D7, 0x3EE, 0x18B}, + /* ㅈ */ {}, + /* ㅊ */ {}, + /* ㅋ */ {}, + /* ㅌ */ {}, + /* ㅍ */ {}, + /* ㅎ */ {}, +}; + +static std::vector> s_hangul_lead_consonant = { + /* ㄱ */ {0x306, 0x306, -9999, 0x306}, + /* ㄲ */ {-9999, -9999}, + /* ㄴ */ {-9999, -9999}, + /* ㄷ */ {-9999, -9999, 0x370, -9999}, + /* ㄸ */ {-9999, -9999}, + /* ㄹ */ {-9999, -9999, 0x372, -9999}, + /* ㅁ */ {-9999, 0x30C, 0x373, -9999}, + /* ㅂ */ {-9999, -9999}, + /* ㅃ */ {-9999, -9999}, + /* ㅅ */ {0x320, -9999}, + /* ㅆ */ {-9999, -9999}, + /* ㅇ */ {-9999, 0x30F, 0x30F, 0x30F, -9999, 0x378}, + /* ㅈ */ {0x310, 0x310, -9999, 0x379}, + /* ㅉ */ {-9999, -9999}, + /* ㅊ */ {-9999, -9999}, + /* ㅋ */ {-9999, -9999}, + /* ㅌ */ {-9999, -9999}, + /* ㅍ */ {-9999, -9999}, + /* ㅎ */ {0x32E, -9999}, +}; + +static std::vector> s_hangul_vowel = { + /* ㅏ */ {0x31A, 0x315, -9999, 0x31A}, + /* ㅐ */ {-9999, -9999}, + /* ㅑ */ {-9999, -9999}, + /* ㅒ */ {-9999, -9999}, + /* ㅓ */ {0x31D, 0x31D, -9999, 0x318}, + /* ㅔ */ {-9999, -9999}, + /* ㅕ */ {0x31E, 0x319}, + /* ㅖ */ {-9999, -9999}, + /* ㅗ */ {-9999, -9999, 0x382, 0x37F}, + /* ㅘ */ {-9999, -9999}, + /* ㅙ */ {-9999, -9999}, + /* ㅚ */ {-9999, -9999}, + /* ㅛ */ {-9999, -9999, 0x383, -9999}, + /* ㅜ */ {-9999, -9999}, + /* ㅝ */ {-9999, -9999}, + /* ㅞ */ {-9999, -9999}, + /* ㅟ */ {-9999, -9999}, + /* ㅠ */ {-9999, -9999}, + /* ㅡ */ {-9999, -9999, 0x384, -9999}, + /* ㅢ */ {-9999, -9999}, + /* ㅣ */ {0x31C, 0x317}, +}; + +static std::vector> s_hangul_trail_consonant = { + /* */ {-9999}, + /* ㄱ */ {0x3C5}, + /* ㄲ */ {-9999}, + /* ㄳ */ {-9999}, + /* ㄴ */ {0x3C8, 0x3C8}, + /* ㄵ */ {-9999}, + /* ㄶ */ {-9999}, + /* ㄷ */ {-9999}, + /* ㄹ */ {0x3CC}, + /* ㄺ */ {-9999}, + /* ㄻ */ {-9999}, + /* ㄼ */ {-9999}, + /* ㄽ */ {-9999}, + /* ㄾ */ {-9999}, + /* ㄿ */ {-9999}, + /* ㅀ */ {-9999}, + /* ㅁ */ {-9999}, + /* ㅂ */ {-9999}, + /* ㅄ */ {-9999}, + /* ㅅ */ {0x3D5}, + /* ㅆ */ {0x3D6}, + /* ㅇ */ {0x3D7, 0x3EE}, + /* ㅈ */ {-9999}, + /* ㅊ */ {-9999}, + /* ㅋ */ {-9999}, + /* ㅌ */ {-9999}, + /* ㅍ */ {-9999}, + /* ㅎ */ {-9999}, +}; + + +// temp +//static std::vector> s_hangul_lead_consonant = { +// /* ㄱ */ {0x306, 0x31F, 0x333, 0x35e}, +// /* ㄲ */ {0x307, -9999, 0x334}, +// /* ㄴ */ {0x308, -9999, 0x335, 0x34a}, +// /* ㄷ */ {0x309, 0x326, 0x336, 0x351}, +// /* ㄸ */ {0x30A, 0x327, 0x337, 0x352}, +// /* ㄹ */ {0x30B, 0x328, 0x338, 0x353}, +// /* ㅁ */ {0x30C, -9999, 0x339}, +// /* ㅂ */ {0x30D, -9999, 0x33a}, +// /* ㅃ */ {0x30E, -9999, 0x33b}, +// /* ㅅ */ {-9999, 0x320, 0x34b}, +// /* ㅆ */ {-9999, 0x321, 0x34c}, +// /* ㅇ */ {0x30F, -9999, 0x33c}, +// /* ㅈ */ {0x310, -9999, 0x33d}, +// /* ㅉ */ {0x311, -9999, 0x33e}, +// /* ㅊ */ {0x32D, 0x358}, +// /* ㅋ */ {0x312, -9999, 0x33f, 0x35f}, +// /* ㅌ */ {0x313, 0x329, 0x340, 0x354}, +// /* ㅍ */ {0x314, 0x32A, 0x341, 0x355}, +// /* ㅎ */ {0x32E, 0x359}, +//}; +//static std::vector> s_hangul_vowel_trio = { +// /* ㅏ */ {0x315, -9999}, +// /* ㅐ */ {0x342, -9999}, +// /* ㅑ */ {0x316, -9999}, +// /* ㅒ */ {0x343, -9999}, +// /* ㅓ */ {0x318, 0x322, 0x32F}, +// /* ㅔ */ {0x344, 0x34d, 0x35a}, +// /* ㅕ */ {0x319, 0x323, 0x32B, 0x330}, +// /* ㅖ */ {0x345, 0x34e, 0x356, 0x35b}, +// /* ㅗ */ {0x360, 0x362}, +// /* ㅘ */ {-9999, -9999}, +// /* ㅙ */ {-9999, -9999}, +// /* ㅚ */ {-9999, -9999}, +// /* ㅛ */ {0x361, 0x363}, +// /* ㅜ */ {-9999, -9999}, +// /* ㅝ */ {-9999, -9999}, +// /* ㅞ */ {-9999, -9999}, +// /* ㅟ */ {-9999, -9999}, +// /* ㅠ */ {-9999, -9999}, +// /* ㅡ */ {-9999, -9999}, +// /* ㅢ */ {-9999, -9999}, +// /* ㅣ */ {0x317, -9999}, +//}; +//static std::vector> s_hangul_vowel_duo = { +// /* ㅏ */ {0x31A, -9999}, +// /* ㅐ */ {0x346, -9999}, +// /* ㅑ */ {0x31B, -9999}, +// /* ㅒ */ {0x347, -9999}, +// /* ㅓ */ {0x31D, 0x324, 0x331}, +// /* ㅔ */ {0x348, 0x34f, 0x35c}, +// /* ㅕ */ {0x31E, 0x325, 0x32C, 0x332}, +// /* ㅖ */ {0x349, 0x350, 0x357, 0x35d}, +// /* ㅗ */ {-9999, -9999}, +// /* ㅘ */ {-9999, -9999}, +// /* ㅙ */ {-9999, -9999}, +// /* ㅚ */ {-9999, -9999}, +// /* ㅛ */ {-9999, -9999}, +// /* ㅜ */ {-9999, -9999}, +// /* ㅝ */ {-9999, -9999}, +// /* ㅞ */ {-9999, -9999}, +// /* ㅟ */ {-9999, -9999}, +// /* ㅠ */ {-9999, -9999}, +// /* ㅡ */ {-9999, -9999}, +// /* ㅢ */ {-9999, -9999}, +// /* ㅣ */ {0x31C, -9999}, +//}; + +static std::vector seqs = {}; + +std::string convert_korean_text_from_game(const char* in) { + std::string out; + while (*in) { + if (*in == 3) { + ++in; + while (*in && *in != 3 && *in != 4) { + out.push_back(*in); + ++in; + } + } else { + ++in; + int len = *in; + ++in; + int i = 0; + bool save_seq = true; + u64 seq = 0; + while (*in && *in != 3 && *in != 4) { + if (*in == 5) { + ++in; + if (save_seq) { + seq |= (0x100ULL | u8(*in)) << (i * 16); + } + out.push_back(0x1); + } else { + if (save_seq) { + seq |= (0x300ULL | u8(*in)) << (i * 16); + } + out.push_back(0x3); + } + out.push_back(*in); + ++in; + ++i; + } + if (save_seq && std::find(seqs.begin(), seqs.end(), seq) == seqs.end()) { + seqs.push_back(seq); + std::sort(seqs.begin(), seqs.end()); + } + } + } + return out; +} + GameTextFontBank::GameTextFontBank(GameTextVersion version, std::vector* encode_info, std::vector* replace_info, @@ -53,6 +368,71 @@ GameTextFontBank::GameTextFontBank(GameTextVersion version, [](const ReplaceInfo& a, const ReplaceInfo& b) { return a.from.size() > b.from.size(); }); } +GameTextFontBank::~GameTextFontBank() { + if (!seqs.empty()) { + printf("\nall seqs:\n"); + std::vector> all_jamo_by_pos(4); + std::vector all_jamo; + for (auto seq : seqs) { + for (int i = 0; i < 4; ++i) { + u16 v = (seq >> (i * 16)) & 0xffff; + if (v == 0) { + break; + } + auto& jamo_seq = all_jamo_by_pos.at(i); + if (std::find(jamo_seq.begin(), jamo_seq.end(), v) == jamo_seq.end()) { + jamo_seq.push_back(v); + } + if (std::find(all_jamo.begin(), all_jamo.end(), v) == all_jamo.end()) { + all_jamo.push_back(v); + } + // printf("0x%x ", v); + } + // printf("\n"); + } + + std::sort(all_jamo_by_pos.at(0).begin(), all_jamo_by_pos.at(0).end()); + std::sort(all_jamo_by_pos.at(1).begin(), all_jamo_by_pos.at(1).end()); + std::sort(all_jamo_by_pos.at(2).begin(), all_jamo_by_pos.at(2).end()); + std::sort(all_jamo_by_pos.at(3).begin(), all_jamo_by_pos.at(3).end()); + std::sort(all_jamo.begin(), all_jamo.end()); + printf("\nall first jamo:\n"); + for (auto v : all_jamo_by_pos.at(0)) { + printf("0x%x\n", v); + } + printf("\nall second jamo:\n"); + for (auto v : all_jamo_by_pos.at(1)) { + printf("0x%x\n", v); + } + printf("\nall third jamo:\n"); + for (auto v : all_jamo_by_pos.at(2)) { + printf("0x%x\n", v); + } + printf("\nall fourth jamo:\n"); + for (auto v : all_jamo_by_pos.at(3)) { + printf("0x%x\n", v); + } + printf("\nall jamo:\n"); + for (auto v : all_jamo) { + printf("%x ", v); + if (std::find(all_jamo_by_pos.at(0).begin(), all_jamo_by_pos.at(0).end(), v) != + all_jamo_by_pos.at(0).end()) { + printf("pos 1\n"); + } else if (std::find(all_jamo_by_pos.at(1).begin(), all_jamo_by_pos.at(1).end(), v) != + all_jamo_by_pos.at(1).end()) { + printf("pos 2\n"); + } else if (std::find(all_jamo_by_pos.at(2).begin(), all_jamo_by_pos.at(2).end(), v) != + all_jamo_by_pos.at(2).end()) { + printf("pos 3\n"); + } else if (std::find(all_jamo_by_pos.at(3).begin(), all_jamo_by_pos.at(3).end(), v) != + all_jamo_by_pos.at(3).end()) { + printf("pos 4\n"); + } + } + seqs.clear(); + } +} + /*! * Finds a remap info that best matches the byte sequence (is the longest match). */ @@ -273,9 +653,15 @@ bool GameTextFontBank::valid_char_range(const char in) const { * Convert a string from the game-text font encoding to something normal. * Unprintable characters become escape sequences, including tab and newline. */ -std::string GameTextFontBank::convert_game_to_utf8(const char* in) const { +std::string GameTextFontBank::convert_game_to_utf8(const char* in, bool korean) const { std::string temp; std::string result; + + if (korean) { + result = convert_korean_text_from_game(in); + in = result.c_str(); + } + while (*in) { auto remap = find_encode_to_utf8(in); if (remap != nullptr) { @@ -288,7 +674,10 @@ std::string GameTextFontBank::convert_game_to_utf8(const char* in) const { } in++; } + replace_to_utf8(temp); + result.clear(); + for (size_t i = 0; i < temp.length(); ++i) { auto c = temp.at(i); if (c == '\n') { @@ -906,7 +1295,9 @@ GameTextFontBank g_font_bank_jak1_v2(GameTextVersion::JAK1_V2, * GAME TEXT FONT BANK - JAK 2 * ================================ * This font is used in: - * - Jak 2 - NTSC - v1 + * - Jak II (NTSC-U, NTSC-K) + * - Jak II - Renegade + * - ジャックXダクスター2 */ static std::unordered_set s_passthrus_jak2 = {'~', ' ', ',', '.', '-', '+', '(', ')', @@ -1559,262 +1950,267 @@ static std::vector s_encode_info_jak2 = { {"刻", {2, 0x8c}}, {"足", {2, 0x8d}}, - {"", {3, 0x00}}, - {"", {3, 0x01}}, - {"", {3, 0x02}}, - {"", {3, 0x03}}, - {"", {3, 0x04}}, - {"", {3, 0x05}}, - {"", {3, 0x06}}, - {"", {3, 0x07}}, - {"", {3, 0x08}}, - {"", {3, 0x09}}, - {"", {3, 0x0a}}, - {"", {3, 0x0b}}, - {"", {3, 0x0c}}, - {"", {3, 0x0d}}, - {"", {3, 0x0e}}, - {"", {3, 0x0f}}, - {"", {3, 0x10}}, - {"", {3, 0x11}}, - {"", {3, 0x12}}, - {"", {3, 0x13}}, - {"", {3, 0x14}}, - {"", {3, 0x15}}, - {"", {3, 0x16}}, - {"", {3, 0x17}}, - {"", {3, 0x18}}, - {"", {3, 0x19}}, - {"", {3, 0x1a}}, - {"", {3, 0x1b}}, - {"", {3, 0x1c}}, - {"", {3, 0x1d}}, - {"", {3, 0x1e}}, - {"", {3, 0x1f}}, - {"", {3, 0x20}}, - {"", {3, 0x21}}, - {"", {3, 0x22}}, - {"", {3, 0x23}}, - {"", {3, 0x24}}, - {"", {3, 0x25}}, - {"", {3, 0x26}}, - {"", {3, 0x27}}, - {"", {3, 0x28}}, - {"", {3, 0x29}}, - {"", {3, 0x2a}}, - {"", {3, 0x2b}}, - {"", {3, 0x2c}}, - {"", {3, 0x2d}}, - {"", {3, 0x2e}}, - {"", {3, 0x2f}}, - {"", {3, 0x30}}, - {"", {3, 0x31}}, - {"", {3, 0x32}}, - {"", {3, 0x33}}, - {"", {3, 0x34}}, - {"", {3, 0x35}}, - {"", {3, 0x36}}, - {"", {3, 0x37}}, - {"", {3, 0x38}}, - {"", {3, 0x39}}, - {"", {3, 0x3a}}, - {"", {3, 0x3b}}, - {"", {3, 0x3c}}, - {"", {3, 0x3d}}, - {"", {3, 0x3e}}, - {"", {3, 0x3f}}, - {"", {3, 0x40}}, - {"", {3, 0x41}}, - {"", {3, 0x42}}, - {"", {3, 0x43}}, - {"", {3, 0x44}}, - {"", {3, 0x45}}, - {"", {3, 0x46}}, - {"", {3, 0x47}}, - {"", {3, 0x48}}, - {"", {3, 0x49}}, - {"", {3, 0x4a}}, - {"", {3, 0x4b}}, - {"", {3, 0x4c}}, - {"", {3, 0x4d}}, - {"", {3, 0x4e}}, - {"", {3, 0x4f}}, - {"", {3, 0x50}}, - {"", {3, 0x51}}, - {"", {3, 0x52}}, - {"", {3, 0x53}}, - {"", {3, 0x54}}, - {"", {3, 0x55}}, - {"", {3, 0x56}}, - {"", {3, 0x57}}, - {"", {3, 0x58}}, - {"", {3, 0x59}}, - {"", {3, 0x5a}}, - {"", {3, 0x5b}}, - {"", {3, 0x5c}}, - {"", {3, 0x5d}}, - {"", {3, 0x5e}}, - {"", {3, 0x5f}}, - {"", {3, 0x60}}, - {"", {3, 0x61}}, - {"", {3, 0x62}}, - {"", {3, 0x63}}, - {"", {3, 0x64}}, - {"", {3, 0x65}}, - {"", {3, 0x66}}, - {"", {3, 0x67}}, - {"", {3, 0x68}}, - {"", {3, 0x69}}, - {"", {3, 0x6a}}, - {"", {3, 0x6b}}, - {"", {3, 0x6c}}, - {"", {3, 0x6d}}, - {"", {3, 0x6e}}, - {"", {3, 0x6f}}, - {"", {3, 0x70}}, - {"", {3, 0x71}}, - {"", {3, 0x72}}, - {"", {3, 0x73}}, - {"", {3, 0x74}}, - {"", {3, 0x75}}, - {"", {3, 0x76}}, - {"", {3, 0x77}}, - {"", {3, 0x78}}, - {"", {3, 0x79}}, - {"", {3, 0x7a}}, - {"", {3, 0x7b}}, - {"", {3, 0x7c}}, - {"", {3, 0x7d}}, - {"", {3, 0x7e}}, - {"", {3, 0x7f}}, - {"", {3, 0x80}}, - {"", {3, 0x81}}, - {"", {3, 0x82}}, - {"", {3, 0x83}}, - {"", {3, 0x84}}, - {"", {3, 0x85}}, - {"", {3, 0x86}}, - {"", {3, 0x87}}, - {"", {3, 0x88}}, - {"", {3, 0x89}}, - {"", {3, 0x8a}}, - {"", {3, 0x8b}}, - {"", {3, 0x8c}}, - {"", {3, 0x8d}}, - {"", {3, 0x8e}}, - {"", {3, 0x8f}}, - {"", {3, 0x90}}, - {"", {3, 0x91}}, - {"", {3, 0x92}}, - {"", {3, 0x93}}, - {"", {3, 0x94}}, - {"", {3, 0x95}}, - {"", {3, 0x96}}, - {"", {3, 0x97}}, - {"", {3, 0x98}}, - {"", {3, 0x99}}, - {"", {3, 0x9a}}, - {"", {3, 0x9b}}, - {"", {3, 0x9c}}, - {"", {3, 0x9d}}, - {"", {3, 0x9e}}, - {"", {3, 0x9f}}, - {"", {3, 0xa0}}, - {"", {3, 0xa1}}, - {"", {3, 0xa2}}, - {"", {3, 0xa3}}, - {"", {3, 0xa4}}, - {"", {3, 0xa5}}, - {"", {3, 0xa6}}, - {"", {3, 0xa7}}, - {"", {3, 0xa8}}, - {"", {3, 0xa9}}, - {"", {3, 0xaa}}, - {"", {3, 0xab}}, - {"", {3, 0xac}}, - {"", {3, 0xad}}, - {"", {3, 0xae}}, - {"", {3, 0xaf}}, - {"", {3, 0xb0}}, - {"", {3, 0xb1}}, - {"", {3, 0xb2}}, - {"", {3, 0xb3}}, - {"", {3, 0xb4}}, - {"", {3, 0xb5}}, - {"", {3, 0xb6}}, - {"", {3, 0xb7}}, - {"", {3, 0xb8}}, - {"", {3, 0xb9}}, - {"", {3, 0xba}}, - {"", {3, 0xbb}}, - {"", {3, 0xbc}}, - {"", {3, 0xbd}}, - {"", {3, 0xbe}}, - {"", {3, 0xbf}}, - {"", {3, 0xc0}}, - {"", {3, 0xc1}}, - {"", {3, 0xc2}}, - {"", {3, 0xc3}}, - {"", {3, 0xc4}}, - {"", {3, 0xc5}}, - {"", {3, 0xc6}}, - {"", {3, 0xc7}}, - {"", {3, 0xc8}}, - {"", {3, 0xc9}}, - {"", {3, 0xca}}, - {"", {3, 0xcb}}, - {"", {3, 0xcc}}, - {"", {3, 0xcd}}, - {"", {3, 0xce}}, - {"", {3, 0xcf}}, - {"", {3, 0xd0}}, - {"", {3, 0xd1}}, - {"", {3, 0xd2}}, - {"", {3, 0xd3}}, - {"", {3, 0xd4}}, - {"", {3, 0xd5}}, - {"", {3, 0xd6}}, - {"", {3, 0xd7}}, - {"", {3, 0xd8}}, - {"", {3, 0xd9}}, - {"", {3, 0xda}}, - {"", {3, 0xdb}}, - {"", {3, 0xdc}}, - {"", {3, 0xdd}}, - {"", {3, 0xde}}, - {"", {3, 0xdf}}, - {"", {3, 0xe0}}, - {"", {3, 0xe1}}, - {"", {3, 0xe2}}, - {"", {3, 0xe3}}, - {"", {3, 0xe4}}, - {"", {3, 0xe5}}, - {"", {3, 0xe6}}, - {"", {3, 0xe7}}, - {"", {3, 0xe8}}, - {"", {3, 0xe9}}, - {"", {3, 0xea}}, - {"", {3, 0xeb}}, - {"", {3, 0xec}}, - {"", {3, 0xed}}, - {"", {3, 0xee}}, - {"", {3, 0xef}}, - {"", {3, 0xf0}}, - {"", {3, 0xf1}}, - {"", {3, 0xf2}}, - {"", {3, 0xf3}}, - {"", {3, 0xf4}}, - {"", {3, 0xf5}}, - {"", {3, 0xf6}}, - {"", {3, 0xf7}}, - {"", {3, 0xf8}}, - {"", {3, 0xf9}}, - {"", {3, 0xfa}}, - {"", {3, 0xfb}}, - {"", {3, 0xfc}}, - {"", {3, 0xfd}}, - {"", {3, 0xfe}}, - {"", {3, 0xff}}, + //{"", {3, 0x00}}, + //{"", {3, 0x01}}, + //{"", {3, 0x02}}, + //{"", {3, 0x03}}, + //{"", {3, 0x04}}, + //{"", {3, 0x05}}, + {"", {1, 0x86}}, + {"", {1, 0x87}}, + {"", {1, 0x88}}, + {"", {1, 0x89}}, + {"", {1, 0x8a}}, + {"", {3, 0x06}}, + {"", {3, 0x07}}, + {"", {3, 0x08}}, + {"", {3, 0x09}}, + {"", {3, 0x0a}}, + {"", {3, 0x0b}}, + {"", {3, 0x0c}}, + {"", {3, 0x0d}}, + {"", {3, 0x0e}}, + {"", {3, 0x0f}}, + {"", {3, 0x10}}, + {"", {3, 0x11}}, + {"", {3, 0x12}}, + {"", {3, 0x13}}, + {"", {3, 0x14}}, + {"", {3, 0x15}}, + {"", {3, 0x16}}, + {"", {3, 0x17}}, + {"", {3, 0x18}}, + {"", {3, 0x19}}, + {"", {3, 0x1a}}, + {"", {3, 0x1b}}, + {"", {3, 0x1c}}, + {"", {3, 0x1d}}, + {"", {3, 0x1e}}, + {"", {3, 0x1f}}, + {"", {3, 0x20}}, + {"", {3, 0x21}}, + {"", {3, 0x22}}, + {"", {3, 0x23}}, + {"", {3, 0x24}}, + {"", {3, 0x25}}, + {"", {3, 0x26}}, + {"", {3, 0x27}}, + {"", {3, 0x28}}, + {"", {3, 0x29}}, + {"", {3, 0x2a}}, + {"", {3, 0x2b}}, + {"", {3, 0x2c}}, + {"", {3, 0x2d}}, + {"", {3, 0x2e}}, + {"", {3, 0x2f}}, + {"", {3, 0x30}}, + {"", {3, 0x31}}, + {"", {3, 0x32}}, + {"", {3, 0x33}}, + {"", {3, 0x34}}, + {"", {3, 0x35}}, + {"", {3, 0x36}}, + {"", {3, 0x37}}, + {"", {3, 0x38}}, + {"", {3, 0x39}}, + {"", {3, 0x3a}}, + {"", {3, 0x3b}}, + {"", {3, 0x3c}}, + {"", {3, 0x3d}}, + {"", {3, 0x3e}}, + {"", {3, 0x3f}}, + {"", {3, 0x40}}, + {"", {3, 0x41}}, + {"", {3, 0x42}}, + {"", {3, 0x43}}, + {"", {3, 0x44}}, + {"", {3, 0x45}}, + {"", {3, 0x46}}, + {"", {3, 0x47}}, + {"", {3, 0x48}}, + {"", {3, 0x49}}, + {"", {3, 0x4a}}, + {"", {3, 0x4b}}, + {"", {3, 0x4c}}, + {"", {3, 0x4d}}, + {"", {3, 0x4e}}, + {"", {3, 0x4f}}, + {"", {3, 0x50}}, + {"", {3, 0x51}}, + {"", {3, 0x52}}, + {"", {3, 0x53}}, + {"", {3, 0x54}}, + {"", {3, 0x55}}, + {"", {3, 0x56}}, + {"", {3, 0x57}}, + {"", {3, 0x58}}, + {"", {3, 0x59}}, + {"", {3, 0x5a}}, + {"", {3, 0x5b}}, + {"", {3, 0x5c}}, + {"", {3, 0x5d}}, + {"", {3, 0x5e}}, + {"", {3, 0x5f}}, + {"", {3, 0x60}}, + {"", {3, 0x61}}, + {"", {3, 0x62}}, + {"", {3, 0x63}}, + {"", {3, 0x64}}, + {"", {3, 0x65}}, + {"", {3, 0x66}}, + {"", {3, 0x67}}, + {"", {3, 0x68}}, + {"", {3, 0x69}}, + {"", {3, 0x6a}}, + {"", {3, 0x6b}}, + {"", {3, 0x6c}}, + {"", {3, 0x6d}}, + {"", {3, 0x6e}}, + {"", {3, 0x6f}}, + {"", {3, 0x70}}, + {"", {3, 0x71}}, + {"", {3, 0x72}}, + {"", {3, 0x73}}, + {"", {3, 0x74}}, + {"", {3, 0x75}}, + {"", {3, 0x76}}, + {"", {3, 0x77}}, + {"", {3, 0x78}}, + {"", {3, 0x79}}, + {"", {3, 0x7a}}, + {"", {3, 0x7b}}, + {"", {3, 0x7c}}, + {"", {3, 0x7d}}, + {"", {3, 0x7e}}, + {"", {3, 0x7f}}, + {"", {3, 0x80}}, + {"", {3, 0x81}}, + {"", {3, 0x82}}, + {"", {3, 0x83}}, + {"", {3, 0x84}}, + {"", {3, 0x85}}, + {"", {3, 0x86}}, + {"", {3, 0x87}}, + {"", {3, 0x88}}, + {"", {3, 0x89}}, + {"", {3, 0x8a}}, + {"", {3, 0x8b}}, + {"", {3, 0x8c}}, + {"", {3, 0x8d}}, + {"", {3, 0x8e}}, + {"", {3, 0x8f}}, + {"", {3, 0x90}}, + {"", {3, 0x91}}, + {"", {3, 0x92}}, + {"", {3, 0x93}}, + {"", {3, 0x94}}, + {"", {3, 0x95}}, + {"", {3, 0x96}}, + {"", {3, 0x97}}, + {"", {3, 0x98}}, + {"", {3, 0x99}}, + {"", {3, 0x9a}}, + {"", {3, 0x9b}}, + {"", {3, 0x9c}}, + {"", {3, 0x9d}}, + {"", {3, 0x9e}}, + {"", {3, 0x9f}}, + {"", {3, 0xa0}}, + {"", {3, 0xa1}}, + {"", {3, 0xa2}}, + {"", {3, 0xa3}}, + {"", {3, 0xa4}}, + {"", {3, 0xa5}}, + {"", {3, 0xa6}}, + {"", {3, 0xa7}}, + {"", {3, 0xa8}}, + {"", {3, 0xa9}}, + {"", {3, 0xaa}}, + {"", {3, 0xab}}, + {"", {3, 0xac}}, + {"", {3, 0xad}}, + {"", {3, 0xae}}, + {"", {3, 0xaf}}, + {"", {3, 0xb0}}, + {"", {3, 0xb1}}, + {"", {3, 0xb2}}, + {"", {3, 0xb3}}, + {"", {3, 0xb4}}, + {"", {3, 0xb5}}, + {"", {3, 0xb6}}, + {"", {3, 0xb7}}, + {"", {3, 0xb8}}, + {"", {3, 0xb9}}, + {"", {3, 0xba}}, + {"", {3, 0xbb}}, + {"", {3, 0xbc}}, + {"", {3, 0xbd}}, + {"", {3, 0xbe}}, + {"", {3, 0xbf}}, + {"", {3, 0xc0}}, + {"", {3, 0xc1}}, + {"", {3, 0xc2}}, + {"", {3, 0xc3}}, + {"", {3, 0xc4}}, + {"", {3, 0xc5}}, + {"", {3, 0xc6}}, + {"", {3, 0xc7}}, + {"", {3, 0xc8}}, + {"", {3, 0xc9}}, + {"", {3, 0xca}}, + {"", {3, 0xcb}}, + {"", {3, 0xcc}}, + {"", {3, 0xcd}}, + {"", {3, 0xce}}, + {"", {3, 0xcf}}, + {"", {3, 0xd0}}, + {"", {3, 0xd1}}, + {"", {3, 0xd2}}, + {"", {3, 0xd3}}, + {"", {3, 0xd4}}, + {"", {3, 0xd5}}, + {"", {3, 0xd6}}, + {"", {3, 0xd7}}, + {"", {3, 0xd8}}, + {"", {3, 0xd9}}, + {"", {3, 0xda}}, + {"", {3, 0xdb}}, + {"", {3, 0xdc}}, + {"", {3, 0xdd}}, + {"", {3, 0xde}}, + {"", {3, 0xdf}}, + {"", {3, 0xe0}}, + {"", {3, 0xe1}}, + {"", {3, 0xe2}}, + {"", {3, 0xe3}}, + {"", {3, 0xe4}}, + {"", {3, 0xe5}}, + {"", {3, 0xe6}}, + {"", {3, 0xe7}}, + {"", {3, 0xe8}}, + {"", {3, 0xe9}}, + {"", {3, 0xea}}, + {"", {3, 0xeb}}, + {"", {3, 0xec}}, + {"", {3, 0xed}}, + {"", {3, 0xee}}, + {"", {3, 0xef}}, + {"", {3, 0xf0}}, + {"", {3, 0xf1}}, + {"", {3, 0xf2}}, + {"", {3, 0xf3}}, + {"", {3, 0xf4}}, + {"", {3, 0xf5}}, + {"", {3, 0xf6}}, + {"", {3, 0xf7}}, + {"", {3, 0xf8}}, + {"", {3, 0xf9}}, + {"", {3, 0xfa}}, + {"", {3, 0xfb}}, + {"", {3, 0xfc}}, + {"", {3, 0xfd}}, + {"", {3, 0xfe}}, + {"", {3, 0xff}}, }; GameTextFontBank g_font_bank_jak2(GameTextVersion::JAK2, diff --git a/common/util/FontUtils.h b/common/util/FontUtils.h index baff0316d1..9fd6264e58 100644 --- a/common/util/FontUtils.h +++ b/common/util/FontUtils.h @@ -71,6 +71,7 @@ class GameTextFontBank { std::vector* encode_info, std::vector* replace_info, std::unordered_set* passthrus); + ~GameTextFontBank(); const std::vector* encode_info() const { return m_encode_info; } const std::vector* replace_info() const { return m_replace_info; } @@ -83,7 +84,7 @@ class GameTextFontBank { bool valid_char_range(const char in) const; std::string convert_utf8_to_game(std::string str, bool escape = false) const; - std::string convert_game_to_utf8(const char* in) const; + std::string convert_game_to_utf8(const char* in, bool korean) const; }; extern GameTextFontBank g_font_bank_jak1_v1; diff --git a/decompiler/config/jak2/ntsc_v1/var_names.jsonc b/decompiler/config/jak2/ntsc_v1/var_names.jsonc index e490f35c39..e5cc8a6c5d 100644 --- a/decompiler/config/jak2/ntsc_v1/var_names.jsonc +++ b/decompiler/config/jak2/ntsc_v1/var_names.jsonc @@ -4214,8 +4214,14 @@ }, "convert-korean-text": { "vars": { - "gp-0": "charp" - } + "gp-0": "src-ptr", + "s5-0": "src-len", + "s3-0": "dst", + "s1-0": "dst-i", + "s4-0": "src-i", + "s2-0": "dst-max" + }, + "args": ["src-str"] }, "(method 55 enemy)": { "args": ["self"] diff --git a/decompiler/data/game_text.cpp b/decompiler/data/game_text.cpp index 7a145a2e44..c77313afbb 100644 --- a/decompiler/data/game_text.cpp +++ b/decompiler/data/game_text.cpp @@ -114,7 +114,8 @@ GameTextResult process_game_text(ObjectFileData& data, GameTextVersion version) // escape characters if (font_bank_exists(version)) { - result.text[text_id] = get_font_bank(version)->convert_game_to_utf8(text.c_str()); + bool korean = version == GameTextVersion::JAK2 && result.language == 6; + result.text[text_id] = get_font_bank(version)->convert_game_to_utf8(text.c_str(), korean); } else { result.text[text_id] = goos::get_readable_string(text.c_str()); // HACK! } @@ -383,7 +384,7 @@ std::vector process_spool_subtitles(ObjectFileData& data, auto text = data.linked_data.get_goal_string_by_label(m_lbl); // escape characters if (font_bank_exists(version)) { - msg.text = get_font_bank(version)->convert_game_to_utf8(text.c_str()); + msg.text = get_font_bank(version)->convert_game_to_utf8(text.c_str(), m == 6); } else { msg.text = goos::get_readable_string(text.c_str()); // HACK! } diff --git a/game/kernel/jak2/kmachine.cpp b/game/kernel/jak2/kmachine.cpp index c1dc719387..456abba643 100644 --- a/game/kernel/jak2/kmachine.cpp +++ b/game/kernel/jak2/kmachine.cpp @@ -547,7 +547,7 @@ void update_discord_rpc(u32 discord_info) { int gems = (int)info->gem_count; // convert encodings std::string status = get_font_bank(GameTextVersion::JAK2) - ->convert_game_to_utf8(Ptr(info->status).c()->data()); + ->convert_game_to_utf8(Ptr(info->status).c()->data(), false); // get rid of special encodings like std::regex r("<.*?>"); diff --git a/goal_src/jak2/engine/ui/text.gc b/goal_src/jak2/engine/ui/text.gc index 4bd7cabc0d..2fca24dd23 100644 --- a/goal_src/jak2/engine/ui/text.gc +++ b/goal_src/jak2/engine/ui/text.gc @@ -72,76 +72,89 @@ obj ) -(defun convert-korean-text ((arg0 string)) +(defun convert-korean-text ((src-str string)) "Converts the provided [[string]] of [[game-text]] into korean. Returns a [[string]]" (local-vars (v1-21 int)) - (let ((gp-0 (-> arg0 data))) + (let ((src-ptr (-> src-str data))) *expanded-text-line0* - (let ((s4-0 0)) + (let ((src-i 0)) 0 - (let ((s1-0 0) - (s5-0 (length arg0)) + (let ((dst-i 0) + (src-len (length src-str)) ) (set! *expand-buf-number* (logxor *expand-buf-number* 1)) - (let ((s3-0 (if (zero? *expand-buf-number*) - *expanded-text-line0* - *expanded-text-line1* - ) - ) + (let ((dst (if (zero? *expand-buf-number*) + *expanded-text-line0* + *expanded-text-line1* + ) + ) ) - (let ((s2-0 (+ (-> s3-0 allocated-length) -1))) - (clear s3-0) - (while (< s4-0 s5-0) + (let ((dst-max (+ (-> dst allocated-length) -1))) + (clear dst) + (while (< src-i src-len) (cond - ((= (-> gp-0 s4-0) 3) - (+! s4-0 1) - (while (and (< s4-0 s5-0) (!= (-> gp-0 s4-0) 3) (!= (-> gp-0 s4-0) 4)) - (set! (-> s3-0 data s1-0) (-> gp-0 s4-0)) - (+! s4-0 1) - (+! s1-0 1) + ;; code 3 = copy chars until we reach a code 4 or 3 + ((= (-> src-ptr src-i) 3) + (+! src-i 1) + (while (and (< src-i src-len) (!= (-> src-ptr src-i) 3) (!= (-> src-ptr src-i) 4)) + (set! (-> dst data dst-i) (-> src-ptr src-i)) + (+! src-i 1) + (+! dst-i 1) ) ) (else - (let ((v1-17 (+ s4-0 1))) - (-> gp-0 v1-17) - (set! s4-0 (+ v1-17 1)) + (let ((v1-17 (+ src-i 1))) + (-> src-ptr v1-17) ;; character byte length. ignored or perhaps debug-only? + (set! src-i (+ v1-17 1)) ) - (set! (-> s3-0 data s1-0) (the-as uint 126)) - (let ((v1-19 (+ s1-0 1))) - (set! (-> s3-0 data v1-19) (the-as uint 89)) + ;; the idea here is we render the jamo all at the same position as the texture for each jamo accounts for their offset + ;; and then advance when we're done. + ;; we use a code of 4 to mark the beginning of a jamo sequence, a.k.a. one hangeul letter. + ;; there is jamo at code-page 1 (#x100-#x1ff) and code-page 3 (#x300-#x3ff), though only a handful are in code-page 1. + ;; since this requires two bytes per jamo, we assume the jamo is in code-page 3 by default and thus only have to read 1 byte per jamo. + ;; however, if we read a code of '5' then that means it is in code-page 1, which means we read 2 bytes. + ;; the jamo sequence terminates when we reach a code 3 (copy chars) or code 4 (new letter). + ;; when the sequence terminates, we move the font trans forwards and move on with our life. + + ;; save font trans (~Y) + (set! (-> dst data dst-i) (the-as uint 126)) + (let ((v1-19 (+ dst-i 1))) + (set! (-> dst data v1-19) (the-as uint 89)) (let ((v1-20 (+ v1-19 1))) - (while (and (< s4-0 s5-0) (< v1-20 s2-0) (!= (-> gp-0 s4-0) 3) (!= (-> gp-0 s4-0) 4)) + (while (and (< src-i src-len) (< v1-20 dst-max) (!= (-> src-ptr src-i) 3) (!= (-> src-ptr src-i) 4)) (cond - ((= (-> gp-0 s4-0) 5) - (set! (-> s3-0 data v1-20) (the-as uint 1)) - (+! s4-0 1) + ((= (-> src-ptr src-i) 5) + (set! (-> dst data v1-20) (the-as uint 1)) + (+! src-i 1) (set! v1-21 (+ v1-20 1)) ) (else - (set! (-> s3-0 data v1-20) (the-as uint 3)) + (set! (-> dst data v1-20) (the-as uint 3)) (set! v1-21 (+ v1-20 1)) ) ) - (set! (-> s3-0 data v1-21) (-> gp-0 s4-0)) - (+! s4-0 1) + (set! (-> dst data v1-21) (-> src-ptr src-i)) + (+! src-i 1) + ;; restore font trans (~Z) (let ((v1-22 (+ v1-21 1))) - (set! (-> s3-0 data v1-22) (the-as uint 126)) + (set! (-> dst data v1-22) (the-as uint 126)) (let ((v1-23 (+ v1-22 1))) - (set! (-> s3-0 data v1-23) (the-as uint 90)) + (set! (-> dst data v1-23) (the-as uint 90)) (set! v1-20 (+ v1-23 1)) ) ) ) - (set! (-> s3-0 data v1-20) (the-as uint 126)) + ;; advance font trans by 26 (~+26H) + (set! (-> dst data v1-20) (the-as uint 126)) (let ((v1-24 (+ v1-20 1))) - (set! (-> s3-0 data v1-24) (the-as uint 43)) + (set! (-> dst data v1-24) (the-as uint 43)) (let ((v1-25 (+ v1-24 1))) - (set! (-> s3-0 data v1-25) (the-as uint 50)) + (set! (-> dst data v1-25) (the-as uint 50)) (let ((v1-26 (+ v1-25 1))) - (set! (-> s3-0 data v1-26) (the-as uint 54)) + (set! (-> dst data v1-26) (the-as uint 54)) (let ((v1-27 (+ v1-26 1))) - (set! (-> s3-0 data v1-27) (the-as uint 72)) - (set! s1-0 (+ v1-27 1)) + (set! (-> dst data v1-27) (the-as uint 72)) + (set! dst-i (+ v1-27 1)) ) ) ) @@ -152,8 +165,8 @@ ) ) ) - (set! (-> s3-0 data s1-0) (the-as uint 0)) - s3-0 + (set! (-> dst data dst-i) (the-as uint 0)) + dst ) ) ) diff --git a/goal_src/jak2/pc/util/font-encode-test.gc b/goal_src/jak2/pc/util/font-encode-test.gc index 909b81ca0c..e15fb277a2 100644 --- a/goal_src/jak2/pc/util/font-encode-test.gc +++ b/goal_src/jak2/pc/util/font-encode-test.gc @@ -53,10 +53,14 @@ (set-width! fnt (get-screen-x 0.8)) (set-height! fnt (get-screen-y 0.1)) + (process-mask-clear! (-> self mask) pause) + (set-master-mode 'pause) + (loop (suspend) (set-setting! 'music *music-to-be-less-annoying* 0.0 0) + (set-setting! 'sfx-volume 'abs 0.0 0) (cond ((not (cpad-hold? 0 r3)) (if (or (cpad-pressed? 0 left) (cpad-hold? 0 l1))