diff --git a/common/serialization/subtitles/subtitles_deser.cpp b/common/serialization/subtitles/subtitles_deser.cpp index 8421d420b1..2c2e8ed86a 100644 --- a/common/serialization/subtitles/subtitles_deser.cpp +++ b/common/serialization/subtitles/subtitles_deser.cpp @@ -13,122 +13,122 @@ // TODO - this can be be massively reduced now bool write_subtitle_db_to_files(const GameSubtitleDB& db) { // Write the subtitles out - std::vector completed_banks = {}; - for (const auto& [id, bank] : db.m_banks) { - // If we've done the bank before, skip it - auto it = find(completed_banks.begin(), completed_banks.end(), bank->m_lang_id); - if (it != completed_banks.end()) { - continue; - } - // Check to see if this bank is shared by any other, if so do it at the same time - // and skip it - // This is basically just to deal with US/UK english in a not so hacky way - std::vector banks = {}; - for (const auto& [_id, _bank] : db.m_banks) { - if (_bank->file_path == bank->file_path) { - banks.push_back(_bank->m_lang_id); - completed_banks.push_back(_bank->m_lang_id); - } - } + //std::vector completed_banks = {}; + //for (const auto& [id, bank] : db.m_banks) { + // // If we've done the bank before, skip it + // auto it = find(completed_banks.begin(), completed_banks.end(), bank->m_lang_id); + // if (it != completed_banks.end()) { + // continue; + // } + // // Check to see if this bank is shared by any other, if so do it at the same time + // // and skip it + // // This is basically just to deal with US/UK english in a not so hacky way + // std::vector banks = {}; + // for (const auto& [_id, _bank] : db.m_banks) { + // if (_bank->file_path == bank->file_path) { + // banks.push_back(_bank->m_lang_id); + // completed_banks.push_back(_bank->m_lang_id); + // } + // } - std::string file_contents = ""; - file_contents += fmt::format("(language-id {})\n", fmt::join(banks, " ")); - auto file_ver = parse_text_only_version(bank->file_path); - auto font = get_font_bank(file_ver); - file_contents += fmt::format("(text-version {})\n", get_text_version_name(file_ver)); + // std::string file_contents = ""; + // file_contents += fmt::format("(language-id {})\n", fmt::join(banks, " ")); + // auto file_ver = parse_text_only_version(bank->file_path); + // auto font = get_font_bank(file_ver); + // file_contents += fmt::format("(text-version {})\n", get_text_version_name(file_ver)); - for (const auto& group_name : db.m_subtitle_groups->m_group_order) { - bool last_was_single = false; - file_contents += - fmt::format("\n;; -----------------\n;; {}\n;; -----------------\n", group_name); - std::vector all_scenes; - for (const auto& [scene_name, scene] : bank->scenes()) { - all_scenes.push_back(scene); - } - std::sort(all_scenes.begin(), all_scenes.end(), - [](const GameSubtitleSceneInfo& a, const GameSubtitleSceneInfo& b) { - if (a.kind() != b.kind()) { - return a.kind() < b.kind(); - } - if (a.kind() == SubtitleSceneKind::Movie) { - return a.name() < b.name(); - } else if (a.kind() == SubtitleSceneKind::HintNamed) { - if (a.id() == b.id()) { - return a.name() < b.name(); - } else { - return a.id() < b.id(); - } - } else if (a.kind() == SubtitleSceneKind::Hint) { - return a.id() < b.id(); - } - return false; - }); - for (const auto& scene : all_scenes) { - if (scene.m_sorting_group != group_name) { - continue; - } + // for (const auto& group_name : db.m_subtitle_groups->m_group_order) { + // bool last_was_single = false; + // file_contents += + // fmt::format("\n;; -----------------\n;; {}\n;; -----------------\n", group_name); + // std::vector all_scenes; + // for (const auto& [scene_name, scene] : bank->scenes()) { + // all_scenes.push_back(scene); + // } + // std::sort(all_scenes.begin(), all_scenes.end(), + // [](const GameSubtitleSceneInfo& a, const GameSubtitleSceneInfo& b) { + // if (a.kind() != b.kind()) { + // return a.kind() < b.kind(); + // } + // if (a.kind() == SubtitleSceneKind::Movie) { + // return a.name() < b.name(); + // } else if (a.kind() == SubtitleSceneKind::HintNamed) { + // if (a.id() == b.id()) { + // return a.name() < b.name(); + // } else { + // return a.id() < b.id(); + // } + // } else if (a.kind() == SubtitleSceneKind::Hint) { + // return a.id() < b.id(); + // } + // return false; + // }); + // for (const auto& scene : all_scenes) { + // if (scene.m_sorting_group != group_name) { + // continue; + // } - if (last_was_single && scene.lines().size() == 1) { - file_contents += fmt::format("(\"{}\"", scene.name()); - } else { - file_contents += fmt::format("\n(\"{}\"", scene.name()); - } - if (scene.kind() == SubtitleSceneKind::Hint) { - file_contents += " :hint #x0"; - } else if (scene.kind() == SubtitleSceneKind::HintNamed) { - file_contents += fmt::format(" :hint #x{0:x}", scene.id()); - } - // more compact formatting for single-line entries - if (scene.lines().size() == 1) { - const auto& line = scene.lines().at(0); - if (line.line.empty()) { - file_contents += fmt::format(" ({})", line.frame); - } else { - file_contents += fmt::format(" ({}", line.frame); - if (line.offscreen && scene.kind() == SubtitleSceneKind::Movie) { - file_contents += " :offscreen"; - } - file_contents += - fmt::format(" \"{}\"", font->convert_game_to_utf8(line.speaker.c_str())); - file_contents += fmt::format(" \"{}\")", font->convert_game_to_utf8(line.line.c_str())); - } - file_contents += ")\n"; - last_was_single = true; - } else { - file_contents += "\n"; - for (auto& line : scene.lines()) { - // Clear screen entries - if (line.line.empty()) { - file_contents += fmt::format(" ({})\n", line.frame); - } else { - file_contents += fmt::format(" ({}", line.frame); - if (line.offscreen && scene.kind() == SubtitleSceneKind::Movie) { - file_contents += " :offscreen"; - } - file_contents += - fmt::format(" \"{}\"", font->convert_game_to_utf8(line.speaker.c_str())); - file_contents += - fmt::format(" \"{}\")\n", font->convert_game_to_utf8(line.line.c_str())); - } - } - file_contents += " )\n"; - last_was_single = false; - } - } - } + // if (last_was_single && scene.lines().size() == 1) { + // file_contents += fmt::format("(\"{}\"", scene.name()); + // } else { + // file_contents += fmt::format("\n(\"{}\"", scene.name()); + // } + // if (scene.kind() == SubtitleSceneKind::Hint) { + // file_contents += " :hint #x0"; + // } else if (scene.kind() == SubtitleSceneKind::HintNamed) { + // file_contents += fmt::format(" :hint #x{0:x}", scene.id()); + // } + // // more compact formatting for single-line entries + // if (scene.lines().size() == 1) { + // const auto& line = scene.lines().at(0); + // if (line.line.empty()) { + // file_contents += fmt::format(" ({})", line.frame); + // } else { + // file_contents += fmt::format(" ({}", line.frame); + // if (line.offscreen && scene.kind() == SubtitleSceneKind::Movie) { + // file_contents += " :offscreen"; + // } + // file_contents += + // fmt::format(" \"{}\"", font->convert_game_to_utf8(line.speaker.c_str())); + // file_contents += fmt::format(" \"{}\")", font->convert_game_to_utf8(line.line.c_str())); + // } + // file_contents += ")\n"; + // last_was_single = true; + // } else { + // file_contents += "\n"; + // for (auto& line : scene.lines()) { + // // Clear screen entries + // if (line.line.empty()) { + // file_contents += fmt::format(" ({})\n", line.frame); + // } else { + // file_contents += fmt::format(" ({}", line.frame); + // if (line.offscreen && scene.kind() == SubtitleSceneKind::Movie) { + // file_contents += " :offscreen"; + // } + // file_contents += + // fmt::format(" \"{}\"", font->convert_game_to_utf8(line.speaker.c_str())); + // file_contents += + // fmt::format(" \"{}\")\n", font->convert_game_to_utf8(line.line.c_str())); + // } + // } + // file_contents += " )\n"; + // last_was_single = false; + // } + // } + // } - // Commit it to the file - std::string full_path = (file_util::get_jak_project_dir() / fs::path(bank->file_path)).string(); - file_util::write_text_file(full_path, file_contents); - } + // // Commit it to the file + // std::string full_path = (file_util::get_jak_project_dir() / fs::path(bank->file_path)).string(); + // file_util::write_text_file(full_path, file_contents); + //} - // Write the subtitle group info out - nlohmann::json json(db.m_subtitle_groups->m_groups); - json[db.m_subtitle_groups->group_order_key] = nlohmann::json(db.m_subtitle_groups->m_group_order); - std::string file_path = (file_util::get_jak_project_dir() / "game" / "assets" / "jak1" / - "subtitle" / "subtitle-groups.json") - .string(); - file_util::write_text_file(file_path, json.dump(2)); + //// Write the subtitle group info out + //nlohmann::json json(db.m_subtitle_groups->m_groups); + //json[db.m_subtitle_groups->group_order_key] = nlohmann::json(db.m_subtitle_groups->m_group_order); + //std::string file_path = (file_util::get_jak_project_dir() / "game" / "assets" / "jak1" / + // "subtitle" / "subtitle-groups.json") + // .string(); + //file_util::write_text_file(file_path, json.dump(2)); - return true; + //return true; } diff --git a/common/serialization/subtitles/subtitles_ser.cpp b/common/serialization/subtitles/subtitles_ser.cpp index ca34f35da2..b853aed9e3 100644 --- a/common/serialization/subtitles/subtitles_ser.cpp +++ b/common/serialization/subtitles/subtitles_ser.cpp @@ -256,10 +256,8 @@ void parse_subtitle(const goos::Object& data, GameSubtitleDB& db, const std::str if (!db.bank_exists(lang)) { // database has no lang yet banks[lang] = db.add_bank(std::make_shared(lang)); - banks[lang]->file_path = file_path; } else { banks[lang] = db.bank_by_id(lang); - banks[lang]->file_path = file_path; } }); } else if (head.is_symbol("text-version")) { @@ -271,7 +269,6 @@ void parse_subtitle(const goos::Object& data, GameSubtitleDB& db, const std::str if (!ver_name.is_symbol()) { throw std::runtime_error("invalid text version entry"); } - font = get_font_bank(ver_name.as_symbol()->name); } @@ -306,8 +303,6 @@ void parse_subtitle(const goos::Object& data, GameSubtitleDB& db, const std::str id = head.as_int(); } scene.set_id(id); - scene.m_sorting_group = db.m_subtitle_groups->find_group(scene.name()); - scene.m_sorting_group_idx = db.m_subtitle_groups->find_group_index(scene.m_sorting_group); for_each_in_list(entries, [&](const goos::Object& entry) { if (entry.is_pair()) { @@ -389,6 +384,8 @@ void parse_subtitle_json(GameSubtitleDB& db, const GameSubtitleDefinitionFile& f } else { bank = db.bank_by_id(file_info.language_id); } + bank->m_text_verison = file_info.text_version; + bank->m_file_path = file_info.lines_path; const GameTextFontBank* font = get_font_bank(file_info.text_version); // Parse the file SubtitleMetadataFile meta_file; @@ -439,11 +436,10 @@ void parse_subtitle_json(GameSubtitleDB& db, const GameSubtitleDefinitionFile& f // Iterate through the metadata file as blank lines are no omitted from the lines file now // Cutscenes First for (const auto& [cutscene_name, cutscene_lines] : meta_file.cutscenes) { - lg::info(cutscene_name); GameSubtitleSceneInfo scene(SubtitleSceneKind::Movie); scene.set_name(cutscene_name); - /*scene.m_sorting_group = db.m_subtitle_groups->find_group(cutscene_name); - scene.m_sorting_group_idx = db.m_subtitle_groups->find_group_index(scene.m_sorting_group);*/ + scene.m_sorting_group = db.m_subtitle_groups->find_group(cutscene_name); + scene.m_sorting_group_idx = db.m_subtitle_groups->find_group_index(scene.m_sorting_group); // Iterate the lines, grab the actual text from the lines file if it's not a clear screen entry int line_idx = 0; for (const auto& line : cutscene_lines) { @@ -458,6 +454,9 @@ void parse_subtitle_json(GameSubtitleDB& db, const GameSubtitleDefinitionFile& f "be resolved {}!", file_info.language_id, cutscene_name, line.speaker); } else { + // NOTE - the convert_utf8_to_game function is really really slow (about 80-90% of the + // time loading the subtitle files) + // TODO - improve that as a follow up sometime in the future scene.add_line( line.frame, font->convert_utf8_to_game(lines_file.cutscenes.at(cutscene_name).at(line_idx)), @@ -476,7 +475,6 @@ void parse_subtitle_json(GameSubtitleDB& db, const GameSubtitleDefinitionFile& f } // Now hints for (const auto& [hint_name, hint_info] : meta_file.hints) { - lg::info(hint_name); GameSubtitleSceneInfo scene(SubtitleSceneKind::Hint); scene.set_name(hint_name); /*scene.m_sorting_group = db.m_subtitle_groups->find_group(hint_name); @@ -500,6 +498,9 @@ void parse_subtitle_json(GameSubtitleDB& db, const GameSubtitleDefinitionFile& f "be resolved {}!", file_info.language_id, hint_name, line.speaker); } else { + // NOTE - the convert_utf8_to_game function is really really slow (about 80-90% of the + // time loading the subtitle files) + // TODO - improve that as a follow up sometime in the future scene.add_line(line.frame, font->convert_utf8_to_game(lines_file.hints.at(hint_name).at(line_idx)), font->convert_utf8_to_game(lines_file.speakers.at(line.speaker)), true); @@ -765,7 +766,7 @@ SubtitleMetadataFile dump_bank_as_meta_json( std::shared_ptr bank, std::unordered_map speaker_lookup) { auto meta_file = SubtitleMetadataFile(); - auto font = get_font_bank(parse_text_only_version(bank->file_path)); + auto font = get_font_bank("jak1-v2"); for (const auto& [scene_name, scene_info] : bank->m_scenes) { if (scene_info.m_kind == SubtitleSceneKind::Movie) { std::vector lines; @@ -821,7 +822,7 @@ SubtitleFile dump_bank_as_json(std::shared_ptr bank, std::unordered_map speaker_lookup) { SubtitleFile file; file.speakers = speaker_lookup; - auto font = get_font_bank(parse_text_only_version(bank->file_path)); + auto font = get_font_bank("jak1-v2"); // Figure out speakers for (const auto& [scene_name, scene_info] : bank->m_scenes) { for (const auto& line : scene_info.m_lines) { diff --git a/common/serialization/subtitles/subtitles_ser.h b/common/serialization/subtitles/subtitles_ser.h index 57f7f10854..cc718a611e 100644 --- a/common/serialization/subtitles/subtitles_ser.h +++ b/common/serialization/subtitles/subtitles_ser.h @@ -207,8 +207,8 @@ class GameSubtitleBank { } int m_lang_id; - std::string file_path; - + std::string m_text_verison; + std::string m_file_path; std::map m_scenes; }; diff --git a/game/assets/jak1/game_subtitle.gp b/game/assets/jak1/game_subtitle.gp index 53a138fb6b..cc38813430 100644 --- a/game/assets/jak1/game_subtitle.gp +++ b/game/assets/jak1/game_subtitle.gp @@ -1,8 +1,4 @@ ;; "project file" for subtitles make tool. -;; it's very simple... a list of (action args...) -;; There is one supported action: -;; - file (A path to a GOAL data file) -;; - the same arguments are provided within the file itself (subtitle (file-json diff --git a/game/tools/subtitles/subtitle_editor.cpp b/game/tools/subtitles/subtitle_editor.cpp index 51d3a56337..001d7dfd08 100644 --- a/game/tools/subtitles/subtitle_editor.cpp +++ b/game/tools/subtitles/subtitle_editor.cpp @@ -196,7 +196,7 @@ void SubtitleEditor::draw_window() { if (ImGui::Button("Add Scene")) { GameSubtitleSceneInfo newScene(SubtitleSceneKind::Movie); newScene.m_name = m_new_scene_name; - newScene.m_id = 0; // id's are only used for non-named hints + newScene.m_id = 0; // id's are only used for non-named hints newScene.m_sorting_group = m_new_scene_group; m_subtitle_db.m_banks.at(m_current_language)->add_scene(newScene); m_subtitle_db.m_subtitle_groups->add_scene(newScene.m_sorting_group, newScene.m_name); @@ -314,11 +314,11 @@ void SubtitleEditor::draw_edit_options() { if (ImGui::BeginCombo( "Editing Language ID", fmt::format("[{}] {}", m_subtitle_db.m_banks[m_current_language]->m_lang_id, - m_subtitle_db.m_banks[m_current_language]->file_path) + m_subtitle_db.m_banks[m_current_language]->m_file_path) .c_str())) { for (const auto& [key, value] : m_subtitle_db.m_banks) { const bool isSelected = m_current_language == key; - if (ImGui::Selectable(fmt::format("[{}] {}", value->m_lang_id, value->file_path).c_str(), + if (ImGui::Selectable(fmt::format("[{}] {}", value->m_lang_id, value->m_file_path).c_str(), isSelected)) { m_current_language = key; } @@ -330,11 +330,11 @@ void SubtitleEditor::draw_edit_options() { } if (ImGui::BeginCombo("Base Language ID", fmt::format("[{}] {}", m_subtitle_db.m_banks[m_base_language]->m_lang_id, - m_subtitle_db.m_banks[m_base_language]->file_path) + m_subtitle_db.m_banks[m_base_language]->m_file_path) .c_str())) { for (const auto& [key, value] : m_subtitle_db.m_banks) { const bool isSelected = m_base_language == key; - if (ImGui::Selectable(fmt::format("[{}] {}", value->m_lang_id, value->file_path).c_str(), + if (ImGui::Selectable(fmt::format("[{}] {}", value->m_lang_id, value->m_file_path).c_str(), isSelected)) { m_base_language = key; } @@ -610,21 +610,20 @@ void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool cu if (current_scene) { draw_new_cutscene_line_form(); } - auto font = - get_font_bank(parse_text_only_version(m_subtitle_db.m_banks[m_current_language]->file_path)); + auto font = get_font_bank(m_subtitle_db.m_banks[m_current_language]->m_text_verison); int i = 0; for (auto subtitleLine = scene.m_lines.begin(); subtitleLine != scene.m_lines.end();) { auto linetext = font->convert_game_to_utf8(subtitleLine->line.c_str()); - auto linespkr = font->convert_game_to_utf8(subtitleLine->speaker.c_str()); + auto line_speaker = font->convert_game_to_utf8(subtitleLine->speaker.c_str()); std::string summary; if (linetext.empty()) { summary = fmt::format("[{}] Clear Screen", subtitleLine->frame); } else if (linetext.length() >= 30) { - summary = - fmt::format("[{}] {} - '{}...'", subtitleLine->frame, linespkr, linetext.substr(0, 30)); + summary = fmt::format("[{}] {} - '{}...'", subtitleLine->frame, line_speaker, + linetext.substr(0, 30)); } else { summary = - fmt::format("[{}] {} - '{}'", subtitleLine->frame, linespkr, linetext.substr(0, 30)); + fmt::format("[{}] {} - '{}'", subtitleLine->frame, line_speaker, linetext.substr(0, 30)); } if (linetext.empty()) { ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color); @@ -637,7 +636,8 @@ void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool cu } ImGui::InputInt("Starting Frame", &subtitleLine->frame, ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal); - ImGui::InputText("Speaker", &linespkr); + // TODO - speaker dropdown instead + ImGui::InputText("Speaker", &line_speaker); ImGui::InputText("Text", &linetext); ImGui::Checkbox("Offscreen?", &subtitleLine->offscreen); if (scene.m_lines.size() > 1) { // prevent creating an empty scene @@ -655,7 +655,7 @@ void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool cu ImGui::PopStyleColor(); } auto newtext = font->convert_utf8_to_game(linetext, true); - auto newspkr = font->convert_utf8_to_game(linespkr, true); + auto newspkr = font->convert_utf8_to_game(line_speaker, true); subtitleLine->line = newtext; subtitleLine->speaker = newspkr; i++; @@ -679,7 +679,7 @@ void SubtitleEditor::draw_new_cutscene_line_form() { rendered_text_entry_btn = true; if (ImGui::Button("Add Text Entry")) { auto font = get_font_bank( - parse_text_only_version(m_subtitle_db.m_banks[m_current_language]->file_path)); + parse_text_only_version(m_subtitle_db.m_banks[m_current_language]->m_file_path)); m_current_scene->add_line( m_current_scene_frame, font->convert_utf8_to_game(m_current_scene_text, true), font->convert_utf8_to_game(m_current_scene_speaker, true), m_current_scene_offscreen);