mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
172 lines
5.8 KiB
C++
172 lines
5.8 KiB
C++
#pragma once
|
|
|
|
#include "common/serialization/subtitles/subtitles.h"
|
|
#include "common/util/Assert.h"
|
|
#include "common/util/FontUtils.h"
|
|
#include "common/util/json_util.h"
|
|
|
|
struct SubtitleLineMetadata {
|
|
int frame_start;
|
|
int frame_end;
|
|
bool offscreen;
|
|
std::string speaker;
|
|
bool merge;
|
|
|
|
bool operator==(const SubtitleLineMetadata& other) const {
|
|
if (frame_start != other.frame_start || frame_end != other.frame_end ||
|
|
offscreen != other.offscreen || speaker != other.speaker || merge != other.merge) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool operator!=(const SubtitleLineMetadata& other) const { return !(*this == other); }
|
|
};
|
|
void to_json(json& j, const SubtitleLineMetadata& obj);
|
|
void from_json(const json& j, SubtitleLineMetadata& obj);
|
|
|
|
struct SubtitleSceneMetadata {
|
|
std::vector<SubtitleLineMetadata> lines;
|
|
int m_hint_id = 0; // used only for jak1, intentionally ignored in serialization/deserialization
|
|
};
|
|
void to_json(json& j, const SubtitleSceneMetadata& obj);
|
|
void from_json(const json& j, SubtitleSceneMetadata& obj);
|
|
|
|
struct SubtitleMetadataFile {
|
|
std::unordered_map<std::string, SubtitleSceneMetadata> cutscenes;
|
|
std::unordered_map<std::string, SubtitleSceneMetadata> other;
|
|
};
|
|
void to_json(json& j, const SubtitleMetadataFile& obj);
|
|
void from_json(const json& j, SubtitleMetadataFile& obj);
|
|
|
|
struct SubtitleFile {
|
|
std::unordered_map<std::string, std::string> speakers;
|
|
std::unordered_map<std::string, std::vector<std::string>> cutscenes;
|
|
std::unordered_map<std::string, std::vector<std::string>> other;
|
|
};
|
|
void to_json(json& j, const SubtitleFile& obj);
|
|
void from_json(const json& j, SubtitleFile& obj);
|
|
|
|
struct SubtitleLine {
|
|
std::string text;
|
|
SubtitleLineMetadata metadata;
|
|
|
|
bool operator<(const SubtitleLine& other) const {
|
|
return (metadata.frame_start < other.metadata.frame_start);
|
|
}
|
|
};
|
|
|
|
// Returns the individual components of each subtitle "package":
|
|
// - the base file
|
|
// - the combination of the two
|
|
// This allows for more context when dumping the files back out and you want
|
|
// to skip duplicate info
|
|
struct GameSubtitlePackage {
|
|
SubtitleMetadataFile base_meta;
|
|
SubtitleMetadataFile combined_meta;
|
|
SubtitleFile base_lines;
|
|
SubtitleFile combined_lines;
|
|
std::unordered_set<std::string> scenes_defined_in_lang;
|
|
};
|
|
|
|
struct GameSubtitleSceneInfo {
|
|
std::string m_name;
|
|
std::vector<SubtitleLine> m_lines;
|
|
bool is_cutscene;
|
|
bool only_defined_in_base = false;
|
|
int m_hint_id; // used only for jak1
|
|
|
|
void add_line(const std::string& text,
|
|
const int frame_start,
|
|
const int frame_end,
|
|
const bool offscreen,
|
|
const std::string& speaker,
|
|
const bool merge) {
|
|
m_lines.push_back({text, {frame_start, frame_end, offscreen, speaker, merge}});
|
|
std::sort(m_lines.begin(), m_lines.end());
|
|
}
|
|
bool same_lines_as_other(const GameSubtitleSceneInfo& other) const {
|
|
if (m_lines.size() != other.m_lines.size()) {
|
|
return false;
|
|
}
|
|
// Check each line
|
|
for (size_t i = 0; i < m_lines.size(); i++) {
|
|
if (m_lines.at(i).text != other.m_lines.at(i).text) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
bool same_metadata_as_other(const GameSubtitleSceneInfo& other) const {
|
|
if (m_name != other.m_name || m_lines.size() != other.m_lines.size() ||
|
|
is_cutscene != other.is_cutscene || m_hint_id != other.m_hint_id) {
|
|
return false;
|
|
}
|
|
// Check each line's metadata
|
|
for (size_t i = 0; i < m_lines.size(); i++) {
|
|
if (m_lines.at(i).metadata != other.m_lines.at(i).metadata) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* The subtitle bank contains subtitles for all scenes in a language.
|
|
*/
|
|
class GameSubtitleBank {
|
|
public:
|
|
GameSubtitleBank(const int lang_id) : m_lang_id(lang_id) {}
|
|
|
|
int m_lang_id;
|
|
GameTextVersion m_text_version;
|
|
std::string m_file_path;
|
|
std::optional<std::string> m_file_base_path;
|
|
|
|
std::map<std::string, GameSubtitleSceneInfo> m_base_scenes;
|
|
std::map<std::string, GameSubtitleSceneInfo> m_lang_scenes;
|
|
std::map<std::string, GameSubtitleSceneInfo> m_scenes;
|
|
bool scene_exists(const std::string& name) const { return m_scenes.find(name) != m_scenes.end(); }
|
|
GameSubtitleSceneInfo new_scene_from_meta(
|
|
const std::string& scene_name,
|
|
const SubtitleSceneMetadata& scene_meta,
|
|
const std::unordered_map<std::string, std::vector<std::string>>& relevant_lines);
|
|
GameSubtitleSceneInfo& scene_by_name(const std::string& name) { return m_scenes.at(name); }
|
|
void add_scenes_from_files(const GameSubtitlePackage& package);
|
|
|
|
std::unordered_map<std::string, std::string> m_speakers;
|
|
std::vector<std::string> speaker_names_ordered_by_enum_value();
|
|
u16 speaker_enum_value_from_name(const std::string& speaker_id);
|
|
};
|
|
|
|
/*!
|
|
* The subtitles database contains a subtitles bank for each language.
|
|
* Each subtitles bank contains a series of subtitle scene infos.
|
|
*/
|
|
class GameSubtitleDB {
|
|
public:
|
|
enum class SubtitleFormat { V1, V2 };
|
|
std::optional<std::string> m_load_error = {};
|
|
std::map<int, std::shared_ptr<GameSubtitleBank>> m_banks;
|
|
SubtitleFormat m_subtitle_version = SubtitleFormat::V2;
|
|
|
|
bool bank_exists(int id) const { return m_banks.find(id) != m_banks.end(); }
|
|
std::shared_ptr<GameSubtitleBank> add_bank(std::shared_ptr<GameSubtitleBank> bank) {
|
|
ASSERT(!bank_exists(bank->m_lang_id));
|
|
m_banks[bank->m_lang_id] = bank;
|
|
return bank;
|
|
}
|
|
std::shared_ptr<GameSubtitleBank> bank_by_id(int id) {
|
|
if (!bank_exists(id)) {
|
|
return nullptr;
|
|
}
|
|
return m_banks.at(id);
|
|
}
|
|
|
|
void init_banks_from_file(const GameSubtitleDefinitionFile& file_info);
|
|
bool write_subtitle_db_to_files(const GameVersion game_version);
|
|
};
|
|
|
|
GameSubtitleDB load_subtitle_project(const GameSubtitleDB::SubtitleFormat format_version,
|
|
GameVersion game_version);
|