Add OverworldMap tile editing
This commit is contained in:
@@ -83,11 +83,11 @@ void ButtonPipe(absl::string_view button_text, std::function<void()> callback) {
|
||||
}
|
||||
}
|
||||
|
||||
void BitmapCanvasPipeline(int width, int height, int tile_size, bool is_loaded,
|
||||
gfx::Bitmap& bitmap, bool scrollbar, int canvas_id) {
|
||||
gui::Canvas canvas;
|
||||
|
||||
auto draw_canvas = [&]() {
|
||||
void BitmapCanvasPipeline(gui::Canvas& canvas, gfx::Bitmap& bitmap, int width,
|
||||
int height, int tile_size, bool is_loaded,
|
||||
bool scrollbar, int canvas_id) {
|
||||
auto draw_canvas = [](gui::Canvas& canvas, gfx::Bitmap& bitmap, int width,
|
||||
int height, int tile_size, bool is_loaded) {
|
||||
canvas.DrawBackground(ImVec2(width + 1, height + 1));
|
||||
canvas.DrawContextMenu();
|
||||
canvas.DrawBitmap(bitmap, 2, is_loaded);
|
||||
@@ -100,11 +100,11 @@ void BitmapCanvasPipeline(int width, int height, int tile_size, bool is_loaded,
|
||||
if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)canvas_id);
|
||||
ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
draw_canvas();
|
||||
draw_canvas(canvas, bitmap, width, height, tile_size, is_loaded);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
} else {
|
||||
draw_canvas();
|
||||
draw_canvas(canvas, bitmap, width, height, tile_size, is_loaded);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "app/core/constants.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
@@ -28,8 +29,9 @@ void GraphicsBinCanvasPipeline(int width, int height, int tile_size,
|
||||
|
||||
void ButtonPipe(absl::string_view button_text, std::function<void()> callback);
|
||||
|
||||
void BitmapCanvasPipeline(int width, int height, int tile_size, bool is_loaded,
|
||||
gfx::Bitmap& bitmap, bool scrollbar, int canvas_id);
|
||||
void BitmapCanvasPipeline(gui::Canvas& canvas, gfx::Bitmap& bitmap, int width,
|
||||
int height, int tile_size, bool is_loaded,
|
||||
bool scrollbar, int canvas_id);
|
||||
|
||||
void BuildAndRenderBitmapPipeline(int width, int height, int depth, Bytes data,
|
||||
ROM& z3_rom, gfx::Bitmap& bitmap,
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "app/gui/style.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
//
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
@@ -33,25 +35,24 @@ absl::Status GraphicsEditor::Update() {
|
||||
}
|
||||
|
||||
BEGIN_TABLE("#gfxEditTable", 4, kGfxEditFlags)
|
||||
SETUP_COLUMN("Graphics (BIN, CGX, SCR)")
|
||||
SETUP_COLUMN("File Import (BIN, CGX, ROM)")
|
||||
SETUP_COLUMN("Palette (COL)")
|
||||
ImGui::TableSetupColumn("Maps and Animations (SCR, PNL)",
|
||||
ImGui::TableSetupColumn("Tilemaps and Objects (SCR, PNL, OBJ)",
|
||||
ImGuiTableColumnFlags_WidthFixed);
|
||||
SETUP_COLUMN("Preview")
|
||||
SETUP_COLUMN("Graphics Preview")
|
||||
TABLE_HEADERS()
|
||||
NEXT_COLUMN()
|
||||
NEXT_COLUMN() {
|
||||
status_ = DrawCgxImport();
|
||||
status_ = DrawClipboardImport();
|
||||
status_ = DrawFileImport();
|
||||
status_ = DrawExperimentalFeatures();
|
||||
}
|
||||
|
||||
status_ = DrawCgxImport();
|
||||
status_ = DrawClipboardImport();
|
||||
status_ = DrawFileImport();
|
||||
status_ = DrawExperimentalFeatures();
|
||||
NEXT_COLUMN() { status_ = DrawPaletteControls(); }
|
||||
|
||||
NEXT_COLUMN()
|
||||
status_ = DrawPaletteControls();
|
||||
|
||||
NEXT_COLUMN()
|
||||
core::BitmapCanvasPipeline(0x200, 0x200, 0x20, scr_loaded_, scr_bitmap_,
|
||||
false, 0);
|
||||
core::BitmapCanvasPipeline(scr_canvas_, scr_bitmap_, 0x200, 0x200, 0x20,
|
||||
scr_loaded_, false, 0);
|
||||
status_ = DrawScrImport();
|
||||
|
||||
NEXT_COLUMN()
|
||||
@@ -69,12 +70,12 @@ absl::Status GraphicsEditor::Update() {
|
||||
super_donkey_, graphics_bin_);
|
||||
} else if (cgx_loaded_ && col_file_) {
|
||||
// Load the CGX graphics
|
||||
core::BitmapCanvasPipeline(0x100, 16384, 0x20, cgx_loaded_, cgx_bitmap_,
|
||||
true, 5);
|
||||
core::BitmapCanvasPipeline(import_canvas_, cgx_bitmap_, 0x100, 16384, 0x20,
|
||||
cgx_loaded_, true, 5);
|
||||
} else {
|
||||
// Load the BIN/Clipboard Graphics
|
||||
core::BitmapCanvasPipeline(0x100, 16384, 0x20, gfx_loaded_, bitmap_, true,
|
||||
2);
|
||||
core::BitmapCanvasPipeline(import_canvas_, bitmap_, 0x100, 16384, 0x20,
|
||||
gfx_loaded_, true, 2);
|
||||
}
|
||||
END_TABLE()
|
||||
|
||||
@@ -124,7 +125,7 @@ absl::Status GraphicsEditor::DrawCgxImport() {
|
||||
core::ButtonPipe("Copy CGX Path",
|
||||
[this]() { ImGui::SetClipboardText(cgx_file_path_); });
|
||||
|
||||
core::ButtonPipe("Decompress CGX Data", [this]() {
|
||||
core::ButtonPipe("Load CGX Data", [this]() {
|
||||
status_ = gfx::LoadCgx(current_bpp_, cgx_file_path_, cgx_data_,
|
||||
decoded_cgx_, extra_cgx_data_);
|
||||
cgx_bitmap_.Create(0x80, 0x200, 8, decoded_cgx_);
|
||||
@@ -217,6 +218,49 @@ absl::Status GraphicsEditor::DrawPaletteControls() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::DrawObjImport() {
|
||||
gui::TextWithSeparators("OBJ Import");
|
||||
|
||||
ImGui::InputText("##ObjFile", obj_file_path_, sizeof(obj_file_path_));
|
||||
ImGui::SameLine();
|
||||
|
||||
core::FileDialogPipeline(
|
||||
"ImportObjKey", ".obj,.OBJ,.bak,.BAK\0", "Open OBJ", [this]() {
|
||||
strncpy(file_path_,
|
||||
ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
|
||||
sizeof(file_path_));
|
||||
status_ = temp_rom_.LoadFromFile(file_path_);
|
||||
is_open_ = true;
|
||||
});
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::DrawTilemapImport() {
|
||||
gui::TextWithSeparators("Tilemap Import");
|
||||
|
||||
ImGui::InputText("##TMapFile", tilemap_file_path_,
|
||||
sizeof(tilemap_file_path_));
|
||||
ImGui::SameLine();
|
||||
|
||||
core::FileDialogPipeline(
|
||||
"ImportTilemapKey", ".DAT,.dat,.BIN,.bin,.hex,.HEX\0", "Open Tilemap",
|
||||
[this]() {
|
||||
strncpy(tilemap_file_path_,
|
||||
ImGuiFileDialog::Instance()->GetFilePathName().c_str(),
|
||||
sizeof(tilemap_file_path_));
|
||||
status_ = tilemap_rom_.LoadFromFile(tilemap_file_path_);
|
||||
|
||||
// Extract the high and low bytes from the file.
|
||||
auto decomp_sheet = gfx::lc_lz2::DecompressV2(
|
||||
tilemap_rom_.data(), gfx::lc_lz2::kNintendoMode1);
|
||||
tilemap_loaded_ = true;
|
||||
is_open_ = true;
|
||||
});
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GraphicsEditor::DrawFileImport() {
|
||||
gui::TextWithSeparators("BIN Import");
|
||||
|
||||
@@ -290,8 +334,7 @@ absl::Status GraphicsEditor::DrawExperimentalFeatures() {
|
||||
}
|
||||
ImGui::SetItemTooltip(
|
||||
"Requires `super_donkey_1.bin` to be imported under the "
|
||||
"BIN import "
|
||||
"section.");
|
||||
"BIN import section.");
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
@@ -314,11 +357,11 @@ absl::Status GraphicsEditor::DecompressImportData(int size) {
|
||||
|
||||
if (rom()->isLoaded()) {
|
||||
auto palette_group = rom()->GetPaletteGroup("ow_main");
|
||||
palette_ = palette_group[current_palette_];
|
||||
z3_rom_palette_ = palette_group[current_palette_];
|
||||
if (col_file_) {
|
||||
bitmap_.ApplyPalette(col_file_palette_);
|
||||
} else {
|
||||
bitmap_.ApplyPalette(palette_);
|
||||
bitmap_.ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,8 +390,8 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
// ROM palette
|
||||
auto palette_group =
|
||||
rom()->GetPaletteGroup(kPaletteGroupAddressesKeys[current_palette_]);
|
||||
palette_ = palette_group[current_palette_index_];
|
||||
graphics_bin_[i].ApplyPalette(palette_);
|
||||
z3_rom_palette_ = palette_group[current_palette_index_];
|
||||
graphics_bin_[i].ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
|
||||
rom()->RenderBitmap(&graphics_bin_[i]);
|
||||
@@ -372,8 +415,8 @@ absl::Status GraphicsEditor::DecompressSuperDonkey() {
|
||||
// ROM palette
|
||||
auto palette_group =
|
||||
rom()->GetPaletteGroup(kPaletteGroupAddressesKeys[current_palette_]);
|
||||
palette_ = palette_group[current_palette_index_];
|
||||
graphics_bin_[i].ApplyPalette(palette_);
|
||||
z3_rom_palette_ = palette_group[current_palette_index_];
|
||||
graphics_bin_[i].ApplyPalette(z3_rom_palette_);
|
||||
}
|
||||
|
||||
rom()->RenderBitmap(&graphics_bin_[i]);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
@@ -65,9 +66,13 @@ class GraphicsEditor : public SharedROM {
|
||||
|
||||
private:
|
||||
absl::Status DrawToolset();
|
||||
|
||||
absl::Status DrawCgxImport();
|
||||
absl::Status DrawScrImport();
|
||||
absl::Status DrawFileImport();
|
||||
absl::Status DrawObjImport();
|
||||
absl::Status DrawTilemapImport();
|
||||
|
||||
absl::Status DrawPaletteControls();
|
||||
absl::Status DrawClipboardImport();
|
||||
absl::Status DrawExperimentalFeatures();
|
||||
@@ -77,9 +82,9 @@ class GraphicsEditor : public SharedROM {
|
||||
|
||||
absl::Status DecompressSuperDonkey();
|
||||
|
||||
int current_palette_ = 0;
|
||||
uint64_t current_offset_ = 0;
|
||||
uint64_t current_size_ = 0;
|
||||
int current_palette_ = 0;
|
||||
uint64_t current_palette_index_ = 0;
|
||||
|
||||
int current_bpp_ = 0;
|
||||
@@ -95,12 +100,17 @@ class GraphicsEditor : public SharedROM {
|
||||
|
||||
bool refresh_graphics_ = false;
|
||||
bool open_memory_editor_ = false;
|
||||
|
||||
bool gfx_loaded_ = false;
|
||||
bool is_open_ = false;
|
||||
bool super_donkey_ = false;
|
||||
|
||||
bool col_file_ = false;
|
||||
bool cgx_loaded_ = false;
|
||||
bool scr_loaded_ = false;
|
||||
bool obj_loaded_ = false;
|
||||
|
||||
bool tilemap_loaded_ = false;
|
||||
|
||||
char file_path_[256] = "";
|
||||
char col_file_path_[256] = "";
|
||||
@@ -112,7 +122,14 @@ class GraphicsEditor : public SharedROM {
|
||||
char scr_file_path_[256] = "";
|
||||
char scr_file_name_[256] = "";
|
||||
|
||||
char obj_file_path_[256] = "";
|
||||
|
||||
char tilemap_file_path_[256] = "";
|
||||
char tilemap_file_name_[256] = "";
|
||||
|
||||
ROM temp_rom_;
|
||||
ROM tilemap_rom_;
|
||||
|
||||
Bytes import_data_;
|
||||
Bytes graphics_buffer_;
|
||||
|
||||
@@ -124,6 +141,8 @@ class GraphicsEditor : public SharedROM {
|
||||
std::vector<uint8_t> scr_data_;
|
||||
std::vector<uint8_t> decoded_scr_data_;
|
||||
|
||||
zelda3::Overworld overworld_;
|
||||
|
||||
MemoryEditor cgx_memory_editor_;
|
||||
MemoryEditor col_memory_editor_;
|
||||
|
||||
@@ -135,6 +154,8 @@ class GraphicsEditor : public SharedROM {
|
||||
gfx::Bitmap bitmap_;
|
||||
gui::Canvas import_canvas_;
|
||||
|
||||
gui::Canvas scr_canvas_;
|
||||
|
||||
gui::Canvas super_donkey_canvas_;
|
||||
gfx::BitmapTable graphics_bin_;
|
||||
|
||||
@@ -142,7 +163,7 @@ class GraphicsEditor : public SharedROM {
|
||||
|
||||
gfx::PaletteGroup col_file_palette_group_;
|
||||
|
||||
gfx::SNESPalette palette_;
|
||||
gfx::SNESPalette z3_rom_palette_;
|
||||
gfx::SNESPalette col_file_palette_;
|
||||
|
||||
absl::Status status_;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/gui/input.h"
|
||||
#include "app/gui/style.h"
|
||||
#include "app/gui/widgets.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld.h"
|
||||
|
||||
@@ -194,14 +195,68 @@ void OverworldEditor::DrawOverworldSprites() {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void OverworldEditor::DrawOverworldEdits() const {
|
||||
void OverworldEditor::DrawOverworldEdits() {
|
||||
auto mouse_position = ow_map_canvas_.GetCurrentDrawnTilePosition();
|
||||
auto canvas_size = ow_map_canvas_.GetCanvasSize();
|
||||
int x = mouse_position.x / canvas_size.x;
|
||||
int y = mouse_position.y / canvas_size.y;
|
||||
auto index = x + (y * 64);
|
||||
|
||||
std::cout << "==> " << index << std::endl;
|
||||
// Determine which overworld map the user is currently editing.
|
||||
DetermineActiveMap(mouse_position);
|
||||
|
||||
// Render the updated map bitmap.
|
||||
RenderUpdatedMapBitmap(mouse_position,
|
||||
tile16_individual_data_[current_tile16_]);
|
||||
|
||||
// Queue up the raw ROM changes.
|
||||
QueueROMChanges(index, current_tile16_);
|
||||
}
|
||||
|
||||
void OverworldEditor::RenderUpdatedMapBitmap(const ImVec2 &click_position,
|
||||
const Bytes &tile_data) {
|
||||
// Calculate the tile position relative to the current active map
|
||||
constexpr int tile_size = 16; // Tile size is 16x16 pixels
|
||||
|
||||
// Calculate the tile index for x and y based on the click_position
|
||||
int tile_index_x = static_cast<int>(click_position.x) / tile_size;
|
||||
int tile_index_y = static_cast<int>(click_position.y) / tile_size;
|
||||
|
||||
// Calculate the pixel start position based on tile index and tile size
|
||||
ImVec2 start_position;
|
||||
start_position.x = tile_index_x * tile_size;
|
||||
start_position.y = tile_index_y * tile_size;
|
||||
|
||||
// Get the current map's bitmap from the BitmapTable
|
||||
gfx::Bitmap ¤t_bitmap = maps_bmp_[current_map_];
|
||||
|
||||
// Update the bitmap's pixel data based on the start_position and tile_data
|
||||
for (int y = 0; y < tile_size; ++y) {
|
||||
for (int x = 0; x < tile_size; ++x) {
|
||||
int pixel_index = (start_position.y + y) * current_bitmap.width() +
|
||||
(start_position.x + x);
|
||||
current_bitmap.WriteToPixel(pixel_index, tile_data[y * tile_size + x]);
|
||||
}
|
||||
}
|
||||
|
||||
// Render the updated bitmap to the canvas
|
||||
rom()->RenderBitmap(¤t_bitmap);
|
||||
}
|
||||
|
||||
void OverworldEditor::QueueROMChanges(int index, ushort new_tile16) {
|
||||
// Store the changes made by the user to the ROM (or project file)
|
||||
}
|
||||
|
||||
void OverworldEditor::DetermineActiveMap(const ImVec2 &mouse_position) {
|
||||
// Assuming each small map is 256x256 pixels (adjust as needed)
|
||||
constexpr int small_map_size = 512;
|
||||
|
||||
// Calculate which small map the mouse is currently over
|
||||
int map_x = mouse_position.x / small_map_size;
|
||||
int map_y = mouse_position.y / small_map_size;
|
||||
|
||||
// Calculate the index of the map in the `maps_bmp_` vector
|
||||
current_map_ = map_x + map_y * 8;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -225,8 +280,7 @@ void OverworldEditor::DrawOverworldCanvas() {
|
||||
if (!blockset_canvas_.Points().empty()) {
|
||||
int x = blockset_canvas_.Points().front().x / 32;
|
||||
int y = blockset_canvas_.Points().front().y / 32;
|
||||
current_tile16_ = x + (y * 0x10);
|
||||
|
||||
current_tile16_ = x + (y * 8);
|
||||
if (ow_map_canvas_.DrawTilePainter(tile16_individual_[current_tile16_],
|
||||
16)) {
|
||||
// Update the overworld map.
|
||||
@@ -272,8 +326,9 @@ void OverworldEditor::DrawTileSelector() {
|
||||
if (ImGui::BeginTabBar(kTileSelectorTab.data(),
|
||||
ImGuiTabBarFlags_FittingPolicyScroll)) {
|
||||
if (ImGui::BeginTabItem("Tile16")) {
|
||||
core::BitmapCanvasPipeline(0x100, (8192 * 2), 0x20, map_blockset_loaded_,
|
||||
tile16_blockset_bmp_, true, 1);
|
||||
core::BitmapCanvasPipeline(blockset_canvas_, tile16_blockset_bmp_, 0x100,
|
||||
(8192 * 2), 0x20, map_blockset_loaded_, true,
|
||||
1);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Tile8")) {
|
||||
@@ -286,8 +341,9 @@ void OverworldEditor::DrawTileSelector() {
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Area Graphics")) {
|
||||
core::BitmapCanvasPipeline(256, 0x10 * 0x40, 0x20, overworld_.isLoaded(),
|
||||
current_gfx_bmp_, true, 3);
|
||||
core::BitmapCanvasPipeline(current_gfx_canvas_, current_gfx_bmp_, 256,
|
||||
0x10 * 0x40, 0x20, overworld_.isLoaded(), true,
|
||||
3);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
@@ -319,17 +375,19 @@ absl::Status OverworldEditor::LoadGraphics() {
|
||||
// Copy the tile16 data into individual tiles.
|
||||
auto tile16_data = overworld_.Tile16Blockset();
|
||||
|
||||
std::cout << tile16_data.size() << std::endl;
|
||||
|
||||
// Loop through the tiles and copy their pixel data into separate vectors
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
// Create a new vector for the pixel data of the current tile
|
||||
Bytes tile_data;
|
||||
for (int j = 0; j < 16 * 16; j++) tile_data.push_back(0x00);
|
||||
Bytes tile_data(16 * 16, 0x00); // More efficient initialization
|
||||
|
||||
// Copy the pixel data for the current tile into the vector
|
||||
for (int ty = 0; ty < 16; ty++) {
|
||||
for (int tx = 0; tx < 16; tx++) {
|
||||
int position = (tx + (ty * 0x10));
|
||||
uchar value = tile16_data[i + tx + (ty * 0x80)];
|
||||
int position = tx + (ty * 0x10);
|
||||
uchar value =
|
||||
tile16_data[(i % 8 * 16) + (i / 8 * 16 * 0x80) + (ty * 0x80) + tx];
|
||||
tile_data[position] = value;
|
||||
}
|
||||
}
|
||||
@@ -389,20 +447,25 @@ absl::Status OverworldEditor::DrawExperimentalModal() {
|
||||
ImGui::InputText("##TilemapFile", &ow_tilemap_filename_);
|
||||
ImGui::SameLine();
|
||||
core::FileDialogPipeline(
|
||||
"ImportTilemapsKey", ".CGX,.cgx\0", "Tilemap Hex File", [this]() {
|
||||
"ImportTilemapsKey", ".DAT,.dat\0", "Tilemap Hex File", [this]() {
|
||||
ow_tilemap_filename_ = ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
});
|
||||
|
||||
ImGui::InputText("##Tile32ConfigurationFile",
|
||||
&tile32_configuration_filename_);
|
||||
ImGui::SameLine();
|
||||
core::FileDialogPipeline("ImportTile32Key", ".CGX,.cgx\0", "Tile32 Hex File",
|
||||
core::FileDialogPipeline("ImportTile32Key", ".DAT,.dat\0", "Tile32 Hex File",
|
||||
[this]() {
|
||||
tile32_configuration_filename_ =
|
||||
ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
});
|
||||
|
||||
ImGui::Button("Load Prototype Overworld with ROM graphics");
|
||||
if (ImGui::Button("Load Prototype Overworld with ROM graphics")) {
|
||||
if (rom()->isLoaded() && !all_gfx_loaded_) {
|
||||
RETURN_IF_ERROR(LoadGraphics())
|
||||
all_gfx_loaded_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
gui::TextWithSeparators("Configuration");
|
||||
|
||||
|
||||
@@ -70,7 +70,13 @@ class OverworldEditor : public Editor, public SharedROM {
|
||||
void DrawOverworldEntrances();
|
||||
void DrawOverworldMaps();
|
||||
void DrawOverworldSprites();
|
||||
void DrawOverworldEdits() const;
|
||||
|
||||
void DrawOverworldEdits();
|
||||
void RenderUpdatedMapBitmap(const ImVec2 &click_position,
|
||||
const Bytes &tile_data);
|
||||
void QueueROMChanges(int index, ushort new_tile16);
|
||||
void DetermineActiveMap(const ImVec2 &mouse_position);
|
||||
|
||||
void DrawOverworldCanvas();
|
||||
|
||||
void DrawTile8Selector();
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <stack>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gui/canvas.h"
|
||||
#include "app/gui/icons.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace editor {
|
||||
@@ -33,6 +30,49 @@ struct PaletteChange {
|
||||
size_t paletteIndex;
|
||||
size_t colorIndex;
|
||||
gfx::SNESColor originalColor;
|
||||
gfx::SNESColor newColor;
|
||||
};
|
||||
|
||||
class PaletteEditorHistory {
|
||||
public:
|
||||
// Record a change in the palette editor
|
||||
void RecordChange(const std::string& groupName, size_t paletteIndex,
|
||||
size_t colorIndex, const gfx::SNESColor& originalColor,
|
||||
const gfx::SNESColor& newColor) {
|
||||
// Check size and remove the oldest if necessary
|
||||
if (recentChanges.size() >= maxHistorySize) {
|
||||
recentChanges.pop_front();
|
||||
}
|
||||
|
||||
// Push the new change
|
||||
recentChanges.push_back(
|
||||
{groupName, paletteIndex, colorIndex, originalColor, newColor});
|
||||
}
|
||||
|
||||
// Get recent changes for display in the palette editor
|
||||
const std::deque<PaletteChange>& GetRecentChanges() const {
|
||||
return recentChanges;
|
||||
}
|
||||
|
||||
// Restore the original color
|
||||
gfx::SNESColor GetOriginalColor(const std::string& groupName,
|
||||
size_t paletteIndex,
|
||||
size_t colorIndex) const {
|
||||
for (const auto& change : recentChanges) {
|
||||
if (change.groupName == groupName &&
|
||||
change.paletteIndex == paletteIndex &&
|
||||
change.colorIndex == colorIndex) {
|
||||
return change.originalColor;
|
||||
}
|
||||
}
|
||||
// Handle error or return default (this is just an example,
|
||||
// handle as appropriate for your application)
|
||||
return gfx::SNESColor();
|
||||
}
|
||||
|
||||
private:
|
||||
std::deque<PaletteChange> recentChanges;
|
||||
static const size_t maxHistorySize = 50; // or any other number you deem fit
|
||||
};
|
||||
|
||||
class PaletteEditor : public SharedROM {
|
||||
@@ -42,7 +82,6 @@ class PaletteEditor : public SharedROM {
|
||||
void EditColorInPalette(gfx::SNESPalette& palette, int index);
|
||||
void ResetColorToOriginal(gfx::SNESPalette& palette, int index,
|
||||
const gfx::SNESPalette& originalPalette);
|
||||
|
||||
void DisplayPalette(gfx::SNESPalette& palette, bool loaded);
|
||||
|
||||
void DrawPortablePalette(gfx::SNESPalette& palette);
|
||||
@@ -60,7 +99,7 @@ class PaletteEditor : public SharedROM {
|
||||
}
|
||||
}
|
||||
|
||||
std::stack<PaletteChange> changeHistory;
|
||||
PaletteEditorHistory history_;
|
||||
|
||||
ImVec4 saved_palette_[256] = {};
|
||||
ImVec4 current_color_;
|
||||
|
||||
@@ -704,6 +704,11 @@ absl::StatusOr<Bytes> DecompressOverworld(const uchar* data, int pos,
|
||||
return DecompressV2(data, pos, size, kNintendoMode1);
|
||||
}
|
||||
|
||||
absl::StatusOr<Bytes> DecompressOverworld(const std::vector<uint8_t> data,
|
||||
int pos, int size) {
|
||||
return DecompressV2(data.data(), pos, size, kNintendoMode1);
|
||||
}
|
||||
|
||||
} // namespace lc_lz2
|
||||
} // namespace gfx
|
||||
} // namespace app
|
||||
|
||||
@@ -107,6 +107,7 @@ absl::StatusOr<Bytes> DecompressV2(const uchar* data, int offset,
|
||||
int size = 0x800, int mode = 1);
|
||||
absl::StatusOr<Bytes> DecompressGraphics(const uchar* data, int pos, int size);
|
||||
absl::StatusOr<Bytes> DecompressOverworld(const uchar* data, int pos, int size);
|
||||
absl::StatusOr<Bytes> DecompressOverworld(const std::vector<uint8_t> data, int pos, int size);
|
||||
|
||||
// Compression V1
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
|
||||
namespace gui {
|
||||
|
||||
constexpr uint32_t kRectangleColor = IM_COL32(32, 32, 32, 255);
|
||||
@@ -209,4 +211,5 @@ void Canvas::DrawOverlay() {
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gui {
|
||||
|
||||
using app::gfx::Bitmap;
|
||||
@@ -83,6 +84,7 @@ class Canvas {
|
||||
};
|
||||
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "app/gfx/snes_palette.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
|
||||
namespace gui {
|
||||
|
||||
void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded) {
|
||||
@@ -83,4 +85,5 @@ void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded) {
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -10,11 +10,14 @@
|
||||
#include "app/gfx/snes_palette.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
|
||||
namespace gui {
|
||||
|
||||
void DisplayPalette(app::gfx::SNESPalette& palette, bool loaded);
|
||||
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gui {
|
||||
|
||||
const int kStepOneHex = 0x01;
|
||||
@@ -67,4 +68,5 @@ void ItemLabel(absl::string_view title, ItemLabelFlags flags) {
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
} // namespace yaze
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gui {
|
||||
|
||||
constexpr ImVec2 kDefaultModalSize = ImVec2(200, 0);
|
||||
@@ -27,6 +28,7 @@ using ItemLabelFlags = enum ItemLabelFlag {
|
||||
IMGUI_API void ItemLabel(absl::string_view title, ItemLabelFlags flags);
|
||||
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "imgui/imgui_internal.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
|
||||
namespace gui {
|
||||
|
||||
void TextWithSeparators(const absl::string_view &text) {
|
||||
@@ -111,4 +113,5 @@ void ColorsYaze() {
|
||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
|
||||
}
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gui {
|
||||
|
||||
void TextWithSeparators(const absl::string_view& text);
|
||||
@@ -14,6 +15,7 @@ void TextWithSeparators(const absl::string_view& text);
|
||||
void ColorsYaze();
|
||||
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "app/core/constants.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
|
||||
@@ -93,4 +94,5 @@ TextEditor::LanguageDefinition GetAssemblyLanguageDef() {
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
@@ -2,18 +2,72 @@
|
||||
#define YAZE_GUI_WIDGETS_H
|
||||
|
||||
#include <ImGuiColorTextEdit/TextEditor.h>
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/misc/cpp/imgui_stdlib.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
|
||||
TextEditor::LanguageDefinition GetAssemblyLanguageDef();
|
||||
|
||||
class BitmapViewer {
|
||||
public:
|
||||
BitmapViewer() : current_bitmap_index_(0) {}
|
||||
|
||||
void Display(const std::vector<gfx::Bitmap>& bitmaps) {
|
||||
if (bitmaps.empty()) {
|
||||
ImGui::Text("No bitmaps available.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Display the current bitmap index and total count.
|
||||
ImGui::Text("Viewing Bitmap %d / %zu", current_bitmap_index_ + 1,
|
||||
bitmaps.size());
|
||||
|
||||
// Buttons to navigate through bitmaps.
|
||||
if (ImGui::Button("<- Prev")) {
|
||||
if (current_bitmap_index_ > 0) {
|
||||
--current_bitmap_index_;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Next ->")) {
|
||||
if (current_bitmap_index_ < bitmaps.size() - 1) {
|
||||
++current_bitmap_index_;
|
||||
}
|
||||
}
|
||||
|
||||
// Display the current bitmap.
|
||||
const gfx::Bitmap& current_bitmap = bitmaps[current_bitmap_index_];
|
||||
// Assuming Bitmap has a function to get its texture ID, and width and
|
||||
// height.
|
||||
ImTextureID tex_id = current_bitmap.texture();
|
||||
ImVec2 size(current_bitmap.width(), current_bitmap.height());
|
||||
ImGui::Image(tex_id, size);
|
||||
|
||||
// Scroll if the image is larger than the display area.
|
||||
if (ImGui::BeginChild("BitmapScrollArea", ImVec2(0, 0), false,
|
||||
ImGuiWindowFlags_HorizontalScrollbar)) {
|
||||
ImGui::Image(tex_id, size);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int current_bitmap_index_;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
} // namespace gui
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
@@ -35,6 +38,57 @@ uint GetOwMapGfxLowPtr(const uchar *rom, int index, uint32_t map_low_ptr) {
|
||||
return core::SnesToPc(p2);
|
||||
}
|
||||
|
||||
absl::flat_hash_map<int, MapData> parseFile(const std::string &filename) {
|
||||
absl::flat_hash_map<int, MapData> resultMap;
|
||||
|
||||
std::ifstream file(filename);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open file: " << filename << std::endl;
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
int currentKey;
|
||||
bool isHigh = true;
|
||||
|
||||
while (getline(file, line)) {
|
||||
// Skip empty or whitespace-only lines
|
||||
if (line.find_first_not_of(" \t\r\n") == std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the line starts with "MAPDTH" or "MAPDTL", extract the ID.
|
||||
if (line.find("MAPDTH") == 0) {
|
||||
auto num_str = line.substr(6); // Extract ID after "MAPDTH"
|
||||
currentKey = std::stoi(num_str);
|
||||
isHigh = true;
|
||||
} else if (line.find("MAPDTL") == 0) {
|
||||
auto num_str = line.substr(6); // Extract ID after "MAPDTH"
|
||||
currentKey = std::stoi(num_str);
|
||||
isHigh = false;
|
||||
} else {
|
||||
// Check if the currentKey is already in the map. If not, initialize it.
|
||||
if (resultMap.find(currentKey) == resultMap.end()) {
|
||||
resultMap[currentKey] = MapData();
|
||||
}
|
||||
|
||||
// Split the line by commas and convert to uint8_t.
|
||||
std::stringstream ss(line);
|
||||
std::string valueStr;
|
||||
while (getline(ss, valueStr, ',')) {
|
||||
uint8_t value = std::stoi(valueStr, nullptr, 16);
|
||||
if (isHigh) {
|
||||
resultMap[currentKey].highData.push_back(value);
|
||||
} else {
|
||||
resultMap[currentKey].lowData.push_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
absl::Status Overworld::Load(ROM &rom) {
|
||||
@@ -463,6 +517,39 @@ absl::Status Overworld::DecompressAllMapTiles() {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status Overworld::DecompressProtoMapTiles(const std::string &filename) {
|
||||
proto_map_data_ = parseFile(filename);
|
||||
int sx = 0;
|
||||
int sy = 0;
|
||||
int c = 0;
|
||||
for (int i = 0; i < proto_map_data_.size(); i++) {
|
||||
int ttpos = 0;
|
||||
|
||||
ASSIGN_OR_RETURN(auto bytes, gfx::lc_lz2::DecompressOverworld(
|
||||
proto_map_data_[i].lowData, 0,
|
||||
proto_map_data_[i].lowData.size()))
|
||||
ASSIGN_OR_RETURN(auto bytes2, gfx::lc_lz2::DecompressOverworld(
|
||||
proto_map_data_[i].highData, 0,
|
||||
proto_map_data_[i].highData.size()))
|
||||
OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos);
|
||||
|
||||
sx++;
|
||||
if (sx >= 8) {
|
||||
sy++;
|
||||
sx = 0;
|
||||
}
|
||||
|
||||
c++;
|
||||
if (c >= 64) {
|
||||
sx = 0;
|
||||
sy = 0;
|
||||
c = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Overworld::FetchLargeMaps() {
|
||||
@@ -619,13 +706,13 @@ void Overworld::LoadSpritesFromMap(int spriteStart, int spriteCount,
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status Overworld::LoadPrototype(ROM &rom, std::vector<uint8_t> &tilemap,
|
||||
std::vector<uint8_t> tile32) {
|
||||
absl::Status Overworld::LoadPrototype(ROM &rom,
|
||||
const std::string &tilemap_filename) {
|
||||
rom_ = rom;
|
||||
|
||||
AssembleMap32Tiles();
|
||||
AssembleMap16Tiles();
|
||||
RETURN_IF_ERROR(DecompressAllMapTiles())
|
||||
RETURN_IF_ERROR(DecompressProtoMapTiles(tilemap_filename))
|
||||
|
||||
for (int map_index = 0; map_index < kNumOverworldMaps; ++map_index)
|
||||
overworld_maps_.emplace_back(map_index, rom_, tiles16);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
@@ -171,6 +172,11 @@ constexpr int LimitOfMap32 = 8864;
|
||||
constexpr int NumberOfOWSprites = 352;
|
||||
constexpr int NumberOfMap32 = Map32PerScreen * kNumOverworldMaps;
|
||||
|
||||
struct MapData {
|
||||
std::vector<uint8_t> highData;
|
||||
std::vector<uint8_t> lowData;
|
||||
};
|
||||
|
||||
class Overworld {
|
||||
public:
|
||||
absl::Status Load(ROM &rom);
|
||||
@@ -189,6 +195,9 @@ class Overworld {
|
||||
auto AreaPalette() const {
|
||||
return overworld_maps_[current_map_].AreaPalette();
|
||||
}
|
||||
auto AreaPaletteById(int id) const {
|
||||
return overworld_maps_[id].AreaPalette();
|
||||
}
|
||||
auto BitmapData() const { return overworld_maps_[current_map_].BitmapData(); }
|
||||
auto Tile16Blockset() const {
|
||||
return overworld_maps_[current_map_].Tile16Blockset();
|
||||
@@ -197,8 +206,7 @@ class Overworld {
|
||||
auto isLoaded() const { return is_loaded_; }
|
||||
void SetCurrentMap(int i) { current_map_ = i; }
|
||||
|
||||
absl::Status LoadPrototype(ROM &rom_, std::vector<uint8_t> &tilemap,
|
||||
std::vector<uint8_t> tile32);
|
||||
absl::Status LoadPrototype(ROM &rom_, const std::string &tilemap_filename);
|
||||
|
||||
private:
|
||||
enum Dimension {
|
||||
@@ -216,13 +224,12 @@ class Overworld {
|
||||
void OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx, int sy,
|
||||
int &ttpos);
|
||||
absl::Status DecompressAllMapTiles();
|
||||
absl::Status DecompressProtoMapTiles(const std::string &filename);
|
||||
void FetchLargeMaps();
|
||||
void LoadEntrances();
|
||||
void LoadSprites();
|
||||
void LoadSpritesFromMap(int spriteStart, int spriteCount, int spriteIndex);
|
||||
|
||||
void LoadOverworldMap();
|
||||
|
||||
int game_state_ = 0;
|
||||
int current_map_ = 0;
|
||||
uchar map_parent_[160];
|
||||
@@ -238,6 +245,8 @@ class Overworld {
|
||||
std::vector<OverworldEntrance> all_entrances_;
|
||||
std::vector<OverworldEntrance> all_holes_;
|
||||
std::vector<std::vector<Sprite>> all_sprites_;
|
||||
|
||||
absl::flat_hash_map<int, MapData> proto_map_data_;
|
||||
};
|
||||
|
||||
} // namespace zelda3
|
||||
|
||||
Reference in New Issue
Block a user