various subtitle editor fixes (#2941)

- fix speaker names and time frames being uneditable in Jak 1
- added toggle to auto-selected a newly created scene as current
- changed the subtitle summary format slightly.
- current scene's name now appears in the UI
This commit is contained in:
ManDude
2023-08-28 17:51:09 +01:00
committed by GitHub
parent de086ff64b
commit 8bb5fa7f04
3 changed files with 62 additions and 31 deletions
+39 -28
View File
@@ -99,7 +99,11 @@ void SubtitleEditor::draw_window() {
} else {
ImGui::PushStyleColor(ImGuiCol_Text, m_selected_text_color);
}
if (ImGui::TreeNode("Currently Selected Cutscene")) {
if (ImGui::TreeNode(
"current_scene", "%s",
m_current_scene
? fmt::format("Currently Selected Scene - {}", m_current_scene->m_name).c_str()
: "Currently Selected Scene")) {
ImGui::PopStyleColor();
if (m_current_scene) {
draw_subtitle_options(*m_current_scene, true);
@@ -207,6 +211,8 @@ void SubtitleEditor::draw_speaker_options() {
const auto& bank = m_subtitle_db.m_banks[m_current_language];
for (auto& [speaker_id, speaker_localized] : bank->m_speakers) {
if (speaker_id == "none") {
// this is a special speaker that has ID zero and does not appear in-game
// it means there was no speaker for the line. (e.g. text-only, not vocal)
continue;
}
// Insertion or deletion not needed here as it has to be wired up in .gc and C++ code
@@ -238,9 +244,15 @@ void SubtitleEditor::draw_scene_section_header(const bool non_cutscenes) {
new_scene.m_hint_id = 0;
}
m_subtitle_db.m_banks.at(m_current_language)->m_scenes.emplace(m_new_scene_name, new_scene);
if (m_new_scene_as_current) {
m_current_scene =
&m_subtitle_db.m_banks.at(m_current_language)->m_scenes.at(m_new_scene_name);
}
m_new_scene_name = "";
}
ImGui::NewLine();
ImGui::SameLine();
ImGui::Checkbox("Set Scene as Current", &m_new_scene_as_current);
}
ImGui::TreePop();
}
@@ -343,7 +355,7 @@ std::string SubtitleEditor::subtitle_line_summary(
std::string line_text = "";
if (!line.text.empty()) {
if (m_truncate_summaries && line.text.size() > 30) {
line_text = line.text.substr(0, 30) + "...";
line_text = line.text.substr(0, 27) + "...";
} else {
line_text = line.text;
}
@@ -351,7 +363,7 @@ std::string SubtitleEditor::subtitle_line_summary(
if (is_v1_format()) {
line_text = "Clear Screen";
} else if (line_meta.merge) {
line_text = "<Merge>";
line_text = "<original game text>";
}
}
// Append important info about the frame / speaker to the front
@@ -359,21 +371,23 @@ std::string SubtitleEditor::subtitle_line_summary(
// V1
if (is_v1_format()) {
if (line.text.empty()) {
return fmt::format("{}] {}", info_header, line_text);
return fmt::format("[{}] {}", line_meta.frame_start, line_text);
} else {
return fmt::format(
"[{}] {}: {}", line_meta.frame_start,
m_subtitle_db.m_banks[m_current_language]->m_speakers.at(line_meta.speaker), line_text);
}
return fmt::format("{}] {} - '{}'", info_header,
m_subtitle_db.m_banks[m_current_language]->m_speakers.at(line_meta.speaker),
line_text);
}
// V2
if (line_meta.merge) {
return fmt::format("{}-{}] {} - {}", info_header, line_meta.frame_end,
m_subtitle_db.m_banks[m_current_language]->m_speakers.at(line_meta.speaker),
else {
auto speaker_text =
line_meta.speaker == "none"
? ""
: fmt::format("{}: ", m_subtitle_db.m_banks[m_current_language]->m_speakers.at(
line_meta.speaker));
return fmt::format("[{}-{}] {}{}", line_meta.frame_start, line_meta.frame_end, speaker_text,
line_text);
}
return fmt::format("{}-{}] {} - '{}'", info_header, line_meta.frame_end,
m_subtitle_db.m_banks[m_current_language]->m_speakers.at(line_meta.speaker),
line_text);
}
void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool current_scene) {
@@ -435,16 +449,18 @@ void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool cu
}
bool hide_line_options = false;
if (is_v1_format()) {
if (line_text.empty()) {
hide_line_options = true;
} else {
ImGui::InputInt("Starting Frame", &subtitle_line->metadata.frame_start,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
}
ImGui::InputInt("Starting Frame", &frames[0],
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
} else {
ImGui::InputInt2("Start and End Frame", frames,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
}
// no text + text isn't going to be filled automatically by the game
if (line_text.empty() && !line_meta.merge) {
hide_line_options = true;
}
if (!hide_line_options) {
if (ImGui::BeginCombo(
"Speaker",
@@ -461,15 +477,14 @@ void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool cu
}
ImGui::EndCombo();
}
ImGui::InputText("Text", &subtitle_line->text,
line_meta.merge ? ImGuiInputTextFlags_ReadOnly : 0);
ImGui::InputText("Text", &line_text, line_meta.merge ? ImGuiInputTextFlags_ReadOnly : 0);
ImGui::Checkbox("Offscreen?", &subtitle_line->metadata.offscreen);
if (!is_v1_format()) {
ImGui::SameLine();
if (ImGui::Checkbox("Merge Text?", &subtitle_line->metadata.merge)) {
// Clear text if they've checked it
if (subtitle_line->metadata.merge) {
subtitle_line->text = "";
line_text = "";
}
}
}
@@ -533,7 +548,7 @@ void SubtitleEditor::draw_new_scene_line_form() {
}
}
}
bool rendered_text_entry_btn = false;
// Validation:
// - start frame > 0
// - end frame > start_frame
@@ -546,7 +561,6 @@ void SubtitleEditor::draw_new_scene_line_form() {
ImGui::Text("Can't add a new text entry with the current fields!");
ImGui::PopStyleColor();
} else {
rendered_text_entry_btn = true;
if (ImGui::Button("Add Text Entry")) {
m_current_scene->add_line(m_current_scene_text, m_current_scene_frames[0],
m_current_scene_frames[1], m_current_scene_offscreen,
@@ -559,9 +573,6 @@ void SubtitleEditor::draw_new_scene_line_form() {
ImGui::Text("Can't add a clear screen entry with the current fields!");
ImGui::PopStyleColor();
} else {
if (rendered_text_entry_btn) {
ImGui::SameLine();
}
if (ImGui::Button("Add Clear Screen Entry")) {
m_current_scene->add_line("", m_current_scene_frames[0], 0, m_current_scene_offscreen, "",
false);
@@ -67,6 +67,7 @@ class SubtitleEditor {
bool m_current_scene_offscreen = false;
bool m_current_scene_merge = false;
bool m_new_scene_as_current = true;
std::string m_new_scene_name = "";
std::string m_new_scene_id = "0";
+22 -3
View File
@@ -99,7 +99,17 @@ void compile_text(GameTextDB& db, const std::string& output_prefix) {
*/
void compile_subtitles_v1(GameSubtitleDB& db, const std::string& output_prefix) {
for (const auto& [lang, bank] : db.m_banks) {
// get font encoding information
auto font = get_font_bank(bank->m_text_version);
// convert speakers once.
auto speakers_converted = bank->m_speakers;
for (auto& [id, name] : speakers_converted) {
// convert name in-place. we copied the map earlier so this is safe.
// the subtitle lines have the speaker "id" stored in them, which is the map key here.
name = font->convert_utf8_to_game(name);
}
DataObjectGenerator gen;
gen.add_type_tag("subtitle-text-info"); // type
gen.add_word(bank->m_scenes.size()); // length
@@ -128,9 +138,18 @@ void compile_subtitles_v1(GameSubtitleDB& db, const std::string& output_prefix)
for (auto& subtitle : scene.m_lines) {
gen.add_word(subtitle.metadata.frame_start); // frame
gen.add_ref_to_string_in_pool(font->convert_utf8_to_game(subtitle.text)); // line
gen.add_ref_to_string_in_pool(
font->convert_utf8_to_game(subtitle.metadata.speaker)); // speaker
gen.add_word(subtitle.metadata.offscreen); // offscreen
// speaker
if (subtitle.metadata.speaker.empty()) {
gen.add_ref_to_string_in_pool("");
} else {
auto it = speakers_converted.find(subtitle.metadata.speaker);
if (it == speakers_converted.end()) {
throw std::runtime_error(fmt::format("in file `{}`: could not find speaker {}",
bank->m_file_path, subtitle.metadata.speaker));
}
gen.add_ref_to_string_in_pool(it->second);
}
gen.add_word(subtitle.metadata.offscreen); // offscreen
}
}