Merge remote-tracking branch 'refs/remotes/origin/master'

Merge changes made on visual studio repo.
This commit is contained in:
scawful
2025-01-06 11:13:29 -05:00
41 changed files with 700 additions and 501 deletions

View File

@@ -1,6 +1,7 @@
#ifndef YAZE_CORE_COMMON_H #ifndef YAZE_CORE_COMMON_H
#define YAZE_CORE_COMMON_H #define YAZE_CORE_COMMON_H
#include <chrono>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
@@ -10,6 +11,7 @@
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/str_cat.h"
namespace yaze { namespace yaze {
@@ -56,12 +58,6 @@ class ExperimentFlags {
// Attempt to run the dungeon room draw routine when opening a room. // Attempt to run the dungeon room draw routine when opening a room.
bool kDrawDungeonRoomGraphics = true; bool kDrawDungeonRoomGraphics = true;
// Use the new platform specific file dialog wrappers.
bool kNewFileDialogWrapper = true;
// Uses texture streaming from SDL for my dynamic updates.
bool kLoadTexturesAsStreaming = true;
// Save dungeon map edits to the Rom. // Save dungeon map edits to the Rom.
bool kSaveDungeonMaps = false; bool kSaveDungeonMaps = false;
@@ -113,10 +109,6 @@ class ExperimentFlags {
"\n"; "\n";
result += "kDrawDungeonRoomGraphics: " + result += "kDrawDungeonRoomGraphics: " +
std::to_string(get().kDrawDungeonRoomGraphics) + "\n"; std::to_string(get().kDrawDungeonRoomGraphics) + "\n";
result += "kNewFileDialogWrapper: " +
std::to_string(get().kNewFileDialogWrapper) + "\n";
result += "kLoadTexturesAsStreaming: " +
std::to_string(get().kLoadTexturesAsStreaming) + "\n";
result += result +=
"kSaveDungeonMaps: " + std::to_string(get().kSaveDungeonMaps) + "\n"; "kSaveDungeonMaps: " + std::to_string(get().kSaveDungeonMaps) + "\n";
result += "kLogToConsole: " + std::to_string(get().kLogToConsole) + "\n"; result += "kLogToConsole: " + std::to_string(get().kLogToConsole) + "\n";
@@ -182,17 +174,23 @@ class NotifyValue {
T temp_value_; T temp_value_;
}; };
static bool log_to_console = false;
static const std::string kLogFileOut = "yaze_log.txt"; static const std::string kLogFileOut = "yaze_log.txt";
template <typename... Args> template <typename... Args>
static void logf(const absl::FormatSpec<Args...> &format, const Args &...args) { static void logf(const absl::FormatSpec<Args...> &format, const Args &...args) {
std::string message = absl::StrFormat(format, args...); std::string message = absl::StrFormat(format, args...);
if (log_to_console) { auto timestamp = std::chrono::system_clock::now();
std::cout << message << std::endl;
std::time_t now_tt = std::chrono::system_clock::to_time_t(timestamp);
std::tm tm = *std::localtime(&now_tt);
message = absl::StrCat("[", tm.tm_hour, ":", tm.tm_min, ":", tm.tm_sec, "] ",
message, "\n");
if (ExperimentFlags::get().kLogToConsole) {
std::cout << message;
} }
static std::ofstream fout(kLogFileOut, std::ios::out | std::ios::app); static std::ofstream fout(kLogFileOut, std::ios::out | std::ios::app);
fout << message << std::endl; fout << message;
} }
constexpr uint32_t kFastRomRegion = 0x808000; constexpr uint32_t kFastRomRegion = 0x808000;

View File

@@ -154,11 +154,11 @@ absl::Status Controller::CreateWindow() {
window_ = std::unique_ptr<SDL_Window, core::SDL_Deleter>( window_ = std::unique_ptr<SDL_Window, core::SDL_Deleter>(
SDL_CreateWindow("Yet Another Zelda3 Editor", // window title SDL_CreateWindow("Yet Another Zelda3 Editor", // window title
SDL_WINDOWPOS_UNDEFINED, // initial x position SDL_WINDOWPOS_UNDEFINED, // initial x position
SDL_WINDOWPOS_UNDEFINED, // initial y position SDL_WINDOWPOS_UNDEFINED, // initial y position
screen_width, // width, in pixels screen_width, // width, in pixels
screen_height, // height, in pixels screen_height, // height, in pixels
SDL_WINDOW_RESIZABLE), SDL_WINDOW_RESIZABLE),
core::SDL_Deleter()); core::SDL_Deleter());
if (window_ == nullptr) { if (window_ == nullptr) {
return absl::InternalError( return absl::InternalError(

View File

@@ -26,7 +26,7 @@ namespace core {
* This class is responsible for managing the main window and the * This class is responsible for managing the main window and the
* main editor. It is the main entry point for the application. * main editor. It is the main entry point for the application.
*/ */
class Controller : public ExperimentFlags { class Controller {
public: public:
bool IsActive() const { return active_; } bool IsActive() const { return active_; }
absl::Status OnEntry(std::string filename = ""); absl::Status OnEntry(std::string filename = "");
@@ -53,13 +53,13 @@ class Controller : public ExperimentFlags {
auto window() -> SDL_Window * { return window_.get(); } auto window() -> SDL_Window * { return window_.get(); }
void init_test_editor(editor::Editor *editor) { test_editor_ = editor; } void init_test_editor(editor::Editor *editor) { test_editor_ = editor; }
void set_active(bool active) { active_ = active; } void set_active(bool active) { active_ = active; }
auto active() { return active_; } auto active() const { return active_; }
private: private:
friend int ::main(int argc, char **argv); friend int ::main(int argc, char **argv);
bool active_ = false; bool active_ = false;
Platform platform_; Platform platform_ = Platform::kUnknown;
editor::Editor *test_editor_ = nullptr; editor::Editor *test_editor_ = nullptr;
editor::EditorManager editor_manager_; editor::EditorManager editor_manager_;

View File

@@ -5,6 +5,7 @@
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include "app/core/constants.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
@@ -15,19 +16,88 @@
namespace yaze { namespace yaze {
namespace core { namespace core {
static const char* KARLA_REGULAR = "Karla-Regular.ttf";
static const char* ROBOTO_MEDIUM = "Roboto-Medium.ttf";
static const char* COUSINE_REGULAR = "Cousine-Regular.ttf";
static const char* DROID_SANS = "DroidSans.ttf";
static const char* NOTO_SANS_JP = "NotoSansJP.ttf";
static const char* IBM_PLEX_JP = "IBMPlexSansJP-Bold.ttf";
static const float FONT_SIZE_DEFAULT = 16.0f;
static const float FONT_SIZE_DROID_SANS = 18.0f;
static const float ICON_FONT_SIZE = 18.0f;
namespace {
std::string SetFontPath(const std::string& font_path) {
#ifdef __APPLE__
#if TARGET_OS_IOS == 1
const std::string kBundlePath = GetBundleResourcePath();
return kBundlePath + font_path;
#else
return absl::StrCat(GetBundleResourcePath(), "Contents/Resources/font/",
font_path);
#endif
#else
return absl::StrCat("assets/font/", font_path);
#endif
}
absl::Status LoadFont(const FontConfig& font_config) {
ImGuiIO& io = ImGui::GetIO();
std::string actual_font_path = SetFontPath(font_config.font_path);
// Check if the file exists with std library first, since ImGui IO will assert
// if the file does not exist
if (!std::filesystem::exists(actual_font_path)) {
return absl::InternalError(
absl::StrFormat("Font file %s does not exist", actual_font_path));
}
if (!io.Fonts->AddFontFromFileTTF(actual_font_path.data(), font_config.font_size)) {
return absl::InternalError(
absl::StrFormat("Failed to load font from %s", actual_font_path));
}
return absl::OkStatus();
}
absl::Status AddIconFont() {
ImGuiIO& io = ImGui::GetIO();
static const ImWchar icons_ranges[] = { ICON_MIN_MD, 0xf900, 0 };
ImFontConfig icons_config;
icons_config.MergeMode = true;
icons_config.GlyphOffset.y = 5.0f;
icons_config.GlyphMinAdvanceX = 13.0f;
icons_config.PixelSnapH = true;
std::string icon_font_path = SetFontPath(FONT_ICON_FILE_NAME_MD);
if (!io.Fonts->AddFontFromFileTTF(icon_font_path.c_str(), ICON_FONT_SIZE,
&icons_config, icons_ranges)) {
return absl::InternalError("Failed to add icon fonts");
}
return absl::OkStatus();
}
absl::Status AddJapaneseFont() {
ImGuiIO& io = ImGui::GetIO();
ImFontConfig japanese_font_config;
japanese_font_config.MergeMode = true;
japanese_font_config.GlyphOffset.y = 5.0f;
japanese_font_config.GlyphMinAdvanceX = 13.0f;
japanese_font_config.PixelSnapH = true;
std::string japanese_font_path = SetFontPath(NOTO_SANS_JP);
if (!io.Fonts->AddFontFromFileTTF(japanese_font_path.data(), ICON_FONT_SIZE,
&japanese_font_config,
io.Fonts->GetGlyphRangesJapanese())) {
return absl::InternalError("Failed to add Japanese fonts");
}
return absl::OkStatus();
}
} // namespace
absl::Status LoadPackageFonts() { absl::Status LoadPackageFonts() {
ImGuiIO &io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
static const char *KARLA_REGULAR = "Karla-Regular.ttf";
static const char *ROBOTO_MEDIUM = "Roboto-Medium.ttf";
static const char *COUSINE_REGULAR = "Cousine-Regular.ttf";
static const char *DROID_SANS = "DroidSans.ttf";
static const char *NOTO_SANS_JP = "NotoSansJP.ttf";
static const char *IBM_PLEX_JP = "IBMPlexSansJP-Bold.ttf";
static const float FONT_SIZE_DEFAULT = 16.0f;
static const float FONT_SIZE_DROID_SANS = 18.0f;
static const float ICON_FONT_SIZE = 18.0f;
// Icon configuration // Icon configuration
static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0}; static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0};
ImFontConfig icons_config; ImFontConfig icons_config;
@@ -52,70 +122,30 @@ absl::Status LoadPackageFonts() {
float font_size = float font_size =
(font_path == DROID_SANS) ? FONT_SIZE_DROID_SANS : FONT_SIZE_DEFAULT; (font_path == DROID_SANS) ? FONT_SIZE_DROID_SANS : FONT_SIZE_DEFAULT;
std::string actual_font_path; FontConfig font_config = { font_path, font_size };
#ifdef __APPLE__ RETURN_IF_ERROR(LoadFont(font_config));
#if TARGET_OS_IOS == 1
const std::string kBundlePath = GetBundleResourcePath();
actual_font_path = kBundlePath + font_path;
#else
actual_font_path = absl::StrCat(GetBundleResourcePath(),
"Contents/Resources/font/", font_path);
#endif
#else
actual_font_path = absl::StrCat("assets/font/", font_path);
actual_font_path = std::filesystem::absolute(actual_font_path).string();
#endif
if (!io.Fonts->AddFontFromFileTTF(actual_font_path.data(), font_size)) {
return absl::InternalError(
absl::StrFormat("Failed to load font from %s", actual_font_path));
}
// Merge icon set // Merge icon set
std::string actual_icon_font_path = ""; RETURN_IF_ERROR(AddIconFont());
const char *icon_font_path = FONT_ICON_FILE_NAME_MD;
#if defined(__APPLE__) && defined(__MACH__)
#if TARGET_OS_IOS == 1
const std::string kIconBundlePath = GetBundleResourcePath();
actual_icon_font_path = kIconBundlePath + "MaterialIcons-Regular.ttf";
#else
actual_icon_font_path =
absl::StrCat(GetBundleResourcePath(),
"Contents/Resources/font/MaterialIcons-Regular.ttf");
#endif
#else
actual_icon_font_path = std::filesystem::absolute(icon_font_path).string();
#endif
if (!io.Fonts->AddFontFromFileTTF(actual_icon_font_path.data(),
ICON_FONT_SIZE, &icons_config,
icons_ranges)) {
return absl::InternalError("Failed to load icon fonts");
}
// Merge Japanese font // Merge Japanese font
std::string actual_japanese_font_path = ""; RETURN_IF_ERROR(AddJapaneseFont());
const char *japanese_font_path = NOTO_SANS_JP;
#if defined(__APPLE__) && defined(__MACH__)
#if TARGET_OS_IOS == 1
const std::string kJapaneseBundlePath = GetBundleResourcePath();
actual_japanese_font_path = kJapaneseBundlePath + japanese_font_path;
#else
actual_japanese_font_path =
absl::StrCat(GetBundleResourcePath(), "Contents/Resources/font/",
japanese_font_path);
#endif
#else
actual_japanese_font_path = absl::StrCat("assets/font/", japanese_font_path);
actual_japanese_font_path =
std::filesystem::absolute(actual_japanese_font_path).string();
#endif
io.Fonts->AddFontFromFileTTF(actual_japanese_font_path.data(), 18.0f,
&japanese_font_config,
io.Fonts->GetGlyphRangesJapanese());
} }
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status ReloadPackageFont(const FontConfig& config) {
ImGuiIO& io = ImGui::GetIO();
std::string actual_font_path = SetFontPath(config.font_path);
if (!io.Fonts->AddFontFromFileTTF(actual_font_path.data(), config.font_size)) {
return absl::InternalError(
absl::StrFormat("Failed to load font from %s", actual_font_path));
}
RETURN_IF_ERROR(AddIconFont());
RETURN_IF_ERROR(AddJapaneseFont());
return absl::OkStatus();
}
#ifdef _WIN32 #ifdef _WIN32
#include <Windows.h> #include <Windows.h>
@@ -235,7 +265,6 @@ void LoadSystemFonts() {
void LoadSystemFonts() { void LoadSystemFonts() {
// Load Linux System Fonts into ImGui // Load Linux System Fonts into ImGui
// ...
} }
#endif #endif

View File

@@ -6,9 +6,17 @@
namespace yaze { namespace yaze {
namespace core { namespace core {
void LoadSystemFonts(); struct FontConfig {
const char* font_path;
float font_size;
};
absl::Status LoadPackageFonts(); absl::Status LoadPackageFonts();
absl::Status ReloadPackageFont(const FontConfig& config);
void LoadSystemFonts();
} // namespace core } // namespace core
} // namespace yaze } // namespace yaze

View File

@@ -109,7 +109,7 @@ absl::Status DungeonEditor::Initialize() {
ASSIGN_OR_RETURN(current_palette_group_, ASSIGN_OR_RETURN(current_palette_group_,
gfx::CreatePaletteGroupFromLargePalette(full_palette_)); gfx::CreatePaletteGroupFromLargePalette(full_palette_));
graphics_bin_ = rom()->gfx_sheets(); graphics_bin_ = GraphicsSheetManager::GetInstance().gfx_sheets();
// Create a vector of pointers to the current block bitmaps // Create a vector of pointers to the current block bitmaps
for (int block : rooms_[current_room_id_].blocks()) { for (int block : rooms_[current_room_id_].blocks()) {
room_gfx_sheets_.emplace_back(&graphics_bin_[block]); room_gfx_sheets_.emplace_back(&graphics_bin_[block]);

View File

@@ -58,19 +58,22 @@ void EditorManager::Initialize(std::string filename) {
absl::Status EditorManager::Update() { absl::Status EditorManager::Update() {
ManageKeyboardShortcuts(); ManageKeyboardShortcuts();
DrawYazeMenu(); DrawMenuBar();
DrawStatusPopup(); DrawPopups();
DrawAboutPopup();
DrawInfoPopup();
if (rom()->is_loaded() && !rom_assets_loaded_) { if (rom()->is_loaded() && !rom_assets_loaded_) {
RETURN_IF_ERROR(rom()->LoadAllGraphicsData()) auto& sheet_manager = GraphicsSheetManager::GetInstance();
ASSIGN_OR_RETURN(*sheet_manager.mutable_gfx_sheets(),
LoadAllGraphicsData(*rom()))
RETURN_IF_ERROR(overworld_editor_.LoadGraphics()); RETURN_IF_ERROR(overworld_editor_.LoadGraphics());
rom_assets_loaded_ = true; rom_assets_loaded_ = true;
} }
ManageActiveEditors(); if (!current_rom_) {
DrawHomepage();
} else {
ManageActiveEditors();
}
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -296,7 +299,7 @@ void EditorManager::ManageKeyboardShortcuts() {
} }
} }
void EditorManager::DrawStatusPopup() { void EditorManager::DrawPopups() {
static absl::Status prev_status; static absl::Status prev_status;
if (!status_.ok()) { if (!status_.ok()) {
show_status_ = true; show_status_ = true;
@@ -322,9 +325,7 @@ void EditorManager::DrawStatusPopup() {
} }
End(); End();
} }
}
void EditorManager::DrawAboutPopup() {
if (about_) OpenPopup("About"); if (about_) OpenPopup("About");
if (BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { if (BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
Text("Yet Another Zelda3 Editor - v%s", version_.c_str()); Text("Yet Another Zelda3 Editor - v%s", version_.c_str());
@@ -339,9 +340,7 @@ void EditorManager::DrawAboutPopup() {
} }
EndPopup(); EndPopup();
} }
}
void EditorManager::DrawInfoPopup() {
if (rom_info_) OpenPopup("ROM Information"); if (rom_info_) OpenPopup("ROM Information");
if (BeginPopupModal("ROM Information", nullptr, if (BeginPopupModal("ROM Information", nullptr,
ImGuiWindowFlags_AlwaysAutoResize)) { ImGuiWindowFlags_AlwaysAutoResize)) {
@@ -357,11 +356,29 @@ void EditorManager::DrawInfoPopup() {
} }
} }
void EditorManager::DrawYazeMenu() { void EditorManager::DrawHomepage() {
TextWrapped("Welcome to the Yet Another Zelda3 Editor (yaze)!");
TextWrapped("This editor is designed to be a comprehensive tool for editing the Legend of Zelda: A Link to the Past.");
TextWrapped("The editor is still in development, so please report any bugs or issues you encounter.");
static bool managed_startup = false;
if (Button("Open ROM", ImVec2(200, 0))) {
LoadRom();
}
SameLine();
ImGui::Checkbox("Manage Startup", &managed_startup);
Separator();
settings_editor_.Update();
}
void EditorManager::DrawMenuBar() {
static bool show_display_settings = false; static bool show_display_settings = false;
if (BeginMenuBar()) { if (BeginMenuBar()) {
DrawYazeMenuBar(); DrawMenuContent();
SameLine(GetWindowWidth() - GetStyle().ItemSpacing.x - SameLine(GetWindowWidth() - GetStyle().ItemSpacing.x -
CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 110); CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 110);
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
@@ -380,7 +397,7 @@ void EditorManager::DrawYazeMenu() {
} }
} }
void EditorManager::DrawYazeMenuBar() { void EditorManager::DrawMenuContent() {
static bool save_as_menu = false; static bool save_as_menu = false;
static bool new_project_menu = false; static bool new_project_menu = false;
@@ -445,11 +462,23 @@ void EditorManager::DrawYazeMenuBar() {
MenuItem("Backup ROM", "", &backup_rom_); MenuItem("Backup ROM", "", &backup_rom_);
MenuItem("Save New Auto", "", &save_new_auto_); MenuItem("Save New Auto", "", &save_new_auto_);
Separator(); Separator();
if (BeginMenu("Experiment Flags")) { static FlagsMenu flags_menu;
static FlagsMenu flags_menu; if (BeginMenu("System Flags")) {
flags_menu.Draw(); flags_menu.DrawSystemFlags();
EndMenu(); EndMenu();
} }
if (BeginMenu("Overworld Flags")) {
flags_menu.DrawOverworldFlags();
EndMenu();
}
if (BeginMenu("Dungeon Flags")) {
flags_menu.DrawDungeonFlags();
EndMenu();
}
if (BeginMenu("Resource Flags")) {
flags_menu.DrawResourceFlags();
EndMenu();
}
EndMenu(); EndMenu();
} }
@@ -671,10 +700,25 @@ void EditorManager::DrawYazeMenuBar() {
} }
} }
void EditorManager::DrawRomMenu() {
if (roms_.empty()) return;
// Dropdown in the center of the menu bar with ROMs
if (BeginMenu("ROM")) {
for (size_t i = 0; i < roms_.size(); ++i) {
if (MenuItem(roms_[i]->title().c_str())) {
current_rom_ = roms_[i].get();
}
}
EndMenu();
}
}
void EditorManager::LoadRom() { void EditorManager::LoadRom() {
auto file_name = FileDialogWrapper::ShowOpenFileDialog(); auto file_name = FileDialogWrapper::ShowOpenFileDialog();
auto load_rom = rom()->LoadFromFile(file_name); auto load_rom = rom()->LoadFromFile(file_name);
if (load_rom.ok()) { if (load_rom.ok()) {
current_rom_ = rom();
static RecentFilesManager manager("recent_files.txt"); static RecentFilesManager manager("recent_files.txt");
manager.Load(); manager.Load();
manager.AddFile(file_name); manager.AddFile(file_name);
@@ -691,6 +735,10 @@ void EditorManager::SaveRom() {
status_ = overworld_editor_.Save(); status_ = overworld_editor_.Save();
RETURN_VOID_IF_ERROR(status_); RETURN_VOID_IF_ERROR(status_);
if (core::ExperimentFlags::get().kSaveGraphicsSheet)
PRINT_IF_ERROR(SaveAllGraphicsData(*rom(),
GraphicsSheetManager::GetInstance().gfx_sheets()));
status_ = rom()->SaveToFile(backup_rom_, save_new_auto_); status_ = rom()->SaveToFile(backup_rom_, save_new_auto_);
} }
@@ -702,11 +750,13 @@ void EditorManager::OpenRomOrProject(const std::string &filename) {
} }
} else { } else {
status_ = rom()->LoadFromFile(filename); status_ = rom()->LoadFromFile(filename);
current_rom_ = rom();
} }
} }
absl::Status EditorManager::OpenProject() { absl::Status EditorManager::OpenProject() {
RETURN_IF_ERROR(rom()->LoadFromFile(current_project_.rom_filename_)); RETURN_IF_ERROR(rom()->LoadFromFile(current_project_.rom_filename_));
current_rom_ = rom();
if (!rom()->resource_label()->LoadLabels(current_project_.labels_filename_)) { if (!rom()->resource_label()->LoadLabels(current_project_.labels_filename_)) {
return absl::InternalError( return absl::InternalError(

View File

@@ -46,6 +46,7 @@ class EditorManager : public SharedRom {
active_editors_.push_back(&sprite_editor_); active_editors_.push_back(&sprite_editor_);
active_editors_.push_back(&message_editor_); active_editors_.push_back(&message_editor_);
active_editors_.push_back(&screen_editor_); active_editors_.push_back(&screen_editor_);
active_editors_.push_back(&settings_editor_);
std::stringstream ss; std::stringstream ss;
ss << YAZE_VERSION_MAJOR << "." << YAZE_VERSION_MINOR << "." ss << YAZE_VERSION_MAJOR << "." << YAZE_VERSION_MINOR << "."
<< YAZE_VERSION_PATCH; << YAZE_VERSION_PATCH;
@@ -56,18 +57,18 @@ class EditorManager : public SharedRom {
absl::Status Update(); absl::Status Update();
auto emulator() -> emu::Emulator & { return emulator_; } auto emulator() -> emu::Emulator & { return emulator_; }
auto quit() { return quit_; } auto quit() const { return quit_; }
private: private:
void ManageActiveEditors(); void ManageActiveEditors();
void ManageKeyboardShortcuts(); void ManageKeyboardShortcuts();
void DrawStatusPopup(); void DrawPopups();
void DrawAboutPopup(); void DrawHomepage();
void DrawInfoPopup();
void DrawYazeMenu(); void DrawMenuBar();
void DrawYazeMenuBar(); void DrawMenuContent();
void DrawRomMenu();
void LoadRom(); void LoadRom();
void SaveRom(); void SaveRom();
@@ -88,6 +89,8 @@ class EditorManager : public SharedRom {
absl::Status status_; absl::Status status_;
emu::Emulator emulator_; emu::Emulator emulator_;
std::vector<Editor *> active_editors_; std::vector<Editor *> active_editors_;
std::vector<std::unique_ptr<Rom>> roms_;
Rom* current_rom_ = nullptr;
Project current_project_; Project current_project_;
EditorContext editor_context_; EditorContext editor_context_;

View File

@@ -112,7 +112,7 @@ void GfxGroupEditor::DrawBlocksetViewer(bool sheet_only) {
BeginGroup(); BeginGroup();
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int sheet_id = rom()->main_blockset_ids[selected_blockset_][i]; int sheet_id = rom()->main_blockset_ids[selected_blockset_][i];
auto sheet = rom()->gfx_sheets().at(sheet_id); auto &sheet = GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(sheet_id);
gui::BitmapCanvasPipeline(blockset_canvas_, sheet, 256, 0x10 * 0x04, gui::BitmapCanvasPipeline(blockset_canvas_, sheet, 256, 0x10 * 0x04,
0x20, true, false, 22); 0x20, true, false, 22);
} }
@@ -165,7 +165,7 @@ void GfxGroupEditor::DrawRoomsetViewer() {
BeginGroup(); BeginGroup();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
int sheet_id = rom()->room_blockset_ids[selected_roomset_][i]; int sheet_id = rom()->room_blockset_ids[selected_roomset_][i];
auto sheet = rom()->gfx_sheets().at(sheet_id); auto &sheet = GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(sheet_id);
gui::BitmapCanvasPipeline(roomset_canvas_, sheet, 256, 0x10 * 0x04, gui::BitmapCanvasPipeline(roomset_canvas_, sheet, 256, 0x10 * 0x04,
0x20, true, false, 23); 0x20, true, false, 23);
} }
@@ -203,7 +203,7 @@ void GfxGroupEditor::DrawSpritesetViewer(bool sheet_only) {
BeginGroup(); BeginGroup();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
int sheet_id = rom()->spriteset_ids[selected_spriteset_][i]; int sheet_id = rom()->spriteset_ids[selected_spriteset_][i];
auto sheet = rom()->gfx_sheets().at(115 + sheet_id); auto &sheet = GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(115 + sheet_id);
gui::BitmapCanvasPipeline(spriteset_canvas_, sheet, 256, 0x10 * 0x04, gui::BitmapCanvasPipeline(spriteset_canvas_, sheet, 256, 0x10 * 0x04,
0x20, true, false, 24); 0x20, true, false, 24);
} }

View File

@@ -46,9 +46,9 @@ absl::Status GraphicsEditor::Update() {
status_ = UpdateGfxEdit(); status_ = UpdateGfxEdit();
TAB_ITEM("Sheet Browser") TAB_ITEM("Sheet Browser")
if (asset_browser_.Initialized == false) { if (asset_browser_.Initialized == false) {
asset_browser_.Initialize(rom()->gfx_sheets()); asset_browser_.Initialize(GraphicsSheetManager::GetInstance().gfx_sheets());
} }
asset_browser_.Draw(rom()->gfx_sheets()); asset_browser_.Draw(GraphicsSheetManager::GetInstance().gfx_sheets());
END_TAB_ITEM() END_TAB_ITEM()
status_ = UpdateScadView(); status_ = UpdateScadView();
status_ = UpdateLinkGfxView(); status_ = UpdateLinkGfxView();
@@ -117,7 +117,7 @@ void GraphicsEditor::DrawGfxEditToolset() {
TableNextColumn(); TableNextColumn();
if (Button(ICON_MD_CONTENT_COPY)) { if (Button(ICON_MD_CONTENT_COPY)) {
std::vector<uint8_t> png_data = std::vector<uint8_t> png_data =
rom()->gfx_sheets().at(current_sheet_).GetPngData(); GraphicsSheetManager::GetInstance().gfx_sheets().at(current_sheet_).GetPngData();
core::CopyImageToClipboard(png_data); core::CopyImageToClipboard(png_data);
} }
HOVER_HINT("Copy to Clipboard"); HOVER_HINT("Copy to Clipboard");
@@ -128,12 +128,11 @@ void GraphicsEditor::DrawGfxEditToolset() {
int width, height; int width, height;
core::GetImageFromClipboard(png_data, width, height); core::GetImageFromClipboard(png_data, width, height);
if (png_data.size() > 0) { if (png_data.size() > 0) {
rom() GraphicsSheetManager::GetInstance().mutable_gfx_sheets()
->mutable_gfx_sheets()
->at(current_sheet_) ->at(current_sheet_)
.Create(width, height, 8, png_data); .Create(width, height, 8, png_data);
Renderer::GetInstance().UpdateBitmap( Renderer::GetInstance().UpdateBitmap(
&rom()->mutable_gfx_sheets()->at(current_sheet_)); &GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(current_sheet_));
} }
} }
HOVER_HINT("Paste from Clipboard"); HOVER_HINT("Paste from Clipboard");
@@ -153,9 +152,9 @@ void GraphicsEditor::DrawGfxEditToolset() {
} }
TableNextColumn(); TableNextColumn();
auto bitmap = rom()->gfx_sheets()[current_sheet_]; auto bitmap = GraphicsSheetManager::GetInstance().gfx_sheets()[current_sheet_];
auto palette = bitmap.palette(); auto palette = bitmap.palette();
for (int i = 0; i < 8; i++) { for (int i = 0; i < palette.size(); i++) {
ImGui::SameLine(); ImGui::SameLine();
auto color = auto color =
ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f, ImVec4(palette[i].rgb().x / 255.0f, palette[i].rgb().y / 255.0f,
@@ -192,7 +191,7 @@ absl::Status GraphicsEditor::UpdateGfxSheetList() {
(int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. (int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
int key = 0; int key = 0;
for (auto& value : rom()->gfx_sheets()) { for (auto& value : GraphicsSheetManager::GetInstance().gfx_sheets()) {
ImGui::BeginChild(absl::StrFormat("##GfxSheet%02X", key).c_str(), ImGui::BeginChild(absl::StrFormat("##GfxSheet%02X", key).c_str(),
ImVec2(0x100 + 1, 0x40 + 1), true, ImVec2(0x100 + 1, 0x40 + 1), true,
ImGuiWindowFlags_NoDecoration); ImGuiWindowFlags_NoDecoration);
@@ -281,7 +280,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysVerticalScrollbar |
ImGuiWindowFlags_AlwaysHorizontalScrollbar); ImGuiWindowFlags_AlwaysHorizontalScrollbar);
gfx::Bitmap& current_bitmap = rom()->mutable_gfx_sheets()->at(sheet_id); gfx::Bitmap& current_bitmap = GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(sheet_id);
auto draw_tile_event = [&]() { auto draw_tile_event = [&]() {
current_sheet_canvas_.DrawTileOnBitmap(tile_size_, &current_bitmap, current_sheet_canvas_.DrawTileOnBitmap(tile_size_, &current_bitmap,
@@ -290,7 +289,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
}; };
current_sheet_canvas_.UpdateColorPainter( current_sheet_canvas_.UpdateColorPainter(
rom()->mutable_gfx_sheets()->at(sheet_id), current_color_, GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(sheet_id), current_color_,
draw_tile_event, tile_size_, current_scale_); draw_tile_event, tile_size_, current_scale_);
ImGui::EndChild(); ImGui::EndChild();
@@ -323,7 +322,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
current_sheet_ = id; current_sheet_ = id;
// ImVec2(0x100, 0x40), // ImVec2(0x100, 0x40),
current_sheet_canvas_.UpdateColorPainter( current_sheet_canvas_.UpdateColorPainter(
rom()->mutable_gfx_sheets()->at(id), current_color_, GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(id), current_color_,
[&]() { [&]() {
}, },
@@ -360,12 +359,11 @@ absl::Status GraphicsEditor::UpdatePaletteColumn() {
if (refresh_graphics_ && !open_sheets_.empty()) { if (refresh_graphics_ && !open_sheets_.empty()) {
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom() GraphicsSheetManager::GetInstance().mutable_gfx_sheets()
->mutable_gfx_sheets()
->data()[current_sheet_] ->data()[current_sheet_]
.ApplyPaletteWithTransparent(palette, edit_palette_sub_index_)); .ApplyPaletteWithTransparent(palette, edit_palette_sub_index_));
Renderer::GetInstance().UpdateBitmap( Renderer::GetInstance().UpdateBitmap(
&rom()->mutable_gfx_sheets()->data()[current_sheet_]); &GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->data()[current_sheet_]);
refresh_graphics_ = false; refresh_graphics_ = false;
} }
} }
@@ -387,7 +385,7 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
link_canvas_.DrawGrid(16.0f); link_canvas_.DrawGrid(16.0f);
int i = 0; int i = 0;
for (auto link_sheet : *rom()->mutable_link_graphics()) { for (auto& link_sheet : link_sheets_) {
int x_offset = 0; int x_offset = 0;
int y_offset = gfx::kTilesheetHeight * i * 4; int y_offset = gfx::kTilesheetHeight * i * 4;
link_canvas_.DrawContextMenu(&link_sheet); link_canvas_.DrawContextMenu(&link_sheet);
@@ -404,7 +402,7 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
if (ImGui::Button("Load Link Graphics (Experimental)")) { if (ImGui::Button("Load Link Graphics (Experimental)")) {
if (rom()->is_loaded()) { if (rom()->is_loaded()) {
// Load Links graphics from the ROM // Load Links graphics from the ROM
RETURN_IF_ERROR(rom()->LoadLinkGraphics()); ASSIGN_OR_RETURN(link_sheets_, LoadLinkGraphics(*rom()));
// Split it into the pose data frames // Split it into the pose data frames
// Create an animation step display for the poses // Create an animation step display for the poses

View File

@@ -159,7 +159,7 @@ class GraphicsEditor : public SharedRom, public Editor {
Rom temp_rom_; Rom temp_rom_;
Rom tilemap_rom_; Rom tilemap_rom_;
zelda3::Overworld overworld_; zelda3::Overworld overworld_{ temp_rom_ };
MemoryEditor cgx_memory_editor_; MemoryEditor cgx_memory_editor_;
MemoryEditor col_memory_editor_; MemoryEditor col_memory_editor_;
PaletteEditor palette_editor_; PaletteEditor palette_editor_;
@@ -176,6 +176,7 @@ class GraphicsEditor : public SharedRom, public Editor {
gfx::Bitmap bin_bitmap_; gfx::Bitmap bin_bitmap_;
gfx::Bitmap link_full_sheet_; gfx::Bitmap link_full_sheet_;
std::array<gfx::Bitmap, kNumGfxSheets> gfx_sheets_; std::array<gfx::Bitmap, kNumGfxSheets> gfx_sheets_;
std::array<gfx::Bitmap, kNumLinkSheets> link_sheets_;
gfx::PaletteGroup col_file_palette_group_; gfx::PaletteGroup col_file_palette_group_;
gfx::SnesPalette z3_rom_palette_; gfx::SnesPalette z3_rom_palette_;

View File

@@ -383,10 +383,10 @@ void ScreenEditor::DrawDungeonMapsEditor() {
if (LoadDungeonMapTile16(rom()->graphics_buffer()).ok()) { if (LoadDungeonMapTile16(rom()->graphics_buffer()).ok()) {
// TODO: Load roomset gfx based on dungeon ID // TODO: Load roomset gfx based on dungeon ID
sheets_.emplace(0, rom()->gfx_sheets()[212]); sheets_.emplace(0, GraphicsSheetManager::GetInstance().gfx_sheets()[212]);
sheets_.emplace(1, rom()->gfx_sheets()[213]); sheets_.emplace(1, GraphicsSheetManager::GetInstance().gfx_sheets()[213]);
sheets_.emplace(2, rom()->gfx_sheets()[214]); sheets_.emplace(2, GraphicsSheetManager::GetInstance().gfx_sheets()[214]);
sheets_.emplace(3, rom()->gfx_sheets()[215]); sheets_.emplace(3, GraphicsSheetManager::GetInstance().gfx_sheets()[215]);
int current_tile8 = 0; int current_tile8 = 0;
int tile_data_offset = 0; int tile_data_offset = 0;
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {

View File

@@ -43,12 +43,12 @@ using ImGui::Text;
absl::Status Tile16Editor::InitBlockset( absl::Status Tile16Editor::InitBlockset(
const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap &current_gfx_bmp, const gfx::Bitmap &tile16_blockset_bmp, const gfx::Bitmap &current_gfx_bmp,
const std::vector<gfx::Bitmap> &tile16_individual,
std::array<uint8_t, 0x200> &all_tiles_types) { std::array<uint8_t, 0x200> &all_tiles_types) {
all_tiles_types_ = all_tiles_types; all_tiles_types_ = all_tiles_types;
tile16_blockset_bmp_ = tile16_blockset_bmp; tile16_blockset_bmp_ = tile16_blockset_bmp;
tile16_individual_ = tile16_individual; current_gfx_bmp_.Create(current_gfx_bmp.width(), current_gfx_bmp.height(),
current_gfx_bmp_ = current_gfx_bmp; current_gfx_bmp.depth(), current_gfx_bmp.vector());
core::Renderer::GetInstance().RenderBitmap(&tile16_blockset_bmp_);
RETURN_IF_ERROR(LoadTile8()); RETURN_IF_ERROR(LoadTile8());
ImVector<std::string> tile16_names; ImVector<std::string> tile16_names;
for (int i = 0; i < 0x200; ++i) { for (int i = 0; i < 0x200; ++i) {
@@ -373,7 +373,7 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() {
// TODO: Implement tile16 transfer // TODO: Implement tile16 transfer
if (transfer_started_ && !transfer_blockset_loaded_) { if (transfer_started_ && !transfer_blockset_loaded_) {
PRINT_IF_ERROR(transfer_rom_.LoadAllGraphicsData()) ASSIGN_OR_RETURN(transfer_gfx_, LoadAllGraphicsData(transfer_rom_))
// Load the Link to the Past overworld. // Load the Link to the Past overworld.
PRINT_IF_ERROR(transfer_overworld_.Load(transfer_rom_)) PRINT_IF_ERROR(transfer_overworld_.Load(transfer_rom_))

View File

@@ -1,6 +1,9 @@
#ifndef YAZE_APP_EDITOR_TILE16EDITOR_H #ifndef YAZE_APP_EDITOR_TILE16EDITOR_H
#define YAZE_APP_EDITOR_TILE16EDITOR_H #define YAZE_APP_EDITOR_TILE16EDITOR_H
#include <array>
#include <vector>
#include "absl/status/status.h" #include "absl/status/status.h"
#include "app/core/common.h" #include "app/core/common.h"
#include "app/editor/graphics/palette_editor.h" #include "app/editor/graphics/palette_editor.h"
@@ -20,9 +23,9 @@ namespace editor {
*/ */
class Tile16Editor : public gfx::GfxContext, public SharedRom { class Tile16Editor : public gfx::GfxContext, public SharedRom {
public: public:
Tile16Editor(std::array<gfx::Bitmap, zelda3::kNumTile16Individual>& tile16_individual) : tile16_individual_(tile16_individual) {}
absl::Status InitBlockset(const gfx::Bitmap &tile16_blockset_bmp, absl::Status InitBlockset(const gfx::Bitmap &tile16_blockset_bmp,
const gfx::Bitmap &current_gfx_bmp, const gfx::Bitmap &current_gfx_bmp,
const std::vector<gfx::Bitmap> &tile16_individual,
std::array<uint8_t, 0x200> &all_tiles_types); std::array<uint8_t, 0x200> &all_tiles_types);
absl::Status Update(); absl::Status Update();
@@ -82,17 +85,17 @@ class Tile16Editor : public gfx::GfxContext, public SharedRom {
gui::Canvas transfer_canvas_; gui::Canvas transfer_canvas_;
gfx::Bitmap transfer_blockset_bmp_; gfx::Bitmap transfer_blockset_bmp_;
std::vector<gfx::Bitmap> tile16_individual_; std::array<gfx::Bitmap, zelda3::kNumTile16Individual>& tile16_individual_;
std::vector<gfx::Bitmap> current_gfx_individual_; std::vector<gfx::Bitmap> current_gfx_individual_;
PaletteEditor palette_editor_; PaletteEditor palette_editor_;
gfx::SnesPalette palette_; gfx::SnesPalette palette_;
zelda3::Overworld transfer_overworld_;
absl::Status status_; absl::Status status_;
Rom transfer_rom_; Rom transfer_rom_;
zelda3::Overworld transfer_overworld_{ transfer_rom_ };
std::array<gfx::Bitmap, kNumGfxSheets> transfer_gfx_;
absl::Status transfer_status_; absl::Status transfer_status_;
}; };

View File

@@ -44,11 +44,11 @@ uint8_t FindDictionaryEntry(uint8_t value);
std::vector<uint8_t> ParseMessageToData(std::string str); std::vector<uint8_t> ParseMessageToData(std::string str);
struct DictionaryEntry { struct DictionaryEntry {
uint8_t ID; uint8_t ID = 0;
std::string Contents; std::string Contents = "";
std::vector<uint8_t> Data; std::vector<uint8_t> Data;
int Length; int Length = 0;
std::string Token; std::string Token = "";
DictionaryEntry() = default; DictionaryEntry() = default;
DictionaryEntry(uint8_t i, std::string s) DictionaryEntry(uint8_t i, std::string s)
@@ -57,11 +57,11 @@ struct DictionaryEntry {
Data = ParseMessageToData(Contents); Data = ParseMessageToData(Contents);
} }
bool ContainedInString(std::string s) { bool ContainedInString(std::string s) const {
return s.find(Contents) != std::string::npos; return s.find(Contents) != std::string::npos;
} }
std::string ReplaceInstancesOfIn(std::string s) { std::string ReplaceInstancesOfIn(std::string s) const {
std::string replacedString = s; std::string replacedString = s;
size_t pos = replacedString.find(Contents); size_t pos = replacedString.find(Contents);
while (pos != std::string::npos) { while (pos != std::string::npos) {
@@ -86,8 +86,8 @@ std::string ReplaceAllDictionaryWords(std::string str,
const std::string CHEESE = "\uBEBE"; const std::string CHEESE = "\uBEBE";
struct MessageData { struct MessageData {
int ID; int ID = 0;
int Address; int Address = 0;
std::string RawString; std::string RawString;
std::string ContentsParsed; std::string ContentsParsed;
std::vector<uint8_t> Data; std::vector<uint8_t> Data;
@@ -115,7 +115,7 @@ struct MessageData {
ContentsParsed = other.ContentsParsed; ContentsParsed = other.ContentsParsed;
} }
std::string ToString() { std::string ToString() const {
return absl::StrFormat("%0X - %s", ID, ContentsParsed); return absl::StrFormat("%0X - %s", ID, ContentsParsed);
} }
@@ -163,8 +163,8 @@ struct TextElement {
bool HasArgument; bool HasArgument;
TextElement() = default; TextElement() = default;
TextElement(uint8_t id, std::string token, bool arg, TextElement(uint8_t id, const std::string& token, bool arg,
std::string description) { const std::string& description) {
ID = id; ID = id;
Token = token; Token = token;
if (arg) { if (arg) {
@@ -181,7 +181,7 @@ struct TextElement {
StrictPattern = "^" + Pattern + "$"; StrictPattern = "^" + Pattern + "$";
} }
std::string GetParameterizedToken(uint8_t value = 0) { std::string GetParameterizedToken(uint8_t value = 0) const {
if (HasArgument) { if (HasArgument) {
return absl::StrFormat("[%s:%02X]", Token, value); return absl::StrFormat("[%s:%02X]", Token, value);
} else { } else {
@@ -189,7 +189,7 @@ struct TextElement {
} }
} }
std::string ToString() { std::string ToString() const {
return absl::StrFormat("%s %s", GenericToken, Description); return absl::StrFormat("%s %s", GenericToken, Description);
} }
@@ -200,37 +200,61 @@ struct TextElement {
return match; return match;
} }
bool Empty() { return ID == 0; } bool Empty() const { return ID == 0; }
// Comparison operator // Comparison operator
bool operator==(const TextElement& other) const { return ID == other.ID; } bool operator==(const TextElement& other) const { return ID == other.ID; }
}; };
const static std::string kWindowBorder = "Window border";
const static std::string kWindowPosition = "Window position";
const static std::string kScrollSpeed = "Scroll speed";
const static std::string kTextDrawSpeed = "Text draw speed";
const static std::string kTextColor = "Text color";
const static std::string kPlayerName = "Player name";
const static std::string kLine1Str = "Line 1";
const static std::string kLine2Str = "Line 2";
const static std::string kLine3Str = "Line 3";
const static std::string kWaitForKey = "Wait for key";
const static std::string kScrollText = "Scroll text";
const static std::string kDelayX = "Delay X";
const static std::string kBCDNumber = "BCD number";
const static std::string kSoundEffect = "Sound effect";
const static std::string kChoose3 = "Choose 3";
const static std::string kChoose2High = "Choose 2 high";
const static std::string kChoose2Low = "Choose 2 low";
const static std::string kChoose2Indented = "Choose 2 indented";
const static std::string kChooseItem = "Choose item";
const static std::string kNextAttractImage = "Next attract image";
const static std::string kBankMarker = "Bank marker (automatic)";
const static std::string kCrash = "Crash";
static const std::vector<TextElement> TextCommands = { static const std::vector<TextElement> TextCommands = {
TextElement(0x6B, "W", true, "Window border"), TextElement(0x6B, "W", true, kWindowBorder),
TextElement(0x6D, "P", true, "Window position"), TextElement(0x6D, "P", true, kWindowPosition),
TextElement(0x6E, "SPD", true, "Scroll speed"), TextElement(0x6E, "SPD", true, kScrollSpeed),
TextElement(0x7A, "S", true, "Text draw speed"), TextElement(0x7A, "S", true, kTextDrawSpeed),
TextElement(0x77, "C", true, "Text color"), TextElement(0x77, "C", true, kTextColor),
TextElement(0x6A, "L", false, "Player name"), TextElement(0x6A, "L", false, kPlayerName),
TextElement(0x74, "1", false, "Line 1"), TextElement(0x74, "1", false, kLine1Str),
TextElement(0x75, "2", false, "Line 2"), TextElement(0x75, "2", false, kLine2Str),
TextElement(0x76, "3", false, "Line 3"), TextElement(0x76, "3", false, kLine3Str),
TextElement(0x7E, "K", false, "Wait for key"), TextElement(0x7E, "K", false, kWaitForKey),
TextElement(0x73, "V", false, "Scroll text"), TextElement(0x73, "V", false, kScrollText),
TextElement(0x78, "WT", true, "Delay X"), TextElement(0x78, "WT", true, kDelayX),
TextElement(0x6C, "N", true, "BCD number"), TextElement(0x6C, "N", true, kBCDNumber),
TextElement(0x79, "SFX", true, "Sound effect"), TextElement(0x79, "SFX", true, kSoundEffect),
TextElement(0x71, "CH3", false, "Choose 3"), TextElement(0x71, "CH3", false, kChoose3),
TextElement(0x72, "CH2", false, "Choose 2 high"), TextElement(0x72, "CH2", false, kChoose2High),
TextElement(0x6F, "CH2L", false, "Choose 2 low"), TextElement(0x6F, "CH2L", false, kChoose2Low),
TextElement(0x68, "CH2I", false, "Choose 2 indented"), TextElement(0x68, "CH2I", false, kChoose2Indented),
TextElement(0x69, "CHI", false, "Choose item"), TextElement(0x69, "CHI", false, kChooseItem),
TextElement(0x67, "IMG", false, "Next attract image"), TextElement(0x67, "IMG", false, kNextAttractImage),
TextElement(0x80, BANKToken, false, "Bank marker (automatic)"), TextElement(0x80, BANKToken, false, kBankMarker),
TextElement(0x70, "NONO", false, "Crash"), TextElement(0x70, "NONO", false, kCrash),
}; };
TextElement FindMatchingCommand(uint8_t b); TextElement FindMatchingCommand(uint8_t b);
static const std::vector<TextElement> SpecialChars = { static const std::vector<TextElement> SpecialChars = {

View File

@@ -626,7 +626,7 @@ absl::Status MessageEditor::Save() {
std::vector<uint8_t> backup = rom()->vector(); std::vector<uint8_t> backup = rom()->vector();
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
RETURN_IF_ERROR(rom()->Write(kCharactersWidth + i, width_array[i])); RETURN_IF_ERROR(rom()->WriteByte(kCharactersWidth + i, width_array[i]));
} }
int pos = kTextData; int pos = kTextData;
@@ -634,7 +634,7 @@ absl::Status MessageEditor::Save() {
for (const auto& message : list_of_texts_) { for (const auto& message : list_of_texts_) {
for (const auto value : message.Data) { for (const auto value : message.Data) {
RETURN_IF_ERROR(rom()->Write(pos, value)); RETURN_IF_ERROR(rom()->WriteByte(pos, value));
if (value == kBlockTerminator) { if (value == kBlockTerminator) {
// Make sure we didn't go over the space available in the first block. // Make sure we didn't go over the space available in the first block.
@@ -652,7 +652,7 @@ absl::Status MessageEditor::Save() {
} }
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom()->Write(pos++, kMessageTerminator)); // , true, "Terminator text" rom()->WriteByte(pos++, kMessageTerminator)); // , true, "Terminator text"
} }
// Verify that we didn't go over the space available for the second block. // Verify that we didn't go over the space available for the second block.
@@ -662,7 +662,7 @@ absl::Status MessageEditor::Save() {
return absl::InternalError(DisplayTextOverflowError(pos, false)); return absl::InternalError(DisplayTextOverflowError(pos, false));
} }
RETURN_IF_ERROR(rom()->Write(pos, 0xFF)); // , true, "End of text" RETURN_IF_ERROR(rom()->WriteByte(pos, 0xFF)); // , true, "End of text"
return absl::OkStatus(); return absl::OkStatus();
} }

View File

@@ -1,6 +1,7 @@
#ifndef YAZE_APP_EDITOR_MESSAGE_EDITOR_H #ifndef YAZE_APP_EDITOR_MESSAGE_EDITOR_H
#define YAZE_APP_EDITOR_MESSAGE_EDITOR_H #define YAZE_APP_EDITOR_MESSAGE_EDITOR_H
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -81,16 +82,13 @@ class MessageEditor : public Editor, public SharedRom {
int text_position_ = 0; int text_position_ = 0;
int shown_lines_ = 0; int shown_lines_ = 0;
uint8_t width_array[kWidthArraySize];
std::string search_text_ = ""; std::string search_text_ = "";
std::array<uint8_t, kWidthArraySize> width_array = {0};
std::vector<uint8_t> font_gfx16_data_; std::vector<uint8_t> font_gfx16_data_;
std::vector<uint8_t> current_font_gfx16_data_; std::vector<uint8_t> current_font_gfx16_data_;
std::vector<std::string> parsed_messages_; std::vector<std::string> parsed_messages_;
std::vector<MessageData> list_of_texts_; std::vector<MessageData> list_of_texts_;
std::vector<DictionaryEntry> all_dictionaries_; std::vector<DictionaryEntry> all_dictionaries_;
MessageData current_message_; MessageData current_message_;

View File

@@ -61,7 +61,7 @@ absl::Status OverworldEditor::Update() {
status_ = absl::OkStatus(); status_ = absl::OkStatus();
if (rom_.is_loaded() && !all_gfx_loaded_) { if (rom_.is_loaded() && !all_gfx_loaded_) {
RETURN_IF_ERROR(tile16_editor_.InitBlockset( RETURN_IF_ERROR(tile16_editor_.InitBlockset(
tile16_blockset_bmp_, current_gfx_bmp_, tile16_individual_, tile16_blockset_bmp_, current_gfx_bmp_,
*overworld_.mutable_all_tiles_types())); *overworld_.mutable_all_tiles_types()));
ASSIGN_OR_RETURN(entrance_tiletypes_, zelda3::LoadEntranceTileTypes(rom_)); ASSIGN_OR_RETURN(entrance_tiletypes_, zelda3::LoadEntranceTileTypes(rom_));
all_gfx_loaded_ = true; all_gfx_loaded_ = true;
@@ -417,7 +417,7 @@ void OverworldEditor::DrawOverworldEdits() {
// Render the updated map bitmap. // Render the updated map bitmap.
RenderUpdatedMapBitmap(mouse_position, RenderUpdatedMapBitmap(mouse_position,
tile16_individual_data_[current_tile16_]); tile16_individual_[current_tile16_].vector());
// Calculate the correct superX and superY values // Calculate the correct superX and superY values
int superY = current_map_ / 8; int superY = current_map_ / 8;
@@ -706,7 +706,7 @@ void OverworldEditor::DrawTile8Selector() {
graphics_bin_canvas_.DrawContextMenu(); graphics_bin_canvas_.DrawContextMenu();
if (all_gfx_loaded_) { if (all_gfx_loaded_) {
int key = 0; int key = 0;
for (auto &value : rom_.gfx_sheets()) { for (auto &value : GraphicsSheetManager::GetInstance().gfx_sheets()) {
int offset = 0x40 * (key + 1); int offset = 0x40 * (key + 1);
int top_left_y = graphics_bin_canvas_.zero_point().y + 2; int top_left_y = graphics_bin_canvas_.zero_point().y + 2;
if (key >= 1) { if (key >= 1) {
@@ -1031,15 +1031,18 @@ absl::Status OverworldEditor::Save() {
} }
absl::Status OverworldEditor::LoadGraphics() { absl::Status OverworldEditor::LoadGraphics() {
core::logf("Loading overworld.");
// Load the Link to the Past overworld. // Load the Link to the Past overworld.
RETURN_IF_ERROR(overworld_.Load(rom_)) RETURN_IF_ERROR(overworld_.Load(rom_))
palette_ = overworld_.current_area_palette(); palette_ = overworld_.current_area_palette();
core::logf("Loading overworld graphics.");
// Create the area graphics image // Create the area graphics image
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
0x80, kOverworldMapSize, 0x40, overworld_.current_graphics(), 0x80, kOverworldMapSize, 0x40, overworld_.current_graphics(),
current_gfx_bmp_, palette_)); current_gfx_bmp_, palette_));
core::logf("Loading overworld tileset.");
// Create the tile16 blockset image // Create the tile16 blockset image
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
0x80, 0x2000, 0x08, overworld_.tile16_blockset_data(), 0x80, 0x2000, 0x08, overworld_.tile16_blockset_data(),
@@ -1048,38 +1051,42 @@ absl::Status OverworldEditor::LoadGraphics() {
// Copy the tile16 data into individual tiles. // Copy the tile16 data into individual tiles.
auto tile16_data = overworld_.tile16_blockset_data(); auto tile16_data = overworld_.tile16_blockset_data();
tile16_individual_.reserve(zelda3::kNumTile16Individual);
core::logf("Loading overworld tile16 graphics.");
// Loop through the tiles and copy their pixel data into separate vectors // Loop through the tiles and copy their pixel data into separate vectors
for (uint i = 0; i < zelda3::kNumTile16Individual; i++) { for (uint i = 0; i < zelda3::kNumTile16Individual; i++) {
std::vector<uint8_t> tile_data(kTile16Size * kTile16Size, 0x00); tile16_individual_[i].Create(kTile16Size, kTile16Size, 0x08, kTile16Size * kTile16Size);
// Copy the pixel data for the current tile into the vector // Copy the pixel data for the current tile into the vector
for (int ty = 0; ty < kTile16Size; ty++) { for (int ty = 0; ty < kTile16Size; ty++) {
for (int tx = 0; tx < kTile16Size; tx++) { for (int tx = 0; tx < kTile16Size; tx++) {
int position = tx + (ty * kTile16Size); int position = tx + (ty * kTile16Size);
uint8_t value = uint8_t value =
tile16_data[(i % 8 * kTile16Size) + (i / 8 * kTile16Size * 0x80) + tile16_data[(i % 8 * kTile16Size) + (i / 8 * kTile16Size * 0x80) +
(ty * 0x80) + tx]; (ty * 0x80) + tx];
tile_data[position] = value; tile16_individual_[i].mutable_data()[position] = value;
} }
} }
// Add the vector for the current tile to the vector of tile pixel data RETURN_IF_ERROR(tile16_individual_[i].ApplyPalette(palette_));
tile16_individual_data_.push_back(tile_data); Renderer::GetInstance().RenderBitmap(&tile16_individual_[i]);
tile16_individual_.emplace_back();
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
kTile16Size, kTile16Size, 0x80, tile16_individual_data_[i],
tile16_individual_[i], palette_));
} }
core::logf("Loading overworld maps.");
// Render the overworld maps loaded from the ROM. // Render the overworld maps loaded from the ROM.
for (int i = 0; i < zelda3::kNumOverworldMaps; ++i) { for (int i = 0; i < zelda3::kNumOverworldMaps; ++i) {
overworld_.set_current_map(i); overworld_.set_current_map(i);
auto palette = overworld_.current_area_palette(); auto palette = overworld_.current_area_palette();
RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap( try {
kOverworldMapSize, kOverworldMapSize, 0x200, RETURN_IF_ERROR(Renderer::GetInstance().CreateAndRenderBitmap(
kOverworldMapSize, kOverworldMapSize, 0x80,
overworld_.current_map_bitmap_data(), maps_bmp_[i], palette)); overworld_.current_map_bitmap_data(), maps_bmp_[i], palette));
}
catch (const std::bad_alloc& e) {
std::cout << "Error: " << e.what() << std::endl;
continue;
}
} }
if (core::ExperimentFlags::get().overworld.kDrawOverworldSprites) { if (core::ExperimentFlags::get().overworld.kDrawOverworldSprites) {
@@ -1148,6 +1155,7 @@ void OverworldEditor::RefreshOverworldMap() {
std::async(std::launch::async, refresh_map_async, source_map_id)); std::async(std::launch::async, refresh_map_async, source_map_id));
for (auto &each : futures) { for (auto &each : futures) {
each.wait();
each.get(); each.get();
} }
int n = is_large ? 4 : 1; int n = is_large ? 4 : 1;
@@ -1215,12 +1223,12 @@ absl::Status OverworldEditor::RefreshTile16Blockset() {
// Copy the tile16 data into individual tiles. // Copy the tile16 data into individual tiles.
const auto tile16_data = overworld_.tile16_blockset_data(); const auto tile16_data = overworld_.tile16_blockset_data();
std::vector<std::future<void>> futures;
// Loop through the tiles and copy their pixel data into separate vectors // Loop through the tiles and copy their pixel data into separate vectors
std::vector<std::future<absl::Status>> futures;
for (uint i = 0; i < zelda3::kNumTile16Individual; i++) { for (uint i = 0; i < zelda3::kNumTile16Individual; i++) {
futures.push_back(std::async( futures.push_back(std::async(
std::launch::async, std::launch::async,
[&](int index) { [&](int index) -> absl::Status {
std::vector<uint8_t> tile_data(16 * 16, 0x00); std::vector<uint8_t> tile_data(16 * 16, 0x00);
for (int ty = 0; ty < 16; ty++) { for (int ty = 0; ty < 16; ty++) {
for (int tx = 0; tx < 16; tx++) { for (int tx = 0; tx < 16; tx++) {
@@ -1232,17 +1240,19 @@ absl::Status OverworldEditor::RefreshTile16Blockset() {
} }
} }
tile16_individual_[index].set_data(tile_data); tile16_individual_[index].set_data(tile_data);
RETURN_IF_ERROR(tile16_individual_[index].ApplyPalette(palette_));
return absl::OkStatus();
}, },
i)); i));
} }
for (auto &future : futures) { for (auto &future : futures) {
future.get(); future.wait();
RETURN_IF_ERROR(future.get());
} }
// Render the bitmaps of each tile. // Render the bitmaps of each tile.
for (uint id = 0; id < zelda3::kNumTile16Individual; id++) { for (uint id = 0; id < zelda3::kNumTile16Individual; id++) {
RETURN_IF_ERROR(tile16_individual_[id].ApplyPalette(palette_));
Renderer::GetInstance().UpdateBitmap(&tile16_individual_[id]); Renderer::GetInstance().UpdateBitmap(&tile16_individual_[id]);
} }

View File

@@ -233,15 +233,14 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
bool is_dragging_entity_ = false; bool is_dragging_entity_ = false;
std::vector<uint8_t> selected_tile_data_; std::vector<uint8_t> selected_tile_data_;
std::vector<std::vector<uint8_t>> tile16_individual_data_; std::array<gfx::Bitmap, zelda3::kNumTile16Individual> tile16_individual_;
std::vector<gfx::Bitmap> tile16_individual_;
std::vector<std::vector<uint8_t>> tile8_individual_data_; std::vector<std::vector<uint8_t>> tile8_individual_data_;
std::vector<gfx::Bitmap> tile8_individual_; std::vector<gfx::Bitmap> tile8_individual_;
Rom& rom_; Rom& rom_;
Tile16Editor tile16_editor_; Tile16Editor tile16_editor_{ tile16_individual_ };
GfxGroupEditor gfx_group_editor_; GfxGroupEditor gfx_group_editor_;
PaletteEditor palette_editor_; PaletteEditor palette_editor_;
@@ -252,11 +251,11 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
gfx::Bitmap current_gfx_bmp_; gfx::Bitmap current_gfx_bmp_;
gfx::Bitmap all_gfx_bmp; gfx::Bitmap all_gfx_bmp;
gfx::BitmapTable maps_bmp_; std::array<gfx::Bitmap, zelda3::kNumOverworldMaps> maps_bmp_;
gfx::BitmapTable current_graphics_set_; gfx::BitmapTable current_graphics_set_;
gfx::BitmapTable sprite_previews_; gfx::BitmapTable sprite_previews_;
zelda3::Overworld overworld_; zelda3::Overworld overworld_{rom_};
zelda3::OverworldBlockset refresh_blockset_; zelda3::OverworldBlockset refresh_blockset_;
zelda3::Sprite current_sprite_; zelda3::Sprite current_sprite_;
@@ -264,10 +263,10 @@ class OverworldEditor : public Editor, public gfx::GfxContext {
zelda3::OverworldEntrance current_entrance_; zelda3::OverworldEntrance current_entrance_;
zelda3::OverworldExit current_exit_; zelda3::OverworldExit current_exit_;
zelda3::OverworldItem current_item_; zelda3::OverworldItem current_item_;
zelda3::OverworldEntranceTileTypes entrance_tiletypes_; zelda3::OverworldEntranceTileTypes entrance_tiletypes_ = {};
zelda3::GameEntity* current_entity_; zelda3::GameEntity* current_entity_ = nullptr;
zelda3::GameEntity* dragged_entity_; zelda3::GameEntity* dragged_entity_ = nullptr;
gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize, gui::Canvas ow_map_canvas_{"OwMap", kOverworldCanvasSize,
gui::CanvasGridSize::k64x64}; gui::CanvasGridSize::k64x64};

View File

@@ -175,7 +175,7 @@ void SpriteEditor::DrawCurrentSheets() {
graphics_sheet_canvas_.DrawTileSelector(32); graphics_sheet_canvas_.DrawTileSelector(32);
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
graphics_sheet_canvas_.DrawBitmap( graphics_sheet_canvas_.DrawBitmap(
rom()->gfx_sheets().at(current_sheets_[i]), 1, (i * 0x40) + 1, 2); GraphicsSheetManager::GetInstance().gfx_sheets().at(current_sheets_[i]), 1, (i * 0x40) + 1, 2);
} }
graphics_sheet_canvas_.DrawGrid(); graphics_sheet_canvas_.DrawGrid();
graphics_sheet_canvas_.DrawOverlay(); graphics_sheet_canvas_.DrawOverlay();

View File

@@ -15,45 +15,42 @@ using ImGui::MenuItem;
using ImGui::Separator; using ImGui::Separator;
struct FlagsMenu { struct FlagsMenu {
void Draw() { void DrawOverworldFlags() {
if (BeginMenu("Overworld Flags")) { Checkbox("Enable Overworld Sprites",
Checkbox("Enable Overworld Sprites", &ExperimentFlags::get().overworld.kDrawOverworldSprites);
&ExperimentFlags::get().overworld.kDrawOverworldSprites); Separator();
Separator(); Checkbox("Save Overworld Maps",
Checkbox("Save Overworld Maps", &ExperimentFlags::get().overworld.kSaveOverworldMaps);
&ExperimentFlags::get().overworld.kSaveOverworldMaps); Checkbox("Save Overworld Entrances",
Checkbox("Save Overworld Entrances", &ExperimentFlags::get().overworld.kSaveOverworldEntrances);
&ExperimentFlags::get().overworld.kSaveOverworldEntrances); Checkbox("Save Overworld Exits",
Checkbox("Save Overworld Exits", &ExperimentFlags::get().overworld.kSaveOverworldExits);
&ExperimentFlags::get().overworld.kSaveOverworldExits); Checkbox("Save Overworld Items",
Checkbox("Save Overworld Items", &ExperimentFlags::get().overworld.kSaveOverworldItems);
&ExperimentFlags::get().overworld.kSaveOverworldItems); Checkbox("Save Overworld Properties",
Checkbox("Save Overworld Properties", &ExperimentFlags::get().overworld.kSaveOverworldProperties);
&ExperimentFlags::get().overworld.kSaveOverworldProperties); Checkbox("Load Custom Overworld",
Checkbox("Load Custom Overworld", &ExperimentFlags::get().overworld.kLoadCustomOverworld);
&ExperimentFlags::get().overworld.kLoadCustomOverworld); }
ImGui::EndMenu();
}
if (BeginMenu("Dungeon Flags")) { void DrawDungeonFlags() {
Checkbox("Draw Dungeon Room Graphics", Checkbox("Draw Dungeon Room Graphics",
&ExperimentFlags::get().kDrawDungeonRoomGraphics); &ExperimentFlags::get().kDrawDungeonRoomGraphics);
Separator(); Separator();
Checkbox("Save Dungeon Maps", &ExperimentFlags::get().kSaveDungeonMaps); Checkbox("Save Dungeon Maps", &ExperimentFlags::get().kSaveDungeonMaps);
ImGui::EndMenu(); }
}
Checkbox("Use built-in file dialog", void DrawResourceFlags() {
&ExperimentFlags::get().kNewFileDialogWrapper);
Checkbox("Enable Console Logging", &ExperimentFlags::get().kLogToConsole);
Checkbox("Enable Texture Streaming",
&ExperimentFlags::get().kLoadTexturesAsStreaming);
Checkbox("Log Instructions to Debugger",
&ExperimentFlags::get().kLogInstructions);
Checkbox("Save All Palettes", &ExperimentFlags::get().kSaveAllPalettes); Checkbox("Save All Palettes", &ExperimentFlags::get().kSaveAllPalettes);
Checkbox("Save Gfx Groups", &ExperimentFlags::get().kSaveGfxGroups); Checkbox("Save Gfx Groups", &ExperimentFlags::get().kSaveGfxGroups);
Checkbox("Save Graphics Sheets", Checkbox("Save Graphics Sheets",
&ExperimentFlags::get().kSaveGraphicsSheet); &ExperimentFlags::get().kSaveGraphicsSheet);
}
void DrawSystemFlags() {
Checkbox("Enable Console Logging", &ExperimentFlags::get().kLogToConsole);
Checkbox("Log Instructions to Emulator Debugger",
&ExperimentFlags::get().kLogInstructions);
} }
}; };

View File

@@ -1,6 +1,7 @@
#include "app/editor/system/settings_editor.h" #include "app/editor/system/settings_editor.h"
#include "app/gui/style.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "app/editor/system/flags.h" #include "app/editor/system/flags.h"
#include "imgui/imgui.h" #include "imgui/imgui.h"
@@ -34,6 +35,10 @@ absl::Status SettingsEditor::Update() {
DrawGeneralSettings(); DrawGeneralSettings();
EndTabItem(); EndTabItem();
} }
if (BeginTabItem("Font Manager")) {
gui::DrawFontManager();
EndTabItem();
}
if (BeginTabItem("Keyboard Shortcuts")) { if (BeginTabItem("Keyboard Shortcuts")) {
EndTabItem(); EndTabItem();
} }
@@ -44,28 +49,44 @@ absl::Status SettingsEditor::Update() {
} }
void SettingsEditor::DrawGeneralSettings() { void SettingsEditor::DrawGeneralSettings() {
if (BeginTable("##SettingsTable", 2, static FlagsMenu flags;
if (BeginTable("##SettingsTable", 4,
ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) { ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) {
TableSetupColumn("Experiment Flags", ImGuiTableColumnFlags_WidthFixed, TableSetupColumn("System Flags", ImGuiTableColumnFlags_WidthStretch);
250.0f); TableSetupColumn("Overworld Flags", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("General Setting", ImGuiTableColumnFlags_WidthStretch, TableSetupColumn("Dungeon Flags", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Resource Flags", ImGuiTableColumnFlags_WidthStretch,
0.0f); 0.0f);
TableHeadersRow(); TableHeadersRow();
TableNextColumn(); TableNextColumn();
if (BeginChild("##GeneralSettingsStyleWrapper", ImVec2(0, 0), if (BeginChild("##SystemFlags", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) { ImGuiChildFlags_FrameStyle)) {
static FlagsMenu flags; flags.DrawSystemFlags();
flags.Draw();
EndChild(); EndChild();
} }
TableNextColumn(); TableNextColumn();
if (BeginChild("##GeneralSettingsWrapper", ImVec2(0, 0), if (BeginChild("##OverworldFlags", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) { ImGuiChildFlags_FrameStyle)) {
Text("TODO: Add some settings here"); flags.DrawOverworldFlags();
EndChild();
}
TableNextColumn();
if (BeginChild("##DungeonFlags", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) {
flags.DrawDungeonFlags();
EndChild();
}
TableNextColumn();
if (BeginChild("##ResourceFlags", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) {
flags.DrawResourceFlags();
EndChild(); EndChild();
} }

View File

@@ -218,6 +218,13 @@ Bitmap::Bitmap(int width, int height, int depth, int data_size) {
Create(width, height, depth, std::vector<uint8_t>(data_size, 0)); Create(width, height, depth, std::vector<uint8_t>(data_size, 0));
} }
void Bitmap::Initialize(int width, int height, int depth, std::span<uint8_t>& data) {
width_ = width;
height_ = height;
depth_ = depth;
data_ = std::vector<uint8_t>(data.begin(), data.end());
}
void Bitmap::Create(int width, int height, int depth, std::span<uint8_t> data) { void Bitmap::Create(int width, int height, int depth, std::span<uint8_t> data) {
data_ = std::vector<uint8_t>(data.begin(), data.end()); data_ = std::vector<uint8_t>(data.begin(), data.end());
Create(width, height, depth, data_); Create(width, height, depth, data_);
@@ -239,19 +246,20 @@ void Bitmap::Create(int width, int height, int depth, int format,
width_ = width; width_ = width;
height_ = height; height_ = height;
depth_ = depth; depth_ = depth;
data_ = data;
data_size_ = data.size(); data_size_ = data.size();
if (data_size_ == 0) { if (data_size_ == 0) {
SDL_Log("Data provided to Bitmap is empty.\n"); SDL_Log("Data provided to Bitmap is empty.\n");
return; return;
} }
data_.reserve(data_size_);
data_ = data;
pixel_data_ = data_.data(); pixel_data_ = data_.data();
surface_ = std::shared_ptr<SDL_Surface>{ surface_ = std::shared_ptr<SDL_Surface>{
SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_, SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_,
GetSnesPixelFormat(format)), GetSnesPixelFormat(format)),
SDL_Surface_Deleter{}}; SDL_Surface_Deleter{}};
if (surface_ == nullptr) { if (surface_ == nullptr) {
SDL_Log("SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError()); SDL_Log("Bitmap::Create.SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError());
active_ = false; active_ = false;
return; return;
} }
@@ -285,14 +293,15 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) {
SDL_TEXTUREACCESS_STREAMING, width_, height_), SDL_TEXTUREACCESS_STREAMING, width_, height_),
SDL_Texture_Deleter{}}; SDL_Texture_Deleter{}};
if (texture_ == nullptr) { if (texture_ == nullptr) {
SDL_Log("SDL_CreateTextureFromSurface failed: %s\n", SDL_GetError()); SDL_Log("Bitmap::CreateTexture.SDL_CreateTextureFromSurface failed: %s\n", SDL_GetError());
} }
texture_pixels = data_.data();
auto converted_surface_ = std::shared_ptr<SDL_Surface>{ auto converted_surface_ = std::shared_ptr<SDL_Surface>{
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0), SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
SDL_Surface_Deleter{}}; SDL_Surface_Deleter{}};
if (converted_surface_ == nullptr) { if (converted_surface_ == nullptr) {
SDL_Log("SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError()); SDL_Log("Bitmap::CreateTexture.SDL_ConvertSurfaceFormat failed: %s\n", SDL_GetError());
return; return;
} }

View File

@@ -46,7 +46,7 @@ enum BitmapFormat {
/** /**
* @brief Convert SDL_Surface to PNG image data. * @brief Convert SDL_Surface to PNG image data.
*/ */
bool ConvertSurfaceToPNG(SDL_Surface *surface, std::vector<uint8_t> &buffer); bool ConvertSurfaceToPng(SDL_Surface *surface, std::vector<uint8_t> &buffer);
/** /**
* @brief Convert PNG image data to SDL_Surface. * @brief Convert PNG image data to SDL_Surface.
@@ -91,9 +91,11 @@ class Bitmap {
void SaveSurfaceToFile(std::string_view filename); void SaveSurfaceToFile(std::string_view filename);
/** void Initialize(int width, int height, int depth, std::span<uint8_t>& data);
* @brief Creates a bitmap object with the provided graphical data.
*/ void Create(int width, int height, int depth, int data_size) {
Create(width, height, depth, std::vector<uint8_t>(data_size, 0));
}
void Create(int width, int height, int depth, std::span<uint8_t> data); void Create(int width, int height, int depth, std::span<uint8_t> data);
void Create(int width, int height, int depth, void Create(int width, int height, int depth,
const std::vector<uint8_t> &data); const std::vector<uint8_t> &data);
@@ -152,7 +154,6 @@ class Bitmap {
auto palette() const { return palette_; } auto palette() const { return palette_; }
auto mutable_palette() { return &palette_; } auto mutable_palette() { return &palette_; }
auto palette_size() const { return palette_.size(); }
int width() const { return width_; } int width() const { return width_; }
int height() const { return height_; } int height() const { return height_; }
@@ -161,7 +162,6 @@ class Bitmap {
auto data() const { return data_.data(); } auto data() const { return data_.data(); }
auto &mutable_data() { return data_; } auto &mutable_data() { return data_; }
auto surface() const { return surface_.get(); } auto surface() const { return surface_.get(); }
auto mutable_surface() { return surface_.get(); }
auto vector() const { return data_; } auto vector() const { return data_; }
auto at(int i) const { return data_[i]; } auto at(int i) const { return data_[i]; }

View File

@@ -533,7 +533,7 @@ void Canvas::DrawOutlineWithColor(int x, int y, int w, int h, uint32_t color) {
} }
void Canvas::DrawBitmapGroup(std::vector<int> &group, void Canvas::DrawBitmapGroup(std::vector<int> &group,
std::vector<gfx::Bitmap> &tile16_individual_, std::array<gfx::Bitmap, 4096> &tile16_individual_,
int tile_size, float scale) { int tile_size, float scale) {
if (selected_points_.size() != 2) { if (selected_points_.size() != 2) {
// points_ should contain exactly two points // points_ should contain exactly two points

View File

@@ -1,6 +1,7 @@
#ifndef YAZE_GUI_CANVAS_H #ifndef YAZE_GUI_CANVAS_H
#define YAZE_GUI_CANVAS_H #define YAZE_GUI_CANVAS_H
#include <cstdint>
#include <string> #include <string>
#include "app/gfx/bitmap.h" #include "app/gfx/bitmap.h"
@@ -110,7 +111,7 @@ public:
void DrawBitmapTable(const BitmapTable &gfx_bin); void DrawBitmapTable(const BitmapTable &gfx_bin);
void DrawBitmapGroup(std::vector<int> &group, void DrawBitmapGroup(std::vector<int> &group,
std::vector<gfx::Bitmap> &tile16_individual_, std::array<gfx::Bitmap, 4096>& tile16_individual_,
int tile_size, float scale = 1.0f); int tile_size, float scale = 1.0f);
void DrawOutline(int x, int y, int w, int h); void DrawOutline(int x, int y, int w, int h);
@@ -130,8 +131,8 @@ public:
void DrawLayeredElements(); void DrawLayeredElements();
int GetTileIdFromMousePos() { int GetTileIdFromMousePos() {
int x = mouse_pos_in_canvas_.x; float x = mouse_pos_in_canvas_.x;
int y = mouse_pos_in_canvas_.y; float y = mouse_pos_in_canvas_.y;
int num_columns = (canvas_sz_.x / global_scale_) / custom_step_; int num_columns = (canvas_sz_.x / global_scale_) / custom_step_;
int num_rows = (canvas_sz_.y / global_scale_) / custom_step_; int num_rows = (canvas_sz_.y / global_scale_) / custom_step_;
int tile_id = (x / custom_step_) + (y / custom_step_) * num_columns; int tile_id = (x / custom_step_) + (y / custom_step_) * num_columns;
@@ -206,6 +207,7 @@ private:
bool enable_context_menu_ = true; bool enable_context_menu_ = true;
bool custom_canvas_size_ = false; bool custom_canvas_size_ = false;
bool select_rect_active_ = false; bool select_rect_active_ = false;
bool refresh_graphics_ = false;
float custom_step_ = 0.0f; float custom_step_ = 0.0f;
float global_scale_ = 1.0f; float global_scale_ = 1.0f;
@@ -216,14 +218,9 @@ private:
uint16_t edit_palette_index_ = 0; uint16_t edit_palette_index_ = 0;
uint64_t edit_palette_group_name_index_ = 0; uint64_t edit_palette_group_name_index_ = 0;
uint64_t edit_palette_sub_index_ = 0; uint64_t edit_palette_sub_index_ = 0;
bool refresh_graphics_ = false;
std::string canvas_id_ = "Canvas"; ImDrawList* draw_list_ = nullptr;
std::string context_id_ = "CanvasContext";
ImDrawList *draw_list_;
ImVector<ImVec2> points_;
ImVector<ImVector<std::string>> labels_;
ImVec2 scrolling_; ImVec2 scrolling_;
ImVec2 canvas_sz_; ImVec2 canvas_sz_;
ImVec2 canvas_p0_; ImVec2 canvas_p0_;
@@ -231,7 +228,13 @@ private:
ImVec2 drawn_tile_pos_; ImVec2 drawn_tile_pos_;
ImVec2 mouse_pos_in_canvas_; ImVec2 mouse_pos_in_canvas_;
ImVec2 selected_tile_pos_ = ImVec2(-1, -1); ImVec2 selected_tile_pos_ = ImVec2(-1, -1);
ImVector<ImVec2> points_;
ImVector<ImVec2> selected_points_; ImVector<ImVec2> selected_points_;
ImVector<ImVector<std::string>> labels_;
std::string canvas_id_ = "Canvas";
std::string context_id_ = "CanvasContext";
std::vector<ImVec2> selected_tiles_; std::vector<ImVec2> selected_tiles_;
}; };

View File

@@ -3,7 +3,7 @@
// for use with https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf // for use with https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf
#pragma once #pragma once
#define FONT_ICON_FILE_NAME_MD "assets/font/MaterialIcons-Regular.ttf" #define FONT_ICON_FILE_NAME_MD "MaterialIcons-Regular.ttf"
#define ICON_MIN_MD 0xe000 #define ICON_MIN_MD 0xe000
#define ICON_MAX_MD 0x10fffd #define ICON_MAX_MD 0x10fffd

View File

@@ -749,5 +749,34 @@ void TextWithSeparators(const absl::string_view &text) {
ImGui::Separator(); ImGui::Separator();
} }
void DrawFontManager() {
ImGuiIO& io = ImGui::GetIO();
ImFontAtlas* atlas = io.Fonts;
static ImFont* current_font = atlas->Fonts[0];
static int current_font_index = 0;
static int font_size = 16;
static bool font_selected = false;
ImGui::Text("Current Font: %s", current_font->GetDebugName());
ImGui::Text("Font Size: %d", font_size);
if (ImGui::BeginCombo("Fonts", current_font->GetDebugName())) {
for (int i = 0; i < atlas->Fonts.Size; i++) {
bool is_selected = (current_font == atlas->Fonts[i]);
if (ImGui::Selectable(atlas->Fonts[i]->GetDebugName(), is_selected)) {
current_font = atlas->Fonts[i];
current_font_index = i;
font_selected = true;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::Separator();
if (ImGui::SliderInt("Font Size", &font_size, 8, 32)) {
current_font->Scale = font_size / 16.0f;
}
}
} // namespace gui } // namespace gui
} // namespace yaze } // namespace yaze

View File

@@ -66,6 +66,8 @@ void DrawDisplaySettings(ImGuiStyle *ref = nullptr);
void TextWithSeparators(const absl::string_view &text); void TextWithSeparators(const absl::string_view &text);
void DrawFontManager();
static const char *ExampleNames[] = { static const char *ExampleNames[] = {
"Artichoke", "Arugula", "Asparagus", "Avocado", "Artichoke", "Arugula", "Asparagus", "Avocado",
"Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet",

View File

@@ -1,5 +1,6 @@
#include "rom.h" #include "rom.h"
#include <array>
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <cstddef> #include <cstddef>
@@ -53,26 +54,27 @@ absl::StatusOr<std::vector<uint8_t>> Load2BppGraphics(const Rom &rom) {
return sheet; return sheet;
} }
absl::Status Rom::LoadLinkGraphics() { absl::StatusOr<std::array<gfx::Bitmap, kNumLinkSheets>> LoadLinkGraphics(const Rom& rom) {
const uint32_t kLinkGfxOffset = 0x80000; // $10:8000 const uint32_t kLinkGfxOffset = 0x80000; // $10:8000
const uint16_t kLinkGfxLength = 0x800; // 0x4000 or 0x7000? const uint16_t kLinkGfxLength = 0x800; // 0x4000 or 0x7000?
std::array<gfx::Bitmap, kNumLinkSheets> link_graphics;
// Load Links graphics from the ROM
for (uint32_t i = 0; i < kNumLinkSheets; i++) { for (uint32_t i = 0; i < kNumLinkSheets; i++) {
ASSIGN_OR_RETURN( ASSIGN_OR_RETURN(
auto link_sheet_data, auto link_sheet_data,
ReadByteVector(/*offset=*/kLinkGfxOffset + (i * kLinkGfxLength), rom.ReadByteVector(/*offset=*/kLinkGfxOffset + (i * kLinkGfxLength),
/*length=*/kLinkGfxLength)) /*length=*/kLinkGfxLength))
auto link_sheet_8bpp = gfx::SnesTo8bppSheet(link_sheet_data, /*bpp=*/4); auto link_sheet_8bpp = gfx::SnesTo8bppSheet(link_sheet_data, /*bpp=*/4);
link_graphics_[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight, link_graphics[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
gfx::kTilesheetDepth, link_sheet_8bpp); gfx::kTilesheetDepth, link_sheet_8bpp);
RETURN_IF_ERROR(link_graphics_[i].ApplyPalette(palette_groups_.armors[0]);) RETURN_IF_ERROR(link_graphics[i].ApplyPalette(rom.palette_group().armors[0]);)
Renderer::GetInstance().RenderBitmap(&link_graphics_[i]); Renderer::GetInstance().RenderBitmap(&link_graphics[i]);
} }
return absl::OkStatus(); return link_graphics;
} }
absl::Status Rom::LoadAllGraphicsData(bool defer_render) { absl::StatusOr<std::array<gfx::Bitmap, kNumGfxSheets>>
LoadAllGraphicsData(Rom& rom, bool defer_render) {
std::array<gfx::Bitmap, kNumGfxSheets> graphics_sheets;
std::vector<uint8_t> sheet; std::vector<uint8_t> sheet;
bool bpp3 = false; bool bpp3 = false;
@@ -80,60 +82,60 @@ absl::Status Rom::LoadAllGraphicsData(bool defer_render) {
if (i >= 115 && i <= 126) { // uncompressed sheets if (i >= 115 && i <= 126) { // uncompressed sheets
sheet.resize(Uncompressed3BPPSize); sheet.resize(Uncompressed3BPPSize);
auto offset = auto offset =
GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1, GetGraphicsAddress(rom.data(), i, rom.version_constants().kOverworldGfxPtr1,
version_constants().kOverworldGfxPtr2, rom.version_constants().kOverworldGfxPtr2,
version_constants().kOverworldGfxPtr3); rom.version_constants().kOverworldGfxPtr3);
for (int j = 0; j < Uncompressed3BPPSize; j++) { std::copy(rom.data() + offset, rom.data() + offset + Uncompressed3BPPSize,
sheet[j] = rom_data_[j + offset]; sheet.begin());
}
bpp3 = true; bpp3 = true;
} else if (i == 113 || i == 114 || i >= 218) { } else if (i == 113 || i == 114 || i >= 218) {
bpp3 = false; bpp3 = false;
} else { } else {
auto offset = auto offset =
GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1, GetGraphicsAddress(rom.data(), i, rom.version_constants().kOverworldGfxPtr1,
version_constants().kOverworldGfxPtr2, rom.version_constants().kOverworldGfxPtr2,
version_constants().kOverworldGfxPtr3); rom.version_constants().kOverworldGfxPtr3);
ASSIGN_OR_RETURN(sheet, ASSIGN_OR_RETURN(sheet,
gfx::lc_lz2::DecompressV2(rom_data_.data(), offset)) gfx::lc_lz2::DecompressV2(rom.data(), offset))
bpp3 = true; bpp3 = true;
} }
if (bpp3) { if (bpp3) {
auto converted_sheet = gfx::SnesTo8bppSheet(sheet, 3); auto converted_sheet = gfx::SnesTo8bppSheet(sheet, 3);
graphics_sheets_[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight, graphics_sheets[i].Create(gfx::kTilesheetWidth, gfx::kTilesheetHeight,
gfx::kTilesheetDepth, converted_sheet); gfx::kTilesheetDepth, converted_sheet);
if (graphics_sheets_[i].is_active()) { if (graphics_sheets[i].is_active()) {
if (i > 115) { if (i > 115) {
// Apply sprites palette // Apply sprites palette
RETURN_IF_ERROR(graphics_sheets_[i].ApplyPaletteWithTransparent( RETURN_IF_ERROR(graphics_sheets[i].ApplyPaletteWithTransparent(
palette_groups_.global_sprites[0], 0)); rom.palette_group().global_sprites[0], 0));
} else { } else {
RETURN_IF_ERROR(graphics_sheets_[i].ApplyPaletteWithTransparent( RETURN_IF_ERROR(graphics_sheets[i].ApplyPaletteWithTransparent(
palette_groups_.dungeon_main[0], 0)); rom.palette_group().dungeon_main[0], 0));
} }
} }
if (!defer_render) { if (!defer_render) {
graphics_sheets_[i].CreateTexture(Renderer::GetInstance().renderer()); graphics_sheets[i].CreateTexture(Renderer::GetInstance().renderer());
} }
for (int j = 0; j < graphics_sheets_[i].size(); ++j) { for (int j = 0; j < graphics_sheets[i].size(); ++j) {
graphics_buffer_.push_back(graphics_sheets_[i].at(j)); rom.mutable_graphics_buffer()->push_back(graphics_sheets[i].at(j));
} }
} else { } else {
for (int j = 0; j < graphics_sheets_[0].size(); ++j) { for (int j = 0; j < graphics_sheets[0].size(); ++j) {
graphics_buffer_.push_back(0xFF); rom.mutable_graphics_buffer()->push_back(0xFF);
} }
} }
} }
return absl::OkStatus(); return graphics_sheets;
} }
absl::Status Rom::SaveAllGraphicsData() { absl::Status
SaveAllGraphicsData(Rom& rom, std::array<gfx::Bitmap, kNumGfxSheets>& gfx_sheets) {
for (int i = 0; i < kNumGfxSheets; i++) { for (int i = 0; i < kNumGfxSheets; i++) {
if (graphics_sheets_[i].is_active()) { if (gfx_sheets[i].is_active()) {
int to_bpp = 3; int to_bpp = 3;
std::vector<uint8_t> final_data; std::vector<uint8_t> final_data;
bool compressed = true; bool compressed = true;
@@ -145,7 +147,7 @@ absl::Status Rom::SaveAllGraphicsData() {
} }
std::cout << "Sheet ID " << i << " BPP: " << to_bpp << std::endl; std::cout << "Sheet ID " << i << " BPP: " << to_bpp << std::endl;
auto sheet_data = graphics_sheets_[i].vector(); auto sheet_data = gfx_sheets[i].vector();
std::cout << "Sheet data size: " << sheet_data.size() << std::endl; std::cout << "Sheet data size: " << sheet_data.size() << std::endl;
final_data = gfx::Bpp8SnesToIndexed(sheet_data, 8); final_data = gfx::Bpp8SnesToIndexed(sheet_data, 8);
int size = 0; int size = 0;
@@ -157,11 +159,10 @@ absl::Status Rom::SaveAllGraphicsData() {
} }
} }
auto offset = auto offset =
GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1, GetGraphicsAddress(rom.data(), i, rom.version_constants().kOverworldGfxPtr1,
version_constants().kOverworldGfxPtr2, rom.version_constants().kOverworldGfxPtr2,
version_constants().kOverworldGfxPtr3); rom.version_constants().kOverworldGfxPtr3);
std::copy(final_data.begin(), final_data.end(), std::copy(final_data.begin(), final_data.end(), rom.begin() + offset);
rom_data_.begin() + offset);
} }
} }
return absl::OkStatus(); return absl::OkStatus();
@@ -230,6 +231,17 @@ absl::Status Rom::LoadFromPointer(uchar *data, size_t length, bool z3_load) {
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status Rom::LoadFromBytes(const std::vector<uint8_t>& data) {
if (data.empty()) {
return absl::InvalidArgumentError(
"Could not load ROM: parameter `data` is empty.");
}
rom_data_ = data;
size_ = data.size();
is_loaded_ = true;
return absl::OkStatus();
}
absl::Status Rom::LoadZelda3() { absl::Status Rom::LoadZelda3() {
// Check if the ROM has a header // Check if the ROM has a header
constexpr size_t kBaseRomSize = 1048576; // 1MB constexpr size_t kBaseRomSize = 1048576; // 1MB
@@ -266,17 +278,6 @@ absl::Status Rom::LoadZelda3() {
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status Rom::LoadFromBytes(const std::vector<uint8_t> &data) {
if (data.empty()) {
return absl::InvalidArgumentError(
"Could not load ROM: parameter `data` is empty.");
}
rom_data_ = data;
size_ = data.size();
is_loaded_ = true;
return absl::OkStatus();
}
absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) { absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) {
absl::Status non_firing_status; absl::Status non_firing_status;
if (rom_data_.empty()) { if (rom_data_.empty()) {
@@ -319,8 +320,6 @@ absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) {
RETURN_IF_ERROR(SaveAllPalettes()); RETURN_IF_ERROR(SaveAllPalettes());
if (core::ExperimentFlags::get().kSaveGfxGroups) if (core::ExperimentFlags::get().kSaveGfxGroups)
RETURN_IF_ERROR(SaveGroupsToRom()); RETURN_IF_ERROR(SaveGroupsToRom());
if (core::ExperimentFlags::get().kSaveGraphicsSheet)
RETURN_IF_ERROR(SaveAllGraphicsData());
if (save_new) { if (save_new) {
// Create a file of the same name and append the date between the filename // Create a file of the same name and append the date between the filename

View File

@@ -27,6 +27,24 @@
#include "app/gfx/snes_tile.h" #include "app/gfx/snes_tile.h"
namespace yaze { namespace yaze {
constexpr uint32_t kNumGfxSheets = 223;
constexpr uint32_t kNumLinkSheets = 14;
constexpr uint32_t kTile16Ptr = 0x78000;
constexpr uint32_t kNormalGfxSpaceStart = 0x87000;
constexpr uint32_t kNormalGfxSpaceEnd = 0xC4200;
constexpr uint32_t kFontSpriteLocation = 0x70000;
constexpr uint32_t kGfxGroupsPointer = 0x6237;
constexpr uint32_t kUncompressedSheetSize = 0x0800;
constexpr uint32_t kNumMainBlocksets = 37;
constexpr uint32_t kNumRoomBlocksets = 82;
constexpr uint32_t kNumSpritesets = 144;
constexpr uint32_t kNumPalettesets = 72;
constexpr uint32_t kEntranceGfxGroup = 0x5D97;
// TODO: Verify what this was used for in ZS
constexpr uint32_t kMaxGraphics = 0xC3FB5;
/** /**
* @brief Different versions of the game supported by the Rom class. * @brief Different versions of the game supported by the Rom class.
*/ */
@@ -111,53 +129,12 @@ static const std::map<Z3_Version, VersionConstants> kVersionConstantsMap = {
{Z3_Version::RANDO, {}}, {Z3_Version::RANDO, {}},
}; };
constexpr uint32_t kNumGfxSheets = 223;
constexpr uint32_t kNumLinkSheets = 14;
constexpr uint32_t kTile16Ptr = 0x78000;
constexpr uint32_t kNormalGfxSpaceStart = 0x87000;
constexpr uint32_t kNormalGfxSpaceEnd = 0xC4200;
constexpr uint32_t kFontSpriteLocation = 0x70000;
constexpr uint32_t kGfxGroupsPointer = 0x6237;
constexpr uint32_t kUncompressedSheetSize = 0x0800;
constexpr uint32_t kNumMainBlocksets = 37;
constexpr uint32_t kNumRoomBlocksets = 82;
constexpr uint32_t kNumSpritesets = 144;
constexpr uint32_t kNumPalettesets = 72;
constexpr uint32_t kEntranceGfxGroup = 0x5D97;
// TODO: Verify what this was used for in ZS
constexpr uint32_t kMaxGraphics = 0xC3FB5;
/** /**
* @brief The Rom class is used to load, save, and modify Rom data. * @brief The Rom class is used to load, save, and modify Rom data.
*/ */
class Rom { class Rom {
public: public:
/**
* @brief Loads the players 4bpp graphics sheet from Rom data.
*/
absl::Status LoadLinkGraphics();
/**
* @brief This function iterates over all graphics sheets in the Rom and loads
* them into memory. Depending on the sheet's index, it may be uncompressed or
* compressed using the LC-LZ2 algorithm. The uncompressed sheets are 3 bits
* per pixel (BPP), while the compressed sheets are 4 BPP. The loaded graphics
* data is converted to 8 BPP and stored in a bitmap.
*
* The graphics sheets are divided into the following ranges:
*
* | Range | Compression Type | Decompressed Size | Number of Chars |
* |---------|------------------|------------------|-----------------|
* | 0-112 | Compressed 3bpp BGR | 0x600 chars | Decompressed each |
* | 113-114 | Compressed 2bpp | 0x800 chars | Decompressed each |
* | 115-126 | Uncompressed 3bpp sprites | 0x600 chars | Each |
* | 127-217 | Compressed 3bpp sprites | 0x600 chars | Decompressed each |
* | 218-222 | Compressed 2bpp | 0x800 chars | Decompressed each |
*
*/
absl::Status LoadAllGraphicsData(bool defer_render = false);
/** /**
* Load Rom data from a file. * Load Rom data from a file.
* *
@@ -181,8 +158,6 @@ class Rom {
absl::Status SaveToFile(bool backup, bool save_new = false, absl::Status SaveToFile(bool backup, bool save_new = false,
std::string filename = ""); std::string filename = "");
absl::Status SaveAllGraphicsData();
/** /**
* Saves the given palette to the Rom if any of its colors have been modified. * Saves the given palette to the Rom if any of its colors have been modified.
* *
@@ -222,7 +197,7 @@ class Rom {
/** /**
* @brief Precondition check for reading and writing to the Rom. * @brief Precondition check for reading and writing to the Rom.
*/ */
absl::Status ReadWritePreconditions() { absl::Status ReadWritePreconditions() const {
if (!is_loaded_) { if (!is_loaded_) {
return absl::FailedPreconditionError("ROM file not loaded"); return absl::FailedPreconditionError("ROM file not loaded");
} }
@@ -233,7 +208,6 @@ class Rom {
return absl::OkStatus(); return absl::OkStatus();
} }
// Read functions
absl::StatusOr<uint8_t> ReadByte(int offset) { absl::StatusOr<uint8_t> ReadByte(int offset) {
RETURN_IF_ERROR(ReadWritePreconditions()); RETURN_IF_ERROR(ReadWritePreconditions());
if (offset >= static_cast<int>(rom_data_.size())) { if (offset >= static_cast<int>(rom_data_.size())) {
@@ -251,10 +225,6 @@ class Rom {
return result; return result;
} }
uint16_t toint16(int offset) {
return (uint16_t)(rom_data_[offset] | (rom_data_[offset + 1] << 8));
}
absl::StatusOr<uint32_t> ReadLong(int offset) { absl::StatusOr<uint32_t> ReadLong(int offset) {
RETURN_IF_ERROR(ReadWritePreconditions()); RETURN_IF_ERROR(ReadWritePreconditions());
if (offset + 2 >= static_cast<int>(rom_data_.size())) { if (offset + 2 >= static_cast<int>(rom_data_.size())) {
@@ -266,7 +236,7 @@ class Rom {
} }
absl::StatusOr<std::vector<uint8_t>> ReadByteVector(uint32_t offset, absl::StatusOr<std::vector<uint8_t>> ReadByteVector(uint32_t offset,
uint32_t length) { uint32_t length) const {
RETURN_IF_ERROR(ReadWritePreconditions()); RETURN_IF_ERROR(ReadWritePreconditions());
if (offset + length > static_cast<uint32_t>(rom_data_.size())) { if (offset + length > static_cast<uint32_t>(rom_data_.size())) {
return absl::OutOfRangeError("Offset and length out of range"); return absl::OutOfRangeError("Offset and length out of range");
@@ -281,7 +251,7 @@ class Rom {
absl::StatusOr<gfx::Tile16> ReadTile16(uint32_t tile16_id) { absl::StatusOr<gfx::Tile16> ReadTile16(uint32_t tile16_id) {
// Skip 8 bytes per tile. // Skip 8 bytes per tile.
auto tpos = kTile16Ptr + (tile16_id * 0x08); auto tpos = kTile16Ptr + (tile16_id * 0x08);
gfx::Tile16 tile16; gfx::Tile16 tile16 = {};
ASSIGN_OR_RETURN(auto new_tile0, ReadWord(tpos)) ASSIGN_OR_RETURN(auto new_tile0, ReadWord(tpos))
tile16.tile0_ = gfx::WordToTileInfo(new_tile0); tile16.tile0_ = gfx::WordToTileInfo(new_tile0);
tpos += 2; tpos += 2;
@@ -309,17 +279,6 @@ class Rom {
return absl::OkStatus(); return absl::OkStatus();
} }
// Write functions
absl::Status Write(int addr, int value) {
if (addr >= static_cast<int>(rom_data_.size())) {
return absl::InvalidArgumentError(absl::StrFormat(
"Attempt to write %d value failed, address %d out of range", value,
addr));
}
rom_data_[addr] = value;
return absl::OkStatus();
}
absl::Status WriteByte(int addr, uint8_t value) { absl::Status WriteByte(int addr, uint8_t value) {
RETURN_IF_ERROR(ReadWritePreconditions()); RETURN_IF_ERROR(ReadWritePreconditions());
if (addr >= static_cast<int>(rom_data_.size())) { if (addr >= static_cast<int>(rom_data_.size())) {
@@ -419,9 +378,7 @@ class Rom {
uint8_t& operator[](unsigned long i) { uint8_t& operator[](unsigned long i) {
if (i > size_) { if (i > size_) {
std::cout << "ROM: Index " << i << " out of bounds, size: " << size_ throw std::out_of_range("Rom index out of range");
<< std::endl;
return rom_data_[0];
} }
return rom_data_[i]; return rom_data_[i];
} }
@@ -434,14 +391,10 @@ class Rom {
return is_loaded_; return is_loaded_;
} }
// Full graphical data for the game
std::vector<uint8_t> graphics_buffer() const { return graphics_buffer_; }
auto title() const { return title_; } auto title() const { return title_; }
auto size() const { return size_; } auto size() const { return size_; }
auto data() const { return rom_data_.data(); } auto data() const { return rom_data_.data(); }
auto mutable_data() { return rom_data_.data(); } auto mutable_data() { return rom_data_.data(); }
auto begin() { return rom_data_.begin(); } auto begin() { return rom_data_.begin(); }
auto end() { return rom_data_.end(); } auto end() { return rom_data_.end(); }
@@ -450,12 +403,9 @@ class Rom {
auto filename() const { return filename_; } auto filename() const { return filename_; }
auto set_filename(std::string name) { filename_ = name; } auto set_filename(std::string name) { filename_ = name; }
auto link_graphics() { return link_graphics_; } std::vector<uint8_t> graphics_buffer() const { return graphics_buffer_; }
auto mutable_link_graphics() { return &link_graphics_; } auto mutable_graphics_buffer() { return &graphics_buffer_; }
auto gfx_sheets() { return graphics_sheets_; } auto palette_group() const { return palette_groups_; }
auto mutable_gfx_sheets() { return &graphics_sheets_; }
auto palette_group() { return palette_groups_; }
auto mutable_palette_group() { return &palette_groups_; } auto mutable_palette_group() { return &palette_groups_; }
auto dungeon_palette(int i) { return palette_groups_.dungeon_main[i]; } auto dungeon_palette(int i) { return palette_groups_.dungeon_main[i]; }
auto mutable_dungeon_palette(int i) { auto mutable_dungeon_palette(int i) {
@@ -482,7 +432,7 @@ class Rom {
private: private:
virtual absl::Status WriteHelper(const WriteAction& action) { virtual absl::Status WriteHelper(const WriteAction& action) {
if (std::holds_alternative<uint8_t>(action.value)) { if (std::holds_alternative<uint8_t>(action.value)) {
return Write(action.address, std::get<uint8_t>(action.value)); return WriteByte(action.address, std::get<uint8_t>(action.value));
} else if (std::holds_alternative<uint16_t>(action.value) || } else if (std::holds_alternative<uint16_t>(action.value) ||
std::holds_alternative<short>(action.value)) { std::holds_alternative<short>(action.value)) {
return WriteShort(action.address, std::get<uint16_t>(action.value)); return WriteShort(action.address, std::get<uint16_t>(action.value));
@@ -538,12 +488,6 @@ class Rom {
// Full contiguous graphics space // Full contiguous graphics space
std::vector<uint8_t> graphics_buffer_; std::vector<uint8_t> graphics_buffer_;
// All graphics sheets in the game
std::array<gfx::Bitmap, kNumGfxSheets> graphics_sheets_;
// All graphics sheets for Link
std::array<gfx::Bitmap, kNumLinkSheets> link_graphics_;
// Label manager for unique resource names. // Label manager for unique resource names.
ResourceLabelManager resource_label_manager_; ResourceLabelManager resource_label_manager_;
@@ -554,6 +498,44 @@ class Rom {
Z3_Version version_ = Z3_Version::US; Z3_Version version_ = Z3_Version::US;
}; };
class GraphicsSheetManager {
public:
static GraphicsSheetManager& GetInstance() {
static GraphicsSheetManager instance;
return instance;
}
GraphicsSheetManager() = default;
virtual ~GraphicsSheetManager() = default;
std::array<gfx::Bitmap, kNumGfxSheets>& gfx_sheets() { return gfx_sheets_; }
auto gfx_sheet(int i) { return gfx_sheets_[i]; }
auto mutable_gfx_sheet(int i) { return &gfx_sheets_[i]; }
auto mutable_gfx_sheets() { return &gfx_sheets_; }
private:
std::array<gfx::Bitmap, kNumGfxSheets> gfx_sheets_;
};
/**
* @brief This function iterates over all graphics sheets in the Rom and loads
* them into memory. Depending on the sheet's index, it may be uncompressed or
* compressed using the LC-LZ2 algorithm. The uncompressed sheets are 3 bits
* per pixel (BPP), while the compressed sheets are 4 BPP. The loaded graphics
* data is converted to 8 BPP and stored in a bitmap.
*
* The graphics sheets are divided into the following ranges:
*
* | Range | Compression Type | Decompressed Size | Number of Chars |
* |---------|------------------|------------------|-----------------|
* | 0-112 | Compressed 3bpp BGR | 0x600 chars | Decompressed each |
* | 113-114 | Compressed 2bpp | 0x800 chars | Decompressed each |
* | 115-126 | Uncompressed 3bpp sprites | 0x600 chars | Each |
* | 127-217 | Compressed 3bpp sprites | 0x600 chars | Decompressed each |
* | 218-222 | Compressed 2bpp | 0x800 chars | Decompressed each |
*
*/
absl::StatusOr<std::array<gfx::Bitmap, kNumGfxSheets>> LoadAllGraphicsData(Rom& rom, bool defer_render = false);
absl::Status SaveAllGraphicsData(Rom& rom, std::array<gfx::Bitmap, kNumGfxSheets>& gfx_sheets);
/** /**
* @brief Loads 2bpp graphics from Rom data. * @brief Loads 2bpp graphics from Rom data.
* *
@@ -564,6 +546,11 @@ class Rom {
*/ */
absl::StatusOr<std::vector<uint8_t>> Load2BppGraphics(const Rom& rom); absl::StatusOr<std::vector<uint8_t>> Load2BppGraphics(const Rom& rom);
/**
* @brief Loads the players 4bpp graphics sheet from Rom data.
*/
absl::StatusOr<std::array<gfx::Bitmap, kNumLinkSheets>> LoadLinkGraphics(const Rom& rom);
/** /**
* @brief A class to hold a shared pointer to a Rom object. * @brief A class to hold a shared pointer to a Rom object.
*/ */

View File

@@ -30,12 +30,12 @@ class GameEntity {
kProperties = 7, kProperties = 7,
kDungeonSprite = 8, kDungeonSprite = 8,
} entity_type_; } entity_type_;
int x_; int x_ = 0;
int y_; int y_ = 0;
int game_x_; int game_x_ = 0;
int game_y_; int game_y_ = 0;
int entity_id_; int entity_id_ = 0;
uint16_t map_id_; uint16_t map_id_ = 0;
auto set_x(int x) { x_ = x; } auto set_x(int x) { x_ = x; }
auto set_y(int y) { y_ = y; } auto set_y(int y) { y_ = y; }

View File

@@ -102,7 +102,7 @@ void DungeonObjectRenderer::UpdateObjectBitmap() {
int x = column * 8; int x = column * 8;
int y = row * 8; int y = row * 8;
auto sheet = rom()->mutable_gfx_sheets()->at(vram_.sheets[sheet_number]); auto sheet = GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(vram_.sheets[sheet_number]);
// Copy the tile from VRAM using the read tile_id // Copy the tile from VRAM using the read tile_id
sheet.Get8x8Tile(tile_id, x, y, tilemap_, tilemap_offset); sheet.Get8x8Tile(tile_id, x, y, tilemap_, tilemap_offset);

View File

@@ -17,7 +17,7 @@ namespace yaze {
namespace zelda3 { namespace zelda3 {
struct PseudoVram { struct PseudoVram {
std::array<uint8_t, 16> sheets; std::array<uint8_t, 16> sheets = { 0 };
std::vector<gfx::SnesPalette> palettes; std::vector<gfx::SnesPalette> palettes;
}; };

View File

@@ -220,37 +220,37 @@ class RoomEntrance {
RETURN_IF_ERROR(rom.WriteShort( RETURN_IF_ERROR(rom.WriteShort(
kEntranceCameraYTrigger + (entrance_id * 2), camera_trigger_y_)); kEntranceCameraYTrigger + (entrance_id * 2), camera_trigger_y_));
RETURN_IF_ERROR(rom.WriteShort(kEntranceExit + (entrance_id * 2), exit_)); RETURN_IF_ERROR(rom.WriteShort(kEntranceExit + (entrance_id * 2), exit_));
RETURN_IF_ERROR(rom.Write(kEntranceBlockset + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kEntranceBlockset + entrance_id,
(uint8_t)(blockset_ & 0xFF))); (uint8_t)(blockset_ & 0xFF)));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kEntranceMusic + entrance_id, (uint8_t)(music_ & 0xFF))); rom.WriteByte(kEntranceMusic + entrance_id, (uint8_t)(music_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntranceDungeon + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kEntranceDungeon + entrance_id,
(uint8_t)(dungeon_id_ & 0xFF))); (uint8_t)(dungeon_id_ & 0xFF)));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kEntranceDoor + entrance_id, (uint8_t)(door_ & 0xFF))); rom.WriteByte(kEntranceDoor + entrance_id, (uint8_t)(door_ & 0xFF)));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kEntranceFloor + entrance_id, (uint8_t)(floor_ & 0xFF))); rom.WriteByte(kEntranceFloor + entrance_id, (uint8_t)(floor_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntranceLadderBG + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kEntranceLadderBG + entrance_id,
(uint8_t)(ladder_bg_ & 0xFF))); (uint8_t)(ladder_bg_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntrancescrolling + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kEntrancescrolling + entrance_id,
(uint8_t)(scrolling_ & 0xFF))); (uint8_t)(scrolling_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntranceScrollQuadrant + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollQuadrant + entrance_id,
(uint8_t)(scroll_quadrant_ & 0xFF))); (uint8_t)(scroll_quadrant_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 0 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 0 + (entrance_id * 8),
camera_boundary_qn_)); camera_boundary_qn_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 1 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 1 + (entrance_id * 8),
camera_boundary_fn_)); camera_boundary_fn_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 2 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 2 + (entrance_id * 8),
camera_boundary_qs_)); camera_boundary_qs_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 3 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 3 + (entrance_id * 8),
camera_boundary_fs_)); camera_boundary_fs_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 4 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 4 + (entrance_id * 8),
camera_boundary_qw_)); camera_boundary_qw_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 5 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 5 + (entrance_id * 8),
camera_boundary_fw_)); camera_boundary_fw_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 6 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 6 + (entrance_id * 8),
camera_boundary_qe_)); camera_boundary_qe_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 7 + (entrance_id * 8), RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 7 + (entrance_id * 8),
camera_boundary_fe_)); camera_boundary_fe_));
} else { } else {
RETURN_IF_ERROR( RETURN_IF_ERROR(
@@ -271,45 +271,45 @@ class RoomEntrance {
camera_trigger_y_)); camera_trigger_y_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.WriteShort(kStartingEntranceexit + (entrance_id * 2), exit_)); rom.WriteShort(kStartingEntranceexit + (entrance_id * 2), exit_));
RETURN_IF_ERROR(rom.Write(kStartingEntranceBlockset + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceBlockset + entrance_id,
(uint8_t)(blockset_ & 0xFF))); (uint8_t)(blockset_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntrancemusic + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntrancemusic + entrance_id,
(uint8_t)(music_ & 0xFF))); (uint8_t)(music_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceDungeon + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceDungeon + entrance_id,
(uint8_t)(dungeon_id_ & 0xFF))); (uint8_t)(dungeon_id_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceDoor + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceDoor + entrance_id,
(uint8_t)(door_ & 0xFF))); (uint8_t)(door_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceFloor + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceFloor + entrance_id,
(uint8_t)(floor_ & 0xFF))); (uint8_t)(floor_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceLadderBG + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceLadderBG + entrance_id,
(uint8_t)(ladder_bg_ & 0xFF))); (uint8_t)(ladder_bg_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntrancescrolling + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntrancescrolling + entrance_id,
(uint8_t)(scrolling_ & 0xFF))); (uint8_t)(scrolling_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceScrollQuadrant + entrance_id, RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceScrollQuadrant + entrance_id,
(uint8_t)(scroll_quadrant_ & 0xFF))); (uint8_t)(scroll_quadrant_ & 0xFF)));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 0 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 0 + (entrance_id * 8),
camera_boundary_qn_)); camera_boundary_qn_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 1 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 1 + (entrance_id * 8),
camera_boundary_fn_)); camera_boundary_fn_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 2 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 2 + (entrance_id * 8),
camera_boundary_qs_)); camera_boundary_qs_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 3 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 3 + (entrance_id * 8),
camera_boundary_fs_)); camera_boundary_fs_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 4 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 4 + (entrance_id * 8),
camera_boundary_qw_)); camera_boundary_qw_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 5 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 5 + (entrance_id * 8),
camera_boundary_fw_)); camera_boundary_fw_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 6 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 6 + (entrance_id * 8),
camera_boundary_qe_)); camera_boundary_qe_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 7 + (entrance_id * 8), rom.WriteByte(kStartingEntranceScrollEdge + 7 + (entrance_id * 8),
camera_boundary_fe_)); camera_boundary_fe_));
} }
return absl::OkStatus(); return absl::OkStatus();

View File

@@ -25,7 +25,8 @@ absl::Status Overworld::Load(Rom &rom) {
overworld_maps_.emplace_back(map_index, rom_); overworld_maps_.emplace_back(map_index, rom_);
FetchLargeMaps(); FetchLargeMaps();
LoadEntrances(); RETURN_IF_ERROR(LoadEntrances());
RETURN_IF_ERROR(LoadHoles());
RETURN_IF_ERROR(LoadExits()); RETURN_IF_ERROR(LoadExits());
RETURN_IF_ERROR(LoadItems()); RETURN_IF_ERROR(LoadItems());
RETURN_IF_ERROR(LoadSprites()); RETURN_IF_ERROR(LoadSprites());
@@ -281,6 +282,7 @@ absl::Status Overworld::LoadOverworldMaps() {
// Wait for all tasks to complete and check their results // Wait for all tasks to complete and check their results
for (auto &future : futures) { for (auto &future : futures) {
future.wait();
RETURN_IF_ERROR(future.get()); RETURN_IF_ERROR(future.get());
} }
return absl::OkStatus(); return absl::OkStatus();
@@ -293,7 +295,7 @@ void Overworld::LoadTileTypes() {
} }
} }
void Overworld::LoadEntrances() { absl::Status Overworld::LoadEntrances() {
int ow_entrance_map_ptr = kOverworldEntranceMap; int ow_entrance_map_ptr = kOverworldEntranceMap;
int ow_entrance_pos_ptr = kOverworldEntrancePos; int ow_entrance_pos_ptr = kOverworldEntrancePos;
int ow_entrance_id_ptr = kOverworldEntranceEntranceId; int ow_entrance_id_ptr = kOverworldEntranceEntranceId;
@@ -307,9 +309,9 @@ void Overworld::LoadEntrances() {
} }
for (int i = 0; i < num_entrances; i++) { for (int i = 0; i < num_entrances; i++) {
short map_id = rom()->toint16(ow_entrance_map_ptr + (i * 2)); ASSIGN_OR_RETURN(auto map_id, rom()->ReadWord(ow_entrance_map_ptr + (i * 2)));
uint16_t map_pos = rom()->toint16(ow_entrance_pos_ptr + (i * 2)); ASSIGN_OR_RETURN(auto map_pos, rom()->ReadWord(ow_entrance_pos_ptr + (i * 2)));
uint8_t entrance_id = rom_[ow_entrance_id_ptr + i]; ASSIGN_OR_RETURN(auto entrance_id, rom()->ReadByte(ow_entrance_id_ptr + i));
int p = map_pos >> 1; int p = map_pos >> 1;
int x = (p % 64); int x = (p % 64);
int y = (p >> 6); int y = (p >> 6);
@@ -323,20 +325,25 @@ void Overworld::LoadEntrances() {
deleted); deleted);
} }
for (int i = 0; i < 0x13; i++) {
auto map_id = (short)((rom_[kOverworldHoleArea + (i * 2) + 1] << 8) + return absl::OkStatus();
(rom_[kOverworldHoleArea + (i * 2)])); }
auto map_pos = (short)((rom_[kOverworldHolePos + (i * 2) + 1] << 8) +
(rom_[kOverworldHolePos + (i * 2)])); absl::Status Overworld::LoadHoles() {
uint8_t entrance_id = (rom_[kOverworldHoleEntrance + i]); constexpr int kNumHoles = 0x13;
for (int i = 0; i < kNumHoles; i++) {
ASSIGN_OR_RETURN(auto map_id, rom()->ReadWord(kOverworldHoleArea + (i * 2)));
ASSIGN_OR_RETURN(auto map_pos, rom()->ReadWord(kOverworldHolePos + (i * 2)));
ASSIGN_OR_RETURN(auto entrance_id, rom()->ReadByte(kOverworldHoleEntrance + i));
int p = (map_pos + 0x400) >> 1; int p = (map_pos + 0x400) >> 1;
int x = (p % 64); int x = (p % 64);
int y = (p >> 6); int y = (p >> 6);
all_holes_.emplace_back( all_holes_.emplace_back(
(x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512), (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
(y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
(uint16_t)(map_pos + 0x400), true); (uint16_t)(map_pos + 0x400), true);
} }
return absl::OkStatus();
} }
absl::Status Overworld::LoadExits() { absl::Status Overworld::LoadExits() {
@@ -447,13 +454,21 @@ absl::Status Overworld::LoadItems() {
} }
absl::Status Overworld::LoadSprites() { absl::Status Overworld::LoadSprites() {
for (int i = 0; i < 3; i++) { std::vector<std::future<absl::Status>> futures;
all_sprites_.emplace_back(); futures.emplace_back(std::async(std::launch::async, [this]() {
} return LoadSpritesFromMap(kOverworldSpritesBeginning, 64, 0);
}));
futures.emplace_back(std::async(std::launch::async, [this]() {
return LoadSpritesFromMap(kOverworldSpritesZelda, 144, 1);
}));
futures.emplace_back(std::async(std::launch::async, [this]() {
return LoadSpritesFromMap(kOverworldSpritesAgahnim, 144, 2);
}));
RETURN_IF_ERROR(LoadSpritesFromMap(kOverworldSpritesBeginning, 64, 0)); for (auto& future : futures) {
RETURN_IF_ERROR(LoadSpritesFromMap(kOverworldSpritesZelda, 144, 1)); future.wait();
RETURN_IF_ERROR(LoadSpritesFromMap(kOverworldSpritesAgahnim, 144, 2)); RETURN_IF_ERROR(future.get());
}
return absl::OkStatus(); return absl::OkStatus();
} }
@@ -484,8 +499,8 @@ absl::Status Overworld::LoadSpritesFromMap(int sprites_per_gamestate_ptr,
int realX = ((b2 & 0x3F) * 16) + mapX * 512; int realX = ((b2 & 0x3F) * 16) + mapX * 512;
int realY = ((b1 & 0x3F) * 16) + mapY * 512; int realY = ((b1 & 0x3F) * 16) + mapY * 512;
auto current_gfx = overworld_maps_[i].current_graphics(); all_sprites_[game_state].emplace_back(*overworld_maps_[i].mutable_current_graphics(),
all_sprites_[game_state].emplace_back(current_gfx, (uint8_t)i, b3, (uint8_t)i, b3,
(uint8_t)(b2 & 0x3F), (uint8_t)(b2 & 0x3F),
(uint8_t)(b1 & 0x3F), realX, realY); (uint8_t)(b1 & 0x3F), realX, realY);
all_sprites_[game_state][i].Draw(); all_sprites_[game_state][i].Draw();
@@ -659,7 +674,7 @@ absl::Status Overworld::SaveLargeMaps() {
// Always write the map parent since it should not matter // Always write the map parent since it should not matter
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom()->Write(kOverworldMapParentId + i, overworld_maps_[i].parent())) rom()->WriteByte(kOverworldMapParentId + i, overworld_maps_[i].parent()))
if (std::find(checked_map.begin(), checked_map.end(), i) != if (std::find(checked_map.begin(), checked_map.end(), i) !=
checked_map.end()) { checked_map.end()) {
@@ -1322,10 +1337,10 @@ absl::Status Overworld::SaveMap16Expanded() {
RETURN_IF_ERROR(rom()->WriteShort(core::SnesToPc(0x02FE33), RETURN_IF_ERROR(rom()->WriteShort(core::SnesToPc(0x02FE33),
core::PcToSnes(kMap16TilesExpanded + 6))); core::PcToSnes(kMap16TilesExpanded + 6)));
RETURN_IF_ERROR(rom()->Write( RETURN_IF_ERROR(rom()->WriteByte(
core::SnesToPc(0x02FD28), core::SnesToPc(0x02FD28),
static_cast<uint8_t>(core::PcToSnes(kMap16TilesExpanded) >> 16))); static_cast<uint8_t>(core::PcToSnes(kMap16TilesExpanded) >> 16)));
RETURN_IF_ERROR(rom()->Write( RETURN_IF_ERROR(rom()->WriteByte(
core::SnesToPc(0x02FD39), core::SnesToPc(0x02FD39),
static_cast<uint8_t>(core::PcToSnes(kMap16TilesExpanded) >> 16))); static_cast<uint8_t>(core::PcToSnes(kMap16TilesExpanded) >> 16)));
@@ -1392,7 +1407,7 @@ absl::Status Overworld::SaveExits() {
for (int i = 0; i < kNumOverworldExits; i++) { for (int i = 0; i < kNumOverworldExits; i++) {
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom()->WriteShort(OWExitRoomId + (i * 2), all_exits_[i].room_id_)); rom()->WriteShort(OWExitRoomId + (i * 2), all_exits_[i].room_id_));
RETURN_IF_ERROR(rom()->Write(OWExitMapId + i, all_exits_[i].map_id_)); RETURN_IF_ERROR(rom()->WriteByte(OWExitMapId + i, all_exits_[i].map_id_));
RETURN_IF_ERROR( RETURN_IF_ERROR(
rom()->WriteShort(OWExitVram + (i * 2), all_exits_[i].map_pos_)); rom()->WriteShort(OWExitVram + (i * 2), all_exits_[i].map_pos_));
RETURN_IF_ERROR( RETURN_IF_ERROR(

View File

@@ -109,16 +109,19 @@ constexpr int NumberOfMap32 = Map32PerScreen * kNumOverworldMaps;
*/ */
class Overworld : public SharedRom { class Overworld : public SharedRom {
public: public:
Overworld(Rom& rom) : rom_(rom) {}
absl::Status Load(Rom &rom); absl::Status Load(Rom &rom);
absl::Status LoadOverworldMaps(); absl::Status LoadOverworldMaps();
void LoadTileTypes(); void LoadTileTypes();
void LoadEntrances(); absl::Status LoadEntrances();
absl::Status LoadHoles();
absl::Status LoadExits(); absl::Status LoadExits();
absl::Status LoadItems(); absl::Status LoadItems();
absl::Status LoadSprites(); absl::Status LoadSprites();
absl::Status LoadSpritesFromMap(int spriteStart, int spriteCount, absl::Status LoadSpritesFromMap(int sprite_start, int sprite_count,
int spriteIndex); int sprite_index);
absl::Status Save(Rom &rom); absl::Status Save(Rom &rom);
absl::Status SaveOverworldMaps(); absl::Status SaveOverworldMaps();
@@ -143,7 +146,9 @@ class Overworld : public SharedRom {
all_entrances_.clear(); all_entrances_.clear();
all_exits_.clear(); all_exits_.clear();
all_items_.clear(); all_items_.clear();
all_sprites_.clear(); for (auto& sprites : all_sprites_) {
sprites.clear();
}
is_loaded_ = false; is_loaded_ = false;
} }
@@ -227,7 +232,7 @@ class Overworld : public SharedRom {
int &ttpos); int &ttpos);
void DecompressAllMapTiles(); void DecompressAllMapTiles();
Rom rom_; Rom& rom_;
bool is_loaded_ = false; bool is_loaded_ = false;
bool expanded_tile16_ = false; bool expanded_tile16_ = false;
@@ -240,8 +245,8 @@ class Overworld : public SharedRom {
OverworldMapTiles map_tiles_; OverworldMapTiles map_tiles_;
std::array<uint8_t, kNumOverworldMaps> map_parent_; std::array<uint8_t, kNumOverworldMaps> map_parent_ = { 0 };
std::array<uint8_t, kNumTileTypes> all_tiles_types_; std::array<uint8_t, kNumTileTypes> all_tiles_types_ = { 0 };
std::vector<gfx::Tile16> tiles16_; std::vector<gfx::Tile16> tiles16_;
std::vector<gfx::Tile32> tiles32_; std::vector<gfx::Tile32> tiles32_;
std::vector<uint16_t> tiles32_list_; std::vector<uint16_t> tiles32_list_;
@@ -251,7 +256,7 @@ class Overworld : public SharedRom {
std::vector<OverworldEntrance> all_holes_; std::vector<OverworldEntrance> all_holes_;
std::vector<OverworldExit> all_exits_; std::vector<OverworldExit> all_exits_;
std::vector<OverworldItem> all_items_; std::vector<OverworldItem> all_items_;
std::vector<std::vector<Sprite>> all_sprites_; std::array<std::vector<Sprite>, 3> all_sprites_;
std::vector<uint64_t> deleted_entrances_; std::vector<uint64_t> deleted_entrances_;
std::vector<std::vector<uint8_t>> map_data_p1 = std::vector<std::vector<uint8_t>> map_data_p1 =
std::vector<std::vector<uint8_t>>(kNumOverworldMaps); std::vector<std::vector<uint8_t>>(kNumOverworldMaps);

View File

@@ -71,7 +71,13 @@ void OverworldMap::LoadAreaInfo() {
} }
} }
message_id_ = rom_.toint16(kOverworldMessageIds + (parent_ * 2)); auto message_id = rom_.ReadWord(kOverworldMessageIds + (parent_ * 2));
if (message_id.ok()) {
message_id_ = message_id.value();
} else {
message_id_ = 0;
core::logf("Error reading message id for map %d", parent_);
}
if (index_ < kDarkWorldMapIdStart) { if (index_ < kDarkWorldMapIdStart) {
area_graphics_ = rom_[kAreaGfxIdPtr + parent_]; area_graphics_ = rom_[kAreaGfxIdPtr + parent_];

View File

@@ -110,6 +110,7 @@ class OverworldMap : public gfx::GfxContext {
auto static_graphics(int i) const { return static_graphics_[i]; } auto static_graphics(int i) const { return static_graphics_[i]; }
auto large_index() const { return large_index_; } auto large_index() const { return large_index_; }
auto mutable_current_graphics() { return &current_gfx_; }
auto mutable_area_graphics() { return &area_graphics_; } auto mutable_area_graphics() { return &area_graphics_; }
auto mutable_area_palette() { return &area_palette_; } auto mutable_area_palette() { return &area_palette_; }
auto mutable_sprite_graphics(int i) { return &sprite_graphics_[i]; } auto mutable_sprite_graphics(int i) { return &sprite_graphics_[i]; }

View File

@@ -17,10 +17,14 @@ absl::Status Inventory::Create() {
} }
RETURN_IF_ERROR(BuildTileset()) RETURN_IF_ERROR(BuildTileset())
for (int i = 0; i < 0x500; i += 0x08) { for (int i = 0; i < 0x500; i += 0x08) {
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos))); ASSIGN_OR_RETURN(auto t1, rom()->ReadWord(i + kBowItemPos));
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos + 0x02))); ASSIGN_OR_RETURN(auto t2, rom()->ReadWord(i + kBowItemPos + 0x02));
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos + 0x04))); ASSIGN_OR_RETURN(auto t3, rom()->ReadWord(i + kBowItemPos + 0x04));
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos + 0x08))); ASSIGN_OR_RETURN(auto t4, rom()->ReadWord(i + kBowItemPos + 0x06));
tiles_.push_back(gfx::GetTilesInfo(t1));
tiles_.push_back(gfx::GetTilesInfo(t2));
tiles_.push_back(gfx::GetTilesInfo(t3));
tiles_.push_back(gfx::GetTilesInfo(t4));
} }
const int offsets[] = {0x00, 0x08, 0x800, 0x808}; const int offsets[] = {0x00, 0x08, 0x800, 0x808};
auto xx = 0; auto xx = 0;

View File

@@ -279,7 +279,7 @@ static const std::string kSpriteDefaultNames[]{
class Sprite : public GameEntity { class Sprite : public GameEntity {
public: public:
Sprite() = default; Sprite() = default;
Sprite(std::vector<uint8_t> src, uint8_t overworld_map_id, uint8_t id, Sprite(const std::vector<uint8_t>& src, uint8_t overworld_map_id, uint8_t id,
uint8_t x, uint8_t y, int map_x, int map_y) uint8_t x, uint8_t y, int map_x, int map_y)
: map_id_(static_cast<int>(overworld_map_id)), : map_id_(static_cast<int>(overworld_map_id)),
id_(id), id_(id),