backend-infra-engineer: Pre-0.2.2 2024 Q4 snapshot

This commit is contained in:
scawful
2024-11-28 11:50:47 -05:00
parent 75bf38fa71
commit 18b7fb9abf
238 changed files with 22057 additions and 8538 deletions

View File

@@ -0,0 +1,182 @@
#include "message_data.h"
#include "app/core/common.h"
namespace yaze {
namespace app {
namespace editor {
uint8_t FindMatchingCharacter(char value) {
for (const auto [key, char_value] : CharEncoder) {
if (value == char_value) {
return key;
}
}
return 0xFF;
}
uint8_t FindDictionaryEntry(uint8_t value) {
if (value < DICTOFF || value == 0xFF) {
return -1;
}
return value - DICTOFF;
}
TextElement FindMatchingCommand(uint8_t b) {
TextElement empty_element;
for (const auto& text_element : TextCommands) {
if (text_element.ID == b) {
return text_element;
}
}
return empty_element;
}
TextElement FindMatchingSpecial(uint8_t value) {
auto it = std::find_if(SpecialChars.begin(), SpecialChars.end(),
[value](const TextElement& text_element) {
return text_element.ID == value;
});
if (it != SpecialChars.end()) {
return *it;
}
return TextElement();
}
ParsedElement FindMatchingElement(const std::string& str) {
std::smatch match;
for (auto& textElement : TextCommands) {
match = textElement.MatchMe(str);
if (match.size() > 0) {
if (textElement.HasArgument) {
return ParsedElement(textElement,
std::stoi(match[1].str(), nullptr, 16));
} else {
return ParsedElement(textElement, 0);
}
}
}
const auto dictionary_element =
TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
match = dictionary_element.MatchMe(str);
if (match.size() > 0) {
return ParsedElement(dictionary_element,
DICTOFF + std::stoi(match[1].str(), nullptr, 16));
}
return ParsedElement();
}
std::string ParseTextDataByte(uint8_t value) {
if (CharEncoder.contains(value)) {
char c = CharEncoder.at(value);
std::string str = "";
str.push_back(c);
return str;
}
// Check for command.
TextElement textElement = FindMatchingCommand(value);
if (!textElement.Empty()) {
return textElement.GenericToken;
}
// Check for special characters.
textElement = FindMatchingSpecial(value);
if (!textElement.Empty()) {
return textElement.GenericToken;
}
// Check for dictionary.
int dictionary = FindDictionaryEntry(value);
if (dictionary >= 0) {
return absl::StrFormat("[%s:%X]", DICTIONARYTOKEN, dictionary);
}
return "";
}
std::vector<uint8_t> ParseMessageToData(std::string str) {
std::vector<uint8_t> bytes;
std::string temp_string = str;
int pos = 0;
while (pos < temp_string.size()) {
// Get next text fragment.
if (temp_string[pos] == '[') {
int next = temp_string.find(']', pos);
if (next == -1) {
break;
}
ParsedElement parsedElement =
FindMatchingElement(temp_string.substr(pos, next - pos + 1));
const auto dictionary_element =
TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
if (!parsedElement.Active) {
core::logf("Error parsing message: %s", temp_string);
break;
} else if (parsedElement.Parent == dictionary_element) {
bytes.push_back(parsedElement.Value);
} else {
bytes.push_back(parsedElement.Parent.ID);
if (parsedElement.Parent.HasArgument) {
bytes.push_back(parsedElement.Value);
}
}
pos = next + 1;
continue;
} else {
uint8_t bb = FindMatchingCharacter(temp_string[pos++]);
if (bb != 0xFF) {
core::logf("Error parsing message: %s", temp_string);
bytes.push_back(bb);
}
}
}
return bytes;
}
std::vector<DictionaryEntry> BuildDictionaryEntries(app::Rom* rom) {
std::vector<DictionaryEntry> AllDictionaries;
for (int i = 0; i < kNumDictionaryEntries; i++) {
std::vector<uint8_t> bytes;
std::stringstream stringBuilder;
int address = core::SnesToPc(
kTextData + (rom->data()[kPointersDictionaries + (i * 2) + 1] << 8) +
rom->data()[kPointersDictionaries + (i * 2)]);
int temppush_backress = core::SnesToPc(
kTextData +
(rom->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) +
rom->data()[kPointersDictionaries + ((i + 1) * 2)]);
while (address < temppush_backress) {
uint8_t uint8_tDictionary = rom->data()[address++];
bytes.push_back(uint8_tDictionary);
stringBuilder << ParseTextDataByte(uint8_tDictionary);
}
AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()});
}
std::sort(AllDictionaries.begin(), AllDictionaries.end(),
[](const DictionaryEntry& a, const DictionaryEntry& b) {
return a.Contents.size() > b.Contents.size();
});
return AllDictionaries;
}
} // namespace editor
} // namespace app
} // namespace yaze

View File

@@ -1,23 +1,90 @@
#ifndef YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
#define YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
#include <regex>
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_replace.h"
#include "app/rom.h"
namespace yaze {
namespace app {
namespace editor {
const uint8_t MESSAGETERMINATOR = 0x7F;
const uint8_t kMessageTerminator = 0x7F;
const std::string BANKToken = "BANK";
const std::string DICTIONARYTOKEN = "D";
constexpr uint8_t DICTOFF = 0x88;
static std::string AddNewLinesToCommands(std::string str);
static std::string ReplaceAllDictionaryWords(std::string str);
static std::vector<uint8_t> ParseMessageToData(std::string str);
static const std::unordered_map<uint8_t, wchar_t> CharEncoder = {
{0x00, 'A'}, {0x01, 'B'}, {0x02, 'C'}, {0x03, 'D'}, {0x04, 'E'},
{0x05, 'F'}, {0x06, 'G'}, {0x07, 'H'}, {0x08, 'I'}, {0x09, 'J'},
{0x0A, 'K'}, {0x0B, 'L'}, {0x0C, 'M'}, {0x0D, 'N'}, {0x0E, 'O'},
{0x0F, 'P'}, {0x10, 'Q'}, {0x11, 'R'}, {0x12, 'S'}, {0x13, 'T'},
{0x14, 'U'}, {0x15, 'V'}, {0x16, 'W'}, {0x17, 'X'}, {0x18, 'Y'},
{0x19, 'Z'}, {0x1A, 'a'}, {0x1B, 'b'}, {0x1C, 'c'}, {0x1D, 'd'},
{0x1E, 'e'}, {0x1F, 'f'}, {0x20, 'g'}, {0x21, 'h'}, {0x22, 'i'},
{0x23, 'j'}, {0x24, 'k'}, {0x25, 'l'}, {0x26, 'm'}, {0x27, 'n'},
{0x28, 'o'}, {0x29, 'p'}, {0x2A, 'q'}, {0x2B, 'r'}, {0x2C, 's'},
{0x2D, 't'}, {0x2E, 'u'}, {0x2F, 'v'}, {0x30, 'w'}, {0x31, 'x'},
{0x32, 'y'}, {0x33, 'z'}, {0x34, '0'}, {0x35, '1'}, {0x36, '2'},
{0x37, '3'}, {0x38, '4'}, {0x39, '5'}, {0x3A, '6'}, {0x3B, '7'},
{0x3C, '8'}, {0x3D, '9'}, {0x3E, '!'}, {0x3F, '?'}, {0x40, '-'},
{0x41, '.'}, {0x42, ','}, {0x44, '>'}, {0x45, '('}, {0x46, ')'},
{0x4C, '"'}, {0x51, '\''}, {0x59, ' '}, {0x5A, '<'}, {0x5F, L'¡'},
{0x60, L'¡'}, {0x61, L'¡'}, {0x62, L' '}, {0x63, L' '}, {0x64, L' '},
{0x65, ' '}, {0x66, '_'},
};
const std::string CHEESE = "\uBEBE"; // Inserted into commands to protect
// them from dictionary replacements.
uint8_t FindMatchingCharacter(char value);
uint8_t FindDictionaryEntry(uint8_t value);
std::vector<uint8_t> ParseMessageToData(std::string str);
struct DictionaryEntry {
uint8_t ID;
std::string Contents;
std::vector<uint8_t> Data;
int Length;
std::string Token;
DictionaryEntry() = default;
DictionaryEntry(uint8_t i, std::string s)
: Contents(s), ID(i), Length(s.length()) {
Token = absl::StrFormat("[%s:%00X]", DICTIONARYTOKEN, ID);
Data = ParseMessageToData(Contents);
}
bool ContainedInString(std::string s) {
return s.find(Contents) != std::string::npos;
}
std::string ReplaceInstancesOfIn(std::string s) {
std::string replacedString = s;
size_t pos = replacedString.find(Contents);
while (pos != std::string::npos) {
replacedString.replace(pos, Contents.length(), Token);
pos = replacedString.find(Contents, pos + Token.length());
}
return replacedString;
}
};
constexpr int kTextData = 0xE0000;
constexpr int kTextDataEnd = 0xE7FFF;
constexpr int kNumDictionaryEntries = 97;
constexpr int kPointersDictionaries = 0x74703;
std::vector<DictionaryEntry> BuildDictionaryEntries(app::Rom* rom);
std::string ReplaceAllDictionaryWords(std::string str,
std::vector<DictionaryEntry> dictionary);
// Inserted into commands to protect them from dictionary replacements.
const std::string CHEESE = "\uBEBE";
struct MessageData {
int ID;
@@ -49,35 +116,13 @@ struct MessageData {
ContentsParsed = other.ContentsParsed;
}
void SetMessage(std::string messageString) {
ContentsParsed = messageString;
RawString = OptimizeMessageForDictionary(messageString);
RecalculateData();
}
std::string ToString() {
return absl::StrFormat("%0X - %s", ID, ContentsParsed);
}
std::string GetReadableDumpedContents() {
std::stringstream stringBuilder;
for (const auto& b : Data) {
stringBuilder << absl::StrFormat("%0X ", b);
}
stringBuilder << absl::StrFormat("%00X", MESSAGETERMINATOR);
return absl::StrFormat(
"[[[[\r\nMessage "
"%000X]]]]\r\n[Contents]\r\n%s\r\n\r\n[Data]\r\n%s"
"\r\n\r\n\r\n\r\n",
ID, AddNewLinesToCommands(ContentsParsed), stringBuilder.str());
}
std::string GetDumpedContents() {
return absl::StrFormat("%000X : %s\r\n\r\n", ID, ContentsParsed);
}
std::string OptimizeMessageForDictionary(std::string messageString) {
std::string OptimizeMessageForDictionary(
std::string messageString,
const std::vector<DictionaryEntry>& dictionary) {
std::stringstream protons;
bool command = false;
for (const auto& c : messageString) {
@@ -94,16 +139,18 @@ struct MessageData {
}
std::string protonsString = protons.str();
std::string replacedString = ReplaceAllDictionaryWords(protonsString);
std::string replacedString =
ReplaceAllDictionaryWords(protonsString, dictionary);
std::string finalString =
absl::StrReplaceAll(replacedString, {{CHEESE, ""}});
return finalString;
}
void RecalculateData() {
Data = ParseMessageToData(RawString);
DataParsed = ParseMessageToData(ContentsParsed);
void SetMessage(const std::string& message,
const std::vector<DictionaryEntry>& dictionary) {
RawString = message;
ContentsParsed = OptimizeMessageForDictionary(message, dictionary);
}
};
@@ -155,8 +202,64 @@ struct TextElement {
}
bool Empty() { return ID == 0; }
// Comparison operator
bool operator==(const TextElement& other) const { return ID == other.ID; }
};
static const std::vector<TextElement> TextCommands = {
TextElement(0x6B, "W", true, "Window border"),
TextElement(0x6D, "P", true, "Window position"),
TextElement(0x6E, "SPD", true, "Scroll speed"),
TextElement(0x7A, "S", true, "Text draw speed"),
TextElement(0x77, "C", true, "Text color"),
TextElement(0x6A, "L", false, "Player name"),
TextElement(0x74, "1", false, "Line 1"),
TextElement(0x75, "2", false, "Line 2"),
TextElement(0x76, "3", false, "Line 3"),
TextElement(0x7E, "K", false, "Wait for key"),
TextElement(0x73, "V", false, "Scroll text"),
TextElement(0x78, "WT", true, "Delay X"),
TextElement(0x6C, "N", true, "BCD number"),
TextElement(0x79, "SFX", true, "Sound effect"),
TextElement(0x71, "CH3", false, "Choose 3"),
TextElement(0x72, "CH2", false, "Choose 2 high"),
TextElement(0x6F, "CH2L", false, "Choose 2 low"),
TextElement(0x68, "CH2I", false, "Choose 2 indented"),
TextElement(0x69, "CHI", false, "Choose item"),
TextElement(0x67, "IMG", false, "Next attract image"),
TextElement(0x80, BANKToken, false, "Bank marker (automatic)"),
TextElement(0x70, "NONO", false, "Crash"),
};
TextElement FindMatchingCommand(uint8_t b);
static const std::vector<TextElement> SpecialChars = {
TextElement(0x43, "...", false, "Ellipsis …"),
TextElement(0x4D, "UP", false, "Arrow ↑"),
TextElement(0x4E, "DOWN", false, "Arrow ↓"),
TextElement(0x4F, "LEFT", false, "Arrow ←"),
TextElement(0x50, "RIGHT", false, "Arrow →"),
TextElement(0x5B, "A", false, "Button Ⓐ"),
TextElement(0x5C, "B", false, "Button Ⓑ"),
TextElement(0x5D, "X", false, "Button ⓧ"),
TextElement(0x5E, "Y", false, "Button ⓨ"),
TextElement(0x52, "HP1L", false, "1 HP left"),
TextElement(0x53, "HP1R", false, "1 HP right"),
TextElement(0x54, "HP2L", false, "2 HP left"),
TextElement(0x55, "HP3L", false, "3 HP left"),
TextElement(0x56, "HP3R", false, "3 HP right"),
TextElement(0x57, "HP4L", false, "4 HP left"),
TextElement(0x58, "HP4R", false, "4 HP right"),
TextElement(0x47, "HY0", false, "Hieroglyph ☥"),
TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"),
TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"),
TextElement(0x4A, "LFL", false, "Link face left"),
TextElement(0x4B, "LFR", false, "Link face right"),
};
TextElement FindMatchingSpecial(uint8_t b);
struct ParsedElement {
TextElement Parent;
uint8_t Value;
@@ -170,8 +273,12 @@ struct ParsedElement {
}
};
ParsedElement FindMatchingElement(const std::string& str);
std::string ParseTextDataByte(uint8_t value);
} // namespace editor
} // namespace app
} // namespace yaze
#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H
#endif // YAZE_APP_EDITOR_MESSAGE_MESSAGE_DATA_H

View File

@@ -1,7 +1,5 @@
#include "message_editor.h"
#include <regex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -9,26 +7,24 @@
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "app/core/common.h"
#include "app/editor/utils/editor.h"
#include "app/core/platform/renderer.h"
#include "app/gfx/bitmap.h"
#include "app/gfx/snes_palette.h"
#include "app/gfx/snes_tile.h"
#include "app/gui/canvas.h"
#include "app/gui/icons.h"
#include "app/gui/style.h"
#include "app/rom.h"
#include "imgui.h"
namespace yaze {
namespace app {
namespace editor {
using ImGui::Begin;
using core::Renderer;
using ImGui::BeginChild;
using ImGui::BeginTable;
using ImGui::Button;
using ImGui::End;
using ImGui::EndChild;
using ImGui::EndTable;
using ImGui::InputText;
@@ -37,216 +33,24 @@ using ImGui::SameLine;
using ImGui::Separator;
using ImGui::TableHeadersRow;
using ImGui::TableNextColumn;
using ImGui::TableNextRow;
using ImGui::TableSetupColumn;
using ImGui::Text;
using ImGui::TextWrapped;
using ImGui::TreeNode;
static ParsedElement FindMatchingElement(string str) {
std::smatch match;
for (auto& textElement : TextCommands) {
match = textElement.MatchMe(str);
if (match.size() > 0) {
if (textElement.HasArgument) {
return ParsedElement(textElement,
std::stoi(match[1].str(), nullptr, 16));
} else {
return ParsedElement(textElement, 0);
}
}
}
constexpr ImGuiTableFlags kMessageTableFlags = ImGuiTableFlags_Hideable |
ImGuiTableFlags_Borders |
ImGuiTableFlags_Resizable;
match = DictionaryElement.MatchMe(str);
if (match.size() > 0) {
return ParsedElement(DictionaryElement,
DICTOFF + std::stoi(match[1].str(), nullptr, 16));
}
return ParsedElement();
}
static string ReplaceAllDictionaryWords(string str) {
string temp = str;
for (const auto& entry : AllDictionaries) {
if (absl::StrContains(temp, entry.Contents)) {
temp = absl::StrReplaceAll(temp, {{entry.Contents, entry.Contents}});
}
}
return temp;
}
static std::vector<uint8_t> ParseMessageToData(string str) {
std::vector<uint8_t> bytes;
string tempString = str;
int pos = 0;
while (pos < tempString.size()) {
// Get next text fragment.
if (tempString[pos] == '[') {
int next = tempString.find(']', pos);
if (next == -1) {
break;
}
ParsedElement parsedElement =
FindMatchingElement(tempString.substr(pos, next - pos + 1));
if (!parsedElement.Active) {
break; // TODO: handle badness.
// } else if (parsedElement.Parent == DictionaryElement) {
// bytes.push_back(parsedElement.Value);
} else {
bytes.push_back(parsedElement.Parent.ID);
if (parsedElement.Parent.HasArgument) {
bytes.push_back(parsedElement.Value);
}
}
pos = next + 1;
continue;
} else {
uint8_t bb = MessageEditor::FindMatchingCharacter(tempString[pos++]);
if (bb != 0xFF) {
// TODO: handle badness.
bytes.push_back(bb);
}
}
}
return bytes;
}
absl::Status MessageEditor::Update() {
if (rom()->is_loaded() && !data_loaded_) {
RETURN_IF_ERROR(Initialize());
CurrentMessage = ListOfTexts[1];
data_loaded_ = true;
}
if (BeginTable("##MessageEditor", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) {
TableSetupColumn("List");
TableSetupColumn("Contents");
TableSetupColumn("Commands");
TableHeadersRow();
TableNextColumn();
DrawMessageList();
TableNextColumn();
DrawCurrentMessage();
TableNextColumn();
DrawTextCommands();
EndTable();
}
return absl::OkStatus();
}
void MessageEditor::DrawMessageList() {
if (InputText("Search", &search_text_)) {
DisplayedMessages.clear();
for (const auto& message : ListOfTexts) {
if (absl::StrContains(message.ContentsParsed, search_text_)) {
DisplayedMessages.push_back(message);
}
}
}
if (BeginChild("##MessagesList", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (BeginTable("##MessagesTable", 3,
ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders |
ImGuiTableFlags_Resizable)) {
TableSetupColumn("ID");
TableSetupColumn("Contents");
TableSetupColumn("Data");
TableHeadersRow();
for (const auto& message : ListOfTexts) {
TableNextColumn();
if (Button(core::UppercaseHexWord(message.ID).c_str())) {
CurrentMessage = message;
DrawMessagePreview();
}
TableNextColumn();
TextWrapped("%s", ParsedMessages[message.ID].c_str());
TableNextColumn();
TextWrapped(
"%s",
core::UppercaseHexLong(ListOfTexts[message.ID].Address).c_str());
}
EndTable();
}
EndChild();
}
}
void MessageEditor::DrawCurrentMessage() {
Button(absl::StrCat("Message ", CurrentMessage.ID).c_str());
if (InputTextMultiline("##MessageEditor", &ParsedMessages[CurrentMessage.ID],
ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
CurrentMessage.Data = ParseMessageToData(message_text_box_.text);
DrawMessagePreview();
}
Separator();
Text("Font Graphics");
gui::BeginPadding(1);
BeginChild("MessageEditorCanvas", ImVec2(0, 130));
font_gfx_canvas_.DrawBackground();
font_gfx_canvas_.DrawContextMenu();
font_gfx_canvas_.DrawBitmap(font_gfx_bitmap_, 0, 0);
font_gfx_canvas_.DrawGrid();
font_gfx_canvas_.DrawOverlay();
EndChild();
gui::EndPadding();
Separator();
Text("Message Preview");
if (Button("Refresh Bitmap")) {
rom()->UpdateBitmap(&current_font_gfx16_bitmap_);
}
gui::BeginPadding(1);
BeginChild("CurrentGfxFont", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar);
current_font_gfx16_canvas_.DrawBackground();
gui::EndPadding();
current_font_gfx16_canvas_.DrawContextMenu();
current_font_gfx16_canvas_.DrawBitmap(current_font_gfx16_bitmap_, 0, 0);
current_font_gfx16_canvas_.DrawGrid();
current_font_gfx16_canvas_.DrawOverlay();
EndChild();
}
void MessageEditor::DrawTextCommands() {
if (BeginChild("##TextCommands", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
for (const auto& text_element : TextCommands) {
if (Button(text_element.GenericToken.c_str())) {
}
SameLine();
TextWrapped("%s", text_element.Description.c_str());
Separator();
}
EndChild();
}
}
constexpr ImGuiTableFlags kDictTableFlags =
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable;
absl::Status MessageEditor::Initialize() {
for (int i = 0; i < 100; i++) {
for (int i = 0; i < kWidthArraySize; i++) {
width_array[i] = rom()->data()[kCharactersWidth + i];
}
BuildDictionaryEntries();
ReadAllTextData();
all_dictionaries_ = BuildDictionaryEntries(rom());
ReadAllTextDataV2();
font_preview_colors_.AddColor(0x7FFF); // White
font_preview_colors_.AddColor(0x7C00); // Red
@@ -257,21 +61,23 @@ absl::Status MessageEditor::Initialize() {
for (int i = 0; i < 0x4000; i++) {
data[i] = rom()->data()[kGfxFont + i];
}
font_gfx16_data = gfx::SnesTo8bppSheet(data, /*bpp=*/2);
font_gfx16_data_ = gfx::SnesTo8bppSheet(data, /*bpp=*/2, /*num_sheets=*/2);
// 4bpp
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
128, 128, 8, font_gfx16_data, font_gfx_bitmap_, font_preview_colors_))
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
kFontGfxMessageSize, kFontGfxMessageSize, kFontGfxMessageDepth,
font_gfx16_data_, font_gfx_bitmap_, font_preview_colors_))
current_font_gfx16_data_.reserve(172 * 4096);
for (int i = 0; i < 172 * 4096; i++) {
current_font_gfx16_data_.reserve(kCurrentMessageWidth *
kCurrentMessageHeight);
for (int i = 0; i < kCurrentMessageWidth * kCurrentMessageHeight; i++) {
current_font_gfx16_data_.push_back(0);
}
// 8bpp
RETURN_IF_ERROR(rom()->CreateAndRenderBitmap(
172, 4096, 64, current_font_gfx16_data_, current_font_gfx16_bitmap_,
font_preview_colors_))
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
kCurrentMessageWidth, kCurrentMessageHeight, 64, current_font_gfx16_data_,
current_font_gfx16_bitmap_, font_preview_colors_))
gfx::SnesPalette color_palette = font_gfx_bitmap_.palette();
for (int i = 0; i < font_preview_colors_.size(); i++) {
@@ -280,11 +86,11 @@ absl::Status MessageEditor::Initialize() {
*font_gfx_bitmap_.mutable_palette() = color_palette;
for (const auto& message : ListOfTexts) {
DisplayedMessages.push_back(message);
}
for (const auto& each_message : list_of_texts_) {
std::cout << "Message #" << each_message.ID << " at address "
<< core::UppercaseHexLong(each_message.Address) << std::endl;
std::cout << " " << each_message.RawString << std::endl;
for (const auto& each_message : ListOfTexts) {
// Each string has a [:XX] char encoded
// The corresponding character is found in CharEncoder unordered_map
std::string parsed_message = "";
@@ -313,7 +119,8 @@ absl::Status MessageEditor::Initialize() {
}
}
}
ParsedMessages.push_back(parsed_message);
std::cout << " > " << parsed_message << std::endl;
parsed_messages_.push_back(parsed_message);
}
DrawMessagePreview();
@@ -321,38 +128,245 @@ absl::Status MessageEditor::Initialize() {
return absl::OkStatus();
}
void MessageEditor::BuildDictionaryEntries() {
for (int i = 0; i < 97; i++) {
std::vector<uint8_t> bytes;
std::stringstream stringBuilder;
int address = core::SnesToPc(
0x0E0000 + (rom()->data()[kPointersDictionaries + (i * 2) + 1] << 8) +
rom()->data()[kPointersDictionaries + (i * 2)]);
int temppush_backress = core::SnesToPc(
0x0E0000 +
(rom()->data()[kPointersDictionaries + ((i + 1) * 2) + 1] << 8) +
rom()->data()[kPointersDictionaries + ((i + 1) * 2)]);
while (address < temppush_backress) {
uint8_t uint8_tDictionary = rom()->data()[address++];
bytes.push_back(uint8_tDictionary);
stringBuilder << ParseTextDataByte(uint8_tDictionary);
}
// AllDictionaries[i] = DictionaryEntry{(uint8_t)i, stringBuilder.str()};
AllDictionaries.push_back(DictionaryEntry{(uint8_t)i, stringBuilder.str()});
absl::Status MessageEditor::Update() {
if (rom()->is_loaded() && !data_loaded_) {
RETURN_IF_ERROR(Initialize());
current_message_ = list_of_texts_[1];
data_loaded_ = true;
}
// AllDictionaries.OrderByDescending(dictionary = > dictionary.Length);
AllDictionaries[0].Length = 0;
if (BeginTable("##MessageEditor", 4, kDictTableFlags)) {
TableSetupColumn("List");
TableSetupColumn("Contents");
TableSetupColumn("Commands");
TableSetupColumn("Dictionary");
TableHeadersRow();
TableNextColumn();
DrawMessageList();
TableNextColumn();
DrawCurrentMessage();
TableNextColumn();
DrawTextCommands();
TableNextColumn();
DrawDictionary();
EndTable();
}
return absl::OkStatus();
}
void MessageEditor::DrawMessageList() {
if (InputText("Search", &search_text_)) {
// TODO: ImGui style text filtering
}
if (BeginChild("##MessagesList", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (BeginTable("##MessagesTable", 3, kMessageTableFlags)) {
TableSetupColumn("ID");
TableSetupColumn("Contents");
TableSetupColumn("Data");
TableHeadersRow();
for (const auto& message : list_of_texts_) {
TableNextColumn();
if (Button(core::UppercaseHexWord(message.ID).c_str())) {
current_message_ = message;
DrawMessagePreview();
}
TableNextColumn();
TextWrapped("%s", parsed_messages_[message.ID].c_str());
TableNextColumn();
TextWrapped(
"%s",
core::UppercaseHexLong(list_of_texts_[message.ID].Address).c_str());
}
EndTable();
}
EndChild();
}
}
void MessageEditor::DrawCurrentMessage() {
Button(absl::StrCat("Message ", current_message_.ID).c_str());
if (InputTextMultiline("##MessageEditor",
&parsed_messages_[current_message_.ID],
ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
current_message_.Data = ParseMessageToData(message_text_box_.text);
DrawMessagePreview();
}
Separator();
Text("Font Graphics");
gui::BeginPadding(1);
BeginChild("MessageEditorCanvas", ImVec2(0, 130));
font_gfx_canvas_.DrawBackground();
font_gfx_canvas_.DrawContextMenu();
font_gfx_canvas_.DrawBitmap(font_gfx_bitmap_, 0, 0);
font_gfx_canvas_.DrawGrid();
font_gfx_canvas_.DrawOverlay();
EndChild();
gui::EndPadding();
Separator();
Text("Message Preview");
if (Button("Refresh Bitmap")) {
Renderer::GetInstance().UpdateBitmap(&current_font_gfx16_bitmap_);
}
gui::BeginPadding(1);
BeginChild("CurrentGfxFont", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar);
current_font_gfx16_canvas_.DrawBackground();
gui::EndPadding();
current_font_gfx16_canvas_.DrawContextMenu();
current_font_gfx16_canvas_.DrawBitmap(current_font_gfx16_bitmap_, 0, 0);
current_font_gfx16_canvas_.DrawGrid();
current_font_gfx16_canvas_.DrawOverlay();
EndChild();
}
void MessageEditor::DrawTextCommands() {
if (BeginChild("##TextCommands", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
for (const auto& text_element : TextCommands) {
if (Button(text_element.GenericToken.c_str())) {
}
SameLine();
TextWrapped("%s", text_element.Description.c_str());
Separator();
}
EndChild();
}
}
void MessageEditor::DrawDictionary() {
if (ImGui::BeginChild("##DictionaryChild", ImVec2(0, 0), true,
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (BeginTable("##Dictionary", 2, kDictTableFlags)) {
TableSetupColumn("ID");
TableSetupColumn("Contents");
for (const auto& dictionary : all_dictionaries_) {
TableNextColumn();
Text("%s", core::UppercaseHexWord(dictionary.ID).c_str());
TableNextColumn();
Text("%s", dictionary.Contents.c_str());
}
EndTable();
}
EndChild();
}
}
// TODO: Fix the command parsing.
void MessageEditor::ReadAllTextDataV2() {
// Read all text data from the ROM.
int pos = kTextData;
int message_id = 0;
std::vector<uint8_t> raw_message;
std::vector<uint8_t> parsed_message;
std::string current_raw_message;
std::string current_parsed_message;
uint8_t current_byte = 0;
while (current_byte != 0xFF) {
current_byte = rom()->data()[pos++];
if (current_byte == kMessageTerminator) {
auto message =
MessageData(message_id++, pos, current_raw_message, raw_message,
current_parsed_message, parsed_message);
list_of_texts_.push_back(message);
raw_message.clear();
parsed_message.clear();
current_raw_message.clear();
current_parsed_message.clear();
continue;
}
raw_message.push_back(current_byte);
// Check for command.
TextElement text_element = FindMatchingCommand(current_byte);
if (!text_element.Empty()) {
parsed_message.push_back(current_byte);
if (text_element.HasArgument) {
current_byte = rom()->data()[pos++];
raw_message.push_back(current_byte);
parsed_message.push_back(current_byte);
}
current_raw_message.append(
text_element.GetParameterizedToken(current_byte));
current_parsed_message.append(
text_element.GetParameterizedToken(current_byte));
if (text_element.Token == BANKToken) {
pos = kTextData2;
}
continue;
}
// Check for special characters.
text_element = FindMatchingSpecial(current_byte);
if (!text_element.Empty()) {
current_raw_message.append(text_element.GetParameterizedToken());
current_parsed_message.append(text_element.GetParameterizedToken());
parsed_message.push_back(current_byte);
continue;
}
// Check for dictionary.
int dictionary = FindDictionaryEntry(current_byte);
if (dictionary >= 0) {
current_raw_message.append("[");
current_raw_message.append(DICTIONARYTOKEN);
current_raw_message.append(":");
current_raw_message.append(core::UppercaseHexWord(dictionary));
current_raw_message.append("]");
uint32_t address = core::Get24LocalFromPC(
rom()->data(), kPointersDictionaries + (dictionary * 2));
uint32_t address_end = core::Get24LocalFromPC(
rom()->data(), kPointersDictionaries + ((dictionary + 1) * 2));
for (uint32_t i = address; i < address_end; i++) {
parsed_message.push_back(rom()->data()[i]);
current_parsed_message.append(ParseTextDataByte(rom()->data()[i]));
}
continue;
}
// Everything else.
if (CharEncoder.contains(current_byte)) {
std::string str = "";
str.push_back(CharEncoder.at(current_byte));
current_raw_message.append(str);
current_parsed_message.append(str);
parsed_message.push_back(current_byte);
}
}
}
void MessageEditor::ReadAllTextData() {
int messageID = 0;
uint8_t current_byte;
int pos = kTextData;
int message_id = 0;
uint8_t current_byte;
std::vector<uint8_t> temp_bytes_raw;
std::vector<uint8_t> temp_bytes_parsed;
@@ -363,12 +377,12 @@ void MessageEditor::ReadAllTextData() {
while (true) {
current_byte = rom()->data()[pos++];
if (current_byte == MESSAGETERMINATOR) {
if (current_byte == kMessageTerminator) {
auto message =
MessageData(messageID++, pos, current_message_raw, temp_bytes_raw,
MessageData(message_id++, pos, current_message_raw, temp_bytes_raw,
current_message_parsed, temp_bytes_parsed);
ListOfTexts.push_back(message);
list_of_texts_.push_back(message);
temp_bytes_raw.clear();
temp_bytes_parsed.clear();
@@ -407,7 +421,6 @@ void MessageEditor::ReadAllTextData() {
// Check for special characters.
text_element = FindMatchingSpecial(current_byte);
if (!text_element.Empty()) {
current_message_raw.append(text_element.GetParameterizedToken());
current_message_parsed.append(text_element.GetParameterizedToken());
@@ -449,83 +462,29 @@ void MessageEditor::ReadAllTextData() {
}
}
TextElement MessageEditor::FindMatchingCommand(uint8_t b) {
TextElement empty_element;
for (const auto text_element : TextCommands) {
if (text_element.ID == b) {
return text_element;
std::string ReplaceAllDictionaryWords(std::string str,
std::vector<DictionaryEntry> dictionary) {
std::string temp = str;
for (const auto& entry : dictionary) {
if (absl::StrContains(temp, entry.Contents)) {
temp = absl::StrReplaceAll(temp, {{entry.Contents, entry.Contents}});
}
}
return empty_element;
return temp;
}
TextElement MessageEditor::FindMatchingSpecial(uint8_t value) {
TextElement empty_element;
for (const auto text_element : SpecialChars) {
if (text_element.ID == value) {
return text_element;
}
}
return empty_element;
}
MessageEditor::DictionaryEntry MessageEditor::GetDictionaryFromID(
uint8_t value) {
if (value < 0 || value >= AllDictionaries.size()) {
DictionaryEntry MessageEditor::GetDictionaryFromID(uint8_t value) {
if (value < 0 || value >= all_dictionaries_.size()) {
return DictionaryEntry();
}
return AllDictionaries[value];
}
uint8_t MessageEditor::FindDictionaryEntry(uint8_t value) {
if (value < DICTOFF || value == 0xFF) {
return -1;
}
return value - DICTOFF;
}
uint8_t MessageEditor::FindMatchingCharacter(char value) {
for (const auto [key, char_value] : CharEncoder) {
if (value == char_value) {
return key;
}
}
return 0xFF;
}
string MessageEditor::ParseTextDataByte(uint8_t value) {
if (CharEncoder.contains(value)) {
char c = CharEncoder.at(value);
string str = "";
str.push_back(c);
return str;
}
// Check for command.
TextElement textElement = FindMatchingCommand(value);
if (!textElement.Empty()) {
return textElement.GenericToken;
}
// Check for special characters.
textElement = FindMatchingSpecial(value);
if (!textElement.Empty()) {
return textElement.GenericToken;
}
// Check for dictionary.
int dictionary = FindDictionaryEntry(value);
if (dictionary >= 0) {
return absl::StrFormat("[%s:%X]", DICTIONARYTOKEN, dictionary);
}
return "";
return all_dictionaries_[value];
}
void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
int sizex, int sizey) {
int drawid = srcx + (srcy * 32);
const int num_x_tiles = 16;
const int img_width = 512; // (imgwidth/2)
int draw_id = srcx + (srcy * 32);
for (int yl = 0; yl < sizey * 8; yl++) {
for (int xl = 0; xl < 4; xl++) {
int mx = xl;
@@ -533,8 +492,9 @@ void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
// Formula information to get tile index position in the array.
// ((ID / nbrofXtiles) * (imgwidth/2) + (ID - ((ID/16)*16) ))
int tx = ((drawid / 16) * 512) + ((drawid - ((drawid / 16) * 16)) * 4);
uint8_t pixel = font_gfx16_data[tx + (yl * 64) + xl];
int tx = ((draw_id / num_x_tiles) * img_width) +
((draw_id - ((draw_id / 16) * 16)) * 4);
uint8_t pixel = font_gfx16_data_[tx + (yl * 64) + xl];
// nx,ny = object position, xx,yy = tile position, xl,yl = pixel
// position
@@ -552,7 +512,7 @@ void MessageEditor::DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
}
}
void MessageEditor::DrawStringToPreview(string str) {
void MessageEditor::DrawStringToPreview(std::string str) {
for (const auto c : str) {
DrawCharacterToPreview(c);
}
@@ -573,25 +533,25 @@ void MessageEditor::DrawCharacterToPreview(const std::vector<uint8_t>& text) {
int srcy = value / 16;
int srcx = value - (value & (~0xF));
if (text_pos >= 170) {
text_pos = 0;
text_line++;
if (text_position_ >= 170) {
text_position_ = 0;
text_line_++;
}
DrawTileToPreview(text_pos, text_line * 16, srcx, srcy, 0, 1, 2);
text_pos += width_array[value];
DrawTileToPreview(text_position_, text_line_ * 16, srcx, srcy, 0, 1, 2);
text_position_ += width_array[value];
} else if (value == kLine1) {
text_pos = 0;
text_line = 0;
text_position_ = 0;
text_line_ = 0;
} else if (value == kScrollVertical) {
text_pos = 0;
text_line += 1;
text_position_ = 0;
text_line_ += 1;
} else if (value == kLine2) {
text_pos = 0;
text_line = 1;
text_position_ = 0;
text_line_ = 1;
} else if (value == kLine3) {
text_pos = 0;
text_line = 2;
text_position_ = 0;
text_line_ = 2;
} else if (value == 0x6B || value == 0x6D || value == 0x6E ||
value == 0x77 || value == 0x78 || value == 0x79 ||
value == 0x7A) {
@@ -615,15 +575,15 @@ void MessageEditor::DrawCharacterToPreview(const std::vector<uint8_t>& text) {
}
}
void MessageEditor::DrawMessagePreview() // From Parsing.
{
text_line = 0;
void MessageEditor::DrawMessagePreview() {
// From Parsing.
text_line_ = 0;
for (int i = 0; i < (172 * 4096); i++) {
current_font_gfx16_data_[i] = 0;
}
text_pos = 0;
DrawCharacterToPreview(CurrentMessage.Data);
shown_lines = 0;
text_position_ = 0;
DrawCharacterToPreview(current_message_.Data);
shown_lines_ = 0;
}
absl::Status MessageEditor::Cut() {
@@ -675,7 +635,7 @@ absl::Status MessageEditor::Save() {
int pos = kTextData;
bool in_second_bank = false;
for (const auto& message : ListOfTexts) {
for (const auto& message : list_of_texts_) {
for (const auto value : message.Data) {
RETURN_IF_ERROR(rom()->Write(pos, value));
@@ -695,7 +655,7 @@ absl::Status MessageEditor::Save() {
}
RETURN_IF_ERROR(
rom()->Write(pos++, MESSAGETERMINATOR)); // , true, "Terminator text"
rom()->Write(pos++, kMessageTerminator)); // , true, "Terminator text"
}
// Verify that we didn't go over the space available for the second block.
@@ -712,9 +672,10 @@ absl::Status MessageEditor::Save() {
std::string MessageEditor::DisplayTextOverflowError(int pos, bool bank) {
int space = bank ? kTextDataEnd - kTextData : kTextData2End - kTextData2;
string bankSTR = bank ? "1st" : "2nd";
string posSTR = bank ? absl::StrFormat("%X4", pos & 0xFFFF)
: absl::StrFormat("%X4", (pos - kTextData2) & 0xFFFF);
std::string bankSTR = bank ? "1st" : "2nd";
std::string posSTR =
bank ? absl::StrFormat("%X4", pos & 0xFFFF)
: absl::StrFormat("%X4", (pos - kTextData2) & 0xFFFF);
std::string message = absl::StrFormat(
"There is too much text data in the %s block to save.\n"
"Available: %X4 | Used: %s",
@@ -722,30 +683,6 @@ std::string MessageEditor::DisplayTextOverflowError(int pos, bool bank) {
return message;
}
// push_backs a command to the text field when the push_back command button is
// pressed or the command is double clicked in the list.
void MessageEditor::InsertCommandButton_Click_1() {
// InsertSelectedText(
// TextCommands[TextCommandList.SelectedIndex].GetParameterizedToken(
// (uint8_t)ParamsBox.HexValue));
}
// push_backs a special character to the text field when the push_back command
// button is pressed or the character is double clicked in the list.
void MessageEditor::InsertSpecialButton_Click() {
// InsertSelectedText(
// SpecialChars[SpecialsList.SelectedIndex].GetParameterizedToken());
}
void MessageEditor::InsertSelectedText(string str) {
int textboxPos = message_text_box_.selection_start;
from_form = true;
// message_text_box_.Text = message_text_box_.Text.Insert(textboxPos, str);
from_form = false;
message_text_box_.selection_start = textboxPos + str.size();
message_text_box_.Focus();
}
void MessageEditor::Delete() {
// Determine if any text is selected in the TextBox control.
if (message_text_box_.selection_length == 0) {

View File

@@ -1,229 +1,54 @@
#ifndef YAZE_APP_EDITOR_MESSAGE_EDITOR_H
#define YAZE_APP_EDITOR_MESSAGE_EDITOR_H
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "app/editor/message/message_data.h"
#include "app/editor/utils/editor.h"
#include "app/editor/editor.h"
#include "app/gfx/bitmap.h"
#include "app/gui/canvas.h"
#include "app/gui/icons.h"
#include "app/rom.h"
namespace yaze {
namespace app {
namespace editor {
using std::string;
// TEXT EDITOR RELATED CONSTANTS
const int kGfxFont = 0x70000; // 2bpp format
const int kTextData = 0xE0000;
const int kTextDataEnd = 0xE7FFF;
const int kTextData2 = 0x75F40;
const int kTextData2End = 0x773FF;
const int kPointersDictionaries = 0x74703;
const int kCharactersWidth = 0x74ADF;
const string DICTIONARYTOKEN = "D";
const uint8_t DICTOFF = 0x88;
const string BANKToken = "BANK";
const uint8_t BANKID = 0x80;
constexpr int kGfxFont = 0x70000; // 2bpp format
constexpr int kTextData2 = 0x75F40;
constexpr int kTextData2End = 0x773FF;
constexpr int kCharactersWidth = 0x74ADF;
constexpr int kNumMessages = 396;
constexpr int kCurrentMessageWidth = 172;
constexpr int kCurrentMessageHeight = 4096;
constexpr int kFontGfxMessageSize = 128;
constexpr int kFontGfxMessageDepth = 8;
constexpr uint8_t kWidthArraySize = 100;
constexpr uint8_t kBlockTerminator = 0x80;
static std::vector<uint8_t> ParseMessageToData(string str);
static ParsedElement FindMatchingElement(string str);
constexpr uint8_t kMessageBankChangeId = 0x80;
constexpr uint8_t kScrollVertical = 0x73;
constexpr uint8_t kLine1 = 0x74;
constexpr uint8_t kLine2 = 0x75;
constexpr uint8_t kLine3 = 0x76;
static const TextElement TextCommands[] = {
TextElement(0x6B, "W", true, "Window border"),
TextElement(0x6D, "P", true, "Window position"),
TextElement(0x6E, "SPD", true, "Scroll speed"),
TextElement(0x7A, "S", true, "Text draw speed"),
TextElement(0x77, "C", true, "Text color"),
TextElement(0x6A, "L", false, "Player name"),
TextElement(0x74, "1", false, "Line 1"),
TextElement(0x75, "2", false, "Line 2"),
TextElement(0x76, "3", false, "Line 3"),
TextElement(0x7E, "K", false, "Wait for key"),
TextElement(0x73, "V", false, "Scroll text"),
TextElement(0x78, "WT", true, "Delay X"),
TextElement(0x6C, "N", true, "BCD number"),
TextElement(0x79, "SFX", true, "Sound effect"),
TextElement(0x71, "CH3", false, "Choose 3"),
TextElement(0x72, "CH2", false, "Choose 2 high"),
TextElement(0x6F, "CH2L", false, "Choose 2 low"),
TextElement(0x68, "CH2I", false, "Choose 2 indented"),
TextElement(0x69, "CHI", false, "Choose item"),
TextElement(0x67, "IMG", false, "Next attract image"),
TextElement(0x80, BANKToken, false, "Bank marker (automatic)"),
TextElement(0x70, "NONO", false, "Crash"),
};
static std::vector<TextElement> SpecialChars = {
TextElement(0x43, "...", false, "Ellipsis …"),
TextElement(0x4D, "UP", false, "Arrow ↑"),
TextElement(0x4E, "DOWN", false, "Arrow ↓"),
TextElement(0x4F, "LEFT", false, "Arrow ←"),
TextElement(0x50, "RIGHT", false, "Arrow →"),
TextElement(0x5B, "A", false, "Button Ⓐ"),
TextElement(0x5C, "B", false, "Button Ⓑ"),
TextElement(0x5D, "X", false, "Button ⓧ"),
TextElement(0x5E, "Y", false, "Button ⓨ"),
TextElement(0x52, "HP1L", false, "1 HP left"),
TextElement(0x53, "HP1R", false, "1 HP right"),
TextElement(0x54, "HP2L", false, "2 HP left"),
TextElement(0x55, "HP3L", false, "3 HP left"),
TextElement(0x56, "HP3R", false, "3 HP right"),
TextElement(0x57, "HP4L", false, "4 HP left"),
TextElement(0x58, "HP4R", false, "4 HP right"),
TextElement(0x47, "HY0", false, "Hieroglyph ☥"),
TextElement(0x48, "HY1", false, "Hieroglyph 𓈗"),
TextElement(0x49, "HY2", false, "Hieroglyph Ƨ"),
TextElement(0x4A, "LFL", false, "Link face left"),
TextElement(0x4B, "LFR", false, "Link face right"),
};
static const std::unordered_map<uint8_t, wchar_t> CharEncoder = {
{0x00, 'A'},
{0x01, 'B'},
{0x02, 'C'},
{0x03, 'D'},
{0x04, 'E'},
{0x05, 'F'},
{0x06, 'G'},
{0x07, 'H'},
{0x08, 'I'},
{0x09, 'J'},
{0x0A, 'K'},
{0x0B, 'L'},
{0x0C, 'M'},
{0x0D, 'N'},
{0x0E, 'O'},
{0x0F, 'P'},
{0x10, 'Q'},
{0x11, 'R'},
{0x12, 'S'},
{0x13, 'T'},
{0x14, 'U'},
{0x15, 'V'},
{0x16, 'W'},
{0x17, 'X'},
{0x18, 'Y'},
{0x19, 'Z'},
{0x1A, 'a'},
{0x1B, 'b'},
{0x1C, 'c'},
{0x1D, 'd'},
{0x1E, 'e'},
{0x1F, 'f'},
{0x20, 'g'},
{0x21, 'h'},
{0x22, 'i'},
{0x23, 'j'},
{0x24, 'k'},
{0x25, 'l'},
{0x26, 'm'},
{0x27, 'n'},
{0x28, 'o'},
{0x29, 'p'},
{0x2A, 'q'},
{0x2B, 'r'},
{0x2C, 's'},
{0x2D, 't'},
{0x2E, 'u'},
{0x2F, 'v'},
{0x30, 'w'},
{0x31, 'x'},
{0x32, 'y'},
{0x33, 'z'},
{0x34, '0'},
{0x35, '1'},
{0x36, '2'},
{0x37, '3'},
{0x38, '4'},
{0x39, '5'},
{0x3A, '6'},
{0x3B, '7'},
{0x3C, '8'},
{0x3D, '9'},
{0x3E, '!'},
{0x3F, '?'},
{0x40, '-'},
{0x41, '.'},
{0x42, ','},
{0x44, '>'},
{0x45, '('},
{0x46, ')'},
{0x4C, '"'},
{0x51, '\''},
{0x59, ' '},
{0x5A, '<'},
// {0x5F, '¡'}, {0x60, '¡'}, {0x61, '¡'}, {0x62, ' '}, {0x63, ' '}, {0x64,
// ' '},
{0x65, ' '},
{0x66, '_'},
};
static TextElement DictionaryElement =
TextElement(0x80, DICTIONARYTOKEN, true, "Dictionary");
class MessageEditor : public Editor, public SharedRom {
public:
struct DictionaryEntry {
uint8_t ID;
std::string Contents;
std::vector<uint8_t> Data;
int Length;
std::string Token;
DictionaryEntry() = default;
DictionaryEntry(uint8_t i, std::string s)
: Contents(s), ID(i), Length(s.length()) {
Token = absl::StrFormat("[%s:%00X]", DICTIONARYTOKEN, ID);
Data = ParseMessageToData(Contents);
}
bool ContainedInString(std::string s) {
return s.find(Contents) != std::string::npos;
}
std::string ReplaceInstancesOfIn(std::string s) {
std::string replacedString = s;
size_t pos = replacedString.find(Contents);
while (pos != std::string::npos) {
replacedString.replace(pos, Contents.length(), Token);
pos = replacedString.find(Contents, pos + Token.length());
}
return replacedString;
}
};
MessageEditor() { type_ = EditorType::kMessage; }
absl::Status Initialize();
absl::Status Update() override;
void DrawMessageList();
void DrawCurrentMessage();
void DrawTextCommands();
void DrawDictionary();
absl::Status Initialize();
void ReadAllTextData();
void BuildDictionaryEntries();
void ReadAllTextDataV2();
[[deprecated]] void ReadAllTextData();
absl::Status Cut() override;
absl::Status Copy() override;
@@ -238,67 +63,47 @@ class MessageEditor : public Editor, public SharedRom {
absl::Status Save();
void Delete();
void SelectAll();
// void RegisterTests(ImGuiTestEngine* e) override;
TextElement FindMatchingCommand(uint8_t byte);
TextElement FindMatchingSpecial(uint8_t value);
string ParseTextDataByte(uint8_t value);
DictionaryEntry GetDictionaryFromID(uint8_t value);
static uint8_t FindDictionaryEntry(uint8_t value);
static uint8_t FindMatchingCharacter(char value);
void DrawTileToPreview(int x, int y, int srcx, int srcy, int pal,
int sizex = 1, int sizey = 1);
void DrawCharacterToPreview(char c);
void DrawCharacterToPreview(const std::vector<uint8_t>& text);
void DrawStringToPreview(string str);
void DrawStringToPreview(std::string str);
void DrawMessagePreview();
std::string DisplayTextOverflowError(int pos, bool bank);
void InsertCommandButton_Click_1();
void InsertSpecialButton_Click();
void InsertSelectedText(string str);
static const std::vector<DictionaryEntry> AllDicts;
uint8_t width_array[100];
string romname = "";
int text_line = 0;
int text_pos = 0;
int shown_lines = 0;
int selected_tile = 0;
bool skip_next = false;
bool from_form = false;
std::vector<MessageData> ListOfTexts;
std::vector<MessageData> DisplayedMessages;
std::vector<std::string> ParsedMessages;
MessageData CurrentMessage;
private:
static const TextElement DictionaryElement;
bool skip_next = false;
bool data_loaded_ = false;
int current_message_id_ = 0;
int text_line_ = 0;
int text_position_ = 0;
int shown_lines_ = 0;
uint8_t width_array[kWidthArraySize];
std::string search_text_ = "";
std::vector<uint8_t> font_gfx16_data_;
std::vector<uint8_t> current_font_gfx16_data_;
std::vector<std::string> parsed_messages_;
std::vector<MessageData> list_of_texts_;
std::vector<DictionaryEntry> all_dictionaries_;
MessageData current_message_;
gfx::Bitmap font_gfx_bitmap_;
gfx::Bitmap current_font_gfx16_bitmap_;
gfx::SnesPalette font_preview_colors_;
gui::Canvas font_gfx_canvas_{"##FontGfxCanvas", ImVec2(128, 128)};
gui::Canvas current_font_gfx16_canvas_{"##CurrentMessageGfx",
ImVec2(172, 4096)};
gfx::Bitmap font_gfx_bitmap_;
gfx::Bitmap current_font_gfx16_bitmap_;
Bytes font_gfx16_data;
Bytes current_font_gfx16_data_;
gfx::SnesPalette font_preview_colors_;
struct TextBox {
std::string text;
std::string buffer;
@@ -357,8 +162,6 @@ class MessageEditor : public Editor, public SharedRom {
TextBox message_text_box_;
};
static std::vector<MessageEditor::DictionaryEntry> AllDictionaries;
} // namespace editor
} // namespace app
} // namespace yaze

View File

@@ -1,7 +0,0 @@
#include "message_editor.h"
namespace yaze {
namespace app {
namespace editor {} // namespace editor
} // namespace app
} // namespace yaze