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
#define YAZE_CORE_COMMON_H
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iostream>
@@ -10,6 +11,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_cat.h"
namespace yaze {
@@ -56,12 +58,6 @@ class ExperimentFlags {
// Attempt to run the dungeon room draw routine when opening a room.
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.
bool kSaveDungeonMaps = false;
@@ -113,10 +109,6 @@ class ExperimentFlags {
"\n";
result += "kDrawDungeonRoomGraphics: " +
std::to_string(get().kDrawDungeonRoomGraphics) + "\n";
result += "kNewFileDialogWrapper: " +
std::to_string(get().kNewFileDialogWrapper) + "\n";
result += "kLoadTexturesAsStreaming: " +
std::to_string(get().kLoadTexturesAsStreaming) + "\n";
result +=
"kSaveDungeonMaps: " + std::to_string(get().kSaveDungeonMaps) + "\n";
result += "kLogToConsole: " + std::to_string(get().kLogToConsole) + "\n";
@@ -182,17 +174,23 @@ class NotifyValue {
T temp_value_;
};
static bool log_to_console = false;
static const std::string kLogFileOut = "yaze_log.txt";
template <typename... Args>
static void logf(const absl::FormatSpec<Args...> &format, const Args &...args) {
std::string message = absl::StrFormat(format, args...);
if (log_to_console) {
std::cout << message << std::endl;
auto timestamp = std::chrono::system_clock::now();
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);
fout << message << std::endl;
fout << message;
}
constexpr uint32_t kFastRomRegion = 0x808000;

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
#include <unordered_set>
#include <vector>
#include "app/core/constants.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
@@ -15,19 +16,88 @@
namespace yaze {
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() {
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
static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0};
ImFontConfig icons_config;
@@ -52,70 +122,30 @@ absl::Status LoadPackageFonts() {
float font_size =
(font_path == DROID_SANS) ? FONT_SIZE_DROID_SANS : FONT_SIZE_DEFAULT;
std::string actual_font_path;
#ifdef __APPLE__
#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));
}
FontConfig font_config = { font_path, font_size };
RETURN_IF_ERROR(LoadFont(font_config));
// Merge icon set
std::string actual_icon_font_path = "";
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");
}
RETURN_IF_ERROR(AddIconFont());
// Merge Japanese font
std::string actual_japanese_font_path = "";
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_IF_ERROR(AddJapaneseFont());
}
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
#include <Windows.h>
@@ -235,7 +265,6 @@ void LoadSystemFonts() {
void LoadSystemFonts() {
// Load Linux System Fonts into ImGui
// ...
}
#endif

View File

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

View File

@@ -109,7 +109,7 @@ absl::Status DungeonEditor::Initialize() {
ASSIGN_OR_RETURN(current_palette_group_,
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
for (int block : rooms_[current_room_id_].blocks()) {
room_gfx_sheets_.emplace_back(&graphics_bin_[block]);

View File

@@ -58,19 +58,22 @@ void EditorManager::Initialize(std::string filename) {
absl::Status EditorManager::Update() {
ManageKeyboardShortcuts();
DrawYazeMenu();
DrawStatusPopup();
DrawAboutPopup();
DrawInfoPopup();
DrawMenuBar();
DrawPopups();
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());
rom_assets_loaded_ = true;
}
ManageActiveEditors();
if (!current_rom_) {
DrawHomepage();
} else {
ManageActiveEditors();
}
return absl::OkStatus();
}
@@ -296,7 +299,7 @@ void EditorManager::ManageKeyboardShortcuts() {
}
}
void EditorManager::DrawStatusPopup() {
void EditorManager::DrawPopups() {
static absl::Status prev_status;
if (!status_.ok()) {
show_status_ = true;
@@ -322,9 +325,7 @@ void EditorManager::DrawStatusPopup() {
}
End();
}
}
void EditorManager::DrawAboutPopup() {
if (about_) OpenPopup("About");
if (BeginPopupModal("About", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
Text("Yet Another Zelda3 Editor - v%s", version_.c_str());
@@ -339,9 +340,7 @@ void EditorManager::DrawAboutPopup() {
}
EndPopup();
}
}
void EditorManager::DrawInfoPopup() {
if (rom_info_) OpenPopup("ROM Information");
if (BeginPopupModal("ROM Information", nullptr,
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;
if (BeginMenuBar()) {
DrawYazeMenuBar();
DrawMenuContent();
SameLine(GetWindowWidth() - GetStyle().ItemSpacing.x -
CalcTextSize(ICON_MD_DISPLAY_SETTINGS).x - 110);
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 new_project_menu = false;
@@ -445,11 +462,23 @@ void EditorManager::DrawYazeMenuBar() {
MenuItem("Backup ROM", "", &backup_rom_);
MenuItem("Save New Auto", "", &save_new_auto_);
Separator();
if (BeginMenu("Experiment Flags")) {
static FlagsMenu flags_menu;
flags_menu.Draw();
static FlagsMenu flags_menu;
if (BeginMenu("System Flags")) {
flags_menu.DrawSystemFlags();
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();
}
@@ -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() {
auto file_name = FileDialogWrapper::ShowOpenFileDialog();
auto load_rom = rom()->LoadFromFile(file_name);
if (load_rom.ok()) {
current_rom_ = rom();
static RecentFilesManager manager("recent_files.txt");
manager.Load();
manager.AddFile(file_name);
@@ -691,6 +735,10 @@ void EditorManager::SaveRom() {
status_ = overworld_editor_.Save();
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_);
}
@@ -702,11 +750,13 @@ void EditorManager::OpenRomOrProject(const std::string &filename) {
}
} else {
status_ = rom()->LoadFromFile(filename);
current_rom_ = rom();
}
}
absl::Status EditorManager::OpenProject() {
RETURN_IF_ERROR(rom()->LoadFromFile(current_project_.rom_filename_));
current_rom_ = rom();
if (!rom()->resource_label()->LoadLabels(current_project_.labels_filename_)) {
return absl::InternalError(

View File

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

View File

@@ -112,7 +112,7 @@ void GfxGroupEditor::DrawBlocksetViewer(bool sheet_only) {
BeginGroup();
for (int i = 0; i < 8; 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,
0x20, true, false, 22);
}
@@ -165,7 +165,7 @@ void GfxGroupEditor::DrawRoomsetViewer() {
BeginGroup();
for (int i = 0; i < 4; 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,
0x20, true, false, 23);
}
@@ -203,7 +203,7 @@ void GfxGroupEditor::DrawSpritesetViewer(bool sheet_only) {
BeginGroup();
for (int i = 0; i < 4; 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,
0x20, true, false, 24);
}

View File

@@ -46,9 +46,9 @@ absl::Status GraphicsEditor::Update() {
status_ = UpdateGfxEdit();
TAB_ITEM("Sheet Browser")
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()
status_ = UpdateScadView();
status_ = UpdateLinkGfxView();
@@ -117,7 +117,7 @@ void GraphicsEditor::DrawGfxEditToolset() {
TableNextColumn();
if (Button(ICON_MD_CONTENT_COPY)) {
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);
}
HOVER_HINT("Copy to Clipboard");
@@ -128,12 +128,11 @@ void GraphicsEditor::DrawGfxEditToolset() {
int width, height;
core::GetImageFromClipboard(png_data, width, height);
if (png_data.size() > 0) {
rom()
->mutable_gfx_sheets()
GraphicsSheetManager::GetInstance().mutable_gfx_sheets()
->at(current_sheet_)
.Create(width, height, 8, png_data);
Renderer::GetInstance().UpdateBitmap(
&rom()->mutable_gfx_sheets()->at(current_sheet_));
&GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->at(current_sheet_));
}
}
HOVER_HINT("Paste from Clipboard");
@@ -153,9 +152,9 @@ void GraphicsEditor::DrawGfxEditToolset() {
}
TableNextColumn();
auto bitmap = rom()->gfx_sheets()[current_sheet_];
auto bitmap = GraphicsSheetManager::GetInstance().gfx_sheets()[current_sheet_];
auto palette = bitmap.palette();
for (int i = 0; i < 8; i++) {
for (int i = 0; i < palette.size(); i++) {
ImGui::SameLine();
auto color =
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 key = 0;
for (auto& value : rom()->gfx_sheets()) {
for (auto& value : GraphicsSheetManager::GetInstance().gfx_sheets()) {
ImGui::BeginChild(absl::StrFormat("##GfxSheet%02X", key).c_str(),
ImVec2(0x100 + 1, 0x40 + 1), true,
ImGuiWindowFlags_NoDecoration);
@@ -281,7 +280,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
ImGuiWindowFlags_AlwaysVerticalScrollbar |
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 = [&]() {
current_sheet_canvas_.DrawTileOnBitmap(tile_size_, &current_bitmap,
@@ -290,7 +289,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
};
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_);
ImGui::EndChild();
@@ -323,7 +322,7 @@ absl::Status GraphicsEditor::UpdateGfxTabView() {
current_sheet_ = id;
// ImVec2(0x100, 0x40),
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()) {
RETURN_IF_ERROR(
rom()
->mutable_gfx_sheets()
GraphicsSheetManager::GetInstance().mutable_gfx_sheets()
->data()[current_sheet_]
.ApplyPaletteWithTransparent(palette, edit_palette_sub_index_));
Renderer::GetInstance().UpdateBitmap(
&rom()->mutable_gfx_sheets()->data()[current_sheet_]);
&GraphicsSheetManager::GetInstance().mutable_gfx_sheets()->data()[current_sheet_]);
refresh_graphics_ = false;
}
}
@@ -387,7 +385,7 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
link_canvas_.DrawGrid(16.0f);
int i = 0;
for (auto link_sheet : *rom()->mutable_link_graphics()) {
for (auto& link_sheet : link_sheets_) {
int x_offset = 0;
int y_offset = gfx::kTilesheetHeight * i * 4;
link_canvas_.DrawContextMenu(&link_sheet);
@@ -404,7 +402,7 @@ absl::Status GraphicsEditor::UpdateLinkGfxView() {
if (ImGui::Button("Load Link Graphics (Experimental)")) {
if (rom()->is_loaded()) {
// 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
// Create an animation step display for the poses

View File

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

View File

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

View File

@@ -43,12 +43,12 @@ using ImGui::Text;
absl::Status Tile16Editor::InitBlockset(
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) {
all_tiles_types_ = all_tiles_types;
tile16_blockset_bmp_ = tile16_blockset_bmp;
tile16_individual_ = tile16_individual;
current_gfx_bmp_ = current_gfx_bmp;
current_gfx_bmp_.Create(current_gfx_bmp.width(), current_gfx_bmp.height(),
current_gfx_bmp.depth(), current_gfx_bmp.vector());
core::Renderer::GetInstance().RenderBitmap(&tile16_blockset_bmp_);
RETURN_IF_ERROR(LoadTile8());
ImVector<std::string> tile16_names;
for (int i = 0; i < 0x200; ++i) {
@@ -373,7 +373,7 @@ absl::Status Tile16Editor::UpdateTransferTileCanvas() {
// TODO: Implement tile16 transfer
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.
PRINT_IF_ERROR(transfer_overworld_.Load(transfer_rom_))

View File

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

View File

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

View File

@@ -626,7 +626,7 @@ absl::Status MessageEditor::Save() {
std::vector<uint8_t> backup = rom()->vector();
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;
@@ -634,7 +634,7 @@ absl::Status MessageEditor::Save() {
for (const auto& message : list_of_texts_) {
for (const auto value : message.Data) {
RETURN_IF_ERROR(rom()->Write(pos, value));
RETURN_IF_ERROR(rom()->WriteByte(pos, value));
if (value == kBlockTerminator) {
// 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(
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.
@@ -662,7 +662,7 @@ absl::Status MessageEditor::Save() {
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();
}

View File

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

View File

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

View File

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

View File

@@ -175,7 +175,7 @@ void SpriteEditor::DrawCurrentSheets() {
graphics_sheet_canvas_.DrawTileSelector(32);
for (int i = 0; i < 8; i++) {
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_.DrawOverlay();

View File

@@ -15,45 +15,42 @@ using ImGui::MenuItem;
using ImGui::Separator;
struct FlagsMenu {
void Draw() {
if (BeginMenu("Overworld Flags")) {
Checkbox("Enable Overworld Sprites",
&ExperimentFlags::get().overworld.kDrawOverworldSprites);
Separator();
Checkbox("Save Overworld Maps",
&ExperimentFlags::get().overworld.kSaveOverworldMaps);
Checkbox("Save Overworld Entrances",
&ExperimentFlags::get().overworld.kSaveOverworldEntrances);
Checkbox("Save Overworld Exits",
&ExperimentFlags::get().overworld.kSaveOverworldExits);
Checkbox("Save Overworld Items",
&ExperimentFlags::get().overworld.kSaveOverworldItems);
Checkbox("Save Overworld Properties",
&ExperimentFlags::get().overworld.kSaveOverworldProperties);
Checkbox("Load Custom Overworld",
&ExperimentFlags::get().overworld.kLoadCustomOverworld);
ImGui::EndMenu();
}
void DrawOverworldFlags() {
Checkbox("Enable Overworld Sprites",
&ExperimentFlags::get().overworld.kDrawOverworldSprites);
Separator();
Checkbox("Save Overworld Maps",
&ExperimentFlags::get().overworld.kSaveOverworldMaps);
Checkbox("Save Overworld Entrances",
&ExperimentFlags::get().overworld.kSaveOverworldEntrances);
Checkbox("Save Overworld Exits",
&ExperimentFlags::get().overworld.kSaveOverworldExits);
Checkbox("Save Overworld Items",
&ExperimentFlags::get().overworld.kSaveOverworldItems);
Checkbox("Save Overworld Properties",
&ExperimentFlags::get().overworld.kSaveOverworldProperties);
Checkbox("Load Custom Overworld",
&ExperimentFlags::get().overworld.kLoadCustomOverworld);
}
if (BeginMenu("Dungeon Flags")) {
Checkbox("Draw Dungeon Room Graphics",
&ExperimentFlags::get().kDrawDungeonRoomGraphics);
Separator();
Checkbox("Save Dungeon Maps", &ExperimentFlags::get().kSaveDungeonMaps);
ImGui::EndMenu();
}
void DrawDungeonFlags() {
Checkbox("Draw Dungeon Room Graphics",
&ExperimentFlags::get().kDrawDungeonRoomGraphics);
Separator();
Checkbox("Save Dungeon Maps", &ExperimentFlags::get().kSaveDungeonMaps);
}
Checkbox("Use built-in file dialog",
&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);
void DrawResourceFlags() {
Checkbox("Save All Palettes", &ExperimentFlags::get().kSaveAllPalettes);
Checkbox("Save Gfx Groups", &ExperimentFlags::get().kSaveGfxGroups);
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/gui/style.h"
#include "absl/status/status.h"
#include "app/editor/system/flags.h"
#include "imgui/imgui.h"
@@ -34,6 +35,10 @@ absl::Status SettingsEditor::Update() {
DrawGeneralSettings();
EndTabItem();
}
if (BeginTabItem("Font Manager")) {
gui::DrawFontManager();
EndTabItem();
}
if (BeginTabItem("Keyboard Shortcuts")) {
EndTabItem();
}
@@ -44,28 +49,44 @@ absl::Status SettingsEditor::Update() {
}
void SettingsEditor::DrawGeneralSettings() {
if (BeginTable("##SettingsTable", 2,
static FlagsMenu flags;
if (BeginTable("##SettingsTable", 4,
ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable)) {
TableSetupColumn("Experiment Flags", ImGuiTableColumnFlags_WidthFixed,
250.0f);
TableSetupColumn("General Setting", ImGuiTableColumnFlags_WidthStretch,
TableSetupColumn("System Flags", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Overworld Flags", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Dungeon Flags", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Resource Flags", ImGuiTableColumnFlags_WidthStretch,
0.0f);
TableHeadersRow();
TableNextColumn();
if (BeginChild("##GeneralSettingsStyleWrapper", ImVec2(0, 0),
if (BeginChild("##SystemFlags", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) {
static FlagsMenu flags;
flags.Draw();
flags.DrawSystemFlags();
EndChild();
}
TableNextColumn();
if (BeginChild("##GeneralSettingsWrapper", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) {
Text("TODO: Add some settings here");
if (BeginChild("##OverworldFlags", ImVec2(0, 0),
ImGuiChildFlags_FrameStyle)) {
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();
}

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));
}
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) {
data_ = std::vector<uint8_t>(data.begin(), data.end());
Create(width, height, depth, data_);
@@ -239,19 +246,20 @@ void Bitmap::Create(int width, int height, int depth, int format,
width_ = width;
height_ = height;
depth_ = depth;
data_ = data;
data_size_ = data.size();
if (data_size_ == 0) {
SDL_Log("Data provided to Bitmap is empty.\n");
return;
}
data_.reserve(data_size_);
data_ = data;
pixel_data_ = data_.data();
surface_ = std::shared_ptr<SDL_Surface>{
SDL_CreateRGBSurfaceWithFormat(0, width_, height_, depth_,
GetSnesPixelFormat(format)),
SDL_Surface_Deleter{}};
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;
return;
}
@@ -285,14 +293,15 @@ void Bitmap::CreateTexture(SDL_Renderer *renderer) {
SDL_TEXTUREACCESS_STREAMING, width_, height_),
SDL_Texture_Deleter{}};
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>{
SDL_ConvertSurfaceFormat(surface_.get(), SDL_PIXELFORMAT_ARGB8888, 0),
SDL_Surface_Deleter{}};
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;
}

View File

@@ -46,7 +46,7 @@ enum BitmapFormat {
/**
* @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.
@@ -91,9 +91,11 @@ class Bitmap {
void SaveSurfaceToFile(std::string_view filename);
/**
* @brief Creates a bitmap object with the provided graphical data.
*/
void Initialize(int width, int height, int depth, std::span<uint8_t>& 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,
const std::vector<uint8_t> &data);
@@ -152,7 +154,6 @@ class Bitmap {
auto palette() const { return palette_; }
auto mutable_palette() { return &palette_; }
auto palette_size() const { return palette_.size(); }
int width() const { return width_; }
int height() const { return height_; }
@@ -161,7 +162,6 @@ class Bitmap {
auto data() const { return data_.data(); }
auto &mutable_data() { return data_; }
auto surface() const { return surface_.get(); }
auto mutable_surface() { return surface_.get(); }
auto vector() const { return data_; }
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,
std::vector<gfx::Bitmap> &tile16_individual_,
std::array<gfx::Bitmap, 4096> &tile16_individual_,
int tile_size, float scale) {
if (selected_points_.size() != 2) {
// points_ should contain exactly two points

View File

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

View File

@@ -3,7 +3,7 @@
// for use with https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf
#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_MAX_MD 0x10fffd

View File

@@ -749,5 +749,34 @@ void TextWithSeparators(const absl::string_view &text) {
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 yaze

View File

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

View File

@@ -1,5 +1,6 @@
#include "rom.h"
#include <array>
#include <algorithm>
#include <chrono>
#include <cstddef>
@@ -53,26 +54,27 @@ absl::StatusOr<std::vector<uint8_t>> Load2BppGraphics(const Rom &rom) {
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 uint16_t kLinkGfxLength = 0x800; // 0x4000 or 0x7000?
// Load Links graphics from the ROM
std::array<gfx::Bitmap, kNumLinkSheets> link_graphics;
for (uint32_t i = 0; i < kNumLinkSheets; i++) {
ASSIGN_OR_RETURN(
auto link_sheet_data,
ReadByteVector(/*offset=*/kLinkGfxOffset + (i * kLinkGfxLength),
/*length=*/kLinkGfxLength))
rom.ReadByteVector(/*offset=*/kLinkGfxOffset + (i * kLinkGfxLength),
/*length=*/kLinkGfxLength))
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);
RETURN_IF_ERROR(link_graphics_[i].ApplyPalette(palette_groups_.armors[0]);)
Renderer::GetInstance().RenderBitmap(&link_graphics_[i]);
RETURN_IF_ERROR(link_graphics[i].ApplyPalette(rom.palette_group().armors[0]);)
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;
bool bpp3 = false;
@@ -80,60 +82,60 @@ absl::Status Rom::LoadAllGraphicsData(bool defer_render) {
if (i >= 115 && i <= 126) { // uncompressed sheets
sheet.resize(Uncompressed3BPPSize);
auto offset =
GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1,
version_constants().kOverworldGfxPtr2,
version_constants().kOverworldGfxPtr3);
for (int j = 0; j < Uncompressed3BPPSize; j++) {
sheet[j] = rom_data_[j + offset];
}
GetGraphicsAddress(rom.data(), i, rom.version_constants().kOverworldGfxPtr1,
rom.version_constants().kOverworldGfxPtr2,
rom.version_constants().kOverworldGfxPtr3);
std::copy(rom.data() + offset, rom.data() + offset + Uncompressed3BPPSize,
sheet.begin());
bpp3 = true;
} else if (i == 113 || i == 114 || i >= 218) {
bpp3 = false;
} else {
auto offset =
GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1,
version_constants().kOverworldGfxPtr2,
version_constants().kOverworldGfxPtr3);
GetGraphicsAddress(rom.data(), i, rom.version_constants().kOverworldGfxPtr1,
rom.version_constants().kOverworldGfxPtr2,
rom.version_constants().kOverworldGfxPtr3);
ASSIGN_OR_RETURN(sheet,
gfx::lc_lz2::DecompressV2(rom_data_.data(), offset))
gfx::lc_lz2::DecompressV2(rom.data(), offset))
bpp3 = true;
}
if (bpp3) {
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);
if (graphics_sheets_[i].is_active()) {
if (graphics_sheets[i].is_active()) {
if (i > 115) {
// Apply sprites palette
RETURN_IF_ERROR(graphics_sheets_[i].ApplyPaletteWithTransparent(
palette_groups_.global_sprites[0], 0));
RETURN_IF_ERROR(graphics_sheets[i].ApplyPaletteWithTransparent(
rom.palette_group().global_sprites[0], 0));
} else {
RETURN_IF_ERROR(graphics_sheets_[i].ApplyPaletteWithTransparent(
palette_groups_.dungeon_main[0], 0));
RETURN_IF_ERROR(graphics_sheets[i].ApplyPaletteWithTransparent(
rom.palette_group().dungeon_main[0], 0));
}
}
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) {
graphics_buffer_.push_back(graphics_sheets_[i].at(j));
for (int j = 0; j < graphics_sheets[i].size(); ++j) {
rom.mutable_graphics_buffer()->push_back(graphics_sheets[i].at(j));
}
} else {
for (int j = 0; j < graphics_sheets_[0].size(); ++j) {
graphics_buffer_.push_back(0xFF);
for (int j = 0; j < graphics_sheets[0].size(); ++j) {
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++) {
if (graphics_sheets_[i].is_active()) {
if (gfx_sheets[i].is_active()) {
int to_bpp = 3;
std::vector<uint8_t> final_data;
bool compressed = true;
@@ -145,7 +147,7 @@ absl::Status Rom::SaveAllGraphicsData() {
}
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;
final_data = gfx::Bpp8SnesToIndexed(sheet_data, 8);
int size = 0;
@@ -157,11 +159,10 @@ absl::Status Rom::SaveAllGraphicsData() {
}
}
auto offset =
GetGraphicsAddress(data(), i, version_constants().kOverworldGfxPtr1,
version_constants().kOverworldGfxPtr2,
version_constants().kOverworldGfxPtr3);
std::copy(final_data.begin(), final_data.end(),
rom_data_.begin() + offset);
GetGraphicsAddress(rom.data(), i, rom.version_constants().kOverworldGfxPtr1,
rom.version_constants().kOverworldGfxPtr2,
rom.version_constants().kOverworldGfxPtr3);
std::copy(final_data.begin(), final_data.end(), rom.begin() + offset);
}
}
return absl::OkStatus();
@@ -230,6 +231,17 @@ absl::Status Rom::LoadFromPointer(uchar *data, size_t length, bool z3_load) {
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() {
// Check if the ROM has a header
constexpr size_t kBaseRomSize = 1048576; // 1MB
@@ -266,17 +278,6 @@ absl::Status Rom::LoadZelda3() {
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 non_firing_status;
if (rom_data_.empty()) {
@@ -319,8 +320,6 @@ absl::Status Rom::SaveToFile(bool backup, bool save_new, std::string filename) {
RETURN_IF_ERROR(SaveAllPalettes());
if (core::ExperimentFlags::get().kSaveGfxGroups)
RETURN_IF_ERROR(SaveGroupsToRom());
if (core::ExperimentFlags::get().kSaveGraphicsSheet)
RETURN_IF_ERROR(SaveAllGraphicsData());
if (save_new) {
// 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"
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.
*/
@@ -111,53 +129,12 @@ static const std::map<Z3_Version, VersionConstants> kVersionConstantsMap = {
{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.
*/
class Rom {
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.
*
@@ -181,8 +158,6 @@ class Rom {
absl::Status SaveToFile(bool backup, bool save_new = false,
std::string filename = "");
absl::Status SaveAllGraphicsData();
/**
* 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.
*/
absl::Status ReadWritePreconditions() {
absl::Status ReadWritePreconditions() const {
if (!is_loaded_) {
return absl::FailedPreconditionError("ROM file not loaded");
}
@@ -233,7 +208,6 @@ class Rom {
return absl::OkStatus();
}
// Read functions
absl::StatusOr<uint8_t> ReadByte(int offset) {
RETURN_IF_ERROR(ReadWritePreconditions());
if (offset >= static_cast<int>(rom_data_.size())) {
@@ -251,10 +225,6 @@ class Rom {
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) {
RETURN_IF_ERROR(ReadWritePreconditions());
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,
uint32_t length) {
uint32_t length) const {
RETURN_IF_ERROR(ReadWritePreconditions());
if (offset + length > static_cast<uint32_t>(rom_data_.size())) {
return absl::OutOfRangeError("Offset and length out of range");
@@ -281,7 +251,7 @@ class Rom {
absl::StatusOr<gfx::Tile16> ReadTile16(uint32_t tile16_id) {
// Skip 8 bytes per tile.
auto tpos = kTile16Ptr + (tile16_id * 0x08);
gfx::Tile16 tile16;
gfx::Tile16 tile16 = {};
ASSIGN_OR_RETURN(auto new_tile0, ReadWord(tpos))
tile16.tile0_ = gfx::WordToTileInfo(new_tile0);
tpos += 2;
@@ -309,17 +279,6 @@ class Rom {
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) {
RETURN_IF_ERROR(ReadWritePreconditions());
if (addr >= static_cast<int>(rom_data_.size())) {
@@ -419,9 +378,7 @@ class Rom {
uint8_t& operator[](unsigned long i) {
if (i > size_) {
std::cout << "ROM: Index " << i << " out of bounds, size: " << size_
<< std::endl;
return rom_data_[0];
throw std::out_of_range("Rom index out of range");
}
return rom_data_[i];
}
@@ -434,14 +391,10 @@ class Rom {
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 size() const { return size_; }
auto data() const { return rom_data_.data(); }
auto mutable_data() { return rom_data_.data(); }
auto begin() { return rom_data_.begin(); }
auto end() { return rom_data_.end(); }
@@ -450,12 +403,9 @@ class Rom {
auto filename() const { return filename_; }
auto set_filename(std::string name) { filename_ = name; }
auto link_graphics() { return link_graphics_; }
auto mutable_link_graphics() { return &link_graphics_; }
auto gfx_sheets() { return graphics_sheets_; }
auto mutable_gfx_sheets() { return &graphics_sheets_; }
auto palette_group() { return palette_groups_; }
std::vector<uint8_t> graphics_buffer() const { return graphics_buffer_; }
auto mutable_graphics_buffer() { return &graphics_buffer_; }
auto palette_group() const { return palette_groups_; }
auto mutable_palette_group() { return &palette_groups_; }
auto dungeon_palette(int i) { return palette_groups_.dungeon_main[i]; }
auto mutable_dungeon_palette(int i) {
@@ -482,7 +432,7 @@ class Rom {
private:
virtual absl::Status WriteHelper(const WriteAction& action) {
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) ||
std::holds_alternative<short>(action.value)) {
return WriteShort(action.address, std::get<uint16_t>(action.value));
@@ -538,12 +488,6 @@ class Rom {
// Full contiguous graphics space
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.
ResourceLabelManager resource_label_manager_;
@@ -554,6 +498,44 @@ class Rom {
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.
*
@@ -564,6 +546,11 @@ class 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.
*/

View File

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

View File

@@ -102,7 +102,7 @@ void DungeonObjectRenderer::UpdateObjectBitmap() {
int x = column * 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
sheet.Get8x8Tile(tile_id, x, y, tilemap_, tilemap_offset);

View File

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

View File

@@ -220,37 +220,37 @@ class RoomEntrance {
RETURN_IF_ERROR(rom.WriteShort(
kEntranceCameraYTrigger + (entrance_id * 2), camera_trigger_y_));
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)));
RETURN_IF_ERROR(
rom.Write(kEntranceMusic + entrance_id, (uint8_t)(music_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntranceDungeon + entrance_id,
rom.WriteByte(kEntranceMusic + entrance_id, (uint8_t)(music_ & 0xFF)));
RETURN_IF_ERROR(rom.WriteByte(kEntranceDungeon + entrance_id,
(uint8_t)(dungeon_id_ & 0xFF)));
RETURN_IF_ERROR(
rom.Write(kEntranceDoor + entrance_id, (uint8_t)(door_ & 0xFF)));
rom.WriteByte(kEntranceDoor + entrance_id, (uint8_t)(door_ & 0xFF)));
RETURN_IF_ERROR(
rom.Write(kEntranceFloor + entrance_id, (uint8_t)(floor_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kEntranceLadderBG + entrance_id,
rom.WriteByte(kEntranceFloor + entrance_id, (uint8_t)(floor_ & 0xFF)));
RETURN_IF_ERROR(rom.WriteByte(kEntranceLadderBG + entrance_id,
(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)));
RETURN_IF_ERROR(rom.Write(kEntranceScrollQuadrant + entrance_id,
RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollQuadrant + entrance_id,
(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_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 1 + (entrance_id * 8),
RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 1 + (entrance_id * 8),
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_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 3 + (entrance_id * 8),
RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 3 + (entrance_id * 8),
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_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 5 + (entrance_id * 8),
RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 5 + (entrance_id * 8),
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_));
RETURN_IF_ERROR(rom.Write(kEntranceScrollEdge + 7 + (entrance_id * 8),
RETURN_IF_ERROR(rom.WriteByte(kEntranceScrollEdge + 7 + (entrance_id * 8),
camera_boundary_fe_));
} else {
RETURN_IF_ERROR(
@@ -271,45 +271,45 @@ class RoomEntrance {
camera_trigger_y_));
RETURN_IF_ERROR(
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)));
RETURN_IF_ERROR(rom.Write(kStartingEntrancemusic + entrance_id,
RETURN_IF_ERROR(rom.WriteByte(kStartingEntrancemusic + entrance_id,
(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)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceDoor + entrance_id,
RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceDoor + entrance_id,
(uint8_t)(door_ & 0xFF)));
RETURN_IF_ERROR(rom.Write(kStartingEntranceFloor + entrance_id,
RETURN_IF_ERROR(rom.WriteByte(kStartingEntranceFloor + entrance_id,
(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)));
RETURN_IF_ERROR(rom.Write(kStartingEntrancescrolling + entrance_id,
RETURN_IF_ERROR(rom.WriteByte(kStartingEntrancescrolling + entrance_id,
(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)));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 0 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 0 + (entrance_id * 8),
camera_boundary_qn_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 1 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 1 + (entrance_id * 8),
camera_boundary_fn_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 2 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 2 + (entrance_id * 8),
camera_boundary_qs_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 3 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 3 + (entrance_id * 8),
camera_boundary_fs_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 4 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 4 + (entrance_id * 8),
camera_boundary_qw_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 5 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 5 + (entrance_id * 8),
camera_boundary_fw_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 6 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 6 + (entrance_id * 8),
camera_boundary_qe_));
RETURN_IF_ERROR(
rom.Write(kStartingEntranceScrollEdge + 7 + (entrance_id * 8),
rom.WriteByte(kStartingEntranceScrollEdge + 7 + (entrance_id * 8),
camera_boundary_fe_));
}
return absl::OkStatus();

View File

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

View File

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

View File

@@ -17,10 +17,14 @@ absl::Status Inventory::Create() {
}
RETURN_IF_ERROR(BuildTileset())
for (int i = 0; i < 0x500; i += 0x08) {
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos)));
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos + 0x02)));
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos + 0x04)));
tiles_.push_back(gfx::GetTilesInfo(rom()->toint16(i + kBowItemPos + 0x08)));
ASSIGN_OR_RETURN(auto t1, rom()->ReadWord(i + kBowItemPos));
ASSIGN_OR_RETURN(auto t2, rom()->ReadWord(i + kBowItemPos + 0x02));
ASSIGN_OR_RETURN(auto t3, rom()->ReadWord(i + kBowItemPos + 0x04));
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};
auto xx = 0;

View File

@@ -279,7 +279,7 @@ static const std::string kSpriteDefaultNames[]{
class Sprite : public GameEntity {
public:
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)
: map_id_(static_cast<int>(overworld_map_id)),
id_(id),